changeset 3882:904575738462 transcoding

implemented IDicomTranscoder::Store()
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 05 May 2020 12:29:33 +0200
parents f23ab7829a8d
children 795c9ca5eb91
files Core/DicomNetworking/DicomStoreUserConnection.cpp Core/DicomNetworking/DicomStoreUserConnection.h Core/DicomParsing/FromDcmtkBridge.cpp Core/DicomParsing/FromDcmtkBridge.h UnitTestsSources/FromDcmtkTests.cpp
diffstat 5 files changed, 332 insertions(+), 153 deletions(-) [+]
line wrap: on
line diff
--- a/Core/DicomNetworking/DicomStoreUserConnection.cpp	Tue May 05 10:35:39 2020 +0200
+++ b/Core/DicomNetworking/DicomStoreUserConnection.cpp	Tue May 05 12:29:33 2020 +0200
@@ -178,11 +178,17 @@
 
   void DicomStoreUserConnection::LookupParameters(std::string& sopClassUid,
                                                   std::string& sopInstanceUid,
-                                                  DcmDataset& dataset)
+                                                  DicomTransferSyntax& transferSyntax,
+                                                  DcmFileFormat& dicom)
   {
+    if (dicom.getDataset() == NULL)
+    {
+      throw OrthancException(ErrorCode_InternalError);
+    }
+    
     OFString a, b;
-    if (!dataset.findAndGetOFString(DCM_SOPClassUID, a).good() ||
-        !dataset.findAndGetOFString(DCM_SOPInstanceUID, b).good())
+    if (!dicom.getDataset()->findAndGetOFString(DCM_SOPClassUID, a).good() ||
+        !dicom.getDataset()->findAndGetOFString(DCM_SOPInstanceUID, b).good())
     {
       throw OrthancException(ErrorCode_NoSopClassOrInstance,
                              "Unable to determine the SOP class/instance for C-STORE with AET " +
@@ -191,6 +197,12 @@
 
     sopClassUid.assign(a.c_str());
     sopInstanceUid.assign(b.c_str());
+
+    if (!FromDcmtkBridge::LookupOrthancTransferSyntax(transferSyntax, dicom))
+    {
+      throw OrthancException(ErrorCode_InternalError,
+                             "Unknown transfer syntax from DCMTK");
+    }
   }
   
 
@@ -308,18 +320,12 @@
 
   void DicomStoreUserConnection::Store(std::string& sopClassUid,
                                        std::string& sopInstanceUid,
-                                       DcmDataset& dataset,
+                                       DcmFileFormat& dicom,
                                        const std::string& moveOriginatorAET,
                                        uint16_t moveOriginatorID)
   {
-    LookupParameters(sopClassUid, sopInstanceUid, dataset);
-
     DicomTransferSyntax transferSyntax;
-    if (!FromDcmtkBridge::LookupOrthancTransferSyntax(transferSyntax, dataset))
-    {
-      throw OrthancException(ErrorCode_InternalError,
-                             "Unknown transfer syntax from DCMTK");
-    }
+    LookupParameters(sopClassUid, sopInstanceUid, transferSyntax, dicom);
 
     uint8_t presID;
     if (!NegotiatePresentationContext(presID, sopClassUid, transferSyntax))
@@ -351,12 +357,17 @@
       request.opts |= O_STORE_MOVEORIGINATORID;
     }
 
+    if (dicom.getDataset() == NULL)
+    {
+      throw OrthancException(ErrorCode_InternalError);
+    }
+
     // Finally conduct transmission of data
     T_DIMSE_C_StoreRSP response;
     DcmDataset* statusDetail = NULL;
     DicomAssociation::CheckCondition(
       DIMSE_storeUser(&association_->GetDcmtkAssociation(), presID, &request,
-                      NULL, &dataset, /*progressCallback*/ NULL, NULL,
+                      NULL, dicom.getDataset(), /*progressCallback*/ NULL, NULL,
                       /*opt_blockMode*/ (GetParameters().HasTimeout() ? DIMSE_NONBLOCKING : DIMSE_BLOCKING),
                       /*opt_dimse_timeout*/ GetParameters().GetTimeout(),
                       &response, &statusDetail, NULL),
@@ -397,18 +408,16 @@
     std::unique_ptr<DcmFileFormat> dicom(
       FromDcmtkBridge::LoadFromMemoryBuffer(buffer, size));
 
-    if (dicom.get() == NULL ||
-        dicom->getDataset() == NULL)
+    if (dicom.get() == NULL)
     {
       throw OrthancException(ErrorCode_InternalError);
     }
     
-    Store(sopClassUid, sopInstanceUid, *dicom->getDataset(),
-          moveOriginatorAET, moveOriginatorID);
+    Store(sopClassUid, sopInstanceUid, *dicom, moveOriginatorAET, moveOriginatorID);
   }
 
 
-  bool DicomStoreUserConnection::LookupTranscoding(std::set<DicomTransferSyntax>& acceptedSyntaxes,
+  void DicomStoreUserConnection::LookupTranscoding(std::set<DicomTransferSyntax>& acceptedSyntaxes,
                                                    const std::string& sopClassUid,
                                                    DicomTransferSyntax sourceSyntax)
   {
@@ -428,12 +437,6 @@
       {
         acceptedSyntaxes.insert(it->first);
       }
-      
-      return true;
-    }
-    else
-    {
-      return false;
     }
   }
 }
--- a/Core/DicomNetworking/DicomStoreUserConnection.h	Tue May 05 10:35:39 2020 +0200
+++ b/Core/DicomNetworking/DicomStoreUserConnection.h	Tue May 05 12:29:33 2020 +0200
@@ -41,7 +41,7 @@
 #include <stdint.h>  // For uint8_t
 
 
-class DcmDataset;
+class DcmFileFormat;
 
 namespace Orthanc
 {
@@ -86,10 +86,6 @@
     bool ProposeStorageClass(const std::string& sopClassUid,
                              const std::set<DicomTransferSyntax>& syntaxes);
 
-    void LookupParameters(std::string& sopClassUid,
-                          std::string& sopInstanceUid,
-                          DcmDataset& dataset);
-
     bool LookupPresentationContext(uint8_t& presentationContextId,
                                    const std::string& sopClassUid,
                                    DicomTransferSyntax transferSyntax);
@@ -141,7 +137,7 @@
 
     void Store(std::string& sopClassUid,
                std::string& sopInstanceUid,
-               DcmDataset& dataset,
+               DcmFileFormat& dicom,
                const std::string& moveOriginatorAET,
                uint16_t moveOriginatorID);
 
@@ -154,9 +150,9 @@
 
     void Store(std::string& sopClassUid,
                std::string& sopInstanceUid,
-               DcmDataset& dataset)
+               DcmFileFormat& dicom)
     {
-      Store(sopClassUid, sopInstanceUid, dataset, "", 0);  // Not a C-Move
+      Store(sopClassUid, sopInstanceUid, dicom, "", 0);  // Not a C-Move
     }
 
     void Store(std::string& sopClassUid,
@@ -167,7 +163,12 @@
       Store(sopClassUid, sopInstanceUid, buffer, size, "", 0);  // Not a C-Move
     }
 
-    bool LookupTranscoding(std::set<DicomTransferSyntax>& acceptedSyntaxes,
+    void LookupParameters(std::string& sopClassUid,
+                          std::string& sopInstanceUid,
+                          DicomTransferSyntax& transferSyntax,
+                          DcmFileFormat& dicom);
+
+    void LookupTranscoding(std::set<DicomTransferSyntax>& acceptedSyntaxes,
                            const std::string& sopClassUid,
                            DicomTransferSyntax sourceSyntax);
   };
--- a/Core/DicomParsing/FromDcmtkBridge.cpp	Tue May 05 10:35:39 2020 +0200
+++ b/Core/DicomParsing/FromDcmtkBridge.cpp	Tue May 05 12:29:33 2020 +0200
@@ -2657,6 +2657,33 @@
     Encoding encoding = DetectEncoding(hasCodeExtensions, dataset, defaultEncoding);
     ApplyVisitorToDataset(dataset, visitor, parentTags, parentIndexes, encoding, hasCodeExtensions);
   }
