changeset 32:517c46f527cd

sync
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 19 Dec 2016 11:00:23 +0100
parents 9aace933cb64
children 12987d11be33
files Framework/Layers/FrameRenderer.cpp Framework/Layers/FrameRenderer.h Framework/Layers/SeriesFrameRendererFactory.cpp Framework/Layers/SeriesFrameRendererFactory.h Framework/Layers/SingleFrameRendererFactory.cpp Framework/Layers/SingleFrameRendererFactory.h Framework/Toolbox/DicomFrameConverter.cpp Framework/Toolbox/DicomFrameConverter.h Framework/Toolbox/DicomStructureSet.cpp Framework/Toolbox/DicomStructureSet.h Framework/Toolbox/GeometryToolbox.cpp Framework/Toolbox/GeometryToolbox.h Framework/Toolbox/ISeriesLoader.h Framework/Toolbox/OrthancSeriesLoader.cpp Framework/Toolbox/OrthancSeriesLoader.h Framework/Toolbox/SliceGeometry.cpp Framework/Toolbox/SliceGeometry.h Framework/Volumes/VolumeImage.cpp Framework/Volumes/VolumeImage.h Resources/CMake/OrthancStone.cmake Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.cpp Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.h Resources/Orthanc/Plugins/Samples/Common/DicomPath.cpp Resources/Orthanc/Plugins/Samples/Common/DicomPath.h Resources/Orthanc/Plugins/Samples/Common/DicomTag.h Resources/Orthanc/Plugins/Samples/Common/OrthancPluginException.h
diffstat 26 files changed, 386 insertions(+), 224 deletions(-) [+]
line wrap: on
line diff
--- a/Framework/Layers/FrameRenderer.cpp	Fri Dec 16 15:41:20 2016 +0100
+++ b/Framework/Layers/FrameRenderer.cpp	Mon Dec 19 11:00:23 2016 +0100
@@ -226,7 +226,7 @@
   ILayerRenderer* FrameRenderer::CreateRenderer(Orthanc::ImageAccessor* frame,
                                                 const SliceGeometry& viewportSlice,
                                                 const SliceGeometry& frameSlice,
-                                                const DicomDataset& dicom,
+                                                const OrthancPlugins::IDicomDataset& dicom,
                                                 double pixelSpacingX,
                                                 double pixelSpacingY,
                                                 bool isFullQuality)
--- a/Framework/Layers/FrameRenderer.h	Fri Dec 16 15:41:20 2016 +0100
+++ b/Framework/Layers/FrameRenderer.h	Mon Dec 19 11:00:23 2016 +0100
@@ -85,7 +85,7 @@
     static ILayerRenderer* CreateRenderer(Orthanc::ImageAccessor* frame,
                                           const SliceGeometry& viewportSlice,
                                           const SliceGeometry& frameSlice,
-                                          const DicomDataset& dicom,
+                                          const OrthancPlugins::IDicomDataset& dicom,
                                           double pixelSpacingX,
                                           double pixelSpacingY,
                                           bool isFullQuality);
--- a/Framework/Layers/SeriesFrameRendererFactory.cpp	Fri Dec 16 15:41:20 2016 +0100
+++ b/Framework/Layers/SeriesFrameRendererFactory.cpp	Mon Dec 19 11:00:23 2016 +0100
@@ -34,6 +34,11 @@
 
 #include "FrameRenderer.h"
 #include "../../Resources/Orthanc/Core/OrthancException.h"
+#include "../../Resources/Orthanc/Core/Logging.h"
+#include "../../Resources/Orthanc/Core/Toolbox.h"
+#include "../../Resources/Orthanc/Plugins/Samples/Common/OrthancPluginException.h"
+#include "../../Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.h"
+
 
 namespace OrthancStone
 {
@@ -66,7 +71,7 @@
       throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
     }
     
-    currentDataset_->GetPixelSpacing(spacingX, spacingY);
+    GeometryToolbox::GetPixelSpacing(spacingX, spacingY, *currentDataset_);
   }
 
 
@@ -77,16 +82,23 @@
       // There was no previous call "ReadCurrentFrameDataset()"
       throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
     }
-      
-    if (currentDataset_->HasTag(DICOM_TAG_SLICE_THICKNESS))
+    
+    try
     {
-      return currentDataset_->GetFloatValue(DICOM_TAG_SLICE_THICKNESS);
+      OrthancPlugins::DicomDatasetReader reader(*currentDataset_);
+
+      double thickness;
+      if (reader.GetDoubleValue(thickness, OrthancPlugins::DICOM_TAG_SLICE_THICKNESS))
+      {
+        return thickness;
+      }
     }
-    else
+    catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
     {
-      // Some arbitrary large slice thickness
-      return std::numeric_limits<double>::infinity();
     }
+
+    // Some arbitrary large slice thickness
+    return std::numeric_limits<double>::infinity();
   }
 
 
--- a/Framework/Layers/SeriesFrameRendererFactory.h	Fri Dec 16 15:41:20 2016 +0100
+++ b/Framework/Layers/SeriesFrameRendererFactory.h	Mon Dec 19 11:00:23 2016 +0100
@@ -42,10 +42,11 @@
   {
   private:
     std::auto_ptr<ISeriesLoader>  loader_;
-    std::auto_ptr<DicomDataset>   currentDataset_;
     size_t                        currentFrame_;
     bool                          fast_;
 
+    std::auto_ptr<OrthancPlugins::IDicomDataset>  currentDataset_;
+
     void ReadCurrentFrameDataset(size_t frame);
 
     void GetCurrentPixelSpacing(double& spacingX,
--- a/Framework/Layers/SingleFrameRendererFactory.cpp	Fri Dec 16 15:41:20 2016 +0100
+++ b/Framework/Layers/SingleFrameRendererFactory.cpp	Mon Dec 19 11:00:23 2016 +0100
@@ -35,6 +35,8 @@
 #include "FrameRenderer.h"
 #include "../Messaging/MessagingToolbox.h"
 #include "../../Resources/Orthanc/Core/OrthancException.h"
+#include "../../Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.h"
+#include "../../Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.h"
 #include "../Toolbox/DicomFrameConverter.h"
 
 namespace OrthancStone
@@ -43,27 +45,14 @@
                                                          const std::string& instanceId,
                                                          unsigned int frame) :
     orthanc_(orthanc),
-    dicom_(orthanc, instanceId),
     instance_(instanceId),
     frame_(frame)
   {
-    DicomFrameConverter converter;
-    converter.ReadParameters(dicom_);
-    format_ = converter.GetExpectedPixelFormat();
-  }
-
+    dicom_.reset(new OrthancPlugins::FullOrthancDataset(orthanc, "/instances/" + instanceId + "/tags"));
 
-  SliceGeometry SingleFrameRendererFactory::GetSliceGeometry()
-  {
-    if (dicom_.HasTag(DICOM_TAG_IMAGE_POSITION_PATIENT) &&
-        dicom_.HasTag(DICOM_TAG_IMAGE_ORIENTATION_PATIENT))
-    {
-      return SliceGeometry(dicom_);
-    }
-    else
-    {
-      return SliceGeometry();
-    }
+    DicomFrameConverter converter;
+    converter.ReadParameters(*dicom_);
+    format_ = converter.GetExpectedPixelFormat();
   }
 
 
@@ -75,8 +64,15 @@
   {
     // Assume that PixelSpacingX == PixelSpacingY == 1
 
-    unsigned int width = dicom_.GetUnsignedIntegerValue(DICOM_TAG_COLUMNS);
-    unsigned int height = dicom_.GetUnsignedIntegerValue(DICOM_TAG_ROWS);
+    OrthancPlugins::DicomDatasetReader reader(*dicom_);
+
+    unsigned int width, height;
+
+    if (!reader.GetUnsignedIntegerValue(width, OrthancPlugins::DICOM_TAG_COLUMNS) ||
+        !reader.GetUnsignedIntegerValue(height, OrthancPlugins::DICOM_TAG_ROWS))
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+    }
 
     x1 = 0;
     y1 = 0;
@@ -89,9 +85,9 @@
 
   ILayerRenderer* SingleFrameRendererFactory::CreateLayerRenderer(const SliceGeometry& viewportSlice)
   {
-    SliceGeometry frameSlice(dicom_);
+    SliceGeometry frameSlice(*dicom_);
     return FrameRenderer::CreateRenderer(MessagingToolbox::DecodeFrame(orthanc_, instance_, frame_, format_), 
-                                         viewportSlice, frameSlice, dicom_, 1, 1, true);
+                                         viewportSlice, frameSlice, *dicom_, 1, 1, true);
   }
 
 
