Mercurial > hg > orthanc
comparison OrthancFramework/Resources/Graveyard/TestTranscoding.cpp @ 4044:d25f4c0fa160 framework
splitting code into OrthancFramework and OrthancServer
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 10 Jun 2020 20:30:34 +0200 |
parents | Resources/Graveyard/TestTranscoding.cpp@e23026566536 |
children | 304842a0d152 |
comparison
equal
deleted
inserted
replaced
4043:6c6239aec462 | 4044:d25f4c0fa160 |
---|---|
1 bool FromDcmtkBridge::SaveToMemoryBuffer(std::string& buffer, | |
2 DcmFileFormat& dicom, | |
3 DicomTransferSyntax syntax) | |
4 { | |
5 E_TransferSyntax xfer; | |
6 if (!LookupDcmtkTransferSyntax(xfer, syntax)) | |
7 { | |
8 return false; | |
9 } | |
10 else if (!dicom.validateMetaInfo(xfer).good()) | |
11 { | |
12 throw OrthancException(ErrorCode_InternalError, | |
13 "Cannot setup the transfer syntax to write a DICOM instance"); | |
14 } | |
15 else | |
16 { | |
17 return SaveToMemoryBufferInternal(buffer, dicom, xfer); | |
18 } | |
19 } | |
20 | |
21 | |
22 bool FromDcmtkBridge::SaveToMemoryBuffer(std::string& buffer, | |
23 DcmFileFormat& dicom) | |
24 { | |
25 E_TransferSyntax xfer = dicom.getDataset()->getCurrentXfer(); | |
26 if (xfer == EXS_Unknown) | |
27 { | |
28 throw OrthancException(ErrorCode_InternalError, | |
29 "Cannot write a DICOM instance with unknown transfer syntax"); | |
30 } | |
31 else if (!dicom.validateMetaInfo(xfer).good()) | |
32 { | |
33 throw OrthancException(ErrorCode_InternalError, | |
34 "Cannot setup the transfer syntax to write a DICOM instance"); | |
35 } | |
36 else | |
37 { | |
38 return SaveToMemoryBufferInternal(buffer, dicom, xfer); | |
39 } | |
40 } | |
41 | |
42 | |
43 | |
44 | |
45 | |
46 #include <dcmtk/dcmdata/dcostrmb.h> | |
47 #include <dcmtk/dcmdata/dcpixel.h> | |
48 #include <dcmtk/dcmdata/dcpxitem.h> | |
49 | |
50 #include "../Core/DicomParsing/Internals/DicomFrameIndex.h" | |
51 | |
52 namespace Orthanc | |
53 { | |
54 class IParsedDicomImage : public boost::noncopyable | |
55 { | |
56 public: | |
57 virtual ~IParsedDicomImage() | |
58 { | |
59 } | |
60 | |
61 virtual DicomTransferSyntax GetTransferSyntax() = 0; | |
62 | |
63 virtual std::string GetSopClassUid() = 0; | |
64 | |
65 virtual std::string GetSopInstanceUid() = 0; | |
66 | |
67 virtual unsigned int GetFramesCount() = 0; | |
68 | |
69 // Can return NULL, for compressed transfer syntaxes | |
70 virtual ImageAccessor* GetUncompressedFrame(unsigned int frame) = 0; | |
71 | |
72 virtual void GetCompressedFrame(std::string& target, | |
73 unsigned int frame) = 0; | |
74 | |
75 virtual void WriteToMemoryBuffer(std::string& target) = 0; | |
76 }; | |
77 | |
78 | |
79 class IDicomImageReader : public boost::noncopyable | |
80 { | |
81 public: | |
82 virtual ~IDicomImageReader() | |
83 { | |
84 } | |
85 | |
86 virtual IParsedDicomImage* Read(const void* data, | |
87 size_t size) = 0; | |
88 | |
89 virtual IParsedDicomImage* Transcode(const void* data, | |
90 size_t size, | |
91 DicomTransferSyntax syntax, | |
92 bool allowNewSopInstanceUid) = 0; | |
93 }; | |
94 | |
95 | |
96 class DcmtkImageReader : public IDicomImageReader | |
97 { | |
98 private: | |
99 class Image : public IParsedDicomImage | |
100 { | |
101 private: | |
102 std::unique_ptr<DcmFileFormat> dicom_; | |
103 std::unique_ptr<DicomFrameIndex> index_; | |
104 DicomTransferSyntax transferSyntax_; | |
105 std::string sopClassUid_; | |
106 std::string sopInstanceUid_; | |
107 | |
108 static std::string GetStringTag(DcmDataset& dataset, | |
109 const DcmTagKey& tag) | |
110 { | |
111 const char* value = NULL; | |
112 | |
113 if (!dataset.findAndGetString(tag, value).good() || | |
114 value == NULL) | |
115 { | |
116 throw OrthancException(ErrorCode_BadFileFormat, | |
117 "Missing SOP class/instance UID in DICOM instance"); | |
118 } | |
119 else | |
120 { | |
121 return std::string(value); | |
122 } | |
123 } | |
124 | |
125 public: | |
126 Image(DcmFileFormat* dicom, | |
127 DicomTransferSyntax syntax) : | |
128 dicom_(dicom), | |
129 transferSyntax_(syntax) | |
130 { | |
131 if (dicom == NULL || | |
132 dicom_->getDataset() == NULL) | |
133 { | |
134 throw OrthancException(ErrorCode_NullPointer); | |
135 } | |
136 | |
137 DcmDataset& dataset = *dicom_->getDataset(); | |
138 index_.reset(new DicomFrameIndex(dataset)); | |
139 | |
140 sopClassUid_ = GetStringTag(dataset, DCM_SOPClassUID); | |
141 sopInstanceUid_ = GetStringTag(dataset, DCM_SOPInstanceUID); | |
142 } | |
143 | |
144 virtual DicomTransferSyntax GetTransferSyntax() ORTHANC_OVERRIDE | |
145 { | |
146 return transferSyntax_; | |
147 } | |
148 | |
149 virtual std::string GetSopClassUid() ORTHANC_OVERRIDE | |
150 { | |
151 return sopClassUid_; | |
152 } | |
153 | |
154 virtual std::string GetSopInstanceUid() ORTHANC_OVERRIDE | |
155 { | |
156 return sopInstanceUid_; | |
157 } | |
158 | |
159 virtual unsigned int GetFramesCount() ORTHANC_OVERRIDE | |
160 { | |
161 return index_->GetFramesCount(); | |
162 } | |
163 | |
164 virtual void WriteToMemoryBuffer(std::string& target) ORTHANC_OVERRIDE | |
165 { | |
166 assert(dicom_.get() != NULL); | |
167 if (!FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, transferSyntax_)) | |
168 { | |
169 throw OrthancException(ErrorCode_InternalError, | |
170 "Cannot write the DICOM instance to a memory buffer"); | |
171 } | |
172 } | |
173 | |
174 virtual ImageAccessor* GetUncompressedFrame(unsigned int frame) ORTHANC_OVERRIDE | |
175 { | |
176 assert(dicom_.get() != NULL && | |
177 dicom_->getDataset() != NULL); | |
178 return DicomImageDecoder::Decode(*dicom_->getDataset(), frame); | |
179 } | |
180 | |
181 virtual void GetCompressedFrame(std::string& target, | |
182 unsigned int frame) ORTHANC_OVERRIDE | |
183 { | |
184 assert(index_.get() != NULL); | |
185 index_->GetRawFrame(target, frame); | |
186 } | |
187 }; | |
188 | |
189 unsigned int lossyQuality_; | |
190 | |
191 static DicomTransferSyntax DetectTransferSyntax(DcmFileFormat& dicom) | |
192 { | |
193 if (dicom.getDataset() == NULL) | |
194 { | |
195 throw OrthancException(ErrorCode_InternalError); | |
196 } | |
197 | |
198 DcmDataset& dataset = *dicom.getDataset(); | |
199 | |
200 E_TransferSyntax xfer = dataset.getCurrentXfer(); | |
201 if (xfer == EXS_Unknown) | |
202 { | |
203 dataset.updateOriginalXfer(); | |
204 xfer = dataset.getCurrentXfer(); | |
205 if (xfer == EXS_Unknown) | |
206 { | |
207 throw OrthancException(ErrorCode_BadFileFormat, | |
208 "Cannot determine the transfer syntax of the DICOM instance"); | |
209 } | |
210 } | |
211 | |
212 DicomTransferSyntax syntax; | |
213 if (FromDcmtkBridge::LookupOrthancTransferSyntax(syntax, xfer)) | |
214 { | |
215 return syntax; | |
216 } | |
217 else | |
218 { | |
219 throw OrthancException( | |
220 ErrorCode_BadFileFormat, | |
221 "Unsupported transfer syntax: " + boost::lexical_cast<std::string>(xfer)); | |
222 } | |
223 } | |
224 | |
225 | |
226 static uint16_t GetBitsStored(DcmFileFormat& dicom) | |
227 { | |
228 if (dicom.getDataset() == NULL) | |
229 { | |
230 throw OrthancException(ErrorCode_InternalError); | |
231 } | |
232 | |
233 uint16_t bitsStored; | |
234 if (dicom.getDataset()->findAndGetUint16(DCM_BitsStored, bitsStored).good()) | |
235 { | |
236 return bitsStored; | |
237 } | |
238 else | |
239 { | |
240 throw OrthancException(ErrorCode_BadFileFormat, | |
241 "Missing \"Bits Stored\" tag in DICOM instance"); | |
242 } | |
243 } | |
244 | |
245 | |
246 public: | |
247 DcmtkImageReader() : | |
248 lossyQuality_(90) | |
249 { | |
250 } | |
251 | |
252 void SetLossyQuality(unsigned int quality) | |
253 { | |
254 if (quality <= 0 || | |
255 quality > 100) | |
256 { | |
257 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
258 } | |
259 else | |
260 { | |
261 lossyQuality_ = quality; | |
262 } | |
263 } | |
264 | |
265 unsigned int GetLossyQuality() const | |
266 { | |
267 return lossyQuality_; | |
268 } | |
269 | |
270 virtual IParsedDicomImage* Read(const void* data, | |
271 size_t size) | |
272 { | |
273 std::unique_ptr<DcmFileFormat> dicom(FromDcmtkBridge::LoadFromMemoryBuffer(data, size)); | |
274 if (dicom.get() == NULL) | |
275 { | |
276 throw OrthancException(ErrorCode_BadFileFormat); | |
277 } | |
278 | |
279 DicomTransferSyntax transferSyntax = DetectTransferSyntax(*dicom); | |
280 | |
281 return new Image(dicom.release(), transferSyntax); | |
282 } | |
283 | |
284 virtual IParsedDicomImage* Transcode(const void* data, | |
285 size_t size, | |
286 DicomTransferSyntax syntax, | |
287 bool allowNewSopInstanceUid) | |
288 { | |
289 std::unique_ptr<DcmFileFormat> dicom(FromDcmtkBridge::LoadFromMemoryBuffer(data, size)); | |
290 if (dicom.get() == NULL) | |
291 { | |
292 throw OrthancException(ErrorCode_BadFileFormat); | |
293 } | |
294 | |
295 const uint16_t bitsStored = GetBitsStored(*dicom); | |
296 | |
297 if (syntax == DetectTransferSyntax(*dicom)) | |
298 { | |
299 // No transcoding is needed | |
300 return new Image(dicom.release(), syntax); | |
301 } | |
302 | |
303 if (syntax == DicomTransferSyntax_LittleEndianImplicit && | |
304 FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_LittleEndianImplicit, NULL)) | |
305 { | |
306 return new Image(dicom.release(), syntax); | |
307 } | |
308 | |
309 if (syntax == DicomTransferSyntax_LittleEndianExplicit && | |
310 FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_LittleEndianExplicit, NULL)) | |
311 { | |
312 return new Image(dicom.release(), syntax); | |
313 } | |
314 | |
315 if (syntax == DicomTransferSyntax_BigEndianExplicit && | |
316 FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_BigEndianExplicit, NULL)) | |
317 { | |
318 return new Image(dicom.release(), syntax); | |
319 } | |
320 | |
321 if (syntax == DicomTransferSyntax_DeflatedLittleEndianExplicit && | |
322 FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_DeflatedLittleEndianExplicit, NULL)) | |
323 { | |
324 return new Image(dicom.release(), syntax); | |
325 } | |
326 | |
327 #if ORTHANC_ENABLE_JPEG == 1 | |
328 if (syntax == DicomTransferSyntax_JPEGProcess1 && | |
329 allowNewSopInstanceUid && | |
330 bitsStored == 8) | |
331 { | |
332 DJ_RPLossy rpLossy(lossyQuality_); | |
333 | |
334 if (FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_JPEGProcess1, &rpLossy)) | |
335 { | |
336 return new Image(dicom.release(), syntax); | |
337 } | |
338 } | |
339 #endif | |
340 | |
341 #if ORTHANC_ENABLE_JPEG == 1 | |
342 if (syntax == DicomTransferSyntax_JPEGProcess2_4 && | |
343 allowNewSopInstanceUid && | |
344 bitsStored <= 12) | |
345 { | |
346 DJ_RPLossy rpLossy(lossyQuality_); | |
347 if (FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_JPEGProcess2_4, &rpLossy)) | |
348 { | |
349 return new Image(dicom.release(), syntax); | |
350 } | |
351 } | |
352 #endif | |
353 | |
354 //LOG(INFO) << "Unable to transcode DICOM image using the built-in reader"; | |
355 return NULL; | |
356 } | |
357 }; | |
358 | |
359 | |
360 | |
361 class IDicomTranscoder1 : public boost::noncopyable | |
362 { | |
363 public: | |
364 virtual ~IDicomTranscoder1() | |
365 { | |
366 } | |
367 | |
368 virtual DcmFileFormat& GetDicom() = 0; | |
369 | |
370 virtual DicomTransferSyntax GetTransferSyntax() = 0; | |
371 | |
372 virtual std::string GetSopClassUid() = 0; | |
373 | |
374 virtual std::string GetSopInstanceUid() = 0; | |
375 | |
376 virtual unsigned int GetFramesCount() = 0; | |
377 | |
378 virtual ImageAccessor* DecodeFrame(unsigned int frame) = 0; | |
379 | |
380 virtual void GetCompressedFrame(std::string& target, | |
381 unsigned int frame) = 0; | |
382 | |
383 // NB: Transcoding can change the value of "GetSopInstanceUid()" | |
384 // and "GetTransferSyntax()" if lossy compression is applied | |
385 virtual bool Transcode(std::string& target, | |
386 DicomTransferSyntax syntax, | |
387 bool allowNewSopInstanceUid) = 0; | |
388 | |
389 virtual void WriteToMemoryBuffer(std::string& target) = 0; | |
390 }; | |
391 | |
392 | |
393 class DcmtkTranscoder2 : public IDicomTranscoder1 | |
394 { | |
395 private: | |
396 std::unique_ptr<DcmFileFormat> dicom_; | |
397 std::unique_ptr<DicomFrameIndex> index_; | |
398 DicomTransferSyntax transferSyntax_; | |
399 std::string sopClassUid_; | |
400 std::string sopInstanceUid_; | |
401 uint16_t bitsStored_; | |
402 unsigned int lossyQuality_; | |
403 | |
404 static std::string GetStringTag(DcmDataset& dataset, | |
405 const DcmTagKey& tag) | |
406 { | |
407 const char* value = NULL; | |
408 | |
409 if (!dataset.findAndGetString(tag, value).good() || | |
410 value == NULL) | |
411 { | |
412 throw OrthancException(ErrorCode_BadFileFormat, | |
413 "Missing SOP class/instance UID in DICOM instance"); | |
414 } | |
415 else | |
416 { | |
417 return std::string(value); | |
418 } | |
419 } | |
420 | |
421 void Setup(DcmFileFormat* dicom) | |
422 { | |
423 lossyQuality_ = 90; | |
424 | |
425 dicom_.reset(dicom); | |
426 | |
427 if (dicom == NULL || | |
428 dicom_->getDataset() == NULL) | |
429 { | |
430 throw OrthancException(ErrorCode_NullPointer); | |
431 } | |
432 | |
433 DcmDataset& dataset = *dicom_->getDataset(); | |
434 index_.reset(new DicomFrameIndex(dataset)); | |
435 | |
436 E_TransferSyntax xfer = dataset.getCurrentXfer(); | |
437 if (xfer == EXS_Unknown) | |
438 { | |
439 dataset.updateOriginalXfer(); | |
440 xfer = dataset.getCurrentXfer(); | |
441 if (xfer == EXS_Unknown) | |
442 { | |
443 throw OrthancException(ErrorCode_BadFileFormat, | |
444 "Cannot determine the transfer syntax of the DICOM instance"); | |
445 } | |
446 } | |
447 | |
448 if (!FromDcmtkBridge::LookupOrthancTransferSyntax(transferSyntax_, xfer)) | |
449 { | |
450 throw OrthancException( | |
451 ErrorCode_BadFileFormat, | |
452 "Unsupported transfer syntax: " + boost::lexical_cast<std::string>(xfer)); | |
453 } | |
454 | |
455 if (!dataset.findAndGetUint16(DCM_BitsStored, bitsStored_).good()) | |
456 { | |
457 throw OrthancException(ErrorCode_BadFileFormat, | |
458 "Missing \"Bits Stored\" tag in DICOM instance"); | |
459 } | |
460 | |
461 sopClassUid_ = GetStringTag(dataset, DCM_SOPClassUID); | |
462 sopInstanceUid_ = GetStringTag(dataset, DCM_SOPInstanceUID); | |
463 } | |
464 | |
465 public: | |
466 DcmtkTranscoder2(DcmFileFormat* dicom) // Takes ownership | |
467 { | |
468 Setup(dicom); | |
469 } | |
470 | |
471 DcmtkTranscoder2(const void* dicom, | |
472 size_t size) | |
473 { | |
474 Setup(FromDcmtkBridge::LoadFromMemoryBuffer(dicom, size)); | |
475 } | |
476 | |
477 void SetLossyQuality(unsigned int quality) | |
478 { | |
479 if (quality <= 0 || | |
480 quality > 100) | |
481 { | |
482 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
483 } | |
484 else | |
485 { | |
486 lossyQuality_ = quality; | |
487 } | |
488 } | |
489 | |
490 unsigned int GetLossyQuality() const | |
491 { | |
492 return lossyQuality_; | |
493 } | |
494 | |
495 unsigned int GetBitsStored() const | |
496 { | |
497 return bitsStored_; | |
498 } | |
499 | |
500 virtual DcmFileFormat& GetDicom() | |
501 { | |
502 assert(dicom_ != NULL); | |
503 return *dicom_; | |
504 } | |
505 | |
506 virtual DicomTransferSyntax GetTransferSyntax() ORTHANC_OVERRIDE | |
507 { | |
508 return transferSyntax_; | |
509 } | |
510 | |
511 virtual std::string GetSopClassUid() ORTHANC_OVERRIDE | |
512 { | |
513 return sopClassUid_; | |
514 } | |
515 | |
516 virtual std::string GetSopInstanceUid() ORTHANC_OVERRIDE | |
517 { | |
518 return sopInstanceUid_; | |
519 } | |
520 | |
521 virtual unsigned int GetFramesCount() ORTHANC_OVERRIDE | |
522 { | |
523 return index_->GetFramesCount(); | |
524 } | |
525 | |
526 virtual void WriteToMemoryBuffer(std::string& target) ORTHANC_OVERRIDE | |
527 { | |
528 if (!FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_)) | |
529 { | |
530 throw OrthancException(ErrorCode_InternalError, | |
531 "Cannot write the DICOM instance to a memory buffer"); | |
532 } | |
533 } | |
534 | |
535 virtual ImageAccessor* DecodeFrame(unsigned int frame) ORTHANC_OVERRIDE | |
536 { | |
537 assert(dicom_->getDataset() != NULL); | |
538 return DicomImageDecoder::Decode(*dicom_->getDataset(), frame); | |
539 } | |
540 | |
541 virtual void GetCompressedFrame(std::string& target, | |
542 unsigned int frame) ORTHANC_OVERRIDE | |
543 { | |
544 index_->GetRawFrame(target, frame); | |
545 } | |
546 | |
547 virtual bool Transcode(std::string& target, | |
548 DicomTransferSyntax syntax, | |
549 bool allowNewSopInstanceUid) ORTHANC_OVERRIDE | |
550 { | |
551 assert(dicom_ != NULL && | |
552 dicom_->getDataset() != NULL); | |
553 | |
554 if (syntax == GetTransferSyntax()) | |
555 { | |
556 printf("NO TRANSCODING\n"); | |
557 | |
558 // No change in the transfer syntax => simply serialize the current dataset | |
559 WriteToMemoryBuffer(target); | |
560 return true; | |
561 } | |
562 | |
563 printf(">> %d\n", bitsStored_); | |
564 | |
565 if (syntax == DicomTransferSyntax_LittleEndianImplicit && | |
566 FromDcmtkBridge::Transcode(*dicom_, syntax, NULL) && | |
567 FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, syntax)) | |
568 { | |
569 transferSyntax_ = DicomTransferSyntax_LittleEndianImplicit; | |
570 return true; | |
571 } | |
572 | |
573 if (syntax == DicomTransferSyntax_LittleEndianExplicit && | |
574 FromDcmtkBridge::Transcode(*dicom_, syntax, NULL) && | |
575 FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, syntax)) | |
576 { | |
577 transferSyntax_ = DicomTransferSyntax_LittleEndianExplicit; | |
578 return true; | |
579 } | |
580 | |
581 if (syntax == DicomTransferSyntax_BigEndianExplicit && | |
582 FromDcmtkBridge::Transcode(*dicom_, syntax, NULL) && | |
583 FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, syntax)) | |
584 { | |
585 transferSyntax_ = DicomTransferSyntax_BigEndianExplicit; | |
586 return true; | |
587 } | |
588 | |
589 if (syntax == DicomTransferSyntax_DeflatedLittleEndianExplicit && | |
590 FromDcmtkBridge::Transcode(*dicom_, syntax, NULL) && | |
591 FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, syntax)) | |
592 { | |
593 transferSyntax_ = DicomTransferSyntax_DeflatedLittleEndianExplicit; | |
594 return true; | |
595 } | |
596 | |
597 #if ORTHANC_ENABLE_JPEG == 1 | |
598 if (syntax == DicomTransferSyntax_JPEGProcess1 && | |
599 allowNewSopInstanceUid && | |
600 GetBitsStored() == 8) | |
601 { | |
602 DJ_RPLossy rpLossy(lossyQuality_); | |
603 | |
604 if (FromDcmtkBridge::Transcode(*dicom_, syntax, &rpLossy) && | |
605 FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, syntax)) | |
606 { | |
607 transferSyntax_ = DicomTransferSyntax_JPEGProcess1; | |
608 sopInstanceUid_ = GetStringTag(*dicom_->getDataset(), DCM_SOPInstanceUID); | |
609 return true; | |
610 } | |
611 } | |
612 #endif | |
613 | |
614 #if ORTHANC_ENABLE_JPEG == 1 | |
615 if (syntax == DicomTransferSyntax_JPEGProcess2_4 && | |
616 allowNewSopInstanceUid && | |
617 GetBitsStored() <= 12) | |
618 { | |
619 DJ_RPLossy rpLossy(lossyQuality_); | |
620 if (FromDcmtkBridge::Transcode(*dicom_, syntax, &rpLossy) && | |
621 FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, syntax)) | |
622 { | |
623 transferSyntax_ = DicomTransferSyntax_JPEGProcess2_4; | |
624 sopInstanceUid_ = GetStringTag(*dicom_->getDataset(), DCM_SOPInstanceUID); | |
625 return true; | |
626 } | |
627 } | |
628 #endif | |
629 | |
630 return false; | |
631 } | |
632 }; | |
633 } | |
634 | |
635 | |
636 | |
637 | |
638 #include <boost/filesystem.hpp> | |
639 | |
640 | |
641 static void TestFile(const std::string& path) | |
642 { | |
643 static unsigned int count = 0; | |
644 count++; | |
645 | |
646 | |
647 printf("** %s\n", path.c_str()); | |
648 | |
649 std::string s; | |
650 SystemToolbox::ReadFile(s, path); | |
651 | |
652 Orthanc::DcmtkTranscoder2 transcoder(s.c_str(), s.size()); | |
653 | |
654 /*if (transcoder.GetBitsStored() != 8) // TODO | |
655 return; */ | |
656 | |
657 { | |
658 char buf[1024]; | |
659 sprintf(buf, "/tmp/source-%06d.dcm", count); | |
660 printf(">> %s\n", buf); | |
661 Orthanc::SystemToolbox::WriteFile(s, buf); | |
662 } | |
663 | |
664 printf("[%s] [%s] [%s] %d %d\n", GetTransferSyntaxUid(transcoder.GetTransferSyntax()), | |
665 transcoder.GetSopClassUid().c_str(), transcoder.GetSopInstanceUid().c_str(), | |
666 transcoder.GetFramesCount(), transcoder.GetTransferSyntax()); | |
667 | |
668 for (size_t i = 0; i < transcoder.GetFramesCount(); i++) | |
669 { | |
670 std::string f; | |
671 transcoder.GetCompressedFrame(f, i); | |
672 | |
673 if (i == 0) | |
674 { | |
675 char buf[1024]; | |
676 sprintf(buf, "/tmp/frame-%06d.raw", count); | |
677 printf(">> %s\n", buf); | |
678 Orthanc::SystemToolbox::WriteFile(f, buf); | |
679 } | |
680 } | |
681 | |
682 { | |
683 std::string t; | |
684 transcoder.WriteToMemoryBuffer(t); | |
685 | |
686 Orthanc::DcmtkTranscoder2 transcoder2(t.c_str(), t.size()); | |
687 printf(">> %d %d ; %lu bytes\n", transcoder.GetTransferSyntax(), transcoder2.GetTransferSyntax(), t.size()); | |
688 } | |
689 | |
690 { | |
691 std::string a = transcoder.GetSopInstanceUid(); | |
692 DicomTransferSyntax b = transcoder.GetTransferSyntax(); | |
693 | |
694 DicomTransferSyntax syntax = DicomTransferSyntax_JPEGProcess2_4; | |
695 //DicomTransferSyntax syntax = DicomTransferSyntax_LittleEndianExplicit; | |
696 | |
697 std::string t; | |
698 bool ok = transcoder.Transcode(t, syntax, true); | |
699 printf("Transcoding: %d\n", ok); | |
700 | |
701 if (ok) | |
702 { | |
703 printf("[%s] => [%s]\n", a.c_str(), transcoder.GetSopInstanceUid().c_str()); | |
704 printf("[%s] => [%s]\n", GetTransferSyntaxUid(b), | |
705 GetTransferSyntaxUid(transcoder.GetTransferSyntax())); | |
706 | |
707 { | |
708 char buf[1024]; | |
709 sprintf(buf, "/tmp/transcoded-%06d.dcm", count); | |
710 printf(">> %s\n", buf); | |
711 Orthanc::SystemToolbox::WriteFile(t, buf); | |
712 } | |
713 | |
714 Orthanc::DcmtkTranscoder2 transcoder2(t.c_str(), t.size()); | |
715 printf(" => transcoded transfer syntax %d ; %lu bytes\n", transcoder2.GetTransferSyntax(), t.size()); | |
716 } | |
717 } | |
718 | |
719 printf("\n"); | |
720 } | |
721 | |
722 TEST(Toto, DISABLED_Transcode) | |
723 { | |
724 //OFLog::configure(OFLogger::DEBUG_LOG_LEVEL); | |
725 | |
726 if (1) | |
727 { | |
728 const char* const PATH = "/home/jodogne/Subversion/orthanc-tests/Database/TransferSyntaxes"; | |
729 | |
730 for (boost::filesystem::directory_iterator it(PATH); | |
731 it != boost::filesystem::directory_iterator(); ++it) | |
732 { | |
733 if (boost::filesystem::is_regular_file(it->status())) | |
734 { | |
735 TestFile(it->path().string()); | |
736 } | |
737 } | |
738 } | |
739 | |
740 if (0) | |
741 { | |
742 TestFile("/home/jodogne/Subversion/orthanc-tests/Database/Multiframe.dcm"); | |
743 TestFile("/home/jodogne/Subversion/orthanc-tests/Database/Issue44/Monochrome1-Jpeg.dcm"); | |
744 } | |
745 | |
746 if (0) | |
747 { | |
748 TestFile("/home/jodogne/Subversion/orthanc-tests/Database/TransferSyntaxes/1.2.840.10008.1.2.1.dcm"); | |
749 } | |
750 } | |
751 | |
752 | |
753 TEST(Toto, DISABLED_Transcode2) | |
754 { | |
755 for (int i = 0; i <= DicomTransferSyntax_XML; i++) | |
756 { | |
757 DicomTransferSyntax a = (DicomTransferSyntax) i; | |
758 | |
759 std::string path = ("/home/jodogne/Subversion/orthanc-tests/Database/TransferSyntaxes/" + | |
760 std::string(GetTransferSyntaxUid(a)) + ".dcm"); | |
761 if (Orthanc::SystemToolbox::IsRegularFile(path)) | |
762 { | |
763 printf("\n======= %s\n", GetTransferSyntaxUid(a)); | |
764 | |
765 std::string source; | |
766 Orthanc::SystemToolbox::ReadFile(source, path); | |
767 | |
768 DcmtkImageReader reader; | |
769 | |
770 { | |
771 std::unique_ptr<IParsedDicomImage> image( | |
772 reader.Read(source.c_str(), source.size())); | |
773 ASSERT_TRUE(image.get() != NULL); | |
774 ASSERT_EQ(a, image->GetTransferSyntax()); | |
775 | |
776 std::string target; | |
777 image->WriteToMemoryBuffer(target); | |
778 } | |
779 | |
780 for (int j = 0; j <= DicomTransferSyntax_XML; j++) | |
781 { | |
782 DicomTransferSyntax b = (DicomTransferSyntax) j; | |
783 //if (a == b) continue; | |
784 | |
785 std::unique_ptr<IParsedDicomImage> image( | |
786 reader.Transcode(source.c_str(), source.size(), b, true)); | |
787 if (image.get() != NULL) | |
788 { | |
789 printf("[%s] -> [%s]\n", GetTransferSyntaxUid(a), GetTransferSyntaxUid(b)); | |
790 | |
791 std::string target; | |
792 image->WriteToMemoryBuffer(target); | |
793 | |
794 char buf[1024]; | |
795 sprintf(buf, "/tmp/%s-%s.dcm", GetTransferSyntaxUid(a), GetTransferSyntaxUid(b)); | |
796 | |
797 SystemToolbox::WriteFile(target, buf); | |
798 } | |
799 else if (a != DicomTransferSyntax_JPEG2000 && | |
800 a != DicomTransferSyntax_JPEG2000LosslessOnly) | |
801 { | |
802 ASSERT_TRUE(b != DicomTransferSyntax_LittleEndianImplicit && | |
803 b != DicomTransferSyntax_LittleEndianExplicit && | |
804 b != DicomTransferSyntax_BigEndianExplicit && | |
805 b != DicomTransferSyntax_DeflatedLittleEndianExplicit); | |
806 } | |
807 } | |
808 } | |
809 } | |
810 } | |
811 | |
812 | |
813 #include "../Core/DicomNetworking/DicomAssociation.h" | |
814 #include "../Core/DicomNetworking/DicomControlUserConnection.h" | |
815 #include "../Core/DicomNetworking/DicomStoreUserConnection.h" | |
816 | |
817 TEST(Toto, DISABLED_DicomAssociation) | |
818 { | |
819 DicomAssociationParameters params; | |
820 params.SetLocalApplicationEntityTitle("ORTHANC"); | |
821 params.SetRemoteApplicationEntityTitle("PACS"); | |
822 params.SetRemotePort(2001); | |
823 | |
824 #if 0 | |
825 DicomAssociation assoc; | |
826 assoc.ProposeGenericPresentationContext(UID_StorageCommitmentPushModelSOPClass); | |
827 assoc.ProposeGenericPresentationContext(UID_VerificationSOPClass); | |
828 assoc.ProposePresentationContext(UID_ComputedRadiographyImageStorage, | |
829 DicomTransferSyntax_JPEGProcess1); | |
830 assoc.ProposePresentationContext(UID_ComputedRadiographyImageStorage, | |
831 DicomTransferSyntax_JPEGProcess2_4); | |
832 assoc.ProposePresentationContext(UID_ComputedRadiographyImageStorage, | |
833 DicomTransferSyntax_JPEG2000); | |
834 | |
835 assoc.Open(params); | |
836 | |
837 int presID = ASC_findAcceptedPresentationContextID(&assoc.GetDcmtkAssociation(), UID_ComputedRadiographyImageStorage); | |
838 printf(">> %d\n", presID); | |
839 | |
840 std::map<DicomTransferSyntax, uint8_t> pc; | |
841 printf(">> %d\n", assoc.LookupAcceptedPresentationContext(pc, UID_ComputedRadiographyImageStorage)); | |
842 | |
843 for (std::map<DicomTransferSyntax, uint8_t>::const_iterator | |
844 it = pc.begin(); it != pc.end(); ++it) | |
845 { | |
846 printf("[%s] => %d\n", GetTransferSyntaxUid(it->first), it->second); | |
847 } | |
848 #else | |
849 { | |
850 DicomControlUserConnection assoc(params); | |
851 | |
852 try | |
853 { | |
854 printf(">> %d\n", assoc.Echo()); | |
855 } | |
856 catch (OrthancException&) | |
857 { | |
858 } | |
859 } | |
860 | |
861 params.SetRemoteApplicationEntityTitle("PACS"); | |
862 params.SetRemotePort(2000); | |
863 | |
864 { | |
865 DicomControlUserConnection assoc(params); | |
866 printf(">> %d\n", assoc.Echo()); | |
867 } | |
868 | |
869 #endif | |
870 } | |
871 | |
872 static void TestTranscode(DicomStoreUserConnection& scu, | |
873 const std::string& sopClassUid, | |
874 DicomTransferSyntax transferSyntax) | |
875 { | |
876 std::set<DicomTransferSyntax> accepted; | |
877 | |
878 scu.LookupTranscoding(accepted, sopClassUid, transferSyntax); | |
879 if (accepted.empty()) | |
880 { | |
881 throw OrthancException(ErrorCode_NetworkProtocol, | |
882 "The SOP class is not supported by the remote modality"); | |
883 } | |
884 | |
885 { | |
886 unsigned int count = 0; | |
887 for (std::set<DicomTransferSyntax>::const_iterator | |
888 it = accepted.begin(); it != accepted.end(); ++it) | |
889 { | |
890 LOG(INFO) << "available for transcoding " << (count++) << ": " << sopClassUid | |
891 << " / " << GetTransferSyntaxUid(*it); | |
892 } | |
893 } | |
894 | |
895 if (accepted.find(transferSyntax) != accepted.end()) | |
896 { | |
897 printf("**** OK, without transcoding !! [%s]\n", GetTransferSyntaxUid(transferSyntax)); | |
898 } | |
899 else | |
900 { | |
901 // Transcoding - only in Orthanc >= 1.7.0 | |
902 | |
903 const DicomTransferSyntax uncompressed[] = { | |
904 DicomTransferSyntax_LittleEndianImplicit, // Default transfer syntax | |
905 DicomTransferSyntax_LittleEndianExplicit, | |
906 DicomTransferSyntax_BigEndianExplicit | |
907 }; | |
908 | |
909 bool found = false; | |
910 for (size_t i = 0; i < 3; i++) | |
911 { | |
912 if (accepted.find(uncompressed[i]) != accepted.end()) | |
913 { | |
914 printf("**** TRANSCODING to %s\n", GetTransferSyntaxUid(uncompressed[i])); | |
915 found = true; | |
916 break; | |
917 } | |
918 } | |
919 | |
920 if (!found) | |
921 { | |
922 printf("**** KO KO KO\n"); | |
923 } | |
924 } | |
925 } | |
926 | |
927 | |
928 TEST(Toto, DISABLED_Store) | |
929 { | |
930 DicomAssociationParameters params; | |
931 params.SetLocalApplicationEntityTitle("ORTHANC"); | |
932 params.SetRemoteApplicationEntityTitle("STORESCP"); | |
933 params.SetRemotePort(2000); | |
934 | |
935 DicomStoreUserConnection assoc(params); | |
936 assoc.RegisterStorageClass(UID_MRImageStorage, DicomTransferSyntax_JPEGProcess1); | |
937 assoc.RegisterStorageClass(UID_MRImageStorage, DicomTransferSyntax_JPEGProcess2_4); | |
938 //assoc.RegisterStorageClass(UID_MRImageStorage, DicomTransferSyntax_LittleEndianExplicit); | |
939 | |
940 //assoc.SetUncompressedSyntaxesProposed(false); // Necessary for transcoding | |
941 assoc.SetCommonClassesProposed(false); | |
942 assoc.SetRetiredBigEndianProposed(true); | |
943 TestTranscode(assoc, UID_MRImageStorage, DicomTransferSyntax_LittleEndianExplicit); | |
944 TestTranscode(assoc, UID_MRImageStorage, DicomTransferSyntax_JPEG2000); | |
945 TestTranscode(assoc, UID_MRImageStorage, DicomTransferSyntax_JPEG2000); | |
946 } | |
947 | |
948 | |
949 TEST(Toto, DISABLED_Store2) | |
950 { | |
951 DicomAssociationParameters params; | |
952 params.SetLocalApplicationEntityTitle("ORTHANC"); | |
953 params.SetRemoteApplicationEntityTitle("STORESCP"); | |
954 params.SetRemotePort(2000); | |
955 | |
956 DicomStoreUserConnection assoc(params); | |
957 //assoc.SetCommonClassesProposed(false); | |
958 assoc.SetRetiredBigEndianProposed(true); | |
959 | |
960 std::string s; | |
961 Orthanc::SystemToolbox::ReadFile(s, "/tmp/i/" + std::string(GetTransferSyntaxUid(DicomTransferSyntax_BigEndianExplicit)) +".dcm"); | |
962 | |
963 std::string c, i; | |
964 assoc.Store(c, i, s.c_str(), s.size()); | |
965 printf("[%s] [%s]\n", c.c_str(), i.c_str()); | |
966 } | |
967 |