comparison OrthancFramework/Sources/DicomParsing/DcmtkTranscoder.cpp @ 5480:58b91f5f4e79

more detailed log if InPlaceTranscode fails
author Alain Mazy <am@osimis.io>
date Thu, 21 Dec 2023 15:33:59 +0100
parents 0ea402b4d901
children 48b8dae6dc77
comparison
equal deleted inserted replaced
5479:dc8e5c65be99 5480:58b91f5f4e79
35 35
36 36
37 #include "FromDcmtkBridge.h" 37 #include "FromDcmtkBridge.h"
38 #include "../Logging.h" 38 #include "../Logging.h"
39 #include "../OrthancException.h" 39 #include "../OrthancException.h"
40 #include "../Toolbox.h"
40 41
41 #include <dcmtk/dcmdata/dcdeftag.h> 42 #include <dcmtk/dcmdata/dcdeftag.h>
42 #include <dcmtk/dcmjpeg/djrploss.h> // for DJ_RPLossy 43 #include <dcmtk/dcmjpeg/djrploss.h> // for DJ_RPLossy
43 #include <dcmtk/dcmjpeg/djrplol.h> // for DJ_RPLossless 44 #include <dcmtk/dcmjpeg/djrplol.h> // for DJ_RPLossless
44 #include <dcmtk/dcmjpls/djrparam.h> // for DJLSRepresentationParameter 45 #include <dcmtk/dcmjpls/djrparam.h> // for DJLSRepresentationParameter
81 unsigned int DcmtkTranscoder::GetLossyQuality() const 82 unsigned int DcmtkTranscoder::GetLossyQuality() const
82 { 83 {
83 return lossyQuality_; 84 return lossyQuality_;
84 } 85 }
85 86
87 bool TryTranscode(std::vector<std::string>& failureReasons, /* out */
88 DicomTransferSyntax& selectedSyntax, /* out*/
89 DcmFileFormat& dicom, /* in/out */
90 const std::set<DicomTransferSyntax>& allowedSyntaxes,
91 DicomTransferSyntax trySyntax)
92 {
93 if (allowedSyntaxes.find(trySyntax) != allowedSyntaxes.end())
94 {
95 if (FromDcmtkBridge::Transcode(dicom, trySyntax, NULL))
96 {
97 selectedSyntax = trySyntax;
98 return true;
99 }
100
101 failureReasons.push_back(std::string("Internal error while transcoding to ") + GetTransferSyntaxUid(trySyntax));
102 }
103 return false;
104 }
86 105
87 bool DcmtkTranscoder::InplaceTranscode(DicomTransferSyntax& selectedSyntax /* out */, 106 bool DcmtkTranscoder::InplaceTranscode(DicomTransferSyntax& selectedSyntax /* out */,
88 DcmFileFormat& dicom, 107 std::string& failureReason /* out */,
108 DcmFileFormat& dicom, /* in/out */
89 const std::set<DicomTransferSyntax>& allowedSyntaxes, 109 const std::set<DicomTransferSyntax>& allowedSyntaxes,
90 bool allowNewSopInstanceUid) 110 bool allowNewSopInstanceUid)
91 { 111 {
112 std::vector<std::string> failureReasons;
113
92 if (dicom.getDataset() == NULL) 114 if (dicom.getDataset() == NULL)
93 { 115 {
94 throw OrthancException(ErrorCode_InternalError); 116 throw OrthancException(ErrorCode_InternalError);
95 } 117 }
96 118
107 if (allowedSyntaxes.find(syntax) != allowedSyntaxes.end()) 129 if (allowedSyntaxes.find(syntax) != allowedSyntaxes.end())
108 { 130 {
109 // No transcoding is needed 131 // No transcoding is needed
110 return true; 132 return true;
111 } 133 }
112 134
113 if (allowedSyntaxes.find(DicomTransferSyntax_LittleEndianImplicit) != allowedSyntaxes.end() && 135 if (TryTranscode(failureReasons, selectedSyntax, dicom, allowedSyntaxes, DicomTransferSyntax_LittleEndianImplicit))
114 FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_LittleEndianImplicit, NULL)) 136 {
115 { 137 return true;
116 selectedSyntax = DicomTransferSyntax_LittleEndianImplicit; 138 }
117 return true; 139
118 } 140 if (TryTranscode(failureReasons, selectedSyntax, dicom, allowedSyntaxes, DicomTransferSyntax_LittleEndianExplicit))
119 141 {
120 if (allowedSyntaxes.find(DicomTransferSyntax_LittleEndianExplicit) != allowedSyntaxes.end() && 142 return true;
121 FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_LittleEndianExplicit, NULL)) 143 }
122 { 144
123 selectedSyntax = DicomTransferSyntax_LittleEndianExplicit; 145 if (TryTranscode(failureReasons, selectedSyntax, dicom, allowedSyntaxes, DicomTransferSyntax_BigEndianExplicit))
124 return true; 146 {
125 } 147 return true;
126 148 }
127 if (allowedSyntaxes.find(DicomTransferSyntax_BigEndianExplicit) != allowedSyntaxes.end() && 149
128 FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_BigEndianExplicit, NULL)) 150 if (TryTranscode(failureReasons, selectedSyntax, dicom, allowedSyntaxes, DicomTransferSyntax_DeflatedLittleEndianExplicit))
129 { 151 {
130 selectedSyntax = DicomTransferSyntax_BigEndianExplicit; 152 return true;
131 return true; 153 }
132 } 154
133 155
134 if (allowedSyntaxes.find(DicomTransferSyntax_DeflatedLittleEndianExplicit) != allowedSyntaxes.end() && 156 #if ORTHANC_ENABLE_DCMTK_JPEG == 1
135 FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_DeflatedLittleEndianExplicit, NULL)) 157 if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess1) != allowedSyntaxes.end())
136 { 158 {
137 selectedSyntax = DicomTransferSyntax_DeflatedLittleEndianExplicit; 159 if (!allowNewSopInstanceUid)
138 return true; 160 {
139 } 161 failureReasons.push_back(std::string("Can not transcode to ") + GetTransferSyntaxUid(DicomTransferSyntax_JPEGProcess1) + " without generating new SOPInstanceUID");
140 162 }
141 #if ORTHANC_ENABLE_DCMTK_JPEG == 1 163 else if (hasBitsStored && bitsStored != 8)
142 if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess1) != allowedSyntaxes.end() && 164 {
143 allowNewSopInstanceUid && 165 failureReasons.push_back(std::string("Can not transcode to ") + GetTransferSyntaxUid(DicomTransferSyntax_JPEGProcess1) + " if BitsStored != 8");
144 (!hasBitsStored || bitsStored == 8)) 166 }
145 { 167 else
146 // Check out "dcmjpeg/apps/dcmcjpeg.cc" 168 {
147 DJ_RPLossy parameters(lossyQuality_); 169 // Check out "dcmjpeg/apps/dcmcjpeg.cc"
148 170 DJ_RPLossy parameters(lossyQuality_);
149 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess1, &parameters)) 171
150 { 172 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess1, &parameters))
151 selectedSyntax = DicomTransferSyntax_JPEGProcess1; 173 {
152 return true; 174 selectedSyntax = DicomTransferSyntax_JPEGProcess1;
153 } 175 return true;
154 } 176 }
155 #endif 177 failureReasons.push_back(std::string("Internal error while transcoding to ") + GetTransferSyntaxUid(DicomTransferSyntax_JPEGProcess1));
156 178 }
157 #if ORTHANC_ENABLE_DCMTK_JPEG == 1 179 }
158 if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess2_4) != allowedSyntaxes.end() && 180 #endif
159 allowNewSopInstanceUid && 181
160 (!hasBitsStored || bitsStored <= 12)) 182 #if ORTHANC_ENABLE_DCMTK_JPEG == 1
161 { 183 if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess2_4) != allowedSyntaxes.end())
162 // Check out "dcmjpeg/apps/dcmcjpeg.cc" 184 {
163 DJ_RPLossy parameters(lossyQuality_); 185 if (!allowNewSopInstanceUid)
164 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess2_4, &parameters)) 186 {
165 { 187 failureReasons.push_back(std::string("Can not transcode to ") + GetTransferSyntaxUid(DicomTransferSyntax_JPEGProcess2_4) + " without generating new SOPInstanceUID");
166 selectedSyntax = DicomTransferSyntax_JPEGProcess2_4; 188 }
167 return true; 189 else if (hasBitsStored && bitsStored > 12)
190 {
191 failureReasons.push_back(std::string("Can not transcode to ") + GetTransferSyntaxUid(DicomTransferSyntax_JPEGProcess2_4) + " if BitsStored != 8");
192 }
193 else
194 {
195 // Check out "dcmjpeg/apps/dcmcjpeg.cc"
196 DJ_RPLossy parameters(lossyQuality_);
197 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess2_4, &parameters))
198 {
199 selectedSyntax = DicomTransferSyntax_JPEGProcess2_4;
200 return true;
201 }
202 failureReasons.push_back(std::string("Internal error while transcoding to ") + GetTransferSyntaxUid(DicomTransferSyntax_JPEGProcess2_4));
168 } 203 }
169 } 204 }
170 #endif 205 #endif
171 206
172 #if ORTHANC_ENABLE_DCMTK_JPEG == 1 207 #if ORTHANC_ENABLE_DCMTK_JPEG == 1
178 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess14, &parameters)) 213 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess14, &parameters))
179 { 214 {
180 selectedSyntax = DicomTransferSyntax_JPEGProcess14; 215 selectedSyntax = DicomTransferSyntax_JPEGProcess14;
181 return true; 216 return true;
182 } 217 }
218 failureReasons.push_back(std::string("Internal error while transcoding to ") + GetTransferSyntaxUid(DicomTransferSyntax_JPEGProcess14));
183 } 219 }
184 #endif 220 #endif
185 221
186 #if ORTHANC_ENABLE_DCMTK_JPEG == 1 222 #if ORTHANC_ENABLE_DCMTK_JPEG == 1
187 if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess14SV1) != allowedSyntaxes.end()) 223 if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess14SV1) != allowedSyntaxes.end())
192 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess14SV1, &parameters)) 228 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess14SV1, &parameters))
193 { 229 {
194 selectedSyntax = DicomTransferSyntax_JPEGProcess14SV1; 230 selectedSyntax = DicomTransferSyntax_JPEGProcess14SV1;
195 return true; 231 return true;
196 } 232 }
233 failureReasons.push_back(std::string("Internal error while transcoding to ") + GetTransferSyntaxUid(DicomTransferSyntax_JPEGProcess14SV1));
197 } 234 }
198 #endif 235 #endif
199 236
200 #if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1 237 #if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1
201 if (allowedSyntaxes.find(DicomTransferSyntax_JPEGLSLossless) != allowedSyntaxes.end()) 238 if (allowedSyntaxes.find(DicomTransferSyntax_JPEGLSLossless) != allowedSyntaxes.end())
211 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGLSLossless, &parameters)) 248 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGLSLossless, &parameters))
212 { 249 {
213 selectedSyntax = DicomTransferSyntax_JPEGLSLossless; 250 selectedSyntax = DicomTransferSyntax_JPEGLSLossless;
214 return true; 251 return true;
215 } 252 }
253 failureReasons.push_back(std::string("Internal error while transcoding to ") + GetTransferSyntaxUid(DicomTransferSyntax_JPEGLSLossless));
216 } 254 }
217 #endif 255 #endif
218 256
219 #if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1 257 #if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1
220 if (allowNewSopInstanceUid && 258 if (allowNewSopInstanceUid &&
231 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGLSLossy, &parameters)) 269 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGLSLossy, &parameters))
232 { 270 {
233 selectedSyntax = DicomTransferSyntax_JPEGLSLossy; 271 selectedSyntax = DicomTransferSyntax_JPEGLSLossy;
234 return true; 272 return true;
235 } 273 }
236 } 274 failureReasons.push_back(std::string("Internal error while transcoding to ") + GetTransferSyntaxUid(DicomTransferSyntax_JPEGLSLossy));
237 #endif 275 }
238 276 #endif
277
278 Orthanc::Toolbox::JoinStrings(failureReason, failureReasons, ", ");
239 return false; 279 return false;
240 } 280 }
241 281
242 bool DcmtkTranscoder::IsSupported(DicomTransferSyntax syntax) 282 bool DcmtkTranscoder::IsSupported(DicomTransferSyntax syntax)
243 { 283 {
283 { 323 {
284 LOG(ERROR) << "Unsupport transfer syntax for transcoding"; 324 LOG(ERROR) << "Unsupport transfer syntax for transcoding";
285 return false; 325 return false;
286 } 326 }
287 327
288 { 328 std::string failureReason;
289 std::string s; 329 std::string s;
290 for (std::set<DicomTransferSyntax>::const_iterator 330 for (std::set<DicomTransferSyntax>::const_iterator
291 it = allowedSyntaxes.begin(); it != allowedSyntaxes.end(); ++it) 331 it = allowedSyntaxes.begin(); it != allowedSyntaxes.end(); ++it)
292 { 332 {
293 if (!s.empty()) 333 if (!s.empty())
294 { 334 {
295 s += ", "; 335 s += ", ";
296 } 336 }
297 337
298 s += GetTransferSyntaxUid(*it); 338 s += GetTransferSyntaxUid(*it);
299 } 339 }
300 340
301 if (s.empty()) 341 if (s.empty())
302 { 342 {
303 s = "<none>"; 343 s = "<none>";
304 } 344 }
305 345
306 LOG(INFO) << "DCMTK transcoding from " << GetTransferSyntaxUid(sourceSyntax) 346 LOG(INFO) << "DCMTK transcoding from " << GetTransferSyntaxUid(sourceSyntax)
307 << " to one of: " << s; 347 << " to one of: " << s;
308 }
309 348
310 #if !defined(NDEBUG) 349 #if !defined(NDEBUG)
311 const std::string sourceSopInstanceUid = GetSopInstanceUid(source.GetParsed()); 350 const std::string sourceSopInstanceUid = GetSopInstanceUid(source.GetParsed());
312 #endif 351 #endif
313 352
317 // No transcoding is needed 356 // No transcoding is needed
318 target.AcquireParsed(source); 357 target.AcquireParsed(source);
319 target.AcquireBuffer(source); 358 target.AcquireBuffer(source);
320 return true; 359 return true;
321 } 360 }
322 else if (InplaceTranscode(targetSyntax, source.GetParsed(), 361 else if (InplaceTranscode(targetSyntax, failureReason, source.GetParsed(),
323 allowedSyntaxes, allowNewSopInstanceUid)) 362 allowedSyntaxes, allowNewSopInstanceUid))
324 { 363 {
325 // Sanity check 364 // Sanity check
326 DicomTransferSyntax targetSyntax2; 365 DicomTransferSyntax targetSyntax2;
327 if (FromDcmtkBridge::LookupOrthancTransferSyntax(targetSyntax2, source.GetParsed()) && 366 if (FromDcmtkBridge::LookupOrthancTransferSyntax(targetSyntax2, source.GetParsed()) &&
345 } 384 }
346 } 385 }
347 else 386 else
348 { 387 {
349 // Cannot transcode 388 // Cannot transcode
389 LOG(WARNING) << "DCMTK was unable to transcode from " << GetTransferSyntaxUid(sourceSyntax)
390 << " to one of: " << s << " " << failureReason;
350 return false; 391 return false;
351 } 392 }
352 } 393 }
353 } 394 }