--- a/Framework/Layers/SingleFrameRendererFactory.h	Fri Dec 16 15:41:20 2016 +0100
+++ b/Framework/Layers/SingleFrameRendererFactory.h	Mon Dec 19 11:00:23 2016 +0100
@@ -33,15 +33,16 @@
 #pragma once
 
 #include "ILayerRendererFactory.h"
+#include "../../Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.h"
 
 namespace OrthancStone
 {
   class SingleFrameRendererFactory : public ILayerRendererFactory
   {
   private:
-    OrthancPlugins::IOrthancConnection&   orthanc_;
+    OrthancPlugins::IOrthancConnection&           orthanc_;
+    std::auto_ptr<OrthancPlugins::IDicomDataset>  dicom_;
 
-    DicomDataset          dicom_;
     std::string           instance_;
     unsigned int          frame_;
     Orthanc::PixelFormat  format_;
@@ -51,12 +52,15 @@
                                const std::string& instanceId,
                                unsigned int frame);
 
-    const DicomDataset& GetDataset() const
+    const OrthancPlugins::IDicomDataset& GetDataset() const
     {
-      return dicom_;
+      return *dicom_;
     }
 
-    SliceGeometry GetSliceGeometry();
+    SliceGeometry GetSliceGeometry()
+    {
+      return SliceGeometry(*dicom_);
+    }
 
     virtual bool GetExtent(double& x1,
                            double& y1,
--- a/Framework/Toolbox/DicomFrameConverter.cpp	Fri Dec 16 15:41:20 2016 +0100
+++ b/Framework/Toolbox/DicomFrameConverter.cpp	Mon Dec 19 11:00:23 2016 +0100
@@ -32,6 +32,8 @@
 
 #include "DicomFrameConverter.h"
 
+#include "GeometryToolbox.h"
+
 #include "../../Resources/Orthanc/Core/Images/Image.h"
 #include "../../Resources/Orthanc/Core/Images/ImageProcessing.h"
 #include "../../Resources/Orthanc/Core/OrthancException.h"
@@ -71,33 +73,41 @@
   }
 
 
-  void DicomFrameConverter::ReadParameters(const DicomDataset& dicom)
+  void DicomFrameConverter::ReadParameters(const OrthancPlugins::IDicomDataset& dicom)
   {
     SetDefaultParameters();
 
-    if (dicom.HasTag(DICOM_TAG_WINDOW_CENTER))
+    Vector c, w;
+    if (GeometryToolbox::ParseVector(c, dicom, OrthancPlugins::DICOM_TAG_WINDOW_CENTER) &&
+        GeometryToolbox::ParseVector(c, dicom, OrthancPlugins::DICOM_TAG_WINDOW_WIDTH))
     {
-      Vector c, w;
-      dicom.GetVectorValue(c, DICOM_TAG_WINDOW_CENTER);
-      dicom.GetVectorValue(w, DICOM_TAG_WINDOW_WIDTH);
-
-      if (c.size() > 0 && w.size() > 0)
+      if (c.size() > 0 && 
+          w.size() > 0)
       {
         defaultWindowCenter_ = static_cast<float>(c[0]);
         defaultWindowWidth_ = static_cast<float>(w[0]);
       }
     }
 
-    isSigned_ = (dicom.GetIntegerValue(DICOM_TAG_PIXEL_REPRESENTATION) == 1);  // Type 1 tag, must be present
+    OrthancPlugins::DicomDatasetReader reader(dicom);
 
-    if (dicom.HasTag(DICOM_TAG_RESCALE_INTERCEPT))
+    int tmp;
+    if (!reader.GetIntegerValue(tmp, OrthancPlugins::DICOM_TAG_PIXEL_REPRESENTATION))
     {
-      rescaleIntercept_ = dicom.GetFloatValue(DICOM_TAG_RESCALE_INTERCEPT);
-      rescaleSlope_ = dicom.GetFloatValue(DICOM_TAG_RESCALE_SLOPE);
+      // Type 1 tag, must be present
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+    }
+
+    isSigned_ = (tmp == 1);
+
+    if (reader.GetFloatValue(rescaleIntercept_, OrthancPlugins::DICOM_TAG_RESCALE_INTERCEPT) &&
+        reader.GetFloatValue(rescaleSlope_, OrthancPlugins::DICOM_TAG_RESCALE_SLOPE))
+    {
       hasRescale_ = true;
     }
 
-    std::string photometric = dicom.GetStringValue(DICOM_TAG_PHOTOMETRIC_INTERPRETATION);  // Type 1 tag, must be present
+    // Type 1 tag, must be present
+    std::string photometric = reader.GetMandatoryStringValue(OrthancPlugins::DICOM_TAG_PHOTOMETRIC_INTERPRETATION);
     photometric = Orthanc::Toolbox::StripSpaces(photometric);
     isColor_ = (photometric != "MONOCHROME1" &&
                 photometric != "MONOCHROME2");
--- a/Framework/Toolbox/DicomFrameConverter.h	Fri Dec 16 15:41:20 2016 +0100
+++ b/Framework/Toolbox/DicomFrameConverter.h	Mon Dec 19 11:00:23 2016 +0100
@@ -32,9 +32,10 @@
 
 #pragma once
 
-#include "DicomDataset.h"
+#include "../../Resources/Orthanc/Core/Images/ImageAccessor.h"
+#include "../../Resources/Orthanc/Plugins/Samples/Common/IDicomDataset.h"
 
-#include "../../Resources/Orthanc/Core/Images/ImageAccessor.h"
+#include <memory>
 
 namespace OrthancStone
 {
@@ -66,7 +67,7 @@
 
     Orthanc::PixelFormat GetExpectedPixelFormat() const;
 
-    void ReadParameters(const DicomDataset& dicom);
+    void ReadParameters(const OrthancPlugins::IDicomDataset& dicom);
 
     float GetDefaultWindowCenter() const
     {
--- a/Framework/Toolbox/DicomStructureSet.cpp	Fri Dec 16 15:41:20 2016 +0100
+++ b/Framework/Toolbox/DicomStructureSet.cpp	Mon Dec 19 11:00:23 2016 +0100
@@ -34,6 +34,7 @@
 
 #include "../../Resources/Orthanc/Core/Logging.h"
 #include "../../Resources/Orthanc/Core/OrthancException.h"
+#include "../../Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.h"
 #include "../Messaging/MessagingToolbox.h"
 
 #include <stdio.h>
@@ -41,27 +42,17 @@
 
 namespace OrthancStone
 {
-  static const Json::Value& GetSequence(const Json::Value& instance,
-                                        uint16_t group,
-                                        uint16_t element)
-  {
-    char buf[16];
-    sprintf(buf, "%04x,%04x", group, element);
-
-    if (instance.type() != Json::objectValue ||
-        !instance.isMember(buf) ||
-        instance[buf].type() != Json::objectValue ||
-        !instance[buf].isMember("Type") ||
-        !instance[buf].isMember("Value") ||
-        instance[buf]["Type"].type() != Json::stringValue ||
-        instance[buf]["Value"].type() != Json::arrayValue ||
-        instance[buf]["Type"].asString() != "Sequence")
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
-    }
-
-    return instance[buf]["Value"];
-  }
+  static const OrthancPlugins::DicomTag DICOM_TAG_CONTOUR_GEOMETRIC_TYPE(0x3006, 0x0042);
+  static const OrthancPlugins::DicomTag DICOM_TAG_CONTOUR_IMAGE_SEQUENCE(0x3006, 0x0016);
+  static const OrthancPlugins::DicomTag DICOM_TAG_CONTOUR_SEQUENCE(0x3006, 0x0040);
+  static const OrthancPlugins::DicomTag DICOM_TAG_NUMBER_OF_CONTOUR_POINTS(0x3006, 0x0046);
+  static const OrthancPlugins::DicomTag DICOM_TAG_REFERENCED_SOP_INSTANCE_UID(0x0008, 0x1155);
+  static const OrthancPlugins::DicomTag DICOM_TAG_ROI_CONTOUR_SEQUENCE(0x3006, 0x0039);
+  static const OrthancPlugins::DicomTag DICOM_TAG_ROI_DISPLAY_COLOR(0x3006, 0x002a);
+  static const OrthancPlugins::DicomTag DICOM_TAG_ROI_NAME(0x3006, 0x0026);
+  static const OrthancPlugins::DicomTag DICOM_TAG_RT_ROI_INTERPRETED_TYPE(0x3006, 0x00a4);
+  static const OrthancPlugins::DicomTag DICOM_TAG_RT_ROI_OBSERVATIONS_SEQUENCE(0x3006, 0x0080);
+  static const OrthancPlugins::DicomTag DICOM_TAG_STRUCTURE_SET_ROI_SEQUENCE(0x3006, 0x0020);
 
 
   static uint8_t ConvertColor(double v)
@@ -83,17 +74,26 @@
 
   SliceGeometry DicomStructureSet::ExtractSliceGeometry(double& sliceThickness,
                                                         OrthancPlugins::IOrthancConnection& orthanc,
-                                                        const Json::Value& contour)
+                                                        const OrthancPlugins::IDicomDataset& tags,
+                                                        size_t contourIndex,
+                                                        size_t sliceIndex)
   {
-    const Json::Value& sequence = GetSequence(contour, 0x3006, 0x0016);
+    using namespace OrthancPlugins;
 
-    if (sequence.size() != 1)
+    size_t size;
+    if (!tags.GetSequenceSize(size, DicomPath(DICOM_TAG_ROI_CONTOUR_SEQUENCE, contourIndex,
+                                              DICOM_TAG_CONTOUR_SEQUENCE, sliceIndex,
+                                              DICOM_TAG_CONTOUR_IMAGE_SEQUENCE)) ||
+        size != 1)
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);          
     }
 
-    DicomDataset contourImageSequence(sequence[0]);
-    std::string parentUid = contourImageSequence.GetStringValue(std::make_pair(0x0008, 0x1155));
+    DicomDatasetReader reader(tags);
+    std::string parentUid = reader.GetMandatoryStringValue(DicomPath(DICOM_TAG_ROI_CONTOUR_SEQUENCE, contourIndex,
+                                                                     DICOM_TAG_CONTOUR_SEQUENCE, sliceIndex,
+                                                                     DICOM_TAG_CONTOUR_IMAGE_SEQUENCE, 0,
+                                                                     DICOM_TAG_REFERENCED_SOP_INSTANCE_UID));
 
     std::string post;
     orthanc.RestApiPost(post, "/tools/lookup", parentUid);
@@ -135,32 +135,18 @@
       throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
     }
 
-    Json::Value parentTags;
-    MessagingToolbox::RestApiGet(parentTags, orthanc, "/instances/" + tmp[0]["ID"].asString() + "/tags?simplify");
-      
-    if (parentTags.type() != Json::objectValue ||
-        !parentTags.isMember("ImageOrientationPatient") ||
-        !parentTags.isMember("ImagePositionPatient") ||
-        parentTags["ImageOrientationPatient"].type() != Json::stringValue ||
-        parentTags["ImagePositionPatient"].type() != Json::stringValue)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);          
-    }
+    FullOrthancDataset parentTags(orthanc, "/instances/" + tmp[0]["ID"].asString() + "/tags");
+    SliceGeometry slice(parentTags);
 
