# HG changeset patch # User Sebastien Jodogne # Date 1583511003 -3600 # Node ID 090022f1b5e182c0696a2d072ea1faf423395828 # Parent 7b7ca203f1a394888acd111707631abea4929967 auto-generation of primitives to handle transfer syntaxes diff -r 7b7ca203f1a3 -r 090022f1b5e1 Core/DicomParsing/FromDcmtkBridge.cpp --- a/Core/DicomParsing/FromDcmtkBridge.cpp Fri Mar 06 11:52:44 2020 +0100 +++ b/Core/DicomParsing/FromDcmtkBridge.cpp Fri Mar 06 17:10:03 2020 +0100 @@ -107,10 +107,16 @@ #if ORTHANC_ENABLE_DCMTK_JPEG == 1 # include +# if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 +# include +# endif #endif #if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1 # include +# if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 +# include +# endif #endif @@ -2045,12 +2051,18 @@ { #if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1 LOG(INFO) << "Registering JPEG Lossless codecs in DCMTK"; - DJLSDecoderRegistration::registerCodecs(); + DJLSDecoderRegistration::registerCodecs(); +# if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 + DJLSEncoderRegistration::registerCodecs(); +# endif #endif #if ORTHANC_ENABLE_DCMTK_JPEG == 1 LOG(INFO) << "Registering JPEG codecs in DCMTK"; DJDecoderRegistration::registerCodecs(); +# if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 + DJEncoderRegistration::registerCodecs(); +# endif #endif } @@ -2060,11 +2072,17 @@ #if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1 // Unregister JPEG-LS codecs DJLSDecoderRegistration::cleanup(); +# if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 + DJLSEncoderRegistration::cleanup(); +# endif #endif #if ORTHANC_ENABLE_DCMTK_JPEG == 1 // Unregister JPEG codecs DJDecoderRegistration::cleanup(); +# if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 + DJDecoderRegistration::cleanup(); +# endif #endif } @@ -2551,4 +2569,181 @@ Encoding encoding = DetectEncoding(hasCodeExtensions, dataset, defaultEncoding); ApplyVisitorToDataset(dataset, visitor, parentTags, parentIndexes, encoding, hasCodeExtensions); } + + + // This function is autogenerated by the script + // "Resources/GenerateTransferSyntaxes.py" + bool FromDcmtkBridge::GetDcmtkTransferSyntax(E_TransferSyntax& target, + DicomTransferSyntax syntax) + { + switch (syntax) + { + case DicomTransferSyntax_LittleEndianImplicit: + target = EXS_LittleEndianImplicit; + return true; + + case DicomTransferSyntax_LittleEndianExplicit: + target = EXS_LittleEndianExplicit; + return true; + + case DicomTransferSyntax_DeflatedLittleEndianExplicit: + target = EXS_DeflatedLittleEndianExplicit; + return true; + + case DicomTransferSyntax_BigEndianExplicit: + target = EXS_BigEndianExplicit; + return true; + + case DicomTransferSyntax_JPEGProcess1: + target = EXS_JPEGProcess1; + return true; + + case DicomTransferSyntax_JPEGProcess2_4: + target = EXS_JPEGProcess2_4; + return true; + + case DicomTransferSyntax_JPEGProcess3_5: + target = EXS_JPEGProcess3_5; + return true; + + case DicomTransferSyntax_JPEGProcess6_8: + target = EXS_JPEGProcess6_8; + return true; + + case DicomTransferSyntax_JPEGProcess7_9: + target = EXS_JPEGProcess7_9; + return true; + + case DicomTransferSyntax_JPEGProcess10_12: + target = EXS_JPEGProcess10_12; + return true; + + case DicomTransferSyntax_JPEGProcess11_13: + target = EXS_JPEGProcess11_13; + return true; + + case DicomTransferSyntax_JPEGProcess14: + target = EXS_JPEGProcess14; + return true; + + case DicomTransferSyntax_JPEGProcess15: + target = EXS_JPEGProcess15; + return true; + + case DicomTransferSyntax_JPEGProcess16_18: + target = EXS_JPEGProcess16_18; + return true; + + case DicomTransferSyntax_JPEGProcess17_19: + target = EXS_JPEGProcess17_19; + return true; + + case DicomTransferSyntax_JPEGProcess20_22: + target = EXS_JPEGProcess20_22; + return true; + + case DicomTransferSyntax_JPEGProcess21_23: + target = EXS_JPEGProcess21_23; + return true; + + case DicomTransferSyntax_JPEGProcess24_26: + target = EXS_JPEGProcess24_26; + return true; + + case DicomTransferSyntax_JPEGProcess25_27: + target = EXS_JPEGProcess25_27; + return true; + + case DicomTransferSyntax_JPEGProcess28: + target = EXS_JPEGProcess28; + return true; + + case DicomTransferSyntax_JPEGProcess29: + target = EXS_JPEGProcess29; + return true; + + case DicomTransferSyntax_JPEGProcess14SV1: + target = EXS_JPEGProcess14SV1; + return true; + + case DicomTransferSyntax_JPEGLSLossless: + target = EXS_JPEGLSLossless; + return true; + + case DicomTransferSyntax_JPEGLSLossy: + target = EXS_JPEGLSLossy; + return true; + + case DicomTransferSyntax_JPEG2000LosslessOnly: + target = EXS_JPEG2000LosslessOnly; + return true; + + case DicomTransferSyntax_JPEG2000: + target = EXS_JPEG2000; + return true; + + case DicomTransferSyntax_JPEG2000MulticomponentLosslessOnly: + target = EXS_JPEG2000MulticomponentLosslessOnly; + return true; + + case DicomTransferSyntax_JPEG2000Multicomponent: + target = EXS_JPEG2000Multicomponent; + return true; + + case DicomTransferSyntax_JPIPReferenced: + target = EXS_JPIPReferenced; + return true; + + case DicomTransferSyntax_JPIPReferencedDeflate: + target = EXS_JPIPReferencedDeflate; + return true; + + case DicomTransferSyntax_MPEG2MainProfileAtMainLevel: + target = EXS_MPEG2MainProfileAtMainLevel; + return true; + + case DicomTransferSyntax_MPEG2MainProfileAtHighLevel: + target = EXS_MPEG2MainProfileAtHighLevel; + return true; + + case DicomTransferSyntax_MPEG4HighProfileLevel4_1: + target = EXS_MPEG4HighProfileLevel4_1; + return true; + + case DicomTransferSyntax_MPEG4BDcompatibleHighProfileLevel4_1: + target = EXS_MPEG4BDcompatibleHighProfileLevel4_1; + return true; + + case DicomTransferSyntax_MPEG4HighProfileLevel4_2_For2DVideo: + target = EXS_MPEG4HighProfileLevel4_2_For2DVideo; + return true; + + case DicomTransferSyntax_MPEG4HighProfileLevel4_2_For3DVideo: + target = EXS_MPEG4HighProfileLevel4_2_For3DVideo; + return true; + + case DicomTransferSyntax_MPEG4StereoHighProfileLevel4_2: + target = EXS_MPEG4StereoHighProfileLevel4_2; + return true; + +#if DCMTK_VERSION_NUMBER >= 362 + case DicomTransferSyntax_HEVCMainProfileLevel5_1: + target = EXS_HEVCMainProfileLevel5_1; + return true; +#endif + +#if DCMTK_VERSION_NUMBER >= 362 + case DicomTransferSyntax_HEVCMain10ProfileLevel5_1: + target = EXS_HEVCMain10ProfileLevel5_1; + return true; +#endif + + case DicomTransferSyntax_RLELossless: + target = EXS_RLELossless; + return true; + + default: + return false; + } + } } diff -r 7b7ca203f1a3 -r 090022f1b5e1 Core/DicomParsing/FromDcmtkBridge.h --- a/Core/DicomParsing/FromDcmtkBridge.h Fri Mar 06 11:52:44 2020 +0100 +++ b/Core/DicomParsing/FromDcmtkBridge.h Fri Mar 06 17:10:03 2020 +0100 @@ -270,5 +270,8 @@ static void Apply(DcmItem& dataset, ITagVisitor& visitor, Encoding defaultEncoding); + + static bool GetDcmtkTransferSyntax(E_TransferSyntax& target, + DicomTransferSyntax syntax); }; } diff -r 7b7ca203f1a3 -r 090022f1b5e1 Core/Enumerations.cpp --- a/Core/Enumerations.cpp Fri Mar 06 11:52:44 2020 +0100 +++ b/Core/Enumerations.cpp Fri Mar 06 17:10:03 2020 +0100 @@ -2245,4 +2245,141 @@ LOG(INFO) << "Default encoding for DICOM was changed to: " << name; } + + // This function is autogenerated by the script + // "Resources/GenerateTransferSyntaxes.py" + const char* GetTransferSyntaxUid(DicomTransferSyntax syntax) + { + switch (syntax) + { + case DicomTransferSyntax_LittleEndianImplicit: + return "1.2.840.10008.1.2"; + + case DicomTransferSyntax_LittleEndianExplicit: + return "1.2.840.10008.1.2.1"; + + case DicomTransferSyntax_DeflatedLittleEndianExplicit: + return "1.2.840.10008.1.2.1.99"; + + case DicomTransferSyntax_BigEndianExplicit: + return "1.2.840.10008.1.2.2"; + + case DicomTransferSyntax_JPEGProcess1: + return "1.2.840.10008.1.2.4.50"; + + case DicomTransferSyntax_JPEGProcess2_4: + return "1.2.840.10008.1.2.4.51"; + + case DicomTransferSyntax_JPEGProcess3_5: + return "1.2.840.10008.1.2.4.52"; + + case DicomTransferSyntax_JPEGProcess6_8: + return "1.2.840.10008.1.2.4.53"; + + case DicomTransferSyntax_JPEGProcess7_9: + return "1.2.840.10008.1.2.4.54"; + + case DicomTransferSyntax_JPEGProcess10_12: + return "1.2.840.10008.1.2.4.55"; + + case DicomTransferSyntax_JPEGProcess11_13: + return "1.2.840.10008.1.2.4.56"; + + case DicomTransferSyntax_JPEGProcess14: + return "1.2.840.10008.1.2.4.57"; + + case DicomTransferSyntax_JPEGProcess15: + return "1.2.840.10008.1.2.4.58"; + + case DicomTransferSyntax_JPEGProcess16_18: + return "1.2.840.10008.1.2.4.59"; + + case DicomTransferSyntax_JPEGProcess17_19: + return "1.2.840.10008.1.2.4.60"; + + case DicomTransferSyntax_JPEGProcess20_22: + return "1.2.840.10008.1.2.4.61"; + + case DicomTransferSyntax_JPEGProcess21_23: + return "1.2.840.10008.1.2.4.62"; + + case DicomTransferSyntax_JPEGProcess24_26: + return "1.2.840.10008.1.2.4.63"; + + case DicomTransferSyntax_JPEGProcess25_27: + return "1.2.840.10008.1.2.4.64"; + + case DicomTransferSyntax_JPEGProcess28: + return "1.2.840.10008.1.2.4.65"; + + case DicomTransferSyntax_JPEGProcess29: + return "1.2.840.10008.1.2.4.66"; + + case DicomTransferSyntax_JPEGProcess14SV1: + return "1.2.840.10008.1.2.4.70"; + + case DicomTransferSyntax_JPEGLSLossless: + return "1.2.840.10008.1.2.4.80"; + + case DicomTransferSyntax_JPEGLSLossy: + return "1.2.840.10008.1.2.4.81"; + + case DicomTransferSyntax_JPEG2000LosslessOnly: + return "1.2.840.10008.1.2.4.90"; + + case DicomTransferSyntax_JPEG2000: + return "1.2.840.10008.1.2.4.91"; + + case DicomTransferSyntax_JPEG2000MulticomponentLosslessOnly: + return "1.2.840.10008.1.2.4.92"; + + case DicomTransferSyntax_JPEG2000Multicomponent: + return "1.2.840.10008.1.2.4.93"; + + case DicomTransferSyntax_JPIPReferenced: + return "1.2.840.10008.1.2.4.94"; + + case DicomTransferSyntax_JPIPReferencedDeflate: + return "1.2.840.10008.1.2.4.95"; + + case DicomTransferSyntax_MPEG2MainProfileAtMainLevel: + return "1.2.840.10008.1.2.4.100"; + + case DicomTransferSyntax_MPEG2MainProfileAtHighLevel: + return "1.2.840.10008.1.2.4.101"; + + case DicomTransferSyntax_MPEG4HighProfileLevel4_1: + return "1.2.840.10008.1.2.4.102"; + + case DicomTransferSyntax_MPEG4BDcompatibleHighProfileLevel4_1: + return "1.2.840.10008.1.2.4.103"; + + case DicomTransferSyntax_MPEG4HighProfileLevel4_2_For2DVideo: + return "1.2.840.10008.1.2.4.104"; + + case DicomTransferSyntax_MPEG4HighProfileLevel4_2_For3DVideo: + return "1.2.840.10008.1.2.4.105"; + + case DicomTransferSyntax_MPEG4StereoHighProfileLevel4_2: + return "1.2.840.10008.1.2.4.106"; + + case DicomTransferSyntax_HEVCMainProfileLevel5_1: + return "1.2.840.10008.1.2.4.107"; + + case DicomTransferSyntax_HEVCMain10ProfileLevel5_1: + return "1.2.840.10008.1.2.4.108"; + + case DicomTransferSyntax_RLELossless: + return "1.2.840.10008.1.2.5"; + + case DicomTransferSyntax_RFC2557MimeEncapsulation: + return "1.2.840.10008.1.2.6.1"; + + case DicomTransferSyntax_XML: + return "1.2.840.10008.1.2.6.2"; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } } diff -r 7b7ca203f1a3 -r 090022f1b5e1 Core/Enumerations.h --- a/Core/Enumerations.h Fri Mar 06 11:52:44 2020 +0100 +++ b/Core/Enumerations.h Fri Mar 06 17:10:03 2020 +0100 @@ -243,6 +243,54 @@ ErrorCode_START_PLUGINS = 1000000 }; + // This enumeration is autogenerated by the script + // "Resources/GenerateTransferSyntaxes.py" + enum DicomTransferSyntax + { + DicomTransferSyntax_LittleEndianImplicit /*!< Implicit VR Little Endian */, + DicomTransferSyntax_LittleEndianExplicit /*!< Explicit VR Little Endian */, + DicomTransferSyntax_DeflatedLittleEndianExplicit /*!< Deflated Explicit VR Little Endian */, + DicomTransferSyntax_BigEndianExplicit /*!< Explicit VR Big Endian */, + DicomTransferSyntax_JPEGProcess1 /*!< JPEG Baseline (process 1, lossy) */, + DicomTransferSyntax_JPEGProcess2_4 /*!< JPEG Extended Sequential (processes 2 & 4) */, + DicomTransferSyntax_JPEGProcess3_5 /*!< JPEG Extended Sequential (lossy, 8/12 bit), arithmetic coding */, + DicomTransferSyntax_JPEGProcess6_8 /*!< JPEG Spectral Selection, Nonhierarchical (lossy, 8/12 bit) */, + DicomTransferSyntax_JPEGProcess7_9 /*!< JPEG Spectral Selection, Nonhierarchical (lossy, 8/12 bit), arithmetic coding */, + DicomTransferSyntax_JPEGProcess10_12 /*!< JPEG Full Progression, Nonhierarchical (lossy, 8/12 bit) */, + DicomTransferSyntax_JPEGProcess11_13 /*!< JPEG Full Progression, Nonhierarchical (lossy, 8/12 bit), arithmetic coding */, + DicomTransferSyntax_JPEGProcess14 /*!< JPEG Lossless, Nonhierarchical with any selection value (process 14) */, + DicomTransferSyntax_JPEGProcess15 /*!< JPEG Lossless with any selection value, arithmetic coding */, + DicomTransferSyntax_JPEGProcess16_18 /*!< JPEG Extended Sequential, Hierarchical (lossy, 8/12 bit) */, + DicomTransferSyntax_JPEGProcess17_19 /*!< JPEG Extended Sequential, Hierarchical (lossy, 8/12 bit), arithmetic coding */, + DicomTransferSyntax_JPEGProcess20_22 /*!< JPEG Spectral Selection, Hierarchical (lossy, 8/12 bit) */, + DicomTransferSyntax_JPEGProcess21_23 /*!< JPEG Spectral Selection, Hierarchical (lossy, 8/12 bit), arithmetic coding */, + DicomTransferSyntax_JPEGProcess24_26 /*!< JPEG Full Progression, Hierarchical (lossy, 8/12 bit) */, + DicomTransferSyntax_JPEGProcess25_27 /*!< JPEG Full Progression, Hierarchical (lossy, 8/12 bit), arithmetic coding */, + DicomTransferSyntax_JPEGProcess28 /*!< JPEG Lossless, Hierarchical */, + DicomTransferSyntax_JPEGProcess29 /*!< JPEG Lossless, Hierarchical, arithmetic coding */, + DicomTransferSyntax_JPEGProcess14SV1 /*!< JPEG Lossless, Nonhierarchical, First-Order Prediction (Processes 14 [Selection Value 1]) */, + DicomTransferSyntax_JPEGLSLossless /*!< JPEG-LS (lossless) */, + DicomTransferSyntax_JPEGLSLossy /*!< JPEG-LS (lossy or near-lossless) */, + DicomTransferSyntax_JPEG2000LosslessOnly /*!< JPEG 2000 (lossless) */, + DicomTransferSyntax_JPEG2000 /*!< JPEG 2000 (lossless or lossy) */, + DicomTransferSyntax_JPEG2000MulticomponentLosslessOnly /*!< JPEG 2000 part 2 multicomponent extensions (lossless) */, + DicomTransferSyntax_JPEG2000Multicomponent /*!< JPEG 2000 part 2 multicomponent extensions (lossless or lossy) */, + DicomTransferSyntax_JPIPReferenced /*!< JPIP Referenced */, + DicomTransferSyntax_JPIPReferencedDeflate /*!< JPIP Referenced Deflate */, + DicomTransferSyntax_MPEG2MainProfileAtMainLevel /*!< MPEG2 Main Profile at Main Level */, + DicomTransferSyntax_MPEG2MainProfileAtHighLevel /*!< MPEG2 Main Profile at High Level */, + DicomTransferSyntax_MPEG4HighProfileLevel4_1 /*!< MPEG4 High Profile / Level 4.1 */, + DicomTransferSyntax_MPEG4BDcompatibleHighProfileLevel4_1 /*!< MPEG4 BD-compatible High Profile / Level 4.1 */, + DicomTransferSyntax_MPEG4HighProfileLevel4_2_For2DVideo /*!< MPEG4 High Profile / Level 4.2 For 2D Video */, + DicomTransferSyntax_MPEG4HighProfileLevel4_2_For3DVideo /*!< MPEG4 High Profile / Level 4.2 For 3D Video */, + DicomTransferSyntax_MPEG4StereoHighProfileLevel4_2 /*!< 1.2.840.10008.1.2.4.106 */, + DicomTransferSyntax_HEVCMainProfileLevel5_1 /*!< HEVC/H.265 Main Profile / Level 5.1 */, + DicomTransferSyntax_HEVCMain10ProfileLevel5_1 /*!< HEVC/H.265 Main 10 Profile / Level 5.1 */, + DicomTransferSyntax_RLELossless /*!< RLE - Run Length Encoding (lossless) */, + DicomTransferSyntax_RFC2557MimeEncapsulation /*!< RFC 2557 MIME Encapsulation */, + DicomTransferSyntax_XML /*!< XML Encoding */ + }; + enum LogLevel { LogLevel_Error, @@ -798,4 +846,6 @@ Encoding GetDefaultDicomEncoding(); void SetDefaultDicomEncoding(Encoding encoding); + + const char* GetTransferSyntaxUid(DicomTransferSyntax syntax); } diff -r 7b7ca203f1a3 -r 090022f1b5e1 Resources/CMake/OrthancFrameworkConfiguration.cmake --- a/Resources/CMake/OrthancFrameworkConfiguration.cmake Fri Mar 06 11:52:44 2020 +0100 +++ b/Resources/CMake/OrthancFrameworkConfiguration.cmake Fri Mar 06 17:10:03 2020 +0100 @@ -107,6 +107,7 @@ add_definitions( -DORTHANC_ENABLE_DCMTK=0 -DORTHANC_ENABLE_DCMTK_NETWORKING=0 + -DORTHANC_ENABLE_DCMTK_TRANSCODING=0 ) unset(DCMTK_DICTIONARY_DIR CACHE) unset(DCMTK_VERSION CACHE) @@ -494,6 +495,13 @@ add_definitions(-DORTHANC_ENABLE_DCMTK_NETWORKING=0) endif() + # New in Orthanc 1.6.0 + if (ENABLE_DCMTK_TRANSCODING) + add_definitions(-DORTHANC_ENABLE_DCMTK_TRANSCODING=1) + else() + add_definitions(-DORTHANC_ENABLE_DCMTK_TRANSCODING=0) + endif() + if (STANDALONE_BUILD AND NOT HAS_EMBEDDED_RESOURCES) EmbedResources( ${DCMTK_DICTIONARIES} diff -r 7b7ca203f1a3 -r 090022f1b5e1 Resources/CMake/OrthancFrameworkParameters.cmake --- a/Resources/CMake/OrthancFrameworkParameters.cmake Fri Mar 06 11:52:44 2020 +0100 +++ b/Resources/CMake/OrthancFrameworkParameters.cmake Fri Mar 06 17:10:03 2020 +0100 @@ -103,6 +103,7 @@ set(ENABLE_WEB_SERVER OFF CACHE INTERNAL "Enable embedded Web server") set(ENABLE_DCMTK OFF CACHE INTERNAL "Enable DCMTK") set(ENABLE_DCMTK_NETWORKING OFF CACHE INTERNAL "Enable DICOM networking in DCMTK") +set(ENABLE_DCMTK_TRANSCODING OFF CACHE INTERNAL "Enable DICOM transcoding in DCMTK") set(ENABLE_OPENSSL_ENGINES OFF CACHE INTERNAL "Enable support of engines in OpenSSL") set(HAS_EMBEDDED_RESOURCES OFF CACHE INTERNAL diff -r 7b7ca203f1a3 -r 090022f1b5e1 Resources/DicomTransferSyntaxes.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/DicomTransferSyntaxes.json Fri Mar 06 17:10:03 2020 +0100 @@ -0,0 +1,353 @@ +[ + { + "UID" : "1.2.840.10008.1.2", + "Name" : "Implicit VR Little Endian", + "Value" : "LittleEndianImplicit", + "Retired" : false, + "DCMTK" : "EXS_LittleEndianImplicit", + "GDCM" : "gdcm::TransferSyntax::ImplicitVRLittleEndian" + }, + + { + "UID" : "1.2.840.10008.1.2.1", + "Name" : "Explicit VR Little Endian", + "Value" : "LittleEndianExplicit", + "Retired" : false, + "DCMTK" : "EXS_LittleEndianExplicit", + "GDCM" : "gdcm::TransferSyntax::ExplicitVRLittleEndian" + }, + + { + "UID" : "1.2.840.10008.1.2.1.99", + "Name" : "Deflated Explicit VR Little Endian", + "Value" : "DeflatedLittleEndianExplicit", + "Retired" : false, + "DCMTK" : "EXS_DeflatedLittleEndianExplicit" + }, + + { + "UID" : "1.2.840.10008.1.2.2", + "Name" : "Explicit VR Big Endian", + "Value" : "BigEndianExplicit", + "Retired" : false, + "DCMTK" : "EXS_BigEndianExplicit" + }, + + { + "UID" : "1.2.840.10008.1.2.4.50", + "Name" : "JPEG Baseline (process 1, lossy)", + "Value" : "JPEGProcess1", + "Retired" : false, + "Note" : "Default Transfer Syntax for Lossy JPEG 8-bit Image Compression", + "DCMTK" : "EXS_JPEGProcess1", + "GDCM" : "gdcm::TransferSyntax::JPEGBaselineProcess1" + }, + + { + "UID" : "1.2.840.10008.1.2.4.51", + "Name" : "JPEG Extended Sequential (processes 2 & 4)", + "Value" : "JPEGProcess2_4", + "Retired" : false, + "Note" : "Default Transfer Syntax for Lossy JPEG (lossy, 8/12 bit), 12-bit Image Compression (Process 4 only)", + "DCMTK" : "EXS_JPEGProcess2_4", + "GDCM" : "gdcm::TransferSyntax::JPEGExtendedProcess2_4" + }, + + { + "UID" : "1.2.840.10008.1.2.4.52", + "Name" : "JPEG Extended Sequential (lossy, 8/12 bit), arithmetic coding", + "Value" : "JPEGProcess3_5", + "Retired" : true, + "DCMTK" : "EXS_JPEGProcess3_5" + }, + + { + "UID" : "1.2.840.10008.1.2.4.53", + "Name" : "JPEG Spectral Selection, Nonhierarchical (lossy, 8/12 bit)", + "Value" : "JPEGProcess6_8", + "Retired" : true, + "DCMTK" : "EXS_JPEGProcess6_8" + }, + + { + "UID" : "1.2.840.10008.1.2.4.54", + "Name" : "JPEG Spectral Selection, Nonhierarchical (lossy, 8/12 bit), arithmetic coding", + "Value" : "JPEGProcess7_9", + "Retired" : true, + "DCMTK" : "EXS_JPEGProcess7_9" + }, + + { + "UID" : "1.2.840.10008.1.2.4.55", + "Name" : "JPEG Full Progression, Nonhierarchical (lossy, 8/12 bit)", + "Value" : "JPEGProcess10_12", + "Retired" : true, + "DCMTK" : "EXS_JPEGProcess10_12" + }, + + { + "UID" : "1.2.840.10008.1.2.4.56", + "Name" : "JPEG Full Progression, Nonhierarchical (lossy, 8/12 bit), arithmetic coding", + "Value" : "JPEGProcess11_13", + "Retired" : true, + "DCMTK" : "EXS_JPEGProcess11_13" + }, + + { + "UID" : "1.2.840.10008.1.2.4.57", + "Name" : "JPEG Lossless, Nonhierarchical with any selection value (process 14)", + "Value" : "JPEGProcess14", + "Retired" : false, + "DCMTK" : "EXS_JPEGProcess14", + "GDCM" : "gdcm::TransferSyntax::JPEGLosslessProcess14" + }, + + { + "UID" : "1.2.840.10008.1.2.4.58", + "Name" : "JPEG Lossless with any selection value, arithmetic coding", + "Value" : "JPEGProcess15", + "Retired" : true, + "DCMTK" : "EXS_JPEGProcess15" + }, + + { + "UID" : "1.2.840.10008.1.2.4.59", + "Name" : "JPEG Extended Sequential, Hierarchical (lossy, 8/12 bit)", + "Value" : "JPEGProcess16_18", + "Retired" : true, + "DCMTK" : "EXS_JPEGProcess16_18" + }, + + { + "UID" : "1.2.840.10008.1.2.4.60", + "Name" : "JPEG Extended Sequential, Hierarchical (lossy, 8/12 bit), arithmetic coding", + "Value" : "JPEGProcess17_19", + "Retired" : true, + "DCMTK" : "EXS_JPEGProcess17_19" + }, + + { + "UID" : "1.2.840.10008.1.2.4.61", + "Name" : "JPEG Spectral Selection, Hierarchical (lossy, 8/12 bit)", + "Value" : "JPEGProcess20_22", + "Retired" : true, + "DCMTK" : "EXS_JPEGProcess20_22" + }, + + { + "UID" : "1.2.840.10008.1.2.4.62", + "Name" : "JPEG Spectral Selection, Hierarchical (lossy, 8/12 bit), arithmetic coding", + "Value" : "JPEGProcess21_23", + "Retired" : true, + "DCMTK" : "EXS_JPEGProcess21_23" + }, + + { + "UID" : "1.2.840.10008.1.2.4.63", + "Name" : "JPEG Full Progression, Hierarchical (lossy, 8/12 bit)", + "Value" : "JPEGProcess24_26", + "Retired" : true, + "DCMTK" : "EXS_JPEGProcess24_26" + }, + + { + "UID" : "1.2.840.10008.1.2.4.64", + "Name" : "JPEG Full Progression, Hierarchical (lossy, 8/12 bit), arithmetic coding", + "Value" : "JPEGProcess25_27", + "Retired" : true, + "DCMTK" : "EXS_JPEGProcess25_27" + }, + + { + "UID" : "1.2.840.10008.1.2.4.65", + "Name" : "JPEG Lossless, Hierarchical", + "Value" : "JPEGProcess28", + "Retired" : true, + "DCMTK" : "EXS_JPEGProcess28" + }, + + { + "UID" : "1.2.840.10008.1.2.4.66", + "Name" : "JPEG Lossless, Hierarchical, arithmetic coding", + "Value" : "JPEGProcess29", + "Retired" : true, + "DCMTK" : "EXS_JPEGProcess29" + }, + + { + "UID" : "1.2.840.10008.1.2.4.70", + "Name" : "JPEG Lossless, Nonhierarchical, First-Order Prediction (Processes 14 [Selection Value 1])", + "Value" : "JPEGProcess14SV1", + "Retired" : false, + "Note" : "Default Transfer Syntax for Lossless JPEG Image Compression", + "DCMTK" : "EXS_JPEGProcess14SV1", + "GDCM" : "gdcm::TransferSyntax::JPEGLosslessProcess14_1" + }, + + { + "UID" : "1.2.840.10008.1.2.4.80", + "Name" : "JPEG-LS (lossless)", + "Value" : "JPEGLSLossless", + "Retired" : false, + "DCMTK" : "EXS_JPEGLSLossless", + "GDCM" : "gdcm::TransferSyntax::JPEGLSLossless" + }, + + { + "UID" : "1.2.840.10008.1.2.4.81", + "Name" : "JPEG-LS (lossy or near-lossless)", + "Value" : "JPEGLSLossy", + "Retired" : false, + "DCMTK" : "EXS_JPEGLSLossy", + "GDCM" : "gdcm::TransferSyntax::JPEGLSNearLossless" + }, + + { + "UID" : "1.2.840.10008.1.2.4.90", + "Name" : "JPEG 2000 (lossless)", + "Value" : "JPEG2000LosslessOnly", + "Retired" : false, + "DCMTK" : "EXS_JPEG2000LosslessOnly", + "GDCM" : "gdcm::TransferSyntax::JPEG2000Lossless" + }, + + { + "UID" : "1.2.840.10008.1.2.4.91", + "Name" : "JPEG 2000 (lossless or lossy)", + "Value" : "JPEG2000", + "Retired" : false, + "DCMTK" : "EXS_JPEG2000", + "GDCM" : "gdcm::TransferSyntax::JPEG2000" + }, + + { + "UID" : "1.2.840.10008.1.2.4.92", + "Name" : "JPEG 2000 part 2 multicomponent extensions (lossless)", + "Value" : "JPEG2000MulticomponentLosslessOnly", + "Retired" : false, + "DCMTK" : "EXS_JPEG2000MulticomponentLosslessOnly", + "GDCM" : "gdcm::TransferSyntax::JPEG2000Part2Lossless" + }, + + { + "UID" : "1.2.840.10008.1.2.4.93", + "Name" : "JPEG 2000 part 2 multicomponent extensions (lossless or lossy)", + "Value" : "JPEG2000Multicomponent", + "Retired" : false, + "DCMTK" : "EXS_JPEG2000Multicomponent", + "GDCM" : "gdcm::TransferSyntax::JPEG2000Part2" + }, + + { + "UID" : "1.2.840.10008.1.2.4.94", + "Name" : "JPIP Referenced", + "Value" : "JPIPReferenced", + "Retired" : false, + "DCMTK" : "EXS_JPIPReferenced" + }, + + { + "UID" : "1.2.840.10008.1.2.4.95", + "Name" : "JPIP Referenced Deflate", + "Value" : "JPIPReferencedDeflate", + "Retired" : false, + "DCMTK" : "EXS_JPIPReferencedDeflate" + }, + + { + "UID" : "1.2.840.10008.1.2.4.100", + "Name" : "MPEG2 Main Profile at Main Level", + "Value" : "MPEG2MainProfileAtMainLevel", + "Retired" : false, + "DCMTK" : "EXS_MPEG2MainProfileAtMainLevel" + }, + + { + "UID" : "1.2.840.10008.1.2.4.101", + "Name" : "MPEG2 Main Profile at High Level", + "Value" : "MPEG2MainProfileAtHighLevel", + "Retired" : false, + "DCMTK" : "EXS_MPEG2MainProfileAtHighLevel" + }, + + { + "UID" : "1.2.840.10008.1.2.4.102", + "Name" : "MPEG4 High Profile / Level 4.1", + "Value" : "MPEG4HighProfileLevel4_1", + "Retired" : false, + "DCMTK" : "EXS_MPEG4HighProfileLevel4_1" + }, + + { + "UID" : "1.2.840.10008.1.2.4.103", + "Name" : "MPEG4 BD-compatible High Profile / Level 4.1", + "Value" : "MPEG4BDcompatibleHighProfileLevel4_1", + "Retired" : false, + "DCMTK" : "EXS_MPEG4BDcompatibleHighProfileLevel4_1" + }, + + { + "UID" : "1.2.840.10008.1.2.4.104", + "Name" : "MPEG4 High Profile / Level 4.2 For 2D Video", + "Value" : "MPEG4HighProfileLevel4_2_For2DVideo", + "Retired" : false, + "DCMTK" : "EXS_MPEG4HighProfileLevel4_2_For2DVideo" + }, + + { + "UID" : "1.2.840.10008.1.2.4.105", + "Name" : "MPEG4 High Profile / Level 4.2 For 3D Video", + "Value" : "MPEG4HighProfileLevel4_2_For3DVideo", + "Retired" : false, + "DCMTK" : "EXS_MPEG4HighProfileLevel4_2_For3DVideo" + }, + + { + "UID" : "1.2.840.10008.1.2.4.106", + "Name" : "1.2.840.10008.1.2.4.106", + "Value" : "MPEG4StereoHighProfileLevel4_2", + "Retired" : false, + "DCMTK" : "EXS_MPEG4StereoHighProfileLevel4_2" + }, + + { + "UID" : "1.2.840.10008.1.2.4.107", + "Name" : "HEVC/H.265 Main Profile / Level 5.1", + "Value" : "HEVCMainProfileLevel5_1", + "Retired" : false, + "DCMTK" : "EXS_HEVCMainProfileLevel5_1", + "SinceDCMTK" : "362" + }, + + { + "UID" : "1.2.840.10008.1.2.4.108", + "Name" : "HEVC/H.265 Main 10 Profile / Level 5.1", + "Value" : "HEVCMain10ProfileLevel5_1", + "Retired" : false, + "DCMTK" : "EXS_HEVCMain10ProfileLevel5_1", + "SinceDCMTK" : "362" + }, + + { + "UID" : "1.2.840.10008.1.2.5", + "Name" : "RLE - Run Length Encoding (lossless)", + "Value" : "RLELossless", + "Retired" : false, + "DCMTK" : "EXS_RLELossless", + "GDCM" : "gdcm::TransferSyntax::RLELossless" + }, + + { + "UID" : "1.2.840.10008.1.2.6.1", + "Name" : "RFC 2557 MIME Encapsulation", + "Value" : "RFC2557MimeEncapsulation", + "Retired" : true + }, + + { + "UID" : "1.2.840.10008.1.2.6.2", + "Name" : "XML Encoding", + "Value" : "XML", + "Retired" : true + } +] diff -r 7b7ca203f1a3 -r 090022f1b5e1 Resources/GenerateTransferSyntaxes.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/GenerateTransferSyntaxes.py Fri Mar 06 17:10:03 2020 +0100 @@ -0,0 +1,107 @@ +#!/usr/bin/python + +# Orthanc - A Lightweight, RESTful DICOM Store +# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics +# Department, University Hospital of Liege, Belgium +# Copyright (C) 2017-2020 Osimis S.A., Belgium +# +# This program is free software: you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# In addition, as a special exception, the copyright holders of this +# program give permission to link the code of its release with the +# OpenSSL project's "OpenSSL" library (or with modified versions of it +# that use the same license as the "OpenSSL" library), and distribute +# the linked executables. You must obey the GNU General Public License +# in all respects for all of the code used other than "OpenSSL". If you +# modify file(s) with this exception, you may extend this exception to +# your version of the file(s), but you are not obligated to do so. If +# you do not wish to do so, delete this exception statement from your +# version. If you delete this exception statement from all source files +# in the program, then also delete it here. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +import json +import os +import re +import sys + +BASE = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) + + + +## https://www.dicomlibrary.com/dicom/transfer-syntax/ +## https://cedocs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=EDICOM_transfer_syntax + + +with open(os.path.join(BASE, 'Resources', 'DicomTransferSyntaxes.json'), 'r') as f: + SYNTAXES = json.loads(f.read()) + + + +## +## Generate the "DicomTransferSyntax" enumeration in "Enumerations.h" +## + +path = os.path.join(BASE, 'Core', 'Enumerations.h') +with open(path, 'r') as f: + a = f.read() + +s = ',\n'.join(map(lambda x: ' DicomTransferSyntax_%s /*!< %s */' % (x['Value'], x['Name']), SYNTAXES)) + +a = re.sub('(enum DicomTransferSyntax\s*{)[^}]*?(\s*};)', r'\1\n%s\2' % s, a, re.DOTALL) + +with open(path, 'w') as f: + f.write(a) + + + +## +## Generate the "GetTransferSyntaxUid()" function in +## "Enumerations.cpp" +## + +path = os.path.join(BASE, 'Core', 'Enumerations.cpp') +with open(path, 'r') as f: + a = f.read() + +s = '\n\n'.join(map(lambda x: ' case DicomTransferSyntax_%s:\n return "%s";' % (x['Value'], x['UID']), SYNTAXES)) +a = re.sub('(GetTransferSyntaxUid\(DicomTransferSyntax.*?\)\s*{\s*switch \([^)]*?\)\s*{)[^}]*?(\s*default:)', + r'\1\n%s\2' % s, a, re.DOTALL) + +with open(path, 'w') as f: + f.write(a) + + +## +## Generate the "GetDcmtkTransferSyntax()" function in +## "FromDcmtkBridge.cpp" +## + +path = os.path.join(BASE, 'Core', 'DicomParsing', 'FromDcmtkBridge.cpp') +with open(path, 'r') as f: + a = f.read() + +def Format(x): + t = ' case DicomTransferSyntax_%s:\n target = %s;\n return true;' % (x['Value'], x['DCMTK']) + if 'SinceDCMTK' in x: + return '#if DCMTK_VERSION_NUMBER >= %s\n%s\n#endif' % (x['SinceDCMTK'], t) + else: + return t + +s = '\n\n'.join(map(Format, filter(lambda x: 'DCMTK' in x, SYNTAXES))) +a = re.sub('(GetDcmtkTransferSyntax\(E_TransferSyntax.*?\s*DicomTransferSyntax.*?\)\s*{\s*switch \([^)]*?\)\s*{)[^}]*?(\s*default:)', + r'\1\n%s\2' % s, a, re.DOTALL) + +with open(path, 'w') as f: + f.write(a) diff -r 7b7ca203f1a3 -r 090022f1b5e1 UnitTestsSources/FromDcmtkTests.cpp --- a/UnitTestsSources/FromDcmtkTests.cpp Fri Mar 06 11:52:44 2020 +0100 +++ b/UnitTestsSources/FromDcmtkTests.cpp Fri Mar 06 17:10:03 2020 +0100 @@ -1912,3 +1912,123 @@ ASSERT_TRUE(lines[3].empty()); } + + + +#if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 + +#include + +static bool Transcode(std::string& buffer, + DcmDataset& dataSet, + E_TransferSyntax xfer) +{ + // Determine the transfer syntax which shall be used to write the + // information to the file. We always switch to the Little Endian + // syntax, with explicit length. + + // http://support.dcmtk.org/docs/dcxfer_8h-source.html + + + /** + * Note that up to Orthanc 0.7.1 (inclusive), the + * "EXS_LittleEndianExplicit" was always used to save the DICOM + * dataset into memory. We now keep the original transfer syntax + * (if available). + **/ + //E_TransferSyntax xfer = dataSet.getOriginalXfer(); + if (xfer == EXS_Unknown) + { + // No information about the original transfer syntax: This is + // most probably a DICOM dataset that was read from memory. + xfer = EXS_LittleEndianExplicit; + } + + E_EncodingType encodingType = /*opt_sequenceType*/ EET_ExplicitLength; + + // Create the meta-header information + DcmFileFormat ff(&dataSet); + ff.validateMetaInfo(xfer); + ff.removeInvalidGroups(); + + // Create a memory buffer with the proper size + { + const uint32_t estimatedSize = ff.calcElementLength(xfer, encodingType); // (*) + buffer.resize(estimatedSize); + } + + DcmOutputBufferStream ob(&buffer[0], buffer.size()); + + // Fill the memory buffer with the meta-header and the dataset + ff.transferInit(); + OFCondition c = ff.write(ob, xfer, encodingType, NULL, + /*opt_groupLength*/ EGL_recalcGL, + /*opt_paddingType*/ EPD_withoutPadding); + ff.transferEnd(); + + if (c.good()) + { + // The DICOM file is successfully written, truncate the target + // buffer if its size was overestimated by (*) + ob.flush(); + + size_t effectiveSize = static_cast(ob.tell()); + if (effectiveSize < buffer.size()) + { + buffer.resize(effectiveSize); + } + + return true; + } + else + { + // Error + buffer.clear(); + return false; + } +} + +#include "dcmtk/dcmjpeg/djrploss.h" /* for DJ_RPLossy */ +#include "dcmtk/dcmjpeg/djrplol.h" /* for DJ_RPLossless */ + +TEST(Toto, Transcode) +{ + OFLog::configure(OFLogger::DEBUG_LOG_LEVEL); + std::string s; + //SystemToolbox::ReadFile(s, "/home/jodogne/Subversion/orthanc-tests/Database/TransferSyntaxes/1.2.840.10008.1.2.4.50.dcm"); + //SystemToolbox::ReadFile(s, "/home/jodogne/DICOM/Alain.dcm"); + SystemToolbox::ReadFile(s, "/home/jodogne/Subversion/orthanc-tests/Database/Brainix/Epi/IM-0001-0002.dcm"); + + std::auto_ptr dicom(FromDcmtkBridge::LoadFromMemoryBuffer(s.c_str(), s.size())); + + // less /home/jodogne/Downloads/dcmtk-3.6.4/dcmdata/include/dcmtk/dcmdata/dcxfer.h + printf(">> %d\n", dicom->getDataset()->getOriginalXfer()); // => 4 == EXS_JPEGProcess1 + + const DcmRepresentationParameter *p; + +#if 0 + E_TransferSyntax target = EXS_LittleEndianExplicit; + p = NULL; +#elif 1 + E_TransferSyntax target = EXS_JPEGProcess14SV1; + DJ_RPLossless rp_lossless(6, 0); + p = &rp_lossless; +#else + E_TransferSyntax target = EXS_JPEGProcess1; + DJ_RPLossy rp_lossy(90); // quality + p = &rp_lossy; +#endif + + //E_TransferSyntax target = EXS_LittleEndianImplicit; + + ASSERT_TRUE(dicom->getDataset()->chooseRepresentation(target, p).good()); + ASSERT_TRUE(dicom->getDataset()->canWriteXfer(target)); + + std::string t; + ASSERT_TRUE(Transcode(t, *dicom->getDataset(), target)); + + SystemToolbox::WriteFile(s, "source.dcm"); + SystemToolbox::WriteFile(t, "target.dcm"); +} + +#endif