changeset 3883:795c9ca5eb91 transcoding

DANGEROUS changeset: replaced "getOriginalXfer()" by "getCurrentXfer()" throughout Orthanc
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 05 May 2020 14:11:47 +0200
parents 904575738462
children 83061cdc7703
files Core/DicomParsing/FromDcmtkBridge.cpp Core/DicomParsing/Internals/DicomImageDecoder.cpp Core/DicomParsing/ParsedDicomFile.cpp UnitTestsSources/FromDcmtkTests.cpp
diffstat 4 files changed, 110 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/Core/DicomParsing/FromDcmtkBridge.cpp	Tue May 05 12:29:33 2020 +0200
+++ b/Core/DicomParsing/FromDcmtkBridge.cpp	Tue May 05 14:11:47 2020 +0200
@@ -1290,7 +1290,7 @@
      * dataset into memory. We now keep the original transfer syntax
      * (if available).
      **/
-    E_TransferSyntax xfer = dataSet.getOriginalXfer();
+    E_TransferSyntax xfer = dataSet.getCurrentXfer();
     if (xfer == EXS_Unknown)
     {
       // No information about the original transfer syntax: This is
@@ -1310,7 +1310,7 @@
   bool FromDcmtkBridge::SaveToMemoryBuffer(std::string& buffer,
                                            DcmFileFormat& dicom)
   {
-    E_TransferSyntax xfer = dicom.getDataset()->getOriginalXfer();
+    E_TransferSyntax xfer = dicom.getDataset()->getCurrentXfer();
     if (xfer == EXS_Unknown)
     {
       throw OrthancException(ErrorCode_InternalError,
@@ -1338,7 +1338,7 @@
       throw OrthancException(ErrorCode_InternalError);
     }
     else
-    {
+    {     
       if (!dicom.getDataset()->chooseRepresentation(xfer, representation).good() ||
           !dicom.getDataset()->canWriteXfer(xfer) ||
           !dicom.validateMetaInfo(xfer, EWM_updateMeta).good())
@@ -1348,6 +1348,20 @@
       else
       {
         dicom.removeInvalidGroups();
+
+        DicomTransferSyntax sourceSyntax;
+        if (LookupOrthancTransferSyntax(sourceSyntax, dicom))
+        {
+          LOG(INFO) << "Transcoded an image from transfer syntax "
+                    << GetTransferSyntaxUid(sourceSyntax) << " to "
+                    << GetTransferSyntaxUid(syntax);
+        }
+        else
+        {
+          LOG(INFO) << "Transcoded an image from unknown transfer syntax to "
+                    << GetTransferSyntaxUid(syntax);
+        }
+        
         return true;
       }
     }
@@ -1808,7 +1822,7 @@
     DcmPixelData& pixelData = dynamic_cast<DcmPixelData&>(*element);
     DcmPixelSequence* pixelSequence = NULL;
     if (!pixelData.getEncapsulatedRepresentation
-        (dataset.getOriginalXfer(), NULL, pixelSequence).good())
+        (dataset.getCurrentXfer(), NULL, pixelSequence).good())
     {
       return NULL;
     }
@@ -2670,7 +2684,7 @@
         
     DcmDataset& dataset = *dicom.getDataset();
 
-    E_TransferSyntax xfer = dataset.getOriginalXfer();
+    E_TransferSyntax xfer = dataset.getCurrentXfer();
     if (xfer == EXS_Unknown)
     {
       dataset.updateOriginalXfer();
--- a/Core/DicomParsing/Internals/DicomImageDecoder.cpp	Tue May 05 12:29:33 2020 +0200
+++ b/Core/DicomParsing/Internals/DicomImageDecoder.cpp	Tue May 05 14:11:47 2020 +0200
@@ -676,7 +676,7 @@
   ImageAccessor* DicomImageDecoder::Decode(DcmDataset& dataset,
                                            unsigned int frame)
   {
-    E_TransferSyntax syntax = dataset.getOriginalXfer();
+    E_TransferSyntax syntax = dataset.getCurrentXfer();
 
     /**
      * Deal with uncompressed, raw images.
--- a/Core/DicomParsing/ParsedDicomFile.cpp	Tue May 05 12:29:33 2020 +0200
+++ b/Core/DicomParsing/ParsedDicomFile.cpp	Tue May 05 14:11:47 2020 +0200
@@ -456,7 +456,7 @@
                                       const UriComponents& uri)
   {
     DcmItem* dicom = pimpl_->file_->getDataset();
-    E_TransferSyntax transferSyntax = pimpl_->file_->getDataset()->getOriginalXfer();
+    E_TransferSyntax transferSyntax = pimpl_->file_->getDataset()->getCurrentXfer();
 
     // Special case: Accessing the pixel data
     if (uri.size() == 1 || 
@@ -1564,7 +1564,7 @@
 
     pimpl_->frameIndex_->GetRawFrame(target, frameId);
 
-    E_TransferSyntax transferSyntax = pimpl_->file_->getDataset()->getOriginalXfer();
+    E_TransferSyntax transferSyntax = pimpl_->file_->getDataset()->getCurrentXfer();
     switch (transferSyntax)
     {
       case EXS_JPEGProcess1:
@@ -1625,7 +1625,7 @@
 
   bool ParsedDicomFile::LookupTransferSyntax(std::string& result)
   {
-    // TODO - Shouldn't "dataset.getOriginalXfer()" be used instead of
+    // TODO - Shouldn't "dataset.getCurrentXfer()" be used instead of
     // using the meta header?
     const char* value = NULL;
 
--- a/UnitTestsSources/FromDcmtkTests.cpp	Tue May 05 12:29:33 2020 +0200
+++ b/UnitTestsSources/FromDcmtkTests.cpp	Tue May 05 14:11:47 2020 +0200
@@ -2091,11 +2091,11 @@
         
       DcmDataset& dataset = *dicom.getDataset();
 
-      E_TransferSyntax xfer = dataset.getOriginalXfer();
+      E_TransferSyntax xfer = dataset.getCurrentXfer();
       if (xfer == EXS_Unknown)
       {
         dataset.updateOriginalXfer();
-        xfer = dataset.getOriginalXfer();
+        xfer = dataset.getCurrentXfer();
         if (xfer == EXS_Unknown)
         {
           throw OrthancException(ErrorCode_BadFileFormat,
@@ -2327,11 +2327,11 @@
       DcmDataset& dataset = *dicom_->getDataset();
       index_.reset(new DicomFrameIndex(dataset));
 
-      E_TransferSyntax xfer = dataset.getOriginalXfer();
+      E_TransferSyntax xfer = dataset.getCurrentXfer();
       if (xfer == EXS_Unknown)
       {
         dataset.updateOriginalXfer();
-        xfer = dataset.getOriginalXfer();
+        xfer = dataset.getCurrentXfer();
         if (xfer == EXS_Unknown)
         {
           throw OrthancException(ErrorCode_BadFileFormat,
@@ -2869,13 +2869,22 @@
     {
     }
 
+    /**
+     * Transcoding flavor that creates a new parsed DICOM file. A
+     * "std::set<>" is used to give the possible plugin the
+     * possibility to do a single parsing for all the possible
+     * transfer syntaxes.
+     **/
     virtual DcmFileFormat* Transcode(const void* buffer,
                                      size_t size,
                                      const std::set<DicomTransferSyntax>& allowedSyntaxes,
                                      bool allowNewSopInstanceUid) = 0;
 
-    // In-place transcoding. This method can return "false" if not supported,
-    // in which case the "Transcode()" method should be used.
+    /**
+     * In-place transcoding. This method is used first during
+     * C-STORE. It can return "false" if inplace is not supported, in
+     * which case the "Transcode()" method should be used.
+     **/
     virtual bool InplaceTranscode(DcmFileFormat& dicom,
                                   const std::set<DicomTransferSyntax>& allowedSyntaxes,
                                   bool allowNewSopInstanceUid) = 0;
@@ -2943,7 +2952,9 @@
           transcoded.reset(transcoder.Transcode(buffer, size, uncompressedSyntaxes, false));
         }
 
-        // The "dicom" variable must not be used below this point
+        // WARNING: The "dicom" variable must not be used below this
+        // point. The "sopInstanceUid" might also have changed (if
+        // using lossy compression).
         
         if (transcoded == NULL ||
             transcoded->getDataset() == NULL)
@@ -2971,6 +2982,17 @@
         }
       }
     }
+
+    static void Store(std::string& sopClassUid /* out */,
+                      std::string& sopInstanceUid /* out */,
+                      DicomStoreUserConnection& connection,
+                      IDicomTranscoder& transcoder,
+                      const void* buffer,
+                      size_t size)
+    {
+      Store(sopClassUid, sopInstanceUid, connection, transcoder,
+            buffer, size, "", 0 /* Not a C-MOVE */);
+    }
   };
 
 
