Mercurial > hg > orthanc
comparison Core/DicomParsing/DcmtkTranscoder.cpp @ 3946:1f33ed7f82e6 transcoding
automatic test of transcoding
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 19 May 2020 13:44:56 +0200 |
parents | 0b3256c3ee14 |
children | 5fe8c6d3212e |
comparison
equal
deleted
inserted
replaced
3945:0b3256c3ee14 | 3946:1f33ed7f82e6 |
---|---|
60 { | 60 { |
61 return dataset.findAndGetUint16(DCM_BitsStored, bitsStored).good(); | 61 return dataset.findAndGetUint16(DCM_BitsStored, bitsStored).good(); |
62 } | 62 } |
63 | 63 |
64 | 64 |
65 static std::string GetSopInstanceUid(DcmDataset& dataset) | |
66 { | |
67 const char* v = NULL; | |
68 | |
69 if (dataset.findAndGetString(DCM_SOPInstanceUID, v).good() && | |
70 v != NULL) | |
71 { | |
72 return std::string(v); | |
73 } | |
74 else | |
75 { | |
76 throw OrthancException(ErrorCode_BadFileFormat, "File without SOP instance UID"); | |
77 } | |
78 } | |
79 | |
80 | |
81 static void CheckSopInstanceUid(DcmFileFormat& dicom, | |
82 const std::string& sopInstanceUid, | |
83 bool mustEqual) | |
84 { | |
85 if (dicom.getDataset() == NULL) | |
86 { | |
87 throw OrthancException(ErrorCode_InternalError); | |
88 } | |
89 | |
90 bool ok; | |
91 | |
92 if (dicom.getDataset()->tagExists(DCM_PixelData)) | |
93 { | |
94 if (mustEqual) | |
95 { | |
96 ok = (GetSopInstanceUid(*dicom.getDataset()) == sopInstanceUid); | |
97 } | |
98 else | |
99 { | |
100 ok = (GetSopInstanceUid(*dicom.getDataset()) != sopInstanceUid); | |
101 } | |
102 } | |
103 else | |
104 { | |
105 // No pixel data: Transcoding must not change the SOP instance UID | |
106 ok = (GetSopInstanceUid(*dicom.getDataset()) == sopInstanceUid); | |
107 } | |
108 | |
109 if (!ok) | |
110 { | |
111 throw OrthancException(ErrorCode_InternalError, | |
112 mustEqual ? "The SOP instance UID has changed unexpectedly during transcoding" : | |
113 "The SOP instance UID has not changed as expected during transcoding"); | |
114 } | |
115 } | |
116 | |
117 | |
118 void DcmtkTranscoder::SetLossyQuality(unsigned int quality) | 65 void DcmtkTranscoder::SetLossyQuality(unsigned int quality) |
119 { | 66 { |
120 if (quality <= 0 || | 67 if (quality <= 0 || |
121 quality > 100) | 68 quality > 100) |
122 { | 69 { |
132 } | 79 } |
133 } | 80 } |
134 | 81 |
135 | 82 |
136 bool DcmtkTranscoder::InplaceTranscode(bool& hasSopInstanceUidChanged /* out */, | 83 bool DcmtkTranscoder::InplaceTranscode(bool& hasSopInstanceUidChanged /* out */, |
84 DicomTransferSyntax& selectedSyntax /* out */, | |
137 DcmFileFormat& dicom, | 85 DcmFileFormat& dicom, |
138 const std::set<DicomTransferSyntax>& allowedSyntaxes, | 86 const std::set<DicomTransferSyntax>& allowedSyntaxes, |
139 bool allowNewSopInstanceUid) | 87 bool allowNewSopInstanceUid) |
140 { | 88 { |
141 if (dicom.getDataset() == NULL) | 89 if (dicom.getDataset() == NULL) |
153 } | 101 } |
154 | 102 |
155 uint16_t bitsStored; | 103 uint16_t bitsStored; |
156 bool hasBitsStored = GetBitsStored(bitsStored, *dicom.getDataset()); | 104 bool hasBitsStored = GetBitsStored(bitsStored, *dicom.getDataset()); |
157 | 105 |
158 std::string sourceSopInstanceUid = GetSopInstanceUid(*dicom.getDataset()); | 106 std::string sourceSopInstanceUid = IDicomTranscoder::GetSopInstanceUid(dicom); |
159 | 107 |
160 if (allowedSyntaxes.find(syntax) != allowedSyntaxes.end()) | 108 if (allowedSyntaxes.find(syntax) != allowedSyntaxes.end()) |
161 { | 109 { |
162 // No transcoding is needed | 110 // No transcoding is needed |
163 return true; | 111 return true; |
164 } | 112 } |
165 | 113 |
166 if (allowedSyntaxes.find(DicomTransferSyntax_LittleEndianImplicit) != allowedSyntaxes.end() && | 114 if (allowedSyntaxes.find(DicomTransferSyntax_LittleEndianImplicit) != allowedSyntaxes.end() && |
167 FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_LittleEndianImplicit, NULL)) | 115 FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_LittleEndianImplicit, NULL)) |
168 { | 116 { |
169 CheckSopInstanceUid(dicom, sourceSopInstanceUid, true); | 117 selectedSyntax = DicomTransferSyntax_LittleEndianImplicit; |
170 return true; | 118 return true; |
171 } | 119 } |
172 | 120 |
173 if (allowedSyntaxes.find(DicomTransferSyntax_LittleEndianExplicit) != allowedSyntaxes.end() && | 121 if (allowedSyntaxes.find(DicomTransferSyntax_LittleEndianExplicit) != allowedSyntaxes.end() && |
174 FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_LittleEndianExplicit, NULL)) | 122 FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_LittleEndianExplicit, NULL)) |
175 { | 123 { |
176 CheckSopInstanceUid(dicom, sourceSopInstanceUid, true); | 124 selectedSyntax = DicomTransferSyntax_LittleEndianExplicit; |
177 return true; | 125 return true; |
178 } | 126 } |
179 | 127 |
180 if (allowedSyntaxes.find(DicomTransferSyntax_BigEndianExplicit) != allowedSyntaxes.end() && | 128 if (allowedSyntaxes.find(DicomTransferSyntax_BigEndianExplicit) != allowedSyntaxes.end() && |
181 FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_BigEndianExplicit, NULL)) | 129 FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_BigEndianExplicit, NULL)) |
182 { | 130 { |
183 CheckSopInstanceUid(dicom, sourceSopInstanceUid, true); | 131 selectedSyntax = DicomTransferSyntax_BigEndianExplicit; |
184 return true; | 132 return true; |
185 } | 133 } |
186 | 134 |
187 if (allowedSyntaxes.find(DicomTransferSyntax_DeflatedLittleEndianExplicit) != allowedSyntaxes.end() && | 135 if (allowedSyntaxes.find(DicomTransferSyntax_DeflatedLittleEndianExplicit) != allowedSyntaxes.end() && |
188 FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_DeflatedLittleEndianExplicit, NULL)) | 136 FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_DeflatedLittleEndianExplicit, NULL)) |
189 { | 137 { |
190 CheckSopInstanceUid(dicom, sourceSopInstanceUid, true); | 138 selectedSyntax = DicomTransferSyntax_DeflatedLittleEndianExplicit; |
191 return true; | 139 return true; |
192 } | 140 } |
193 | 141 |
194 #if ORTHANC_ENABLE_DCMTK_JPEG == 1 | 142 #if ORTHANC_ENABLE_DCMTK_JPEG == 1 |
195 if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess1) != allowedSyntaxes.end() && | 143 if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess1) != allowedSyntaxes.end() && |
199 // Check out "dcmjpeg/apps/dcmcjpeg.cc" | 147 // Check out "dcmjpeg/apps/dcmcjpeg.cc" |
200 DJ_RPLossy parameters(lossyQuality_); | 148 DJ_RPLossy parameters(lossyQuality_); |
201 | 149 |
202 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess1, ¶meters)) | 150 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess1, ¶meters)) |
203 { | 151 { |
204 CheckSopInstanceUid(dicom, sourceSopInstanceUid, false); | 152 selectedSyntax = DicomTransferSyntax_JPEGProcess1; |
205 hasSopInstanceUidChanged = true; | 153 hasSopInstanceUidChanged = true; |
206 return true; | 154 return true; |
207 } | 155 } |
208 } | 156 } |
209 #endif | 157 #endif |
215 { | 163 { |
216 // Check out "dcmjpeg/apps/dcmcjpeg.cc" | 164 // Check out "dcmjpeg/apps/dcmcjpeg.cc" |
217 DJ_RPLossy parameters(lossyQuality_); | 165 DJ_RPLossy parameters(lossyQuality_); |
218 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess2_4, ¶meters)) | 166 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess2_4, ¶meters)) |
219 { | 167 { |
220 CheckSopInstanceUid(dicom, sourceSopInstanceUid, false); | 168 selectedSyntax = DicomTransferSyntax_JPEGProcess2_4; |
221 hasSopInstanceUidChanged = true; | 169 hasSopInstanceUidChanged = true; |
222 return true; | 170 return true; |
223 } | 171 } |
224 } | 172 } |
225 #endif | 173 #endif |
230 // Check out "dcmjpeg/apps/dcmcjpeg.cc" | 178 // Check out "dcmjpeg/apps/dcmcjpeg.cc" |
231 DJ_RPLossless parameters(6 /* opt_selection_value */, | 179 DJ_RPLossless parameters(6 /* opt_selection_value */, |
232 0 /* opt_point_transform */); | 180 0 /* opt_point_transform */); |
233 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess14, ¶meters)) | 181 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess14, ¶meters)) |
234 { | 182 { |
235 CheckSopInstanceUid(dicom, sourceSopInstanceUid, true); | 183 selectedSyntax = DicomTransferSyntax_JPEGProcess14; |
236 return true; | 184 return true; |
237 } | 185 } |
238 } | 186 } |
239 #endif | 187 #endif |
240 | 188 |
244 // Check out "dcmjpeg/apps/dcmcjpeg.cc" | 192 // Check out "dcmjpeg/apps/dcmcjpeg.cc" |
245 DJ_RPLossless parameters(6 /* opt_selection_value */, | 193 DJ_RPLossless parameters(6 /* opt_selection_value */, |
246 0 /* opt_point_transform */); | 194 0 /* opt_point_transform */); |
247 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess14SV1, ¶meters)) | 195 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess14SV1, ¶meters)) |
248 { | 196 { |
249 CheckSopInstanceUid(dicom, sourceSopInstanceUid, true); | 197 selectedSyntax = DicomTransferSyntax_JPEGProcess14SV1; |
250 return true; | 198 return true; |
251 } | 199 } |
252 } | 200 } |
253 #endif | 201 #endif |
254 | 202 |
263 * WARNING: This call results in a segmentation fault if using | 211 * WARNING: This call results in a segmentation fault if using |
264 * the DCMTK package 3.6.2 from Ubuntu 18.04. | 212 * the DCMTK package 3.6.2 from Ubuntu 18.04. |
265 **/ | 213 **/ |
266 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGLSLossless, ¶meters)) | 214 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGLSLossless, ¶meters)) |
267 { | 215 { |
268 CheckSopInstanceUid(dicom, sourceSopInstanceUid, true); | 216 selectedSyntax = DicomTransferSyntax_JPEGLSLossless; |
269 return true; | 217 return true; |
270 } | 218 } |
271 } | 219 } |
272 #endif | 220 #endif |
273 | 221 |
283 * WARNING: This call results in a segmentation fault if using | 231 * WARNING: This call results in a segmentation fault if using |
284 * the DCMTK package 3.6.2 from Ubuntu 18.04. | 232 * the DCMTK package 3.6.2 from Ubuntu 18.04. |
285 **/ | 233 **/ |
286 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGLSLossy, ¶meters)) | 234 if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGLSLossy, ¶meters)) |
287 { | 235 { |
288 CheckSopInstanceUid(dicom, sourceSopInstanceUid, false); | 236 selectedSyntax = DicomTransferSyntax_JPEGLSLossy; |
289 hasSopInstanceUidChanged = true; | 237 hasSopInstanceUidChanged = true; |
290 return true; | 238 return true; |
291 } | 239 } |
292 } | 240 } |
293 #endif | 241 #endif |
341 { | 289 { |
342 LOG(ERROR) << "Unsupport transfer syntax for transcoding"; | 290 LOG(ERROR) << "Unsupport transfer syntax for transcoding"; |
343 return false; | 291 return false; |
344 } | 292 } |
345 | 293 |
294 #if !defined(NDEBUG) | |
295 const std::string sourceSopInstanceUid = GetSopInstanceUid(source.GetParsed()); | |
296 #endif | |
297 | |
298 DicomTransferSyntax targetSyntax; | |
346 if (allowedSyntaxes.find(sourceSyntax) != allowedSyntaxes.end()) | 299 if (allowedSyntaxes.find(sourceSyntax) != allowedSyntaxes.end()) |
347 { | 300 { |
348 // No transcoding is needed | 301 // No transcoding is needed |
349 target.AcquireParsed(source); | 302 target.AcquireParsed(source); |
350 target.AcquireBuffer(source); | 303 target.AcquireBuffer(source); |
351 return true; | 304 return true; |
352 } | 305 } |
353 else if (InplaceTranscode(hasSopInstanceUidChanged, source.GetParsed(), | 306 else if (InplaceTranscode(hasSopInstanceUidChanged, targetSyntax, source.GetParsed(), |
354 allowedSyntaxes, allowNewSopInstanceUid)) | 307 allowedSyntaxes, allowNewSopInstanceUid)) |
355 { | 308 { |
356 // Sanity check | 309 // Sanity check |
357 DicomTransferSyntax targetSyntax; | 310 DicomTransferSyntax targetSyntax2; |
358 if (FromDcmtkBridge::LookupOrthancTransferSyntax(targetSyntax, source.GetParsed()) && | 311 if (FromDcmtkBridge::LookupOrthancTransferSyntax(targetSyntax2, source.GetParsed()) && |
359 allowedSyntaxes.find(targetSyntax) != allowedSyntaxes.end()) | 312 targetSyntax == targetSyntax2 && |
313 allowedSyntaxes.find(targetSyntax2) != allowedSyntaxes.end()) | |
360 { | 314 { |
361 target.AcquireParsed(source); | 315 target.AcquireParsed(source); |
362 source.Clear(); | 316 source.Clear(); |
317 | |
318 #if !defined(NDEBUG) | |
319 // Only run the sanity check in debug mode | |
320 CheckTranscoding(target, hasSopInstanceUidChanged, sourceSyntax, sourceSopInstanceUid, | |
321 allowedSyntaxes, allowNewSopInstanceUid); | |
322 #endif | |
323 | |
363 return true; | 324 return true; |
364 } | 325 } |
365 else | 326 else |
366 { | 327 { |
367 throw OrthancException(ErrorCode_InternalError); | 328 throw OrthancException(ErrorCode_InternalError); |