changeset 3748:ca36e3f1112c transcoding

transcoding to uncompressed transfer syntaxes
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 13 Mar 2020 16:50:13 +0100
parents 7b6058f8f7aa
children 3b5feb2bbd4b
files Core/DicomParsing/FromDcmtkBridge.cpp Core/DicomParsing/FromDcmtkBridge.h UnitTestsSources/FromDcmtkTests.cpp
diffstat 3 files changed, 166 insertions(+), 72 deletions(-) [+]
line wrap: on
line diff
--- a/Core/DicomParsing/FromDcmtkBridge.cpp	Fri Mar 13 08:32:13 2020 +0100
+++ b/Core/DicomParsing/FromDcmtkBridge.cpp	Fri Mar 13 16:50:13 2020 +0100
@@ -120,6 +120,12 @@
 #endif
 
 
+#include <dcmtk/dcmdata/dcrledrg.h>
+#if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1
+#  include <dcmtk/dcmdata/dcrleerg.h>
+#endif
+
+
 namespace Orthanc
 {
   static bool IsBinaryTag(const DcmTag& key)
@@ -1197,6 +1203,52 @@
     }
   }
 
+
+
+  static bool SaveToMemoryBufferInternal(std::string& buffer,
+                                         DcmFileFormat& dicom,
+                                         E_TransferSyntax xfer)
+  {
+    E_EncodingType encodingType = /*opt_sequenceType*/ EET_ExplicitLength;
+
+    // Create a memory buffer with the proper size
+    {
+      const uint32_t estimatedSize = dicom.calcElementLength(xfer, encodingType);  // (*)
+      buffer.resize(estimatedSize);
+    }
+
+    DcmOutputBufferStream ob(&buffer[0], buffer.size());
+
+    // Fill the memory buffer with the meta-header and the dataset
+    dicom.transferInit();
+    OFCondition c = dicom.write(ob, xfer, encodingType, NULL,
+                                /*opt_groupLength*/ EGL_recalcGL,
+                                /*opt_paddingType*/ EPD_withoutPadding);
+    dicom.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;
+    }
+  }
+  
+
   bool FromDcmtkBridge::SaveToMemoryBuffer(std::string& buffer,
                                            DcmDataset& dataSet)
   {
@@ -1221,47 +1273,51 @@
       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
+    return SaveToMemoryBufferInternal(buffer, ff, xfer);
+  }
+
+
+  bool FromDcmtkBridge::SaveToMemoryBuffer(std::string& buffer,
+                                           DcmFileFormat& dicom)
+  {
+    E_TransferSyntax xfer = dicom.getDataset()->getOriginalXfer();
+    if (xfer == EXS_Unknown)
     {
-      const uint32_t estimatedSize = ff.calcElementLength(xfer, encodingType);  // (*)
-      buffer.resize(estimatedSize);
+      throw OrthancException(ErrorCode_InternalError,
+                             "Cannot write a DICOM instance with unknown transfer syntax");
     }
-
-    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())
+    else if (!dicom.validateMetaInfo(xfer).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;
+      throw OrthancException(ErrorCode_InternalError,
+                             "Cannot setup the transfer syntax to write a DICOM instance");
     }
     else
     {
-      // Error
-      buffer.clear();
-      return false;
+      return SaveToMemoryBufferInternal(buffer, dicom, xfer);
+    }
+  }
+
+
+  bool FromDcmtkBridge::Transcode(std::string& buffer,
+                                  DcmFileFormat& dicom,
+                                  DicomTransferSyntax syntax,
+                                  const DcmRepresentationParameter* representation)
+  {
+    E_TransferSyntax xfer;
+    if (!LookupDcmtkTransferSyntax(xfer, syntax))
+    {
+      throw OrthancException(ErrorCode_InternalError);
+    }
+    else
+    {
+      return (dicom.getDataset()->chooseRepresentation(xfer, representation).good() &&
+              dicom.getDataset()->canWriteXfer(xfer) &&
+              SaveToMemoryBufferInternal(buffer, dicom, xfer));
     }
   }
 
@@ -2064,6 +2120,12 @@
     DJEncoderRegistration::registerCodecs();
 # endif
 #endif
+
+    LOG(INFO) << "Registering RLE codecs in DCMTK";
+    DcmRLEDecoderRegistration::registerCodecs(); 
+#if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1
+    DcmRLEEncoderRegistration::registerCodecs();
+#endif
   }
 
 
@@ -2084,6 +2146,11 @@
     DJEncoderRegistration::cleanup();
 # endif
 #endif
+
+    DcmRLEDecoderRegistration::cleanup(); 
+#if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1
+    DcmRLEEncoderRegistration::cleanup();
+#endif
   }
 
 
--- a/Core/DicomParsing/FromDcmtkBridge.h	Fri Mar 13 08:32:13 2020 +0100
+++ b/Core/DicomParsing/FromDcmtkBridge.h	Fri Mar 13 16:50:13 2020 +0100
@@ -205,6 +205,14 @@
     static bool SaveToMemoryBuffer(std::string& buffer,
                                    DcmDataset& dataSet);
 
+    static bool SaveToMemoryBuffer(std::string& buffer,
+                                   DcmFileFormat& dicom);
+
+    static bool Transcode(std::string& buffer,
+                          DcmFileFormat& dicom,
+                          DicomTransferSyntax syntax,
+                          const DcmRepresentationParameter* representation);
+
     static ValueRepresentation Convert(DcmEVR vr);
 
     static ValueRepresentation LookupValueRepresentation(const DicomTag& tag);