-    SliceGeometry slice(parentTags["ImagePositionPatient"].asString(),
-                        parentTags["ImageOrientationPatient"].asString());
-                          
-    sliceThickness = 1;  // 1 mm by default
-
-    if (parentTags.isMember("SliceThickness") &&
-        parentTags["SliceThickness"].type() == Json::stringValue)
+    Vector v;
+    if (GeometryToolbox::ParseVector(v, parentTags, DICOM_TAG_SLICE_THICKNESS) &&
+        v.size() > 0)
     {
-      Vector tmp;
-      GeometryToolbox::ParseVector(tmp, parentTags["SliceThickness"].asString());
-      if (tmp.size() > 0)
-      {
-        sliceThickness = tmp[0];
-      }
+      sliceThickness = v[0];
+    }
+    else
+    {
+      sliceThickness = 1;  // 1 mm by default
     }
 
     if (isFirst)
@@ -201,68 +187,87 @@
   DicomStructureSet::DicomStructureSet(OrthancPlugins::IOrthancConnection& orthanc,
                                        const std::string& instanceId)
   {
-    Json::Value instance;
-    MessagingToolbox::RestApiGet(instance, orthanc, "/instances/" + instanceId + "/tags");
- 
-    Json::Value rtRoiObservationSequence = GetSequence(instance, 0x3006, 0x0080);
-    Json::Value roiContourSequence = GetSequence(instance, 0x3006, 0x0039);
-    Json::Value structureSetRoiSequence = GetSequence(instance, 0x3006, 0x0020);
+    using namespace OrthancPlugins;
 
-    Json::Value::ArrayIndex count = rtRoiObservationSequence.size();
-    if (count != roiContourSequence.size() ||
-        count != structureSetRoiSequence.size())
+    FullOrthancDataset tags(orthanc, "/instances/" + instanceId + "/tags");
+    DicomDatasetReader reader(tags);
+    
+    size_t count, tmp;
+    if (!tags.GetSequenceSize(count, DICOM_TAG_RT_ROI_OBSERVATIONS_SEQUENCE) ||
+        !tags.GetSequenceSize(tmp, DICOM_TAG_ROI_CONTOUR_SEQUENCE) ||
+        tmp != count ||
+        !tags.GetSequenceSize(tmp, DICOM_TAG_STRUCTURE_SET_ROI_SEQUENCE) ||
+        tmp != count)
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
     }