@@ -3048,73 +3070,107 @@
         throw OrthancException(ErrorCode_InternalError);
       }
 
+      DicomTransferSyntax syntax;
+      if (!FromDcmtkBridge::LookupOrthancTransferSyntax(syntax, dicom))
+      {
+        throw OrthancException(ErrorCode_BadFileFormat,
+                               "Cannot determine the transfer syntax");
+      }
+
       const uint16_t bitsStored = GetBitsStored(*dicom.getDataset());
 
-#if 0     
-
-      if (syntax == DetectTransferSyntax(*dicom))
+      if (allowedSyntaxes.find(syntax) != allowedSyntaxes.end())
       {
         // No transcoding is needed
-        return new Image(dicom.release(), syntax);
+        return true;
       }
       
-      if (syntax == DicomTransferSyntax_LittleEndianImplicit &&
-          FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_LittleEndianImplicit, NULL))
+      if (allowedSyntaxes.find(DicomTransferSyntax_LittleEndianImplicit) != allowedSyntaxes.end() &&
+          FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_LittleEndianImplicit, NULL))
       {
-        return new Image(dicom.release(), syntax);
+        return true;
       }
 
-      if (syntax == DicomTransferSyntax_LittleEndianExplicit &&
-          FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_LittleEndianExplicit, NULL))
+      if (allowedSyntaxes.find(DicomTransferSyntax_LittleEndianExplicit) != allowedSyntaxes.end() &&
+          FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_LittleEndianExplicit, NULL))
       {
-        return new Image(dicom.release(), syntax);
+        return true;
       }
       
