changeset 1556:b8dc2f855a83

Preview of PDF files encapsulated in DICOM from Orthanc Explorer
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 20 Aug 2015 17:05:05 +0200
parents d6a93e12b1c1
children ad1e127b4ed5
files Core/DicomFormat/DicomTag.h NEWS OrthancExplorer/explorer.js OrthancServer/OrthancRestApi/OrthancRestResources.cpp OrthancServer/ParsedDicomFile.cpp OrthancServer/ParsedDicomFile.h
diffstat 6 files changed, 113 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/Core/DicomFormat/DicomTag.h	Thu Aug 20 15:18:13 2015 +0200
+++ b/Core/DicomFormat/DicomTag.h	Thu Aug 20 17:05:05 2015 +0200
@@ -107,6 +107,7 @@
   static const DicomTag DICOM_TAG_CARDIAC_NUMBER_OF_IMAGES(0x0018, 0x1090);
   static const DicomTag DICOM_TAG_IMAGES_IN_ACQUISITION(0x0020, 0x1002);
   static const DicomTag DICOM_TAG_PATIENT_NAME(0x0010, 0x0010);
+  static const DicomTag DICOM_TAG_ENCAPSULATED_DOCUMENT(0x0042, 0x0011);
 
   // The following is used for "modify/anonymize" operations
   static const DicomTag DICOM_TAG_SOP_CLASS_UID(0x0008, 0x0016);
--- a/NEWS	Thu Aug 20 15:18:13 2015 +0200
+++ b/NEWS	Thu Aug 20 17:05:05 2015 +0200
@@ -2,6 +2,7 @@
 ===============================
 
 
+* Preview of PDF files encapsulated in DICOM from Orthanc Explorer
 * Creation of DICOM files with encapsulated PDF through "/tools/create-dicom"
 * "limit" and "since" arguments while retrieving DICOM resources in the REST API
 * Support of "deflate" and "gzip" content-types in HTTP requests
--- a/OrthancExplorer/explorer.js	Thu Aug 20 15:18:13 2015 +0200
+++ b/OrthancExplorer/explorer.js	Thu Aug 20 17:05:05 2015 +0200
@@ -30,6 +30,19 @@
 };
 
 
+function Refresh()
+{
+  if (currentPage == 'patient')
+    RefreshPatient();
+  else if (currentPage == 'study')
+    RefreshStudy();
+  else if (currentPage == 'series')
+    RefreshSeries();
+  else if (currentPage == 'instance')
+    RefreshInstance();
+}
+
+
 $(document).ready(function() {
   var $tree = $('#dicom-tree');
   $tree.tree({
@@ -45,6 +58,14 @@
         $tree.tree('openNode', event.node, true);
     }
   );
+  
+  currentPage = $.mobile.pageData.active;
+  currentUuid = $.mobile.pageData.uuid;
+  if (currentPage.length > 0 && 
+      currentUuid.length > 0)
+  {
+    Refresh();
+  }
 });
 
 
@@ -586,14 +607,7 @@
     if ('uuid' in $.mobile.pageData &&
         currentPage == $.mobile.pageData.active &&
         currentUuid != $.mobile.pageData.uuid) {
-      if (currentPage == 'patient')
-        RefreshPatient();
-      else if (currentPage == 'study')
-        RefreshStudy();
-      else if (currentPage == 'series')
-        RefreshSeries();
-      else if (currentPage == 'instance')
-        RefreshInstance();
+      Refresh();
     }
   });
 });