-      
-    structures_.resize(count);
-    for (Json::Value::ArrayIndex i = 0; i < count; i++)
-    {
-      DicomDataset observation(rtRoiObservationSequence[i]);
-      DicomDataset roi(structureSetRoiSequence[i]);
-      DicomDataset content(roiContourSequence[i]);
 
-      structures_[i].interpretation_ = observation.GetStringValue(std::make_pair(0x3006, 0x00a4), "No interpretation");
-      structures_[i].name_ = roi.GetStringValue(std::make_pair(0x3006, 0x0026), "No name");
-      structures_[i].red_ = 255;
-      structures_[i].green_ = 0;
-      structures_[i].blue_ = 0;
+    structures_.resize(count);
+    for (size_t i = 0; i < count; i++)
+    {
+      structures_[i].interpretation_ = reader.GetStringValue(DicomPath(DICOM_TAG_RT_ROI_OBSERVATIONS_SEQUENCE, i,
+                                                                       DICOM_TAG_RT_ROI_INTERPRETED_TYPE),
+                                                             "No interpretation");
 
-      DicomDataset::Tag tag(0x3006, 0x002a);
+      structures_[i].name_ = reader.GetStringValue(DicomPath(DICOM_TAG_STRUCTURE_SET_ROI_SEQUENCE, i,
+                                                             DICOM_TAG_ROI_NAME),
+                                                   "No interpretation");
 
       Vector color;
-      if (content.HasTag(tag))
+      if (GeometryToolbox::ParseVector(color, tags, DicomPath(DICOM_TAG_ROI_CONTOUR_SEQUENCE, i,
+                                                              DICOM_TAG_ROI_DISPLAY_COLOR)) &&
+          color.size() == 3)
       {
-        content.GetVectorValue(color, tag);
-        if (color.size() == 3)
-        {
-          structures_[i].red_ = ConvertColor(color[0]);
-          structures_[i].green_ = ConvertColor(color[1]);
-          structures_[i].blue_ = ConvertColor(color[2]);
-        }
+        structures_[i].red_ = ConvertColor(color[0]);
+        structures_[i].green_ = ConvertColor(color[1]);
+        structures_[i].blue_ = ConvertColor(color[2]);
+      }
+      else
+      {
+        structures_[i].red_ = 255;
+        structures_[i].green_ = 0;
+        structures_[i].blue_ = 0;
       }
 
-      const Json::Value& slices = GetSequence(roiContourSequence[i], 0x3006, 0x0040);
+      size_t countSlices;
+      if (!tags.GetSequenceSize(countSlices, DicomPath(DICOM_TAG_ROI_CONTOUR_SEQUENCE, i,
+                                                       DICOM_TAG_CONTOUR_SEQUENCE)))
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+      }
 
       LOG(WARNING) << "New RT structure: \"" << structures_[i].name_ 
                    << "\" with interpretation \"" << structures_[i].interpretation_
-                   << "\" containing " << slices.size() << " slices (color: " 
+                   << "\" containing " << countSlices << " slices (color: " 
                    << static_cast<int>(structures_[i].red_) << "," 
                    << static_cast<int>(structures_[i].green_) << ","
                    << static_cast<int>(structures_[i].blue_) << ")";
 
-      for (Json::Value::ArrayIndex j = 0; j < slices.size(); j++)
+      for (size_t j = 0; j < countSlices; j++)
       {
-        DicomDataset slice(slices[j]);
+        unsigned int countPoints;
 
-        unsigned int npoints = slice.GetUnsignedIntegerValue(std::make_pair(0x3006, 0x0046));
-        LOG(INFO) << "Parsing slice containing " << npoints << " vertices";
+        if (!reader.GetUnsignedIntegerValue(countPoints, DicomPath(DICOM_TAG_ROI_CONTOUR_SEQUENCE, i,
+                                                                   DICOM_TAG_CONTOUR_SEQUENCE, j,
+                                                                   DICOM_TAG_NUMBER_OF_CONTOUR_POINTS)))
+        {
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+        }
+            
+        LOG(INFO) << "Parsing slice containing " << countPoints << " vertices";
 
-        if (slice.GetStringValue(std::make_pair(0x3006, 0x0042)) != "CLOSED_PLANAR")
+        std::string type = reader.GetMandatoryStringValue(DicomPath(DICOM_TAG_ROI_CONTOUR_SEQUENCE, i,
+                                                                    DICOM_TAG_CONTOUR_SEQUENCE, j,
+                                                                    DICOM_TAG_CONTOUR_GEOMETRIC_TYPE));
+        if (type != "CLOSED_PLANAR")
         {
+          LOG(ERROR) << "Cannot handle contour with geometry type: " << type;
           throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);          
         }
 
+        // The "CountourData" tag (3006,0050) is too large to be
+        // returned by the "/instances/{id}/tags" URI: Access it using
+        // the raw "/instances/{id}/content/{...}" endpoint
         std::string slicesData;
         orthanc.RestApiGet(slicesData, "/instances/" + instanceId + "/content/3006-0039/" +
                            boost::lexical_cast<std::string>(i) + "/3006-0040/" +
@@ -270,16 +275,16 @@
 
         Vector points;
         if (!GeometryToolbox::ParseVector(points, slicesData) ||
-            points.size() != 3 * npoints)
+            points.size() != 3 * countPoints)
         {
           throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);          
         }
 
         Polygon polygon;
-        SliceGeometry geometry = ExtractSliceGeometry(polygon.sliceThickness_, orthanc, slices[j]);
+        SliceGeometry geometry = ExtractSliceGeometry(polygon.sliceThickness_, orthanc, tags, i, j);
         polygon.projectionAlongNormal_ = geometry.ProjectAlongNormal(geometry.GetOrigin());
 