-      if (syntax == DicomTransferSyntax_BigEndianExplicit &&
-          FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_BigEndianExplicit, NULL))
+      if (allowedSyntaxes.find(DicomTransferSyntax_BigEndianExplicit) != allowedSyntaxes.end() &&
+          FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_BigEndianExplicit, NULL))
       {
-        return new Image(dicom.release(), syntax);
+        return true;
       }
 
-      if (syntax == DicomTransferSyntax_DeflatedLittleEndianExplicit &&
-          FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_DeflatedLittleEndianExplicit, NULL))
+      if (allowedSyntaxes.find(DicomTransferSyntax_DeflatedLittleEndianExplicit) != allowedSyntaxes.end() &&
+          FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_DeflatedLittleEndianExplicit, NULL))
       {
-        return new Image(dicom.release(), syntax);
+        return true;
       }
 
 #if ORTHANC_ENABLE_JPEG == 1
-      if (syntax == DicomTransferSyntax_JPEGProcess1 &&
+      if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess1) != allowedSyntaxes.end() &&
           allowNewSopInstanceUid &&
           bitsStored == 8)
       {
         DJ_RPLossy rpLossy(lossyQuality_);
         
-        if (FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_JPEGProcess1, &rpLossy))
+        if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess1, &rpLossy))
         {
-          return new Image(dicom.release(), syntax);
+          return true;
         }
       }
 #endif
       
 #if ORTHANC_ENABLE_JPEG == 1
-      if (syntax == DicomTransferSyntax_JPEGProcess2_4 &&
+      if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess2_4) != allowedSyntaxes.end() &&
           allowNewSopInstanceUid &&
           bitsStored <= 12)
       {
         DJ_RPLossy rpLossy(lossyQuality_);
-        if (FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_JPEGProcess2_4, &rpLossy))
+        if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess2_4, &rpLossy))
         {
-          return new Image(dicom.release(), syntax);
+          return true;
         }
       }
 #endif
 
-#endif
-
       return false;
     }
   };
 }
 
 
+TEST(Toto, DISABLED_Transcode3)
+{
+  DicomAssociationParameters p;
+  p.SetRemotePort(2000);
+
+  DcmtkTranscoder transcoder;
+  
+  for (int i = 0; i <= DicomTransferSyntax_XML; i++)
+  {
+    DicomTransferSyntax a = (DicomTransferSyntax) i;
+
+    std::string path = ("/home/jodogne/Subversion/orthanc-tests/Database/TransferSyntaxes/" +
+                        std::string(GetTransferSyntaxUid(a)) + ".dcm");
+    if (Orthanc::SystemToolbox::IsRegularFile(path))
+    {
+      printf("\n======= %s\n", GetTransferSyntaxUid(a));
+
+      std::string source;
+      Orthanc::SystemToolbox::ReadFile(source, path);
+
+      DicomStoreUserConnection scu(p);
+      scu.SetCommonClassesProposed(false);
+      scu.SetRetiredBigEndianProposed(true);
+
+      std::string c, i;
+      IDicomTranscoder::Store(c, i, scu, transcoder, source.c_str(), source.size());
+    }
+  }
+}
+
+
 #endif