changeset 42:ea48f38afe5f

access to raw images
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 03 Sep 2012 11:34:00 +0200
parents c1097a676eca
children 9be852ad33d2
files NEWS PalantirServer/FromDcmtkBridge.cpp PalantirServer/FromDcmtkBridge.h PalantirServer/PalantirRestApi.cpp
diffstat 4 files changed, 131 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Fri Aug 31 11:45:48 2012 +0200
+++ b/NEWS	Mon Sep 03 11:34:00 2012 +0200
@@ -1,6 +1,7 @@
 Pending changes
 ===============
 
+* Access to the raw PNG images (in 8bpp and 16bpp)
 * Support of SSL and HTTP Basic Authentication
 * Change of the licensing of the "Core/SQLite" folder to BSD, (to
   reflect the original licensing terms of Chromium, from which the
--- a/PalantirServer/FromDcmtkBridge.cpp	Fri Aug 31 11:45:48 2012 +0200
+++ b/PalantirServer/FromDcmtkBridge.cpp	Mon Sep 03 11:34:00 2012 +0200
@@ -379,12 +379,69 @@
   }
 
 
-  void FromDcmtkBridge::ExtractPreviewImage(std::string& result,
-                                            DcmDataset& dataset)
+  static void ExtractPngImagePreview(std::string& result,
+                                     DicomIntegerPixelAccessor& accessor)
+  {
+    PngWriter w;
+
+    int32_t min, max;
+    accessor.GetExtremeValues(min, max);
+
+    std::vector<uint8_t> image(accessor.GetWidth() * accessor.GetHeight(), 0);
+    if (min != max)
+    {
+      uint8_t* pixel = &image[0];
+      for (unsigned int y = 0; y < accessor.GetHeight(); y++)
+      {
+        for (unsigned int x = 0; x < accessor.GetWidth(); x++, pixel++)
+        {
+          int32_t v = accessor.GetValue(x, y);
+          *pixel = static_cast<uint8_t>(
+            boost::math::lround(static_cast<float>(v - min) / 
+                                static_cast<float>(max - min) * 255.0f));
+        }
+      }
+    }
+
+    w.WriteToMemory(result, accessor.GetWidth(), accessor.GetHeight(),
+                    accessor.GetWidth(), PixelFormat_Grayscale8, &image[0]);
+  }
+
+
+  template <typename T>
+  static void ExtractPngImageTruncate(std::string& result,
+                                      DicomIntegerPixelAccessor& accessor,
+                                      PixelFormat format)
+  {
+    PngWriter w;
+
+    std::vector<T> image(accessor.GetWidth() * accessor.GetHeight(), 0);
+    T* pixel = &image[0];
+    for (unsigned int y = 0; y < accessor.GetHeight(); y++)
+    {
+      for (unsigned int x = 0; x < accessor.GetWidth(); x++, pixel++)
+      {
+        int32_t v = accessor.GetValue(x, y);
+        if (v < std::numeric_limits<T>::min())
+          *pixel = std::numeric_limits<T>::min();
+        else if (v > std::numeric_limits<T>::max())
+          *pixel = std::numeric_limits<T>::max();
+        else
+          *pixel = static_cast<T>(v);
+      }
+    }
+
+    w.WriteToMemory(result, accessor.GetWidth(), accessor.GetHeight(),
+                    accessor.GetWidth() * sizeof(T), format, &image[0]);
+  }
+
+
+  void FromDcmtkBridge::ExtractPngImage(std::string& result,
+                                        DcmDataset& dataset,
+                                        ImageExtractionMode mode)
   {
     // See also: http://support.dcmtk.org/wiki/dcmtk/howto/accessing-compressed-data
 
-    PngWriter w;
     std::auto_ptr<DicomIntegerPixelAccessor> accessor;
 
     DicomMap m;
@@ -401,39 +458,55 @@
       }
     }
 