-        for (size_t k = 0; k < npoints; k++)
+        for (size_t k = 0; k < countPoints; k++)
         {
           Vector v(3);
           v[0] = points[3 * k];
--- a/Framework/Toolbox/DicomStructureSet.h	Fri Dec 16 15:41:20 2016 +0100
+++ b/Framework/Toolbox/DicomStructureSet.h	Mon Dec 19 11:00:23 2016 +0100
@@ -34,6 +34,7 @@
 
 #include "SliceGeometry.h"
 #include "../Viewport/CairoContext.h"
+#include "../../Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.h"
 
 #include <list>
 
@@ -71,7 +72,9 @@
 
     SliceGeometry ExtractSliceGeometry(double& sliceThickness,
                                        OrthancPlugins::IOrthancConnection& orthanc,
-                                       const Json::Value& contour);
+                                       const OrthancPlugins::IDicomDataset& tags,
+                                       size_t contourIndex,
+                                       size_t sliceIndex);
 
     const Structure& GetStructure(size_t index) const;
 
--- a/Framework/Toolbox/GeometryToolbox.cpp	Fri Dec 16 15:41:20 2016 +0100
+++ b/Framework/Toolbox/GeometryToolbox.cpp	Mon Dec 19 11:00:23 2016 +0100
@@ -32,6 +32,7 @@
 
 #include "GeometryToolbox.h"
 
+#include "../../Resources/Orthanc/Core/Logging.h"
 #include "../../Resources/Orthanc/Core/OrthancException.h"
 #include "../../Resources/Orthanc/Core/Toolbox.h"
 
@@ -77,6 +78,16 @@
     }
 
 
+    bool ParseVector(Vector& target,
+                     const OrthancPlugins::IDicomDataset& dataset,
+                     const OrthancPlugins::DicomPath& tag)
+    {
+      std::string value;
+      return (dataset.GetStringValue(value, tag) &&
+              ParseVector(target, value));
+    }
+
+
     void AssignVector(Vector& v,
                       double v1,
                       double v2)
@@ -347,5 +358,36 @@
         return true;
       }
     }
+
+
+    void GetPixelSpacing(double& spacingX, 
+                         double& spacingY,
+                         const OrthancPlugins::IDicomDataset& dicom)
+    {
+      Vector v;
+
+      if (ParseVector(v, dicom, OrthancPlugins::DICOM_TAG_PIXEL_SPACING))
+      {
+        if (v.size() != 2 ||
+            v[0] <= 0 ||
+            v[1] <= 0)
+        {
+          LOG(ERROR) << "Bad value for PixelSpacing tag";
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+        }
+        else
+        {
+          spacingX = v[0];
+          spacingY = v[1];
+        }
+      }
+      else
+      {
+        // The "PixelSpacing" is of type 1C: It could be absent, use
+        // default value in such a case
+        spacingX = 1;
+        spacingY = 1;
+      }
+    }
   }
 }
--- a/Framework/Toolbox/GeometryToolbox.h	Fri Dec 16 15:41:20 2016 +0100
+++ b/Framework/Toolbox/GeometryToolbox.h	Mon Dec 19 11:00:23 2016 +0100
@@ -34,6 +34,7 @@
 
 #include <boost/numeric/ublas/vector.hpp>
 
+#include "../../Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.h"
 
 namespace OrthancStone
 {
@@ -44,7 +45,11 @@
     void Print(const Vector& v);
 
     bool ParseVector(Vector& target,
-                     const std::string& value);
+                     const std::string& s);
+
+    bool ParseVector(Vector& target,
+                     const OrthancPlugins::IDicomDataset& dataset,
+                     const OrthancPlugins::DicomPath& tag);
 
     void AssignVector(Vector& v,
                       double v1,
@@ -107,5 +112,9 @@
                              const double& ymin,
                              const double& xmax,
                              const double& ymax);
+
+    void GetPixelSpacing(double& spacingX, 
+                         double& spacingY,
+                         const OrthancPlugins::IDicomDataset& dicom);
   };
 }
--- a/Framework/Toolbox/ISeriesLoader.h	Fri Dec 16 15:41:20 2016 +0100
+++ b/Framework/Toolbox/ISeriesLoader.h	Mon Dec 19 11:00:23 2016 +0100
@@ -36,6 +36,7 @@
 
 #include "IThreadSafety.h"
 #include "../../Resources/Orthanc/Core/Images/ImageAccessor.h"
+#include "../../Resources/Orthanc/Plugins/Samples/Common/IDicomDataset.h"
 
 namespace OrthancStone
 {
@@ -51,7 +52,7 @@
 
     virtual unsigned int GetHeight() = 0;
 
-    virtual DicomDataset* DownloadDicom(size_t index) = 0;
+    virtual OrthancPlugins::IDicomDataset* DownloadDicom(size_t index) = 0;
 
     // This downloads the frame from Orthanc. The resulting pixel
     // format must be Grayscale8, Grayscale16, SignedGrayscale16 or
--- a/Framework/Toolbox/OrthancSeriesLoader.cpp	Fri Dec 16 15:41:20 2016 +0100
+++ b/Framework/Toolbox/OrthancSeriesLoader.cpp	Mon Dec 19 11:00:23 2016 +0100
@@ -37,6 +37,7 @@
 #include "../../Resources/Orthanc/Core/Images/ImageProcessing.h"
 #include "../../Resources/Orthanc/Core/Logging.h"
 #include "../../Resources/Orthanc/Core/OrthancException.h"
+#include "../../Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.h"
 #include "DicomFrameConverter.h"
 
 namespace OrthancStone
@@ -361,28 +362,33 @@
       geometry_.AddSlice(slices_->GetSlice(i).GetGeometry());
     }
 
-    std::auto_ptr<DicomDataset> dataset(new DicomDataset(orthanc_, slices_->GetSlice(0).GetInstanceId()));
-    if (!dataset->HasTag(DICOM_TAG_ROWS) ||
-        !dataset->HasTag(DICOM_TAG_COLUMNS))
+    std::string uri = "/instances/" + slices_->GetSlice(0).GetInstanceId() + "/tags";
+
+    OrthancPlugins::FullOrthancDataset dataset(orthanc_, uri);
+    OrthancPlugins::DicomDatasetReader reader(dataset);
+
+    if (!reader.GetUnsignedIntegerValue(width_, OrthancPlugins::DICOM_TAG_COLUMNS) ||
+        !reader.GetUnsignedIntegerValue(height_, OrthancPlugins::DICOM_TAG_ROWS))
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentTag);
     }
 
     DicomFrameConverter converter;
-    converter.ReadParameters(*dataset);
-
+    converter.ReadParameters(dataset);
     format_ = converter.GetExpectedPixelFormat();
-    width_ = dataset->GetUnsignedIntegerValue(DICOM_TAG_COLUMNS);
-    height_ = dataset->GetUnsignedIntegerValue(DICOM_TAG_ROWS);
   }
     
 
