Mercurial > hg > orthanc
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, ¶meters)) | 171 |
150 { | 172 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess1, ¶meters)) |
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, ¶meters)) | 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, ¶meters)) | |
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, ¶meters)) | 213 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess14, ¶meters)) |
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, ¶meters)) | 228 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess14SV1, ¶meters)) |
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, ¶meters)) | 248 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGLSLossless, ¶meters)) |
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, ¶meters)) | 269 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGLSLossy, ¶meters)) |
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 } |