+    PixelFormat format;
+    switch (mode)
+    {
+    case ImageExtractionMode_Preview:
+    case ImageExtractionMode_UInt8:
+      format = PixelFormat_Grayscale8;
+      break;
+
+    case ImageExtractionMode_UInt16:
+      format = PixelFormat_Grayscale16;
+      break;
+
+    default:
+      throw PalantirException(ErrorCode_NotImplemented);
+    }
+
     if (accessor.get() == NULL ||
         accessor->GetWidth() == 0 ||
         accessor->GetHeight() == 0)
     {
-      w.WriteToMemory(result, 0, 0, 0, PixelFormat_Grayscale8, NULL);
+      PngWriter w;
+      w.WriteToMemory(result, 0, 0, 0, format, NULL);
     }
     else
     {
-      int32_t min, max;
-      accessor->GetExtremeValues(min, max);
-
-      std::vector<uint8_t> image(accessor->GetWidth() * accessor->GetHeight(), 0);
-      if (min != max)
+      switch (mode)
       {
-        uint8_t* result = &image[0];
-        for (unsigned int y = 0; y < accessor->GetHeight(); y++)
-        {
-          for (unsigned int x = 0; x < accessor->GetWidth(); x++, result++)
-          {
-            int32_t v = accessor->GetValue(x, y);
-            *result = static_cast<uint8_t>(boost::math::lround(static_cast<float>(v - min) / static_cast<float>(max - min) * 255.0f));
-          }
-        }
+      case ImageExtractionMode_Preview:
+        ExtractPngImagePreview(result, *accessor);
+        break;
+
+      case ImageExtractionMode_UInt8:
+        ExtractPngImageTruncate<uint8_t>(result, *accessor, format);
+        break;
+
+      case ImageExtractionMode_UInt16:
+        ExtractPngImageTruncate<uint16_t>(result, *accessor, format);
+        break;
+
+      default:
+        throw PalantirException(ErrorCode_NotImplemented);
       }
-
-      w.WriteToMemory(result, accessor->GetWidth(), accessor->GetHeight(),
-                      accessor->GetWidth(), PixelFormat_Grayscale8, &image[0]);
     }
   }
 
 
-  void FromDcmtkBridge::ExtractPreviewImage(std::string& result,
-                                            const std::string& dicomContent)
+  void FromDcmtkBridge::ExtractPngImage(std::string& result,
+                                        const std::string& dicomContent,
+                                        ImageExtractionMode mode)
   {
     DcmInputBufferStream is;
     if (dicomContent.size() > 0)
@@ -445,7 +518,7 @@
     DcmFileFormat dicom;
     if (dicom.read(is).good())
     {
-      ExtractPreviewImage(result, *dicom.getDataset());
+      ExtractPngImage(result, *dicom.getDataset(), mode);
     }
     else
     {
--- a/PalantirServer/FromDcmtkBridge.h	Fri Aug 31 11:45:48 2012 +0200
+++ b/PalantirServer/FromDcmtkBridge.h	Mon Sep 03 11:34:00 2012 +0200
@@ -26,6 +26,13 @@
 
 namespace Palantir
 {
+  enum ImageExtractionMode
+  {
+    ImageExtractionMode_Preview,
+    ImageExtractionMode_UInt8,
+    ImageExtractionMode_UInt16
+  };
+
   class FromDcmtkBridge
   {
   public:
@@ -43,11 +50,13 @@
                        const std::string& path,
                        unsigned int maxStringLength = 256);
 
-    static void ExtractPreviewImage(std::string& result,
-                                    DcmDataset& dataset);
+    static void ExtractPngImage(std::string& result,
+                                DcmDataset& dataset,
+                                ImageExtractionMode mode);
 
-    static void ExtractPreviewImage(std::string& result,
-                                    const std::string& dicomContent);
+    static void ExtractPngImage(std::string& result,
+                                const std::string& dicomContent,
+                                ImageExtractionMode mode);
 
     static std::string GetName(const DicomTag& tag);
 
--- a/PalantirServer/PalantirRestApi.cpp	Fri Aug 31 11:45:48 2012 +0200
+++ b/PalantirServer/PalantirRestApi.cpp	Mon Sep 03 11:34:00 2012 +0200
@@ -568,7 +568,9 @@
 
     else if (uri.size() == 3 &&
              uri[0] == "instances" &&
-             uri[2] == "preview")
+             (uri[2] == "preview" ||
+              uri[2] == "image-uint8" ||
+              uri[2] == "image-uint16"))
     {
       std::string uuid;
       existingResource = index_.GetDicomFile(uuid, uri[1]);
@@ -579,7 +581,23 @@
         storage_.ReadFile(dicomContent, uuid);
         try
         {
-          FromDcmtkBridge::ExtractPreviewImage(png, dicomContent);
+          if (uri[2] == "preview")
+          {
+            FromDcmtkBridge::ExtractPngImage(png, dicomContent, ImageExtractionMode_Preview);
+          }
+          else if (uri[2] == "image-uint8")
+          {
+            FromDcmtkBridge::ExtractPngImage(png, dicomContent, ImageExtractionMode_UInt8);
+          }
+          else if (uri[2] == "image-uint16")
+          {
+            FromDcmtkBridge::ExtractPngImage(png, dicomContent, ImageExtractionMode_UInt16);
+          }
+          else
+          {
+            throw PalantirException(ErrorCode_InternalError);
+          }
+
           output.AnswerBufferWithContentType(png, "image/png");
           return;
         }