-  DicomDataset* OrthancSeriesLoader::DownloadDicom(size_t index)
+  OrthancPlugins::IDicomDataset* OrthancSeriesLoader::DownloadDicom(size_t index)
   {
-    std::auto_ptr<DicomDataset> dataset(new DicomDataset(orthanc_, slices_->GetSlice(index).GetInstanceId()));
+    std::string uri = "/instances/" + slices_->GetSlice(index).GetInstanceId() + "/tags";
 
-    if (dataset->HasTag(DICOM_TAG_NUMBER_OF_FRAMES) &&
-        dataset->GetUnsignedIntegerValue(DICOM_TAG_NUMBER_OF_FRAMES) != 1)
+    std::auto_ptr<OrthancPlugins::IDicomDataset> dataset(new OrthancPlugins::FullOrthancDataset(orthanc_, uri));
+    OrthancPlugins::DicomDatasetReader reader(*dataset);
+
+    unsigned int frames;
+    if (reader.GetUnsignedIntegerValue(frames, OrthancPlugins::DICOM_TAG_NUMBER_OF_FRAMES) &&
+        frames != 1)
     {
       LOG(ERROR) << "One instance in this series has more than 1 frame";
       throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);          
--- a/Framework/Toolbox/OrthancSeriesLoader.h	Fri Dec 16 15:41:20 2016 +0100
+++ b/Framework/Toolbox/OrthancSeriesLoader.h	Mon Dec 19 11:00:23 2016 +0100
@@ -33,6 +33,7 @@
 #pragma once
 
 #include "ISeriesLoader.h"
+#include "../../Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.h"
 
 #include <boost/shared_ptr.hpp>
 
@@ -81,7 +82,7 @@
       return height_;
     }
 
-    virtual DicomDataset* DownloadDicom(size_t index);
+    virtual OrthancPlugins::IDicomDataset* DownloadDicom(size_t index);
 
     virtual Orthanc::ImageAccessor* DownloadFrame(size_t index);
 
--- a/Framework/Toolbox/SliceGeometry.cpp	Fri Dec 16 15:41:20 2016 +0100
+++ b/Framework/Toolbox/SliceGeometry.cpp	Mon Dec 19 11:00:23 2016 +0100
@@ -119,13 +119,14 @@
   }   
 
 