+
+
+
+  bool FromDcmtkBridge::LookupOrthancTransferSyntax(DicomTransferSyntax& target,
+                                                    DcmFileFormat& dicom)
+  {
+    if (dicom.getDataset() == NULL)
+    {
+      throw OrthancException(ErrorCode_InternalError);
+    }
+        
+    DcmDataset& dataset = *dicom.getDataset();
+
+    E_TransferSyntax xfer = dataset.getOriginalXfer();
+    if (xfer == EXS_Unknown)
+    {
+      dataset.updateOriginalXfer();
+      xfer = dataset.getOriginalXfer();
+      if (xfer == EXS_Unknown)
+      {
+        throw OrthancException(ErrorCode_BadFileFormat,
+                               "Cannot determine the transfer syntax of the DICOM instance");
+      }
+    }
+
+    return FromDcmtkBridge::LookupOrthancTransferSyntax(target, xfer);
+  }
 }
 
 
--- a/Core/DicomParsing/FromDcmtkBridge.h	Tue May 05 10:35:39 2020 +0200
+++ b/Core/DicomParsing/FromDcmtkBridge.h	Tue May 05 12:29:33 2020 +0200
@@ -286,9 +286,6 @@
                                             E_TransferSyntax source);
 
     static bool LookupOrthancTransferSyntax(DicomTransferSyntax& target,
-                                            const DcmDataset& dataset)
-    {
-      return LookupOrthancTransferSyntax(target, dataset.getOriginalXfer());
-    }
+                                            DcmFileFormat& dicom);
   };
 }
