diff OrthancServer/ParsedDicomFile.cpp @ 1982:b5d4f9c156ad

Modification of instances can now replace PixelData
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 22 Apr 2016 10:28:55 +0200
parents 4b545a8b1f95
children 0ae26237569a
line wrap: on
line diff
--- a/OrthancServer/ParsedDicomFile.cpp	Fri Apr 22 09:05:06 2016 +0200
+++ b/OrthancServer/ParsedDicomFile.cpp	Fri Apr 22 10:28:55 2016 +0200
@@ -581,16 +581,26 @@
       throw OrthancException(ErrorCode_AlreadyExistingTag);
     }
 
+    if (decodeDataUriScheme &&
+        value.type() == Json::stringValue &&
+        (tag == DICOM_TAG_ENCAPSULATED_DOCUMENT ||
+         tag == DICOM_TAG_PIXEL_DATA))
+    {
+      if (EmbedContentInternal(value.asString()))
+      {
+        return;
+      }
+    }
+
     InvalidateCache();
-
     std::auto_ptr<DcmElement> element(FromDcmtkBridge::FromJson(tag, value, decodeDataUriScheme, GetEncoding()));
     InsertInternal(*pimpl_->file_->getDataset(), element.release());
   }
 
 
-  static bool IsReplaceAllowed(DcmDataset& dicom,
-                               const DcmTagKey& tag,
-                               DicomReplaceMode mode)
+  static bool CanReplaceProceed(DcmDataset& dicom,
+                                const DcmTagKey& tag,
+                                DicomReplaceMode mode)
   {
     if (dicom.findAndDeleteElement(tag).good())
     {
@@ -663,30 +673,42 @@
 
     if (tag == DICOM_TAG_SOP_CLASS_UID)
     {
-      Replace(DICOM_TAG_MEDIA_STORAGE_SOP_CLASS_UID, *decoded, DicomReplaceMode_InsertIfAbsent);
+      ReplacePlainString(DICOM_TAG_MEDIA_STORAGE_SOP_CLASS_UID, *decoded);
     }
 
     if (tag == DICOM_TAG_SOP_INSTANCE_UID)
     {
-      Replace(DICOM_TAG_MEDIA_STORAGE_SOP_INSTANCE_UID, *decoded, DicomReplaceMode_InsertIfAbsent);
+      ReplacePlainString(DICOM_TAG_MEDIA_STORAGE_SOP_INSTANCE_UID, *decoded);
     }    
   }
 
 
   void ParsedDicomFile::Replace(const DicomTag& tag,
                                 const std::string& utf8Value,
+                                bool decodeDataUriScheme,
                                 DicomReplaceMode mode)
   {
     InvalidateCache();
 
-    std::auto_ptr<DcmElement> element(FromDcmtkBridge::CreateElementForTag(tag));
-    FromDcmtkBridge::FillElementWithString(*element, tag, utf8Value, false, GetEncoding());
+    DcmDataset& dicom = *pimpl_->file_->getDataset();
+    if (CanReplaceProceed(dicom, ToDcmtkBridge::Convert(tag), mode))
+    {
+      // Either the tag was previously existing (and now removed), or
+      // the replace mode was set to "InsertIfAbsent"
 
-    DcmDataset& dicom = *pimpl_->file_->getDataset();
-    if (IsReplaceAllowed(dicom, element->getTag(), mode))
-    {
-      // Either the tag was previously existing, or the replace mode
-      // was set to "InsertIfAbsent"
+      if (decodeDataUriScheme &&
+          (tag == DICOM_TAG_ENCAPSULATED_DOCUMENT ||
+           tag == DICOM_TAG_PIXEL_DATA))
+      {
+        if (EmbedContentInternal(utf8Value))
+        {
+          return;
+        }
+      }
+
+      std::auto_ptr<DcmElement> element(FromDcmtkBridge::CreateElementForTag(tag));
+      FromDcmtkBridge::FillElementWithString(*element, tag, utf8Value, decodeDataUriScheme, GetEncoding());
+
       InsertInternal(dicom, element.release());
       UpdateStorageUid(tag, utf8Value, false);
     }
@@ -700,14 +722,24 @@
   {
     InvalidateCache();
 
-    std::auto_ptr<DcmElement> element(FromDcmtkBridge::FromJson(tag, value, decodeDataUriScheme, GetEncoding()));
+    DcmDataset& dicom = *pimpl_->file_->getDataset();
+    if (CanReplaceProceed(dicom, ToDcmtkBridge::Convert(tag), mode))
+    {
+      // Either the tag was previously existing (and now removed), or
+      // the replace mode was set to "InsertIfAbsent"
 
-    DcmDataset& dicom = *pimpl_->file_->getDataset();
-    if (IsReplaceAllowed(dicom, element->getTag(), mode))
-    {
-      // Either the tag was previously existing, or the replace mode
-      // was set to "InsertIfAbsent"
-      InsertInternal(dicom, element.release());
+      if (decodeDataUriScheme &&
+          value.type() == Json::stringValue &&
+          (tag == DICOM_TAG_ENCAPSULATED_DOCUMENT ||
+           tag == DICOM_TAG_PIXEL_DATA))
+      {
+        if (EmbedContentInternal(value.asString()))
+        {
+          return;
+        }
+      }
+
+      InsertInternal(dicom, FromDcmtkBridge::FromJson(tag, value, decodeDataUriScheme, GetEncoding()));
 
       if (tag == DICOM_TAG_SOP_CLASS_UID ||
           tag == DICOM_TAG_SOP_INSTANCE_UID)
@@ -833,10 +865,10 @@
 
     if (createIdentifiers)
     {
-      Replace(DICOM_TAG_PATIENT_ID, FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Patient));
-      Replace(DICOM_TAG_STUDY_INSTANCE_UID, FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Study));
-      Replace(DICOM_TAG_SERIES_INSTANCE_UID, FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Series));
-      Replace(DICOM_TAG_SOP_INSTANCE_UID, FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Instance));
+      ReplacePlainString(DICOM_TAG_PATIENT_ID, FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Patient));
+      ReplacePlainString(DICOM_TAG_STUDY_INSTANCE_UID, FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Study));
+      ReplacePlainString(DICOM_TAG_SERIES_INSTANCE_UID, FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Series));
+      ReplacePlainString(DICOM_TAG_SOP_INSTANCE_UID, FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Instance));
     }
   }
 
