diff UnitTestsSources/FromDcmtkTests.cpp @ 3893:7a5fa8f307e9 transcoding

reorganization
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 06 May 2020 12:48:28 +0200
parents 56ce23ba93b7
children 8f7ad4989fec
line wrap: on
line diff
--- a/UnitTestsSources/FromDcmtkTests.cpp	Tue May 05 18:08:51 2020 +0200
+++ b/UnitTestsSources/FromDcmtkTests.cpp	Wed May 06 12:48:28 2020 +0200
@@ -1925,535 +1925,7 @@
 #if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1
 
 #include "../Core/DicomNetworking/DicomStoreUserConnection.h"
-
-#include <dcmtk/dcmjpeg/djrploss.h>  // for DJ_RPLossy
-#include <dcmtk/dcmjpeg/djrplol.h>   // for DJ_RPLossless
-#include <dcmtk/dcmjpls/djrparam.h>  // for DJLSRepresentationParameter
-
-
-#if !defined(ORTHANC_ENABLE_DCMTK_JPEG)
-#  error Macro ORTHANC_ENABLE_DCMTK_JPEG must be defined
-#endif
-
-#if !defined(ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS)
-#  error Macro ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS must be defined
-#endif
-
-
-
-namespace Orthanc
-{
-  /**
-   * WARNING: This class might be called from several threads at
-   * once. Make sure to implement proper locking.
-   **/
-  
-  class IDicomTranscoder : public boost::noncopyable
-  {
-  public:
-    virtual ~IDicomTranscoder()
-    {
-    }
-
-    virtual bool TranscodeToBuffer(std::string& target,
-                                   const void* buffer,
-                                   size_t size,
-                                   const std::set<DicomTransferSyntax>& allowedSyntaxes,
-                                   bool allowNewSopInstanceUid) = 0;
-
-    /**
-     * 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* TranscodeToParsed(const void* buffer,
-                                             size_t size,
-                                             const std::set<DicomTransferSyntax>& allowedSyntaxes,
-                                             bool allowNewSopInstanceUid) = 0;
-
-    virtual bool HasInplaceTranscode() const = 0;
-
-    /**
-     * In-place transcoding. This method is preferred for C-STORE.
-     **/
-    virtual bool InplaceTranscode(DcmFileFormat& dicom,
-                                  const std::set<DicomTransferSyntax>& allowedSyntaxes,
-                                  bool allowNewSopInstanceUid) = 0;
-
-    /**
-     * Important: Transcoding over the DICOM protocol is only
-     * implemented towards uncompressed transfer syntaxes.
-     **/
-    static void Store(std::string& sopClassUid /* out */,
-                      std::string& sopInstanceUid /* out */,
-                      DicomStoreUserConnection& connection,
-                      IDicomTranscoder& transcoder,
-                      const void* buffer,
-                      size_t size,
-                      const std::string& moveOriginatorAET,
-                      uint16_t moveOriginatorID)
-    {
-      std::unique_ptr<DcmFileFormat> dicom(FromDcmtkBridge::LoadFromMemoryBuffer(buffer, size));
-      if (dicom.get() == NULL ||
-          dicom->getDataset() == NULL)
-      {
-        throw OrthancException(ErrorCode_NullPointer);
-      }
-
-      DicomTransferSyntax inputSyntax;
-      connection.LookupParameters(sopClassUid, sopInstanceUid, inputSyntax, *dicom);
-
-      std::set<DicomTransferSyntax> accepted;
-      connection.LookupTranscoding(accepted, sopClassUid, inputSyntax);
-
-      if (accepted.find(inputSyntax) != accepted.end())
-      {
-        // No need for transcoding
-        connection.Store(sopClassUid, sopInstanceUid, *dicom, moveOriginatorAET, moveOriginatorID);
-      }
-      else
-      {
-        // Transcoding is needed
-        std::set<DicomTransferSyntax> uncompressedSyntaxes;
-
-        if (accepted.find(DicomTransferSyntax_LittleEndianImplicit) != accepted.end())
-        {
-          uncompressedSyntaxes.insert(DicomTransferSyntax_LittleEndianImplicit);
-        }
-
-        if (accepted.find(DicomTransferSyntax_LittleEndianExplicit) != accepted.end())
-        {
-          uncompressedSyntaxes.insert(DicomTransferSyntax_LittleEndianExplicit);
-        }
-
-        if (accepted.find(DicomTransferSyntax_BigEndianExplicit) != accepted.end())
-        {
-          uncompressedSyntaxes.insert(DicomTransferSyntax_BigEndianExplicit);
-        }
-
-        std::unique_ptr<DcmFileFormat> transcoded;
-
-        if (transcoder.HasInplaceTranscode())
-        {
-          if (transcoder.InplaceTranscode(*dicom, uncompressedSyntaxes, false))
-          {
-            // In-place transcoding is supported and has succeeded
-            transcoded.reset(dicom.release());
-          }
-        }
-        else
-        {
-          transcoded.reset(transcoder.TranscodeToParsed(buffer, size, uncompressedSyntaxes, false));
-        }
-
-        // 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)
-        {
-          throw OrthancException(
-            ErrorCode_NotImplemented,
-            "Cannot transcode from \"" + std::string(GetTransferSyntaxUid(inputSyntax)) +
-            "\" to an uncompressed syntax for modality: " +
-            connection.GetParameters().GetRemoteModality().GetApplicationEntityTitle());
-        }
-        else
-        {
-          DicomTransferSyntax transcodedSyntax;
-
-          // Sanity check
-          if (!FromDcmtkBridge::LookupOrthancTransferSyntax(transcodedSyntax, *transcoded) ||
-              accepted.find(transcodedSyntax) == accepted.end())
-          {
-            throw OrthancException(ErrorCode_InternalError);
-          }
-          else
-          {
-            connection.Store(sopClassUid, sopInstanceUid, *transcoded, moveOriginatorAET, moveOriginatorID);
-          }
-        }
-      }
-    }
-
-    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 */);
-    }
-  };
-
-
-  class DcmtkTranscoder : public IDicomTranscoder
-  {
-  private:
-    unsigned int  lossyQuality_;
-    
-    static uint16_t GetBitsStored(DcmDataset& dataset)
-    {
-      uint16_t bitsStored;
-      if (dataset.findAndGetUint16(DCM_BitsStored, bitsStored).good())
-      {
-        return bitsStored;
-      }
-      else
-      {
-        throw OrthancException(ErrorCode_BadFileFormat,
-                               "Missing \"Bits Stored\" tag in DICOM instance");
-      }      
-    }
-
-    static std::string GetSopInstanceUid(DcmDataset& dataset)
-    {
-      const char* v = NULL;
-
-      if (dataset.findAndGetString(DCM_SOPInstanceUID, v).good() &&
-          v != NULL)
-      {
-        return std::string(v);
-      }
-      else
-      {
-        throw OrthancException(ErrorCode_BadFileFormat, "File without SOP instance UID");
-      }
-    }
-
-    static void CheckSopInstanceUid(DcmFileFormat& dicom,
-                                    const std::string& sopInstanceUid,
-                                    bool mustEqual)
-    {
-      if (dicom.getDataset() == NULL)
-      {
-        throw OrthancException(ErrorCode_InternalError);
-      }
-      
-      bool ok;
-      
-      if (mustEqual)
-      {
-        ok = (GetSopInstanceUid(*dicom.getDataset()) == sopInstanceUid);
-      }
-      else
-      {
-        ok = (GetSopInstanceUid(*dicom.getDataset()) != sopInstanceUid);
-      }
-
-      if (!ok)
-      {
-        throw OrthancException(ErrorCode_InternalError,
-                               mustEqual ? "The SOP instance UID has changed unexpectedly during transcoding" :
-                               "The SOP instance UID has not changed as expected during transcoding");
-      }
-    }
-    
-  public:
-    DcmtkTranscoder() :
-      lossyQuality_(90)
-    {
-    }
-
-    void SetLossyQuality(unsigned int quality)
-    {
-      if (quality <= 0 ||
-          quality > 100)
-      {
-        throw OrthancException(ErrorCode_ParameterOutOfRange);
-      }
-      else
-      {
-        lossyQuality_ = quality;
-      }
-    }
-
-    unsigned int GetLossyQuality() const
-    {
-      return lossyQuality_;
-    }
-    
-    virtual DcmFileFormat* TranscodeToParsed(const void* buffer,
-                                             size_t size,
-                                             const std::set<DicomTransferSyntax>& allowedSyntaxes,
-                                             bool allowNewSopInstanceUid) ORTHANC_OVERRIDE
-    {
-      std::unique_ptr<DcmFileFormat> dicom(FromDcmtkBridge::LoadFromMemoryBuffer(buffer, size));
-
-      if (dicom.get() == NULL)
-      {
-        throw OrthancException(ErrorCode_InternalError);
-      }
-
-      if (InplaceTranscode(*dicom, allowedSyntaxes, allowNewSopInstanceUid))
-      {
-        return dicom.release();
-      }
-      else
-      {
-        return NULL;
-      }
-    }
-
-    virtual bool HasInplaceTranscode() const
-    {
-      return true;
-    }
-
-    virtual bool InplaceTranscode(DcmFileFormat& dicom,
-                                  const std::set<DicomTransferSyntax>& allowedSyntaxes,
-                                  bool allowNewSopInstanceUid) ORTHANC_OVERRIDE
-    {
-      if (dicom.getDataset() == NULL)
-      {
-        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());
-      std::string sourceSopInstanceUid = GetSopInstanceUid(*dicom.getDataset());
-
-      if (allowedSyntaxes.find(syntax) != allowedSyntaxes.end())
-      {
-        // No transcoding is needed
-        return true;
-      }
-      
-      if (allowedSyntaxes.find(DicomTransferSyntax_LittleEndianImplicit) != allowedSyntaxes.end() &&
-          FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_LittleEndianImplicit, NULL))
-      {
-        CheckSopInstanceUid(dicom, sourceSopInstanceUid, true);
-        return true;
-      }
-
-      if (allowedSyntaxes.find(DicomTransferSyntax_LittleEndianExplicit) != allowedSyntaxes.end() &&
-          FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_LittleEndianExplicit, NULL))
-      {
-        CheckSopInstanceUid(dicom, sourceSopInstanceUid, true);
-        return true;
-      }
-      
-      if (allowedSyntaxes.find(DicomTransferSyntax_BigEndianExplicit) != allowedSyntaxes.end() &&
-          FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_BigEndianExplicit, NULL))
-      {
-        CheckSopInstanceUid(dicom, sourceSopInstanceUid, true);
-        return true;
-      }
-
-      if (allowedSyntaxes.find(DicomTransferSyntax_DeflatedLittleEndianExplicit) != allowedSyntaxes.end() &&
-          FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_DeflatedLittleEndianExplicit, NULL))
-      {
-        CheckSopInstanceUid(dicom, sourceSopInstanceUid, true);
-        return true;
-      }
-
-#if ORTHANC_ENABLE_DCMTK_JPEG == 1
-      if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess1) != allowedSyntaxes.end() &&
-          allowNewSopInstanceUid &&
-          bitsStored == 8)
-      {
-        // Check out "dcmjpeg/apps/dcmcjpeg.cc"
-        DJ_RPLossy parameters(lossyQuality_);
-        
-        if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess1, &parameters))
-        {
-          CheckSopInstanceUid(dicom, sourceSopInstanceUid, false);
-          return true;
-        }
-      }
-#endif
-      
-#if ORTHANC_ENABLE_DCMTK_JPEG == 1
-      if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess2_4) != allowedSyntaxes.end() &&
-          allowNewSopInstanceUid &&
-          bitsStored <= 12)
-      {
-        // Check out "dcmjpeg/apps/dcmcjpeg.cc"
-        DJ_RPLossy parameters(lossyQuality_);
-        if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess2_4, &parameters))
-        {
-          CheckSopInstanceUid(dicom, sourceSopInstanceUid, false);
-          return true;
-        }
-      }
-#endif
-      
-#if ORTHANC_ENABLE_DCMTK_JPEG == 1
-      if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess14SV1) != allowedSyntaxes.end())
-      {
-        // Check out "dcmjpeg/apps/dcmcjpeg.cc"
-        DJ_RPLossless parameters(6 /* opt_selection_value */,
-                                 0 /* opt_point_transform */);
-        if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess14SV1, &parameters))
-        {
-          CheckSopInstanceUid(dicom, sourceSopInstanceUid, true);
-          return true;
-        }
-      }
-#endif
-      
-#if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1
-      if (allowedSyntaxes.find(DicomTransferSyntax_JPEGLSLossless) != allowedSyntaxes.end())
-      {
-        // Check out "dcmjpls/apps/dcmcjpls.cc"
-        DJLSRepresentationParameter parameters(2 /* opt_nearlossless_deviation */,
-                                               OFTrue /* opt_useLosslessProcess */);
-
-        /**
-         * WARNING: This call results in a segmentation fault if using
-         * the DCMTK package 3.6.2 from Ubuntu 18.04.
-         **/              
-        if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGLSLossless, &parameters))
-        {
-          CheckSopInstanceUid(dicom, sourceSopInstanceUid, true);
-          return true;
-        }
-      }
-#endif
-      
-#if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1
-      if (allowNewSopInstanceUid &&
-          allowedSyntaxes.find(DicomTransferSyntax_JPEGLSLossy) != allowedSyntaxes.end())
-      {
-        // Check out "dcmjpls/apps/dcmcjpls.cc"
-        DJLSRepresentationParameter parameters(2 /* opt_nearlossless_deviation */,
-                                               OFFalse /* opt_useLosslessProcess */);
-
-        /**
-         * WARNING: This call results in a segmentation fault if using
-         * the DCMTK package 3.6.2 from Ubuntu 18.04.
-         **/              
-        if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGLSLossy, &parameters))
-        {
-          CheckSopInstanceUid(dicom, sourceSopInstanceUid, false);
-          return true;
-        }
-      }
-#endif
-
-      return false;
-    }
-
-    
-    virtual bool TranscodeToBuffer(std::string& target,
-                                   const void* buffer,
-                                   size_t size,
-                                   const std::set<DicomTransferSyntax>& allowedSyntaxes,
-                                   bool allowNewSopInstanceUid) ORTHANC_OVERRIDE
-    {
-      std::unique_ptr<DcmFileFormat> transcoded(
-        TranscodeToParsed(buffer, size, allowedSyntaxes, allowNewSopInstanceUid));
-
-      if (transcoded.get() == NULL)
-      {
-        return false;
-      }
-      else
-      {
-        if (transcoded->getDataset() == NULL)
-        {
-          throw OrthancException(ErrorCode_InternalError);
-        }          
-        
-        FromDcmtkBridge::SaveToMemoryBuffer(target, *transcoded->getDataset());
-        return true;
-      }
-    }
-  };
-
-
-
-  class PluginDicomTranscoder: public IDicomTranscoder
-  {
-  private:
-    bool             tryDcmtk_;
-    DcmtkTranscoder  dcmtk_;
-
-  protected:
-    virtual bool TranscodeInternal(std::string& target,
-                                   const void* buffer,
-                                   size_t size,
-                                   const std::set<DicomTransferSyntax>& allowedSyntaxes,
-                                   bool allowNewSopInstanceUid) = 0;
-    
-  public:
-    PluginDicomTranscoder(bool tryDcmtk) :
-      tryDcmtk_(tryDcmtk)
-    {
-    }
-    
-    virtual bool TranscodeToBuffer(std::string& target,
-                                   const void* buffer,
-                                   size_t size,
-                                   const std::set<DicomTransferSyntax>& allowedSyntaxes,
-                                   bool allowNewSopInstanceUid) ORTHANC_OVERRIDE
-    {
-      if (tryDcmtk_)
-      {
-        return dcmtk_.TranscodeToBuffer(target, buffer, size, allowedSyntaxes, allowNewSopInstanceUid);
-      }
-      else
-      {
-        return TranscodeInternal(target, buffer, size, allowedSyntaxes, allowNewSopInstanceUid);
-      }
-    }
-    
-    virtual DcmFileFormat* TranscodeToParsed(const void* buffer,
-                                             size_t size,
-                                             const std::set<DicomTransferSyntax>& allowedSyntaxes,
-                                             bool allowNewSopInstanceUid) ORTHANC_OVERRIDE
-    {
-      if (tryDcmtk_)
-      {
-        return dcmtk_.TranscodeToParsed(buffer, size, allowedSyntaxes, allowNewSopInstanceUid);
-      }
-      else
-      {
-        std::string transcoded;
-        if (TranscodeInternal(transcoded, buffer, size, allowedSyntaxes, allowNewSopInstanceUid))
-        {
-          return FromDcmtkBridge::LoadFromMemoryBuffer(
-            transcoded.empty() ? NULL : transcoded.c_str(), transcoded.size());
-        }
-        else
-        {
-          return NULL;
-        }
-      }
-    }
-
-    virtual bool HasInplaceTranscode() const ORTHANC_OVERRIDE
-    {
-      return tryDcmtk_;
-    }
-    
-    virtual bool InplaceTranscode(DcmFileFormat& dicom,
-                                  const std::set<DicomTransferSyntax>& allowedSyntaxes,
-                                  bool allowNewSopInstanceUid) ORTHANC_OVERRIDE
-    {
-      if (tryDcmtk_)
-      {
-        return dcmtk_.InplaceTranscode(dicom, allowedSyntaxes, allowNewSopInstanceUid);
-      }
-      else
-      {
-        // "HasInplaceTranscode()" should have been called
-        throw OrthancException(ErrorCode_BadSequenceOfCalls);
-      }
-    }
-  };
-}
-
+#include "../Core/DicomParsing/DcmtkTranscoder.h"
 
 TEST(Toto, DISABLED_Transcode3)
 {
@@ -2483,7 +1955,7 @@
         std::string c, i;
         try
         {
-          IDicomTranscoder::Store(c, i, scu, transcoder, source.c_str(), source.size());
+          scu.Transcode(c, i, transcoder, source.c_str(), source.size());
         }
         catch (OrthancException& e)
         {
@@ -2501,8 +1973,6 @@
 }
 
 
-
-
 TEST(Toto, DISABLED_Transcode4)
 {
   std::string source;
@@ -2534,5 +2004,4 @@
   }
 }
 
-
 #endif