-  SliceGeometry::SliceGeometry(const DicomDataset& dicom)
+  SliceGeometry::SliceGeometry(const OrthancPlugins::IDicomDataset& dicom)
   {
-    if (dicom.HasTag(DICOM_TAG_IMAGE_POSITION_PATIENT) &&
-        dicom.HasTag(DICOM_TAG_IMAGE_ORIENTATION_PATIENT))
+    std::string a, b;
+
+    if (dicom.GetStringValue(a, OrthancPlugins::DICOM_TAG_IMAGE_POSITION_PATIENT) &&
+        dicom.GetStringValue(b, OrthancPlugins::DICOM_TAG_IMAGE_ORIENTATION_PATIENT))
     {
-      Setup(dicom.GetStringValue(DICOM_TAG_IMAGE_POSITION_PATIENT),
-            dicom.GetStringValue(DICOM_TAG_IMAGE_ORIENTATION_PATIENT));
+      Setup(a, b);
     }
     else
     {
--- a/Framework/Toolbox/SliceGeometry.h	Fri Dec 16 15:41:20 2016 +0100
+++ b/Framework/Toolbox/SliceGeometry.h	Mon Dec 19 11:00:23 2016 +0100
@@ -32,7 +32,8 @@
 
 #pragma once
 
-#include "DicomDataset.h"
+#include "GeometryToolbox.h"
+#include "../../Resources/Orthanc/Plugins/Samples/Common/IDicomDataset.h"
 
 namespace OrthancStone
 {
@@ -62,7 +63,7 @@
                   const Vector& axisX,
                   const Vector& axisY);
 
-    SliceGeometry(const DicomDataset& dicom);
+    SliceGeometry(const OrthancPlugins::IDicomDataset& dicom);
 
     SliceGeometry(const std::string& imagePositionPatient,
                   const std::string& imageOrientationPatient)
--- a/Framework/Volumes/VolumeImage.cpp	Fri Dec 16 15:41:20 2016 +0100
+++ b/Framework/Volumes/VolumeImage.cpp	Mon Dec 19 11:00:23 2016 +0100
@@ -140,7 +140,7 @@
     buffer_->SetAxialGeometry(loader_->GetGeometry().GetSlice(0));
 
     double spacingX, spacingY;
-    referenceDataset_->GetPixelSpacing(spacingX, spacingY);
+    GeometryToolbox::GetPixelSpacing(spacingX, spacingY, *referenceDataset_);
     buffer_->SetVoxelDimensions(spacingX, spacingY, spacingZ);
 
     // These 3 values are only used to speed up the LayerFactory
--- a/Framework/Volumes/VolumeImage.h	Fri Dec 16 15:41:20 2016 +0100
+++ b/Framework/Volumes/VolumeImage.h	Mon Dec 19 11:00:23 2016 +0100
@@ -64,16 +64,16 @@
 
 
   private:
-    std::auto_ptr<ISeriesLoader>         loader_;
-    std::auto_ptr<ImageBuffer3D>         buffer_;
-    std::vector<boost::thread*>          threads_;
-    bool                                 started_;
-    bool                                 continue_;
-    ObserversRegistry<ISliceableVolume>  observers_;
-    bool                                 loadingComplete_;
-    MessagingToolbox::Timestamp          lastUpdate_;
-    std::auto_ptr<DicomDataset>          referenceDataset_;
-    std::auto_ptr<IDownloadPolicy>       policy_;
+    std::auto_ptr<ISeriesLoader>                  loader_;
+    std::auto_ptr<ImageBuffer3D>                  buffer_;
+    std::vector<boost::thread*>                   threads_;
+    bool                                          started_;
+    bool                                          continue_;
+    ObserversRegistry<ISliceableVolume>           observers_;
+    bool                                          loadingComplete_;
+    MessagingToolbox::Timestamp                   lastUpdate_;
+    std::auto_ptr<OrthancPlugins::IDicomDataset>  referenceDataset_;
+    std::auto_ptr<IDownloadPolicy>                policy_;
     
     std::auto_ptr<ParallelSlices>        axialGeometry_;
     std::auto_ptr<ParallelSlices>        coronalGeometry_;
--- a/Resources/CMake/OrthancStone.cmake	Fri Dec 16 15:41:20 2016 +0100
+++ b/Resources/CMake/OrthancStone.cmake	Mon Dec 19 11:00:23 2016 +0100
@@ -173,7 +173,6 @@
   ${ORTHANC_STONE_DIR}/Framework/Layers/SingleFrameRendererFactory.cpp
   ${ORTHANC_STONE_DIR}/Framework/Messaging/MessagingToolbox.cpp
   ${ORTHANC_STONE_DIR}/Framework/Toolbox/BinarySemaphore.cpp
-  ${ORTHANC_STONE_DIR}/Framework/Toolbox/DicomDataset.cpp
   ${ORTHANC_STONE_DIR}/Framework/Toolbox/DicomFrameConverter.cpp
   ${ORTHANC_STONE_DIR}/Framework/Toolbox/DicomStructureSet.cpp
   ${ORTHANC_STONE_DIR}/Framework/Toolbox/DownloadStack.cpp
--- a/Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.cpp	Fri Dec 16 15:41:20 2016 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.cpp	Mon Dec 19 11:00:23 2016 +0100
@@ -68,20 +68,31 @@
   }
 
 
-  DicomDatasetReader::DicomDatasetReader(IDicomDataset* dataset) :  // takes ownership
+  DicomDatasetReader::DicomDatasetReader(const IDicomDataset& dataset) :
     dataset_(dataset)
   {
-    if (dataset == NULL)
+  }
+  
+
+  std::string DicomDatasetReader::GetStringValue(const DicomPath& path,
+                                                 const std::string& defaultValue) const
+  {
+    std::string s;
+    if (dataset_.GetStringValue(s, path))
     {
-      ORTHANC_PLUGINS_THROW_EXCEPTION(ParameterOutOfRange);
+      return s;
+    }
+    else
+    {
+      return defaultValue;
     }
   }
-  
+
 
   std::string DicomDatasetReader::GetMandatoryStringValue(const DicomPath& path) const
   {
     std::string s;
-    if (dataset_->GetStringValue(s, path))
+    if (dataset_.GetStringValue(s, path))
     {
       return s;
     }
@@ -92,12 +103,24 @@
   }
 
 
-  int DicomDatasetReader::GetIntegerValue(const DicomPath& path)
+  template <typename T>
+  static bool GetValueInternal(T& target,
+                               const IDicomDataset& dataset,
+                               const DicomPath& path)
   {
     try
     {
-      std::string s = StripSpaces(GetMandatoryStringValue(path));
-      return boost::lexical_cast<int>(s);
+      std::string s;
+
+      if (dataset.GetStringValue(s, path))
+      {
+        target = boost::lexical_cast<T>(StripSpaces(s));
+        return true;
+      }
+      else
+      {
+        return false;
+      }
     }
     catch (boost::bad_lexical_cast&)
     {
@@ -106,17 +129,44 @@
   }
 
 
-  unsigned int DicomDatasetReader::GetUnsignedIntegerValue(const DicomPath& path)
+  bool DicomDatasetReader::GetIntegerValue(int& target,
+                                           const DicomPath& path) const
   {
-    int value = GetIntegerValue(path);
+    return GetValueInternal<int>(target, dataset_, path);
+  }
+
 
-    if (value >= 0)
+  bool DicomDatasetReader::GetUnsignedIntegerValue(unsigned int& target,
+                                                   const DicomPath& path) const
+  {
+    int value;
+
+    if (!GetIntegerValue(value, path))
     {
-      return static_cast<unsigned int>(value);
+      return false;
+    }
+    else if (value >= 0)
+    {
+      target = static_cast<unsigned int>(value);
+      return true;
     }
     else
     {
       ORTHANC_PLUGINS_THROW_EXCEPTION(ParameterOutOfRange);
     }
   }
+
+
+  bool DicomDatasetReader::GetFloatValue(float& target,
+                                         const DicomPath& path) const
+  {
+    return GetValueInternal<float>(target, dataset_, path);
+  }
+
+
+  bool DicomDatasetReader::GetDoubleValue(double& target,
+                                          const DicomPath& path) const
+  {
+    return GetValueInternal<double>(target, dataset_, path);
+  }
 }
--- a/Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.h	Fri Dec 16 15:41:20 2016 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.h	Mon Dec 19 11:00:23 2016 +0100
@@ -35,26 +35,38 @@
 #include "IDicomDataset.h"
 
 #include <memory>
+#include <vector>
 
 namespace OrthancPlugins
 {
   class DicomDatasetReader : public boost::noncopyable
   {
   private:
-    std::auto_ptr<IDicomDataset>  dataset_;
+    const IDicomDataset&  dataset_;
 
   public:
-    DicomDatasetReader(IDicomDataset* dataset);  // takes ownership
+    DicomDatasetReader(const IDicomDataset& dataset);
 
-    IDicomDataset& GetDataset() const
+    const IDicomDataset& GetDataset() const
     {
-      return *dataset_;
+      return dataset_;
     }
 
+    std::string GetStringValue(const DicomPath& path,
+                               const std::string& defaultValue) const;
+
     std::string GetMandatoryStringValue(const DicomPath& path) const;
 
-    int GetIntegerValue(const DicomPath& path);
+    bool GetIntegerValue(int& target,
+                         const DicomPath& path) const;
+
+    bool GetUnsignedIntegerValue(unsigned int& target,
+                                 const DicomPath& path) const;
 
-    unsigned int GetUnsignedIntegerValue(const DicomPath& path);
+    bool GetFloatValue(float& target,
+                       const DicomPath& path) const;
+
+    bool GetDoubleValue(double& target,
+                        const DicomPath& path) const;
   };
 }
--- a/Resources/Orthanc/Plugins/Samples/Common/DicomPath.cpp	Fri Dec 16 15:41:20 2016 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/DicomPath.cpp	Mon Dec 19 11:00:23 2016 +0100
@@ -49,20 +49,20 @@
   }
 
 
-  DicomPath::DicomPath(const DicomTag& sequence,
+  DicomPath::DicomPath(DicomTag sequence,
                        size_t index,
-                       const DicomTag& tag) :
+                       DicomTag tag) :
     finalTag_(tag)
   {
     AddToPrefix(sequence, index);
   }
 
 
-  DicomPath::DicomPath(const DicomTag& sequence1,
+  DicomPath::DicomPath(DicomTag sequence1,
                        size_t index1,
-                       const DicomTag& sequence2,
+                       DicomTag sequence2,
                        size_t index2,
-                       const DicomTag& tag) :
+                       DicomTag tag) :
     finalTag_(tag)
   {
     AddToPrefix(sequence1, index1);
@@ -70,13 +70,13 @@
   }
 
 