--- a/UnitTestsSources/FromDcmtkTests.cpp	Tue May 05 10:35:39 2020 +0200
+++ b/UnitTestsSources/FromDcmtkTests.cpp	Tue May 05 12:29:33 2020 +0200
@@ -2252,10 +2252,10 @@
   
 
   
-  class IDicomTranscoder : public boost::noncopyable
+  class IDicomTranscoder1 : public boost::noncopyable
   {
   public:
-    virtual ~IDicomTranscoder()
+    virtual ~IDicomTranscoder1()
     {
     }
 
@@ -2284,7 +2284,7 @@
   };
 
 
-  class DcmtkTranscoder : public IDicomTranscoder
+  class DcmtkTranscoder2 : public IDicomTranscoder1
   {
   private:
     std::unique_ptr<DcmFileFormat>    dicom_;
@@ -2357,12 +2357,12 @@
     }
     
   public:
-    DcmtkTranscoder(DcmFileFormat* dicom)  // Takes ownership
+    DcmtkTranscoder2(DcmFileFormat* dicom)  // Takes ownership
     {
       Setup(dicom);
     }
 
-    DcmtkTranscoder(const void* dicom,
+    DcmtkTranscoder2(const void* dicom,
                     size_t size)
     {
       Setup(FromDcmtkBridge::LoadFromMemoryBuffer(dicom, size));
@@ -2529,76 +2529,6 @@
 
 
 
-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 <boost/filesystem.hpp>
 
 
@@ -2613,7 +2543,7 @@
   std::string s;
   SystemToolbox::ReadFile(s, path);
 
-  Orthanc::DcmtkTranscoder transcoder(s.c_str(), s.size());
+  Orthanc::DcmtkTranscoder2 transcoder(s.c_str(), s.size());
 
   /*if (transcoder.GetBitsStored() != 8)  // TODO
     return; */
@@ -2647,7 +2577,7 @@
     std::string t;
     transcoder.WriteToMemoryBuffer(t);
 
-    Orthanc::DcmtkTranscoder transcoder2(t.c_str(), t.size());
+    Orthanc::DcmtkTranscoder2 transcoder2(t.c_str(), t.size());
     printf(">> %d %d ; %lu bytes\n", transcoder.GetTransferSyntax(), transcoder2.GetTransferSyntax(), t.size());
   }
 
@@ -2675,7 +2605,7 @@
         Orthanc::SystemToolbox::WriteFile(t, buf);
       }
 
-      Orthanc::DcmtkTranscoder transcoder2(t.c_str(), t.size());
+      Orthanc::DcmtkTranscoder2 transcoder2(t.c_str(), t.size());
       printf("  => transcoded transfer syntax %d ; %lu bytes\n", transcoder2.GetTransferSyntax(), t.size());
     }
   }