@@ -686,34 +700,43 @@
 
 $('#instance-preview').live('click', function(e) {
   if ($.mobile.pageData) {
-    GetResource('/instances/' + $.mobile.pageData.uuid + '/frames', function(frames) {
-      if (frames.length == 1)
-      {
-        // Viewing a single-frame image
-        jQuery.slimbox('../instances/' + $.mobile.pageData.uuid + '/preview', '', {
-          overlayFadeDuration : 1,
-          resizeDuration : 1,
-          imageFadeDuration : 1
-        });
-      }
-      else
-      {
-        // Viewing a multi-frame image
+    var pdf = '../instances/' + $.mobile.pageData.uuid + '/pdf';
+    $.ajax({
+      url: pdf,
+      cache: false,
+      success: function(s) {
+        window.location.assign(pdf);
+      },
+      error: function() {
+        GetResource('/instances/' + $.mobile.pageData.uuid + '/frames', function(frames) {
+          if (frames.length == 1)
+          {
+            // Viewing a single-frame image
+            jQuery.slimbox('../instances/' + $.mobile.pageData.uuid + '/preview', '', {
+              overlayFadeDuration : 1,
+              resizeDuration : 1,
+              imageFadeDuration : 1
+            });
+          }
+          else
+          {
+            // Viewing a multi-frame image
 
-        var images = [];
-        for (var i = 0; i < frames.length; i++) {
-          images.push([ '../instances/' + $.mobile.pageData.uuid + '/frames/' + i + '/preview' ]);
-        }
+            var images = [];
+            for (var i = 0; i < frames.length; i++) {
+              images.push([ '../instances/' + $.mobile.pageData.uuid + '/frames/' + i + '/preview' ]);
+            }
 
-        jQuery.slimbox(images, 0, {
-          overlayFadeDuration : 1,
-          resizeDuration : 1,
-          imageFadeDuration : 1,
-          loop : true
+            jQuery.slimbox(images, 0, {
+              overlayFadeDuration : 1,
+              resizeDuration : 1,
+              imageFadeDuration : 1,
+              loop : true
+            });
+          }
         });
       }
     });
-
   }
 });
 
--- a/OrthancServer/OrthancRestApi/OrthancRestResources.cpp	Thu Aug 20 15:18:13 2015 +0200
+++ b/OrthancServer/OrthancRestApi/OrthancRestResources.cpp	Thu Aug 20 17:05:05 2015 +0200
@@ -1050,6 +1050,20 @@
   }
 
 
+  static void ExtractPdf(RestApiGetCall& call)
+  {
+    const std::string id = call.GetUriComponent("id", "");
+
+    std::string pdf;
+    ServerContext::DicomCacheLocker locker(OrthancRestApi::GetContext(call), id);
+
+    if (locker.GetDicom().ExtractPdf(pdf))
+    {
+      call.GetOutput().AnswerBuffer(pdf, "application/pdf");
+      return;
+    }
+  }
+
 
   void OrthancRestApi::RegisterResources()
   {
@@ -1093,6 +1107,7 @@
     Register("/instances/{id}/frames/{frame}/image-uint16", GetImage<ImageExtractionMode_UInt16>);
     Register("/instances/{id}/frames/{frame}/image-int16", GetImage<ImageExtractionMode_Int16>);
     Register("/instances/{id}/frames/{frame}/matlab", GetMatlabImage);
+    Register("/instances/{id}/pdf", ExtractPdf);
     Register("/instances/{id}/preview", GetImage<ImageExtractionMode_Preview>);
     Register("/instances/{id}/image-uint8", GetImage<ImageExtractionMode_UInt8>);
     Register("/instances/{id}/image-uint16", GetImage<ImageExtractionMode_UInt16>);
--- a/OrthancServer/ParsedDicomFile.cpp	Thu Aug 20 15:18:13 2015 +0200
+++ b/OrthancServer/ParsedDicomFile.cpp	Thu Aug 20 17:05:05 2015 +0200
@@ -966,7 +966,9 @@
     DcmTagKey k(tag.GetGroup(), tag.GetElement());
     DcmDataset& dataset = *pimpl_->file_->getDataset();
 
-    if (FromDcmtkBridge::IsPrivateTag(tag))
+    if (FromDcmtkBridge::IsPrivateTag(tag) ||
+        tag == DICOM_TAG_PIXEL_DATA ||
+        tag == DICOM_TAG_ENCAPSULATED_DOCUMENT)
     {
       const Uint8* data = NULL;   // This is freed in the destructor of the dataset
       long unsigned int count = 0;
@@ -1000,7 +1002,7 @@
       }
 
       std::auto_ptr<DicomValue> v(FromDcmtkBridge::ConvertLeafElement(*element, pimpl_->encoding_));
-
+      
       if (v.get() == NULL)
       {
         value = "";
@@ -1009,7 +1011,7 @@
       {
         value = v->AsString();
       }
-
+      
       return true;
     }
   }
@@ -1471,4 +1473,39 @@
     }
   }
 
+
+  bool ParsedDicomFile::ExtractPdf(std::string& pdf)
+  {
+    std::string sop, mime;
+    
+    if (!GetTagValue(sop, DICOM_TAG_SOP_CLASS_UID) ||
+        !GetTagValue(mime, FromDcmtkBridge::Convert(DCM_MIMETypeOfEncapsulatedDocument)) ||
+        sop != UID_EncapsulatedPDFStorage ||
+        mime != "application/pdf")
+    {
+      return false;
+    }
+
+    if (!GetTagValue(pdf, DICOM_TAG_ENCAPSULATED_DOCUMENT))
+    {
+      return false;
+    }
+
+    // Strip the possible pad byte at the end of file, because the
+    // encapsulated documents must always have an even length. The PDF
+    // format expects files to end with %%EOF followed by CR/LF. If
+    // the last character of the file is not a CR or LF, we assume it
+    // is a pad byte and remove it.
+    if (pdf.size() > 0)
+    {
+      char last = *pdf.rbegin();
+
+      if (last != 10 && last != 13)
+      {
+        pdf.resize(pdf.size() - 1);
+      }
+    }
+
+    return true;
+  }
 }
--- a/OrthancServer/ParsedDicomFile.h	Thu Aug 20 15:18:13 2015 +0200
+++ b/OrthancServer/ParsedDicomFile.h	Thu Aug 20 17:05:05 2015 +0200
@@ -128,6 +128,8 @@
     bool HasTag(const DicomTag& tag) const;
 
     void EmbedPdf(const std::string& pdf);
+
+    bool ExtractPdf(std::string& pdf);
   };
 
 }