diff Core/DicomParsing/IDicomTranscoder.cpp @ 3946:1f33ed7f82e6 transcoding

automatic test of transcoding
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 19 May 2020 13:44:56 +0200
parents 0b3256c3ee14
children 5fe8c6d3212e
line wrap: on
line diff
--- a/Core/DicomParsing/IDicomTranscoder.cpp	Tue May 19 11:24:00 2020 +0200
+++ b/Core/DicomParsing/IDicomTranscoder.cpp	Tue May 19 13:44:56 2020 +0200
@@ -39,9 +39,156 @@
 #include "ParsedDicomFile.h"
 
 #include <dcmtk/dcmdata/dcfilefo.h>
+#include <dcmtk/dcmdata/dcdeftag.h>
 
 namespace Orthanc
 {
+  IDicomTranscoder::TranscodingType IDicomTranscoder::GetTranscodingType(DicomTransferSyntax target,
+                                                                         DicomTransferSyntax source)
+  {
+    if (target == source)
+    {
+      return TranscodingType_Lossless;
+    }
+    else if (target == DicomTransferSyntax_LittleEndianImplicit ||
+             target == DicomTransferSyntax_LittleEndianExplicit ||
+             target == DicomTransferSyntax_BigEndianExplicit ||
+             target == DicomTransferSyntax_DeflatedLittleEndianExplicit ||
+             target == DicomTransferSyntax_JPEGProcess14 ||
+             target == DicomTransferSyntax_JPEGProcess14SV1 ||
+             target == DicomTransferSyntax_JPEGLSLossless ||
+             target == DicomTransferSyntax_JPEG2000LosslessOnly ||
+             target == DicomTransferSyntax_JPEG2000MulticomponentLosslessOnly)
+    {
+      return TranscodingType_Lossless;
+    }
+    else if (target == DicomTransferSyntax_JPEGProcess1 ||
+             target == DicomTransferSyntax_JPEGProcess2_4 ||
+             target == DicomTransferSyntax_JPEGLSLossy ||
+             target == DicomTransferSyntax_JPEG2000 ||
+             target == DicomTransferSyntax_JPEG2000Multicomponent)
+    {
+      return TranscodingType_Lossy;
+    }
+    else
+    {
+      return TranscodingType_Unknown;
+    }
+  }
+
+
+  std::string IDicomTranscoder::GetSopInstanceUid(DcmFileFormat& dicom)
+  {
+    if (dicom.getDataset() == NULL)
+    {
+      throw OrthancException(ErrorCode_InternalError);
+    }
+    
+    DcmDataset& dataset = *dicom.getDataset();
+    
+    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");
+    }
+  }
+
+
+  void IDicomTranscoder::CheckTranscoding(IDicomTranscoder::DicomImage& transcoded,
+                                          bool hasSopInstanceUidChanged,
+                                          DicomTransferSyntax sourceSyntax,
+                                          const std::string& sourceSopInstanceUid,
+                                          const std::set<DicomTransferSyntax>& allowedSyntaxes,
+                                          bool allowNewSopInstanceUid)
+  {
+    DcmFileFormat& parsed = transcoded.GetParsed();
+    
+    if (parsed.getDataset() == NULL)
+    {
+      throw OrthancException(ErrorCode_InternalError);
+    }
+
+    std::string targetSopInstanceUid = GetSopInstanceUid(parsed);
+
+    if (hasSopInstanceUidChanged && (targetSopInstanceUid == sourceSopInstanceUid))
+    {
+      throw OrthancException(ErrorCode_InternalError);
+    }
+
+    if (!hasSopInstanceUidChanged && (targetSopInstanceUid != sourceSopInstanceUid))
+    {
+      throw OrthancException(ErrorCode_InternalError);
+    }
+
+    if (parsed.getDataset()->tagExists(DCM_PixelData))
+    {
+      if (!allowNewSopInstanceUid && (targetSopInstanceUid != sourceSopInstanceUid))
+      {
+        throw OrthancException(ErrorCode_InternalError);
+      }
+    }
+    else
+    {
+      if (hasSopInstanceUidChanged ||
+          targetSopInstanceUid != sourceSopInstanceUid)
+      {
+        throw OrthancException(ErrorCode_InternalError,
+                               "No pixel data: Transcoding must not change the SOP instance UID");
+      }
+    }
+
+    DicomTransferSyntax targetSyntax;
+    if (!FromDcmtkBridge::LookupOrthancTransferSyntax(targetSyntax, parsed))
+    {
+      return;  // Unknown transfer syntax, cannot do further test
+    }
+
+    if (allowedSyntaxes.find(sourceSyntax) != allowedSyntaxes.end())
+    {
+      // No transcoding should have happened
+      if (targetSopInstanceUid != sourceSopInstanceUid ||
+          hasSopInstanceUidChanged)
+      {
+        throw OrthancException(ErrorCode_InternalError);
+      }
+    }
+        
+    if (allowedSyntaxes.find(targetSyntax) == allowedSyntaxes.end())
+    {
+      throw OrthancException(ErrorCode_InternalError, "An incorrect output transfer syntax was chosen");
+    }
+    
+    if (parsed.getDataset()->tagExists(DCM_PixelData))
+    {
+      switch (GetTranscodingType(targetSyntax, sourceSyntax))
+      {
+        case TranscodingType_Lossy:
+          if (targetSopInstanceUid == sourceSopInstanceUid)
+          {
+            throw OrthancException(ErrorCode_InternalError);
+          }
+          break;
+
+        case TranscodingType_Lossless:
+          if (targetSopInstanceUid != sourceSopInstanceUid)
+          {
+            throw OrthancException(ErrorCode_InternalError);
+          }
+          break;
+
+        default:
+          break;
+      }
+    }
+  }
+    
+
   void IDicomTranscoder::DicomImage::Parse()
   {
     if (parsed_.get() != NULL)