@@ -2687,44 +2617,6 @@
 {
   //OFLog::configure(OFLogger::DEBUG_LOG_LEVEL);
 
-  if (0)
-  {
-    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");
-    SystemToolbox::ReadFile(s, "/home/jodogne/Subversion/orthanc-tests/Database/TransferSyntaxes/1.2.840.10008.1.2.1.dcm");
-
-    std::unique_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 0
-    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 
-  
-    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");
-  }
-
   if (1)
   {
     const char* const PATH = "/home/jodogne/Subversion/orthanc-tests/Database/TransferSyntaxes";
@@ -2877,7 +2769,8 @@
 {
   std::set<DicomTransferSyntax> accepted;
 
-  if (!scu.LookupTranscoding(accepted, sopClassUid, transferSyntax))
+  scu.LookupTranscoding(accepted, sopClassUid, transferSyntax);
+  if (accepted.empty())
   {
     throw OrthancException(ErrorCode_NetworkProtocol,
                            "The SOP class is not supported by the remote modality");
@@ -2966,4 +2859,262 @@
   printf("[%s] [%s]\n", c.c_str(), i.c_str());
 }
 
+
+namespace Orthanc
+{
+  class IDicomTranscoder : public boost::noncopyable
+  {
+  public:
+    virtual ~IDicomTranscoder()
+    {
+    }
+
+    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.
+    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.InplaceTranscode(*dicom, uncompressedSyntaxes, false))
+        {
+          // In-place transcoding is supported
+          transcoded.reset(dicom.release());
+        }
+        else
+        {
+          transcoded.reset(transcoder.Transcode(buffer, size, uncompressedSyntaxes, false));
+        }
+
+        // The "dicom" variable must not be used below this point
+        
+        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);
+          }
+        }
+      }
+    }
+  };
+
+
+  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");
+      }      
+    }
+
+  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* Transcode(const void* buffer,
+                                     size_t size,
+                                     const std::set<DicomTransferSyntax>& allowedSyntaxes,
+                                     bool allowNewSopInstanceUid)
+    {
+      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 InplaceTranscode(DcmFileFormat& dicom,
+                                  const std::set<DicomTransferSyntax>& allowedSyntaxes,
+                                  bool allowNewSopInstanceUid)
+    {
+      if (dicom.getDataset() == NULL)
+      {
+        throw OrthancException(ErrorCode_InternalError);
+      }
+
+      const uint16_t bitsStored = GetBitsStored(*dicom.getDataset());
+
+#if 0     
+
+      if (syntax == DetectTransferSyntax(*dicom))
+      {
+        // No transcoding is needed
+        return new Image(dicom.release(), syntax);
+      }
+      
+      if (syntax == DicomTransferSyntax_LittleEndianImplicit &&
+          FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_LittleEndianImplicit, NULL))
+      {
+        return new Image(dicom.release(), syntax);
+      }
+
+      if (syntax == DicomTransferSyntax_LittleEndianExplicit &&
+          FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_LittleEndianExplicit, NULL))
+      {
+        return new Image(dicom.release(), syntax);
+      }
+      
+      if (syntax == DicomTransferSyntax_BigEndianExplicit &&
+          FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_BigEndianExplicit, NULL))
+      {
+        return new Image(dicom.release(), syntax);
+      }
+
+      if (syntax == DicomTransferSyntax_DeflatedLittleEndianExplicit &&
+          FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_DeflatedLittleEndianExplicit, NULL))
+      {
+        return new Image(dicom.release(), syntax);
+      }
+
+#if ORTHANC_ENABLE_JPEG == 1
+      if (syntax == DicomTransferSyntax_JPEGProcess1 &&
+          allowNewSopInstanceUid &&
+          bitsStored == 8)
+      {
+        DJ_RPLossy rpLossy(lossyQuality_);
+        
+        if (FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_JPEGProcess1, &rpLossy))
+        {
+          return new Image(dicom.release(), syntax);
+        }
+      }
 #endif
+      
+#if ORTHANC_ENABLE_JPEG == 1
+      if (syntax == DicomTransferSyntax_JPEGProcess2_4 &&
+          allowNewSopInstanceUid &&
+          bitsStored <= 12)
+      {
+        DJ_RPLossy rpLossy(lossyQuality_);
+        if (FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_JPEGProcess2_4, &rpLossy))
+        {
+          return new Image(dicom.release(), syntax);
+        }
+      }
+#endif
+
+#endif
+
+      return false;
+    }
+  };
+}
+
+
+#endif