--- a/UnitTestsSources/FromDcmtkTests.cpp	Fri Mar 13 08:32:13 2020 +0100
+++ b/UnitTestsSources/FromDcmtkTests.cpp	Fri Mar 13 16:50:13 2020 +0100
@@ -1946,8 +1946,11 @@
     virtual void GetCompressedFrame(std::string& target,
                                     unsigned int frame) = 0;
 
-    virtual IDicomTranscoder* Transcode(std::set<DicomTransferSyntax> syntaxes,
-                                        bool allowNewSopInstanceUid) = 0;
+    virtual bool Transcode(std::string& target,
+                           std::set<DicomTransferSyntax> syntaxes,
+                           bool allowNewSopInstanceUid) = 0;
+
+    virtual void WriteToMemoryBuffer(std::string& target) = 0;
   };
 
 
@@ -2040,6 +2043,15 @@
       return index_->GetFramesCount();
     }
 
+    virtual void WriteToMemoryBuffer(std::string& target) ORTHANC_OVERRIDE
+    {
+      if (!FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_))
+      {
+        throw OrthancException(ErrorCode_InternalError,
+                               "Cannot write the DICOM instance to a memory buffer");
+      }
+    }
+
     virtual ImageAccessor* DecodeFrame(unsigned int frame) ORTHANC_OVERRIDE
     {
       assert(dicom_->getDataset() != NULL);
@@ -2049,48 +2061,32 @@
     virtual void GetCompressedFrame(std::string& target,
                                     unsigned int frame) ORTHANC_OVERRIDE
     {
-#if 1
       index_->GetRawFrame(target, frame);
-      printf("%d: %d\n", frame, target.size());
-#endif
-
-#if 1
-      assert(dicom_->getDataset() != NULL);
-      DcmDataset& dataset = *dicom_->getDataset();
-      
-      DcmPixelSequence* pixelSequence = FromDcmtkBridge::GetPixelSequence(dataset);
-
-      if (pixelSequence != NULL &&
-          frame == 0 &&
-          pixelSequence->card() != GetFramesCount() + 1)
-      {
-        printf("COMPRESSED\n");
-        
-        // Check out "djcodecd.cc"
-        
-        printf("%d fragments\n", pixelSequence->card());
-        
-        // Skip the first fragment, that is the offset table
-        for (unsigned long i = 1; ;i++)
-        {
-          DcmPixelItem *fragment = NULL;
-          if (pixelSequence->getItem(fragment, i).good())
-          {
-            printf("fragment %d %d\n", i, fragment->getLength());
-          }
-          else
-          {
-            break;
-          }
-        }
-      }
-#endif
     }
 
-    virtual IDicomTranscoder* Transcode(std::set<DicomTransferSyntax> syntaxes,
-                                        bool allowNewSopInstanceUid) ORTHANC_OVERRIDE
+    virtual bool Transcode(std::string& target,
+                           std::set<DicomTransferSyntax> syntaxes,
+                           bool allowNewSopInstanceUid) ORTHANC_OVERRIDE
     {
-      throw OrthancException(ErrorCode_NotImplemented);
+      if (syntaxes.find(DicomTransferSyntax_LittleEndianImplicit) != syntaxes.end() &&
+          FromDcmtkBridge::Transcode(target, *dicom_, DicomTransferSyntax_LittleEndianImplicit, NULL))
+      {
+        return true;
+      }
+      else if (syntaxes.find(DicomTransferSyntax_LittleEndianExplicit) != syntaxes.end() &&
+               FromDcmtkBridge::Transcode(target, *dicom_, DicomTransferSyntax_LittleEndianExplicit, NULL))
+      {
+        return true;
+      }
+      else if (syntaxes.find(DicomTransferSyntax_BigEndianExplicit) != syntaxes.end() &&
+               FromDcmtkBridge::Transcode(target, *dicom_, DicomTransferSyntax_BigEndianExplicit, NULL))
+      {
+        return true;
+      }
+      else
+      {
+        return false;
+      }
     }
   };
 }
@@ -2182,9 +2178,9 @@
 
   Orthanc::DcmtkTranscoder transcoder(s.c_str(), s.size());
 
-  printf("[%s] [%s] [%s] %d\n", GetTransferSyntaxUid(transcoder.GetTransferSyntax()),
+  printf("[%s] [%s] [%s] %d %d\n", GetTransferSyntaxUid(transcoder.GetTransferSyntax()),
          transcoder.GetSopClassUid().c_str(), transcoder.GetSopInstanceUid().c_str(),
-         transcoder.GetFramesCount());
+         transcoder.GetFramesCount(), transcoder.GetTransferSyntax());
 
   for (size_t i = 0; i < transcoder.GetFramesCount(); i++)
   {
@@ -2201,6 +2197,29 @@
     }
   }
 
+  {
+    std::string t;
+    transcoder.WriteToMemoryBuffer(t);
+
+    Orthanc::DcmtkTranscoder transcoder2(t.c_str(), t.size());
+    printf(">> %d %d ; %d bytes\n", transcoder.GetTransferSyntax(), transcoder2.GetTransferSyntax(), t.size());
+  }
+
+  {
+    std::set<DicomTransferSyntax> syntaxes;
+    syntaxes.insert(DicomTransferSyntax_LittleEndianExplicit);
+
+    std::string t;
+    bool ok = transcoder.Transcode(t, syntaxes, false);
+    printf("Transcoding: %d\n", ok);
+
+    if (ok)
+    {
+      Orthanc::DcmtkTranscoder transcoder2(t.c_str(), t.size());
+      printf("  => transcoded transfer syntax %d ; %d bytes\n", transcoder2.GetTransferSyntax(), t.size());
+    }
+  }
+  
   printf("\n");
 }