changeset 3727:090022f1b5e1

auto-generation of primitives to handle transfer syntaxes
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 06 Mar 2020 17:10:03 +0100
parents 7b7ca203f1a3
children 982c24a70dfd
files Core/DicomParsing/FromDcmtkBridge.cpp Core/DicomParsing/FromDcmtkBridge.h Core/Enumerations.cpp Core/Enumerations.h Resources/CMake/OrthancFrameworkConfiguration.cmake Resources/CMake/OrthancFrameworkParameters.cmake Resources/DicomTransferSyntaxes.json Resources/GenerateTransferSyntaxes.py UnitTestsSources/FromDcmtkTests.cpp
diffstat 9 files changed, 975 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- 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 <dcmtk/dcmjpeg/djdecode.h>
+#  if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1
+#    include <dcmtk/dcmjpeg/djencode.h>
+#  endif
 #endif
 
 #if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1
 #  include <dcmtk/dcmjpls/djdecode.h>
+#  if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1
+#    include <dcmtk/dcmjpls/djencode.h>
+#  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;
+    }
+  }
 }
--- 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);
   };
 }
--- 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);
+    }
+  }
 }
--- 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);
 }
--- 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}
--- 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
--- /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
+  }
+]
--- /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 <http://www.gnu.org/licenses/>.
+
+
+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)
--- 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 <dcmtk/dcmdata/dcostrmb.h>
+
+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<size_t>(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<DcmFileFormat> 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