-  DicomPath::DicomPath(const DicomTag& sequence1,
+  DicomPath::DicomPath(DicomTag sequence1,
                        size_t index1,
-                       const DicomTag& sequence2,
+                       DicomTag sequence2,
                        size_t index2,
-                       const DicomTag& sequence3,
+                       DicomTag sequence3,
                        size_t index3,
-                       const DicomTag& tag) :
+                       DicomTag tag) :
     finalTag_(tag)
   {
     AddToPrefix(sequence1, index1);
--- a/Resources/Orthanc/Plugins/Samples/Common/DicomPath.h	Fri Dec 16 15:41:20 2016 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/DicomPath.h	Mon Dec 19 11:00:23 2016 +0100
@@ -50,30 +50,30 @@
     const Prefix& GetPrefixItem(size_t depth) const;
 
   public:
-    DicomPath(const DicomTag& finalTag) :
+    DicomPath(DicomTag finalTag) :
     finalTag_(finalTag)
     {
     }
 
-    DicomPath(const DicomTag& sequence,
+    DicomPath(DicomTag sequence,
               size_t index,
-              const DicomTag& tag);
+              DicomTag tag);
 
-    DicomPath(const DicomTag& sequence1,
+    DicomPath(DicomTag sequence1,
               size_t index1,
-              const DicomTag& sequence2,
+              DicomTag sequence2,
               size_t index2,
-              const DicomTag& tag);
+              DicomTag tag);
 
-    DicomPath(const DicomTag& sequence1,
+    DicomPath(DicomTag sequence1,
               size_t index1,
-              const DicomTag& sequence2,
+              DicomTag sequence2,
               size_t index2,
-              const DicomTag& sequence3,
+              DicomTag sequence3,
               size_t index3,
-              const DicomTag& tag);
+              DicomTag tag);
 
-    void AddToPrefix(const DicomTag& tag,
+    void AddToPrefix(DicomTag tag,
                      size_t position)
     {
       prefix_.push_back(std::make_pair(tag, position));
--- a/Resources/Orthanc/Plugins/Samples/Common/DicomTag.h	Fri Dec 16 15:41:20 2016 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/DicomTag.h	Mon Dec 19 11:00:23 2016 +0100
@@ -77,19 +77,27 @@
 
 
   static const DicomTag DICOM_TAG_BITS_STORED(0x0028, 0x0101);
+  static const DicomTag DICOM_TAG_COLUMNS(0x0028, 0x0011);
   static const DicomTag DICOM_TAG_COLUMN_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX(0x0048, 0x021e);
-  static const DicomTag DICOM_TAG_COLUMNS(0x0028, 0x0011);
+  static const DicomTag DICOM_TAG_IMAGE_ORIENTATION_PATIENT(0x0020, 0x0037);
+  static const DicomTag DICOM_TAG_IMAGE_POSITION_PATIENT(0x0020, 0x0032);
   static const DicomTag DICOM_TAG_MODALITY(0x0008, 0x0060);
   static const DicomTag DICOM_TAG_NUMBER_OF_FRAMES(0x0028, 0x0008);
   static const DicomTag DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE(0x5200, 0x9230);
   static const DicomTag DICOM_TAG_PHOTOMETRIC_INTERPRETATION(0x0028, 0x0004);
   static const DicomTag DICOM_TAG_PIXEL_REPRESENTATION(0x0028, 0x0103);
+  static const DicomTag DICOM_TAG_PIXEL_SPACING(0x0028, 0x0030);
   static const DicomTag DICOM_TAG_PLANE_POSITION_SLIDE_SEQUENCE(0x0048, 0x021a);
-  static const DicomTag DICOM_TAG_ROW_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX(0x0048, 0x021f);
+  static const DicomTag DICOM_TAG_RESCALE_INTERCEPT(0x0028, 0x1052);
+  static const DicomTag DICOM_TAG_RESCALE_SLOPE(0x0028, 0x1053);
   static const DicomTag DICOM_TAG_ROWS(0x0028, 0x0010);
+  static const DicomTag DICOM_TAG_ROW_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX(0x0048, 0x021f);
+  static const DicomTag DICOM_TAG_SAMPLES_PER_PIXEL(0x0028, 0x0002);
+  static const DicomTag DICOM_TAG_SLICE_THICKNESS(0x0018, 0x0050);
   static const DicomTag DICOM_TAG_SOP_CLASS_UID(0x0008, 0x0016);
-  static const DicomTag DICOM_TAG_SAMPLES_PER_PIXEL(0x0028, 0x0002);
   static const DicomTag DICOM_TAG_TOTAL_PIXEL_MATRIX_COLUMNS(0x0048, 0x0006);
   static const DicomTag DICOM_TAG_TOTAL_PIXEL_MATRIX_ROWS(0x0048, 0x0007);
   static const DicomTag DICOM_TAG_TRANSFER_SYNTAX_UID(0x0002, 0x0010);
+  static const DicomTag DICOM_TAG_WINDOW_CENTER(0x0028, 0x1050);
+  static const DicomTag DICOM_TAG_WINDOW_WIDTH(0x0028, 0x1051);
 }
--- a/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginException.h	Fri Dec 16 15:41:20 2016 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginException.h	Mon Dec 19 11:00:23 2016 +0100
@@ -39,23 +39,23 @@
 
 #if HAS_ORTHANC_EXCEPTION == 1
 #  include "../../../Core/OrthancException.h"
-#  define ORTHANC_PLUGINS_GET_ERROR_ENUMERATION  ::Orthanc::ErrorCode
-#  define ORTHANC_PLUGINS_GET_ERROR_CODE(code)   ::Orthanc::ErrorCode_ ## code
-#  define ORTHANC_PLUGINS_GET_EXCEPTION_CLASS    ::Orthanc::OrthancException
+#  define ORTHANC_PLUGINS_ERROR_ENUMERATION     ::Orthanc::ErrorCode
+#  define ORTHANC_PLUGINS_EXCEPTION_CLASS       ::Orthanc::OrthancException
+#  define ORTHANC_PLUGINS_GET_ERROR_CODE(code)  ::Orthanc::ErrorCode_ ## code
 #else
 #  include <orthanc/OrthancCPlugin.h>
-#  define ORTHANC_PLUGINS_GET_ERROR_ENUMERATION  ::OrthancPluginErrorCode
-#  define ORTHANC_PLUGINS_GET_ERROR_CODE(code)   ::OrthancPluginErrorCode_ ## code
-#  define ORTHANC_PLUGINS_GET_EXCEPTION_CLASS    ::OrthancPlugins::PluginException
+#  define ORTHANC_PLUGINS_ERROR_ENUMERATION     ::OrthancPluginErrorCode
+#  define ORTHANC_PLUGINS_EXCEPTION_CLASS       ::OrthancPlugins::PluginException
+#  define ORTHANC_PLUGINS_GET_ERROR_CODE(code)  ::OrthancPluginErrorCode_ ## code
 #endif
 
 
 #define ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code)                   \
-  throw ORTHANC_PLUGINS_GET_EXCEPTION_CLASS(static_cast<ORTHANC_PLUGINS_GET_ERROR_ENUMERATION>(code));
+  throw ORTHANC_PLUGINS_EXCEPTION_CLASS(static_cast<ORTHANC_PLUGINS_ERROR_ENUMERATION>(code));
 
 
 #define ORTHANC_PLUGINS_THROW_EXCEPTION(code)                           \
-  throw ORTHANC_PLUGINS_GET_EXCEPTION_CLASS(ORTHANC_PLUGINS_GET_ERROR_CODE(code));
+  throw ORTHANC_PLUGINS_EXCEPTION_CLASS(ORTHANC_PLUGINS_GET_ERROR_CODE(code));
                                                   
 
 #define ORTHANC_PLUGINS_CHECK_ERROR(code)                           \