@@ -878,7 +910,7 @@
     pimpl_->file_.reset(dynamic_cast<DcmFileFormat*>(other.pimpl_->file_->clone()));
 
     // Create a new instance-level identifier
-    Replace(DICOM_TAG_SOP_INSTANCE_UID, FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Instance));
+    ReplacePlainString(DICOM_TAG_SOP_INSTANCE_UID, FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Instance));
   }
 
 
@@ -912,12 +944,12 @@
   }
 
 
-  void ParsedDicomFile::EmbedContent(const std::string& dataUriScheme)
+  bool ParsedDicomFile::EmbedContentInternal(const std::string& dataUriScheme)
   {
     std::string mime, content;
     if (!Toolbox::DecodeDataUriScheme(mime, content, dataUriScheme))
     {
-      throw OrthancException(ErrorCode_BadFileFormat);
+      return false;
     }
 
     Toolbox::ToLowerCase(mime);
@@ -936,14 +968,23 @@
       LOG(ERROR) << "Unsupported MIME type for the content of a new DICOM file: " << mime;
       throw OrthancException(ErrorCode_NotImplemented);
     }
+
+    return true;
+  }
+
+
+  void ParsedDicomFile::EmbedContent(const std::string& dataUriScheme)
+  {
+    if (!EmbedContentInternal(dataUriScheme))
+    {
+      throw OrthancException(ErrorCode_BadFileFormat);
+    }
   }
 
 
   void ParsedDicomFile::EmbedImage(const std::string& mime,
                                    const std::string& content)
   {
-    InvalidateCache();
-
     if (mime == "image/png")
     {
       PngReader reader;
@@ -974,6 +1015,8 @@
       throw OrthancException(ErrorCode_NotImplemented);
     }
 
+    InvalidateCache();
+
     if (accessor.GetFormat() == PixelFormat_RGBA32)
     {
       LOG(WARNING) << "Getting rid of the alpha channel when embedding a RGBA image inside DICOM";
@@ -982,49 +1025,49 @@
     // http://dicomiseasy.blogspot.be/2012/08/chapter-12-pixel-data.html
 
     Remove(DICOM_TAG_PIXEL_DATA);
-    Replace(DICOM_TAG_COLUMNS, boost::lexical_cast<std::string>(accessor.GetWidth()));
-    Replace(DICOM_TAG_ROWS, boost::lexical_cast<std::string>(accessor.GetHeight()));
-    Replace(DICOM_TAG_SAMPLES_PER_PIXEL, "1");
-    Replace(DICOM_TAG_NUMBER_OF_FRAMES, "1");
+    ReplacePlainString(DICOM_TAG_COLUMNS, boost::lexical_cast<std::string>(accessor.GetWidth()));
+    ReplacePlainString(DICOM_TAG_ROWS, boost::lexical_cast<std::string>(accessor.GetHeight()));
+    ReplacePlainString(DICOM_TAG_SAMPLES_PER_PIXEL, "1");
+    ReplacePlainString(DICOM_TAG_NUMBER_OF_FRAMES, "1");
 
     if (accessor.GetFormat() == PixelFormat_SignedGrayscale16)
     {
-      Replace(DICOM_TAG_PIXEL_REPRESENTATION, "1");
+      ReplacePlainString(DICOM_TAG_PIXEL_REPRESENTATION, "1");
     }
     else
     {
-      Replace(DICOM_TAG_PIXEL_REPRESENTATION, "0");  // Unsigned pixels
+      ReplacePlainString(DICOM_TAG_PIXEL_REPRESENTATION, "0");  // Unsigned pixels
     }
 
-    Replace(DICOM_TAG_PLANAR_CONFIGURATION, "0");  // Color channels are interleaved
-    Replace(DICOM_TAG_PHOTOMETRIC_INTERPRETATION, "MONOCHROME2");
+    ReplacePlainString(DICOM_TAG_PLANAR_CONFIGURATION, "0");  // Color channels are interleaved
+    ReplacePlainString(DICOM_TAG_PHOTOMETRIC_INTERPRETATION, "MONOCHROME2");
 
     unsigned int bytesPerPixel = 0;
 
     switch (accessor.GetFormat())
     {
       case PixelFormat_Grayscale8:
-        Replace(DICOM_TAG_BITS_ALLOCATED, "8");
-        Replace(DICOM_TAG_BITS_STORED, "8");
-        Replace(DICOM_TAG_HIGH_BIT, "7");
+        ReplacePlainString(DICOM_TAG_BITS_ALLOCATED, "8");
+        ReplacePlainString(DICOM_TAG_BITS_STORED, "8");
+        ReplacePlainString(DICOM_TAG_HIGH_BIT, "7");
         bytesPerPixel = 1;
         break;
 
       case PixelFormat_RGB24:
       case PixelFormat_RGBA32:
-        Replace(DICOM_TAG_PHOTOMETRIC_INTERPRETATION, "RGB");
-        Replace(DICOM_TAG_SAMPLES_PER_PIXEL, "3");
-        Replace(DICOM_TAG_BITS_ALLOCATED, "8");
-        Replace(DICOM_TAG_BITS_STORED, "8");
-        Replace(DICOM_TAG_HIGH_BIT, "7");
+        ReplacePlainString(DICOM_TAG_PHOTOMETRIC_INTERPRETATION, "RGB");
+        ReplacePlainString(DICOM_TAG_SAMPLES_PER_PIXEL, "3");
+        ReplacePlainString(DICOM_TAG_BITS_ALLOCATED, "8");
+        ReplacePlainString(DICOM_TAG_BITS_STORED, "8");
+        ReplacePlainString(DICOM_TAG_HIGH_BIT, "7");
         bytesPerPixel = 3;
         break;
 
       case PixelFormat_Grayscale16:
       case PixelFormat_SignedGrayscale16:
-        Replace(DICOM_TAG_BITS_ALLOCATED, "16");
-        Replace(DICOM_TAG_BITS_STORED, "16");
-        Replace(DICOM_TAG_HIGH_BIT, "15");
+        ReplacePlainString(DICOM_TAG_BITS_ALLOCATED, "16");
+        ReplacePlainString(DICOM_TAG_BITS_STORED, "16");
+        ReplacePlainString(DICOM_TAG_HIGH_BIT, "15");
         bytesPerPixel = 2;
         break;
 
@@ -1100,7 +1143,7 @@
     }
 
     std::string s = GetDicomSpecificCharacterSet(encoding);
-    Replace(DICOM_TAG_SPECIFIC_CHARACTER_SET, s, DicomReplaceMode_InsertIfAbsent);
+    ReplacePlainString(DICOM_TAG_SPECIFIC_CHARACTER_SET, s);
   }
 
   void ParsedDicomFile::ToJson(Json::Value& target, 
@@ -1137,11 +1180,13 @@
       throw OrthancException(ErrorCode_BadFileFormat);
     }
 
-    Replace(DICOM_TAG_SOP_CLASS_UID, UID_EncapsulatedPDFStorage);
-    Replace(FromDcmtkBridge::Convert(DCM_Modality), "OT");
-    Replace(FromDcmtkBridge::Convert(DCM_ConversionType), "WSD");
-    Replace(FromDcmtkBridge::Convert(DCM_MIMETypeOfEncapsulatedDocument), "application/pdf");
-    //Replace(FromDcmtkBridge::Convert(DCM_SeriesNumber), "1");
+    InvalidateCache();
+
+    ReplacePlainString(DICOM_TAG_SOP_CLASS_UID, UID_EncapsulatedPDFStorage);
+    ReplacePlainString(FromDcmtkBridge::Convert(DCM_Modality), "OT");
+    ReplacePlainString(FromDcmtkBridge::Convert(DCM_ConversionType), "WSD");
+    ReplacePlainString(FromDcmtkBridge::Convert(DCM_MIMETypeOfEncapsulatedDocument), "application/pdf");
+    //ReplacePlainString(FromDcmtkBridge::Convert(DCM_SeriesNumber), "1");
 
     std::auto_ptr<DcmPolymorphOBOW> element(new DcmPolymorphOBOW(DCM_EncapsulatedDocument));
 
@@ -1249,7 +1294,7 @@
       }
       else if (tag != DICOM_TAG_SPECIFIC_CHARACTER_SET)
       {
-        result->Replace(tag, value, decodeDataUriScheme);
+        result->Replace(tag, value, decodeDataUriScheme, DicomReplaceMode_InsertIfAbsent);
       }
     }