changeset 186:ab66a6baf2ae

sync
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 22 Mar 2018 16:59:06 +0100
parents 3e45f3752074
children 4b9da483ae4d
files Orthanc/Core/Enumerations.cpp Orthanc/Core/Enumerations.h Orthanc/Core/Images/ImageAccessor.h Orthanc/Core/Images/ImageProcessing.cpp Orthanc/Core/Images/ImageProcessing.h Orthanc/Core/Images/PixelTraits.h Orthanc/Core/Logging.h Orthanc/Core/SystemToolbox.cpp Orthanc/Core/SystemToolbox.h Orthanc/NEWS Orthanc/Plugins/Samples/GdcmDecoder/GdcmImageDecoder.cpp Orthanc/Resources/CMake/BoostConfiguration.cmake Orthanc/Resources/CMake/Compiler.cmake Orthanc/Resources/CMake/JsonCppConfiguration.cmake Resources/SyncOrthancFolder.py
diffstat 15 files changed, 1800 insertions(+), 96 deletions(-) [+]
line wrap: on
line diff
--- a/Orthanc/Core/Enumerations.cpp	Tue Mar 13 10:24:38 2018 +0100
+++ b/Orthanc/Core/Enumerations.cpp	Thu Mar 22 16:59:06 2018 +0100
@@ -161,6 +161,9 @@
       case ErrorCode_NullPointer:
         return "Cannot handle a NULL pointer";
 
+      case ErrorCode_DatabaseUnavailable:
+        return "The database is currently not available (probably a transient situation)";
+
       case ErrorCode_SQLiteNotOpened:
         return "SQLite: The database is not opened";
 
@@ -1617,6 +1620,9 @@
       case ErrorCode_NotAcceptable:
         return HttpStatus_406_NotAcceptable;
 
+      case ErrorCode_DatabaseUnavailable:
+        return HttpStatus_503_ServiceUnavailable;
+
       default:
         return HttpStatus_500_InternalServerError;
     }
--- a/Orthanc/Core/Enumerations.h	Tue Mar 13 10:24:38 2018 +0100
+++ b/Orthanc/Core/Enumerations.h	Thu Mar 22 16:59:06 2018 +0100
@@ -35,6 +35,16 @@
 
 #include <string>
 
+
+#if defined(_MSC_VER)
+#  define ORTHANC_FORCE_INLINE __forceinline
+#elif defined(__GNUC__) || defined(__clang__) || defined(__EMSCRIPTEN__)
+#  define ORTHANC_FORCE_INLINE inline __attribute((always_inline))
+#else
+#  error Please support your compiler here
+#endif
+
+
 namespace Orthanc
 {
   enum Endianness
@@ -85,6 +95,7 @@
     ErrorCode_EmptyRequest = 33    /*!< The request is empty */,
     ErrorCode_NotAcceptable = 34    /*!< Cannot send a response which is acceptable according to the Accept HTTP header */,
     ErrorCode_NullPointer = 35    /*!< Cannot handle a NULL pointer */,
+    ErrorCode_DatabaseUnavailable = 36    /*!< The database is currently not available (probably a transient situation) */,
     ErrorCode_SQLiteNotOpened = 1000    /*!< SQLite: The database is not opened */,
     ErrorCode_SQLiteAlreadyOpened = 1001    /*!< SQLite: Connection is already open */,
     ErrorCode_SQLiteCannotOpen = 1002    /*!< SQLite: Unable to open the database */,
--- a/Orthanc/Core/Images/ImageAccessor.h	Tue Mar 13 10:24:38 2018 +0100
+++ b/Orthanc/Core/Images/ImageAccessor.h	Thu Mar 22 16:59:06 2018 +0100
@@ -43,6 +43,9 @@
   class ImageAccessor
   {
   private:
+    template <Orthanc::PixelFormat Format>
+    friend struct ImageTraits;
+    
     bool readOnly_;
     PixelFormat format_;
     unsigned int width_;
@@ -50,6 +53,23 @@
     unsigned int pitch_;
     uint8_t *buffer_;
 
+    template <typename T>
+    const T& GetPixelUnchecked(unsigned int x,
+                               unsigned int y) const
+    {
+      const uint8_t* row = reinterpret_cast<const uint8_t*>(buffer_) + y * pitch_;
+      return reinterpret_cast<const T*>(row) [x];
+    }
+
+
+    template <typename T>
+    T& GetPixelUnchecked(unsigned int x,
+                         unsigned int y)
+    {
+      uint8_t* row = reinterpret_cast<uint8_t*>(buffer_) + y * pitch_;
+      return reinterpret_cast<T*>(row) [x];
+    }
+
   public:
     ImageAccessor()
     {
--- a/Orthanc/Core/Images/ImageProcessing.cpp	Tue Mar 13 10:24:38 2018 +0100
+++ b/Orthanc/Core/Images/ImageProcessing.cpp	Thu Mar 22 16:59:06 2018 +0100
@@ -34,7 +34,7 @@
 #include "../PrecompiledHeaders.h"
 #include "ImageProcessing.h"
 
-#include "../OrthancException.h"
+#include "PixelTraits.h"
 
 #include <boost/math/special_functions/round.hpp>
 
@@ -114,7 +114,7 @@
         // Y = 0.2126 R + 0.7152 G + 0.0722 B
         int32_t v = (2126 * static_cast<int32_t>(s[0]) +
                      7152 * static_cast<int32_t>(s[1]) +
-                     0722 * static_cast<int32_t>(s[2])) / 1000;
+                     0722 * static_cast<int32_t>(s[2])) / 10000;
         
         if (static_cast<int32_t>(v) < static_cast<int32_t>(minValue))
         {
@@ -166,11 +166,13 @@
     minValue = std::numeric_limits<PixelType>::max();
     maxValue = std::numeric_limits<PixelType>::min();
 
+    const unsigned int width = source.GetWidth();
+
     for (unsigned int y = 0; y < source.GetHeight(); y++)
     {
       const PixelType* p = reinterpret_cast<const PixelType*>(source.GetConstRow(y));
 
-      for (unsigned int x = 0; x < source.GetWidth(); x++, p++)
+      for (unsigned int x = 0; x < width; x++, p++)
       {
         if (*p < minValue)
         {
@@ -225,9 +227,10 @@
 
 
 
-  template <typename PixelType>
-  void MultiplyConstantInternal(ImageAccessor& image,
-                                float factor)
+  template <typename PixelType,
+            bool UseRound>
+  static void MultiplyConstantInternal(ImageAccessor& image,
+                                       float factor)
   {
     if (std::abs(factor - 1.0f) <= std::numeric_limits<float>::epsilon())
     {
@@ -236,14 +239,24 @@
 
     const int64_t minValue = std::numeric_limits<PixelType>::min();
     const int64_t maxValue = std::numeric_limits<PixelType>::max();
+    const unsigned int width = image.GetWidth();
 
     for (unsigned int y = 0; y < image.GetHeight(); y++)
     {
       PixelType* p = reinterpret_cast<PixelType*>(image.GetRow(y));
 
-      for (unsigned int x = 0; x < image.GetWidth(); x++, p++)
+      for (unsigned int x = 0; x < width; x++, p++)
       {
-        int64_t v = boost::math::llround(static_cast<float>(*p) * factor);
+        int64_t v;
+        if (UseRound)
+        {
+          // The "round" operation is very costly
+          v = boost::math::llround(static_cast<float>(*p) * factor);
+        }
+        else
+        {
+          v = static_cast<int64_t>(static_cast<float>(*p) * factor);
+        }
 
         if (v > maxValue)
         {
@@ -262,33 +275,44 @@
   }
 
 
-  template <typename PixelType>
-  void ShiftScaleInternal(ImageAccessor& image,
-                          float offset,
-                          float scaling)
+  template <typename PixelType,
+            bool UseRound>
+  static void ShiftScaleInternal(ImageAccessor& image,
+                                 float offset,
+                                 float scaling)
   {
-    const float minValue = static_cast<float>(std::numeric_limits<PixelType>::min());
-    const float maxValue = static_cast<float>(std::numeric_limits<PixelType>::max());
+    const float minFloatValue = static_cast<float>(std::numeric_limits<PixelType>::min());
+    const float maxFloatValue = static_cast<float>(std::numeric_limits<PixelType>::max());
+    const PixelType minPixelValue = std::numeric_limits<PixelType>::min();
+    const PixelType maxPixelValue = std::numeric_limits<PixelType>::max();
 
-    for (unsigned int y = 0; y < image.GetHeight(); y++)
+    const unsigned int height = image.GetHeight();
+    const unsigned int width = image.GetWidth();
+    
+    for (unsigned int y = 0; y < height; y++)
     {
       PixelType* p = reinterpret_cast<PixelType*>(image.GetRow(y));
 
-      for (unsigned int x = 0; x < image.GetWidth(); x++, p++)
+      for (unsigned int x = 0; x < width; x++, p++)
       {
         float v = (static_cast<float>(*p) + offset) * scaling;
 
-        if (v > maxValue)
+        if (v > maxFloatValue)
         {
-          *p = std::numeric_limits<PixelType>::max();
+          *p = maxPixelValue;
         }
-        else if (v < minValue)
+        else if (v < minFloatValue)
         {
-          *p = std::numeric_limits<PixelType>::min();
+          *p = minPixelValue;
+        }
+        else if (UseRound)
+        {
+          // The "round" operation is very costly
+          *p = static_cast<PixelType>(boost::math::iround(v));
         }
         else
         {
-          *p = static_cast<PixelType>(boost::math::iround(v));
+          *p = static_cast<PixelType>(v);
         }
       }
     }
@@ -548,6 +572,63 @@
     }
 
     if (target.GetFormat() == PixelFormat_BGRA32 &&
+        source.GetFormat() == PixelFormat_Grayscale16)
+    {
+      for (unsigned int y = 0; y < source.GetHeight(); y++)
+      {
+        const uint16_t* p = reinterpret_cast<const uint16_t*>(source.GetConstRow(y));
+        uint8_t* q = reinterpret_cast<uint8_t*>(target.GetRow(y));
+        for (unsigned int x = 0; x < source.GetWidth(); x++)
+        {
+          uint8_t value = (*p < 256 ? *p : 255);
+          q[0] = value;
+          q[1] = value;
+          q[2] = value;
+          q[3] = 255;
+          p += 1;
+          q += 4;
+        }
+      }
+
+      return;
+    }
+
+    if (target.GetFormat() == PixelFormat_BGRA32 &&
+        source.GetFormat() == PixelFormat_SignedGrayscale16)
+    {
+      for (unsigned int y = 0; y < source.GetHeight(); y++)
+      {
+        const int16_t* p = reinterpret_cast<const int16_t*>(source.GetConstRow(y));
+        uint8_t* q = reinterpret_cast<uint8_t*>(target.GetRow(y));
+        for (unsigned int x = 0; x < source.GetWidth(); x++)
+        {
+          uint8_t value;
+          if (*p < 0)
+          {
+            value = 0;
+          }
+          else if (*p > 255)
+          {
+            value = 255;
+          }
+          else
+          {
+            value = static_cast<uint8_t>(*p);
+          }
+
+          q[0] = value;
+          q[1] = value;
+          q[2] = value;
+          q[3] = 255;
+          p += 1;
+          q += 4;
+        }
+      }
+
+      return;
+    }
+
+    if (target.GetFormat() == PixelFormat_BGRA32 &&
         source.GetFormat() == PixelFormat_RGB24)
     {
       for (unsigned int y = 0; y < source.GetHeight(); y++)
@@ -599,19 +680,40 @@
     switch (image.GetFormat())
     {
       case PixelFormat_Grayscale8:
-        SetInternal<uint8_t>(image, value);
+        memset(image.GetBuffer(), static_cast<uint8_t>(value), image.GetPitch() * image.GetHeight());
         return;
 
       case PixelFormat_Grayscale16:
-        SetInternal<uint16_t>(image, value);
+        if (value == 0)
+        {
+          memset(image.GetBuffer(), 0, image.GetPitch() * image.GetHeight());
+        }
+        else
+        {
+          SetInternal<uint16_t>(image, value);
+        }
         return;
 
       case PixelFormat_Grayscale32:
-        SetInternal<uint32_t>(image, value);
+        if (value == 0)
+        {
+          memset(image.GetBuffer(), 0, image.GetPitch() * image.GetHeight());
+        }
+        else
+        {
+          SetInternal<uint32_t>(image, value);
+        }
         return;
 
       case PixelFormat_SignedGrayscale16:
-        SetInternal<int16_t>(image, value);
+        if (value == 0)
+        {
+          memset(image.GetBuffer(), 0, image.GetPitch() * image.GetHeight());
+        }
+        else
+        {
+          SetInternal<int16_t>(image, value);
+        }
         return;
 
       case PixelFormat_Float32:
@@ -790,20 +892,42 @@
 
 
   void ImageProcessing::MultiplyConstant(ImageAccessor& image,
-                                         float factor)
+                                         float factor,
+                                         bool useRound)
   {
     switch (image.GetFormat())
     {
       case PixelFormat_Grayscale8:
-        MultiplyConstantInternal<uint8_t>(image, factor);
+        if (useRound)
+        {
+          MultiplyConstantInternal<uint8_t, true>(image, factor);
+        }
+        else
+        {
+          MultiplyConstantInternal<uint8_t, false>(image, factor);
+        }
         return;
 
       case PixelFormat_Grayscale16:
-        MultiplyConstantInternal<uint16_t>(image, factor);
+        if (useRound)
+        {
+          MultiplyConstantInternal<uint16_t, true>(image, factor);
+        }
+        else
+        {
+          MultiplyConstantInternal<uint16_t, false>(image, factor);
+        }
         return;
 
       case PixelFormat_SignedGrayscale16:
-        MultiplyConstantInternal<int16_t>(image, factor);
+        if (useRound)
+        {
+          MultiplyConstantInternal<int16_t, true>(image, factor);
+        }
+        else
+        {
+          MultiplyConstantInternal<int16_t, false>(image, factor);
+        }
         return;
 
       default:
@@ -814,20 +938,42 @@
 
   void ImageProcessing::ShiftScale(ImageAccessor& image,
                                    float offset,
-                                   float scaling)
+                                   float scaling,
+                                   bool useRound)
   {
     switch (image.GetFormat())
     {
       case PixelFormat_Grayscale8:
-        ShiftScaleInternal<uint8_t>(image, offset, scaling);
+        if (useRound)
+        {
+          ShiftScaleInternal<uint8_t, true>(image, offset, scaling);
+        }
+        else
+        {
+          ShiftScaleInternal<uint8_t, false>(image, offset, scaling);
+        }
         return;
 
       case PixelFormat_Grayscale16:
-        ShiftScaleInternal<uint16_t>(image, offset, scaling);
+        if (useRound)
+        {
+          ShiftScaleInternal<uint16_t, true>(image, offset, scaling);
+        }
+        else
+        {
+          ShiftScaleInternal<uint16_t, false>(image, offset, scaling);
+        }
         return;
 
       case PixelFormat_SignedGrayscale16:
-        ShiftScaleInternal<int16_t>(image, offset, scaling);
+        if (useRound)
+        {
+          ShiftScaleInternal<int16_t, true>(image, offset, scaling);
+        }
+        else
+        {
+          ShiftScaleInternal<int16_t, false>(image, offset, scaling);
+        }
         return;
 
       default:
@@ -859,4 +1005,222 @@
         throw OrthancException(ErrorCode_NotImplemented);
     }   
   }
+
+
+
+  namespace
+  {
+    template <Orthanc::PixelFormat Format>
+    class BresenhamPixelWriter
+    {
+    private:
+      typedef typename PixelTraits<Format>::PixelType  PixelType;
+    
+      Orthanc::ImageAccessor&  image_;
+      PixelType                value_;
+
+      void PlotLineLow(int x0,
+                       int y0,
+                       int x1,
+                       int y1)
+      {
+        int dx = x1 - x0;
+        int dy = y1 - y0;
+        int yi = 1;
+
+        if (dy < 0)
+        {
+          yi = -1;
+          dy = -dy;
+        }
+
+        int d = 2 * dy - dx;
+        int y = y0;
+
+        for (int x = x0; x <= x1; x++)
+        {
+          Write(x, y);
+          
+          if (d > 0)
+          {
+            y = y + yi;
+            d = d - 2 * dx;
+          }
+      
+          d = d + 2*dy;
+        }
+      }
+      
+      void PlotLineHigh(int x0,
+                        int y0,
+                        int x1,
+                        int y1)
+      {
+        int dx = x1 - x0;
+        int dy = y1 - y0;
+        int xi = 1;
+    
+        if (dx < 0)
+        {
+          xi = -1;
+          dx = -dx;
+        }
+    
+        int d = 2 * dx - dy;
+        int x = x0;
+
+        for (int y = y0; y <= y1; y++)
+        {
+          Write(x, y);
+          
+          if (d > 0)
+          {
+            x = x + xi;
+            d = d - 2 * dy;
+          }
+      
+          d = d + 2 * dx;
+        }
+      }
+
+    public:
+      BresenhamPixelWriter(Orthanc::ImageAccessor& image,
+                           int64_t value) :
+        image_(image),
+        value_(PixelTraits<Format>::IntegerToPixel(value))
+      {
+      }
+
+      BresenhamPixelWriter(Orthanc::ImageAccessor& image,
+                           const PixelType& value) :
+        image_(image),
+        value_(value)
+      {
+      }
+
+      void Write(int x,
+                 int y)
+      {
+        if (x >= 0 &&
+            y >= 0 &&
+            static_cast<unsigned int>(x) < image_.GetWidth() &&
+            static_cast<unsigned int>(y) < image_.GetHeight())
+        {
+          PixelType* p = reinterpret_cast<PixelType*>(image_.GetRow(y));
+          p[x] = value_;
+        }
+      }
+
+      void DrawSegment(int x0,
+                       int y0,
+                       int x1,
+                       int y1)
+      {
+        // This is an implementation of Bresenham's line algorithm
+        // https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm#All_cases
+    
+        if (abs(y1 - y0) < abs(x1 - x0))
+        {
+          if (x0 > x1)
+          {
+            PlotLineLow(x1, y1, x0, y0);
+          }
+          else
+          {
+            PlotLineLow(x0, y0, x1, y1);
+          }
+        }
+        else
+        {
+          if (y0 > y1)
+          {
+            PlotLineHigh(x1, y1, x0, y0);
+          }
+          else
+          {
+            PlotLineHigh(x0, y0, x1, y1);
+          }
+        }
+      }
+    };
+  }
+
+  
+  void ImageProcessing::DrawLineSegment(ImageAccessor& image,
+                                        int x0,
+                                        int y0,
+                                        int x1,
+                                        int y1,
+                                        int64_t value)
+  {
+    switch (image.GetFormat())
+    {       
+      case Orthanc::PixelFormat_Grayscale8:
+      {
+        BresenhamPixelWriter<Orthanc::PixelFormat_Grayscale8> writer(image, value);
+        writer.DrawSegment(x0, y0, x1, y1);
+        break;
+      }
+
+      case Orthanc::PixelFormat_Grayscale16:
+      {
+        BresenhamPixelWriter<Orthanc::PixelFormat_Grayscale16> writer(image, value);
+        writer.DrawSegment(x0, y0, x1, y1);
+        break;
+      }
+
+      case Orthanc::PixelFormat_SignedGrayscale16:
+      {
+        BresenhamPixelWriter<Orthanc::PixelFormat_SignedGrayscale16> writer(image, value);
+        writer.DrawSegment(x0, y0, x1, y1);
+        break;
+      }
+        
+      default:
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
+    }
+  }
+
+  
+  void ImageProcessing::DrawLineSegment(ImageAccessor& image,
+                                        int x0,
+                                        int y0,
+                                        int x1,
+                                        int y1,
+                                        uint8_t red,
+                                        uint8_t green,
+                                        uint8_t blue,
+                                        uint8_t alpha)
+  {
+    switch (image.GetFormat())
+    {
+      case Orthanc::PixelFormat_BGRA32:
+      {
+        PixelTraits<Orthanc::PixelFormat_BGRA32>::PixelType pixel;
+        pixel.red_ = red;
+        pixel.green_ = green;
+        pixel.blue_ = blue;
+        pixel.alpha_ = alpha;
+
+        BresenhamPixelWriter<Orthanc::PixelFormat_BGRA32> writer(image, pixel);
+        writer.DrawSegment(x0, y0, x1, y1);
+        break;
+      }
+        
+      case Orthanc::PixelFormat_RGB24:
+      {
+        PixelTraits<Orthanc::PixelFormat_RGB24>::PixelType pixel;
+        pixel.red_ = red;
+        pixel.green_ = green;
+        pixel.blue_ = blue;
+
+        BresenhamPixelWriter<Orthanc::PixelFormat_RGB24> writer(image, pixel);
+        writer.DrawSegment(x0, y0, x1, y1);
+        break;
+      }
+        
+      default:
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
+    }
+  }
 }
--- a/Orthanc/Core/Images/ImageProcessing.h	Tue Mar 13 10:24:38 2018 +0100
+++ b/Orthanc/Core/Images/ImageProcessing.h	Thu Mar 22 16:59:06 2018 +0100
@@ -39,45 +39,65 @@
 
 namespace Orthanc
 {
-  class ImageProcessing
+  namespace ImageProcessing
   {
-  public:
-    static void Copy(ImageAccessor& target,
-                     const ImageAccessor& source);
+    void Copy(ImageAccessor& target,
+              const ImageAccessor& source);
 
-    static void Convert(ImageAccessor& target,
-                        const ImageAccessor& source);
+    void Convert(ImageAccessor& target,
+                 const ImageAccessor& source);
+
+    void Set(ImageAccessor& image,
+             int64_t value);
 
-    static void Set(ImageAccessor& image,
-                    int64_t value);
+    void Set(ImageAccessor& image,
+             uint8_t red,
+             uint8_t green,
+             uint8_t blue,
+             uint8_t alpha);
 
-    static void Set(ImageAccessor& image,
-                    uint8_t red,
-                    uint8_t green,
-                    uint8_t blue,
-                    uint8_t alpha);
+    void ShiftRight(ImageAccessor& target,
+                    unsigned int shift);
+
+    void GetMinMaxIntegerValue(int64_t& minValue,
+                               int64_t& maxValue,
+                               const ImageAccessor& image);
+
+    void GetMinMaxFloatValue(float& minValue,
+                             float& maxValue,
+                             const ImageAccessor& image);
 
-    static void ShiftRight(ImageAccessor& target,
-                           unsigned int shift);
+    void AddConstant(ImageAccessor& image,
+                     int64_t value);
+
+    // "useRound" is expensive
+    void MultiplyConstant(ImageAccessor& image,
+                          float factor,
+                          bool useRound);
 
-    static void GetMinMaxIntegerValue(int64_t& minValue,
-                                      int64_t& maxValue,
-                                      const ImageAccessor& image);
+    // "useRound" is expensive
+    void ShiftScale(ImageAccessor& image,
+                    float offset,
+                    float scaling,
+                    bool useRound);
 
-    static void GetMinMaxFloatValue(float& minValue,
-                                    float& maxValue,
-                                    const ImageAccessor& image);
+    void Invert(ImageAccessor& image);
 
-    static void AddConstant(ImageAccessor& image,
-                            int64_t value);
-
-    static void MultiplyConstant(ImageAccessor& image,
-                                 float factor);
+    void DrawLineSegment(ImageAccessor& image,
+                         int x0,
+                         int y0,
+                         int x1,
+                         int y1,
+                         int64_t value);
 
-    static void ShiftScale(ImageAccessor& image,
-                           float offset,
-                           float scaling);
-
-    static void Invert(ImageAccessor& image);
+    void DrawLineSegment(ImageAccessor& image,
+                         int x0,
+                         int y0,
+                         int x1,
+                         int y1,
+                         uint8_t red,
+                         uint8_t green,
+                         uint8_t blue,
+                         uint8_t alpha);
   };
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Orthanc/Core/Images/PixelTraits.h	Thu Mar 22 16:59:06 2018 +0100
@@ -0,0 +1,267 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "../Enumerations.h"
+#include "../OrthancException.h"
+
+#include <limits>
+
+namespace Orthanc
+{
+  template <PixelFormat format,
+            typename _PixelType>
+  struct IntegerPixelTraits
+  {
+    typedef _PixelType  PixelType;
+
+    ORTHANC_FORCE_INLINE
+    static PixelFormat GetPixelFormat()
+    {
+      return format;
+    }
+
+    ORTHANC_FORCE_INLINE
+    static PixelType IntegerToPixel(int64_t value)
+    {
+      if (value < static_cast<int64_t>(std::numeric_limits<PixelType>::min()) ||
+          value > static_cast<int64_t>(std::numeric_limits<PixelType>::max()))
+      {
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+      }
+      else
+      {
+        return static_cast<PixelType>(value);
+      }
+    }
+
+    ORTHANC_FORCE_INLINE
+    static void SetZero(PixelType& target)
+    {
+      target = 0;
+    }
+
+    ORTHANC_FORCE_INLINE
+    static void SetMinValue(PixelType& target)
+    {
+      target = std::numeric_limits<PixelType>::min();
+    }
+
+    ORTHANC_FORCE_INLINE
+    static void SetMaxValue(PixelType& target)
+    {
+      target = std::numeric_limits<PixelType>::max();
+    }
+
+    ORTHANC_FORCE_INLINE
+    static void Copy(PixelType& target,
+                     const PixelType& source)
+    {
+      target = source;
+    }
+
+    ORTHANC_FORCE_INLINE
+    static float PixelToFloat(const PixelType& source)
+    {
+      return static_cast<float>(source);
+    }
+
+    ORTHANC_FORCE_INLINE
+    static void FloatToPixel(PixelType& target,
+                             float value)
+    {
+      if (value < static_cast<float>(std::numeric_limits<PixelType>::min()))
+      {
+        target = std::numeric_limits<PixelType>::min();
+      }
+      else if (value > static_cast<float>(std::numeric_limits<PixelType>::max()))
+      {
+        target = std::numeric_limits<PixelType>::max();
+      }
+      else
+      {
+        target = static_cast<PixelType>(value);
+      }
+    }
+
+    ORTHANC_FORCE_INLINE
+    static bool IsEqual(const PixelType& a,
+                        const PixelType& b)
+    {
+      return a == b;
+    }
+  };
+
+
+  template <PixelFormat Format>
+  struct PixelTraits;
+
+
+  template <>
+  struct PixelTraits<PixelFormat_Grayscale8> :
+    public IntegerPixelTraits<PixelFormat_Grayscale8, uint8_t>
+  {
+  };
+
+  
+  template <>
+  struct PixelTraits<PixelFormat_Grayscale16> :
+    public IntegerPixelTraits<PixelFormat_Grayscale16, uint16_t>
+  {
+  };
+
+  
+  template <>
+  struct PixelTraits<PixelFormat_SignedGrayscale16> :
+    public IntegerPixelTraits<PixelFormat_SignedGrayscale16, int16_t>
+  {
+  };
+
+
+  template <>
+  struct PixelTraits<PixelFormat_RGB24>
+  {
+    struct PixelType
+    {
+      uint8_t  red_;
+      uint8_t  green_;
+      uint8_t  blue_;
+    };
+
+    ORTHANC_FORCE_INLINE
+    static PixelFormat GetPixelFormat()
+    {
+      return PixelFormat_RGB24;
+    }
+
+    ORTHANC_FORCE_INLINE
+    static void SetZero(PixelType& target)
+    {
+      target.red_ = 0;
+      target.green_ = 0;
+      target.blue_ = 0;
+    }
+
+    ORTHANC_FORCE_INLINE
+    static void Copy(PixelType& target,
+                     const PixelType& source)
+    {
+      target.red_ = source.red_;
+      target.green_ = source.green_;
+      target.blue_ = source.blue_;
+    }
+
+    ORTHANC_FORCE_INLINE
+    static bool IsEqual(const PixelType& a,
+                        const PixelType& b)
+    {
+      return (a.red_ == b.red_ &&
+              a.green_ == b.green_ &&
+              a.blue_ == b.blue_);
+    }
+
+    ORTHANC_FORCE_INLINE
+    static void FloatToPixel(PixelType& target,
+                             float value)
+    {
+      uint8_t v;
+      PixelTraits<PixelFormat_Grayscale8>::FloatToPixel(v, value);
+
+      target.red_ = v;
+      target.green_ = v;
+      target.blue_ = v;
+    }
+  };
+
+
+  template <>
+  struct PixelTraits<PixelFormat_BGRA32>
+  {
+    struct PixelType
+    {
+      uint8_t  blue_;
+      uint8_t  green_;
+      uint8_t  red_;
+      uint8_t  alpha_;
+    };
+
+    ORTHANC_FORCE_INLINE
+    static PixelFormat GetPixelFormat()
+    {
+      return PixelFormat_BGRA32;
+    }
+
+    ORTHANC_FORCE_INLINE
+    static void SetZero(PixelType& target)
+    {
+      target.blue_ = 0;
+      target.green_ = 0;
+      target.red_ = 0;
+      target.alpha_ = 0;
+    }
+
+    ORTHANC_FORCE_INLINE
+    static void Copy(PixelType& target,
+                     const PixelType& source)
+    {
+      target.blue_ = source.blue_;
+      target.green_ = source.green_;
+      target.red_ = source.red_;
+      target.alpha_ = source.alpha_;
+    }
+
+    ORTHANC_FORCE_INLINE
+    static bool IsEqual(const PixelType& a,
+                        const PixelType& b)
+    {
+      return (a.blue_ == b.blue_ &&
+              a.green_ == b.green_ &&
+              a.red_ == b.red_ &&
+              a.alpha_ == b.alpha_);
+    }
+
+    ORTHANC_FORCE_INLINE
+    static void FloatToPixel(PixelType& target,
+                             float value)
+    {
+      uint8_t v;
+      PixelTraits<PixelFormat_Grayscale8>::FloatToPixel(v, value);
+
+      target.blue_ = v;
+      target.green_ = v;
+      target.red_ = v;
+      target.alpha_ = 255;      
+    }
+  };
+}
--- a/Orthanc/Core/Logging.h	Tue Mar 13 10:24:38 2018 +0100
+++ b/Orthanc/Core/Logging.h	Thu Mar 22 16:59:06 2018 +0100
@@ -47,6 +47,14 @@
 #  endif
 #endif
 
+#if !defined(ORTHANC_ENABLE_LOGGING_STDIO)
+#  if ORTHANC_ENABLE_LOGGING == 1
+#    error The macro ORTHANC_ENABLE_LOGGING_STDIO must be defined
+#  else
+#    define ORTHANC_ENABLE_LOGGING_STDIO 0
+#  endif
+#endif
+
 #if ORTHANC_ENABLE_LOGGING_PLUGIN == 1
 #  include <orthanc/OrthancCPlugin.h>
 #endif
@@ -104,40 +112,57 @@
 #  define VLOG(level)  ::Orthanc::Logging::NullStream()
 
 
-#elif ORTHANC_ENABLE_LOGGING_PLUGIN == 1
+#elif (ORTHANC_ENABLE_LOGGING_PLUGIN == 1 ||    \
+       ORTHANC_ENABLE_LOGGING_STDIO == 1)
 
 #  include <boost/noncopyable.hpp>
-#  define LOG(level)  ::Orthanc::Logging::InternalLogger(#level,  __FILE__, __LINE__)
-#  define VLOG(level) ::Orthanc::Logging::InternalLogger("TRACE", __FILE__, __LINE__)
+#  include <boost/lexical_cast.hpp>
+#  define LOG(level)  ::Orthanc::Logging::InternalLogger \
+  (::Orthanc::Logging::level, __FILE__, __LINE__)
+#  define VLOG(level) ::Orthanc::Logging::InternalLogger \
+  (::Orthanc::Logging::TRACE, __FILE__, __LINE__)
 
 namespace Orthanc
 {
   namespace Logging
   {
+    enum Level
+    {
+      ERROR,
+      WARNING,
+      INFO,
+      TRACE
+    };
+    
     class InternalLogger : public boost::noncopyable
     {
     private:
-      std::string level_;
+      Level       level_;
       std::string message_;
 
     public:
-      InternalLogger(const char* level,
+      InternalLogger(Level level,
                      const char* file,
                      int line);
 
       ~InternalLogger();
       
-      InternalLogger& operator<< (const std::string& message);
-
-      InternalLogger& operator<< (const char* message);
-
-      InternalLogger& operator<< (int message);
+      template <typename T>
+      InternalLogger& operator<< (T message)
+      {
+        message_ += boost::lexical_cast<std::string>(message);
+        return *this;
+      }
     };
   }
 }
 
 
-#else  /* ORTHANC_ENABLE_LOGGING_PLUGIN == 0 && ORTHANC_ENABLE_LOGGING == 1 */
+
+
+#else  /* ORTHANC_ENABLE_LOGGING_PLUGIN == 0 && 
+          ORTHANC_ENABLE_LOGGING_STDIO == 0 && 
+          ORTHANC_ENABLE_LOGGING == 1 */
 
 #  include <boost/thread/mutex.hpp>
 #  define LOG(level)  ::Orthanc::Logging::InternalLogger(#level,  __FILE__, __LINE__)
--- a/Orthanc/Core/SystemToolbox.cpp	Tue Mar 13 10:24:38 2018 +0100
+++ b/Orthanc/Core/SystemToolbox.cpp	Thu Mar 22 16:59:06 2018 +0100
@@ -561,17 +561,30 @@
   }
 
 
-  std::string SystemToolbox::GetNowIsoString()
+  static boost::posix_time::ptime GetNow(bool utc)
   {
-    boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
-    return boost::posix_time::to_iso_string(now);
+    if (utc)
+    {
+      return boost::posix_time::second_clock::universal_time();
+    }
+    else
+    {
+      return boost::posix_time::second_clock::local_time();
+    }
+  }
+
+
+  std::string SystemToolbox::GetNowIsoString(bool utc)
+  {
+    return boost::posix_time::to_iso_string(GetNow(utc));
   }
 
   
   void SystemToolbox::GetNowDicom(std::string& date,
-                                  std::string& time)
+                                  std::string& time,
+                                  bool utc)
   {
-    boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
+    boost::posix_time::ptime now = GetNow(utc);
     tm tm = boost::posix_time::to_tm(now);
 
     char s[32];
--- a/Orthanc/Core/SystemToolbox.h	Tue Mar 13 10:24:38 2018 +0100
+++ b/Orthanc/Core/SystemToolbox.h	Thu Mar 22 16:59:06 2018 +0100
@@ -95,9 +95,10 @@
 
     std::string GenerateUuid();
 
-    std::string GetNowIsoString();
+    std::string GetNowIsoString(bool utc);
 
     void GetNowDicom(std::string& date,
-                     std::string& time);
+                     std::string& time,
+                     bool utc);
   }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Orthanc/NEWS	Thu Mar 22 16:59:06 2018 +0100
@@ -0,0 +1,942 @@
+Pending changes in the mainline
+===============================
+
+REST API
+--------
+
+* "/system" URI returns the version of the Orthanc REST API
+* "/tools/now" returns the current UTC (universal) time
+* "/tools/now-local" returns the curent local time.
+  This was the behavior of "/tools/now" until release 1.3.1.
+* Added "?expand" GET argument to "/peers" and "/modalities" routes
+* New URI: "/tools/create-media-extended" to generate a DICOMDIR
+  archive from several resources, including additional type-3 tags
+
+Lua
+---
+
+* New CMake option: "-DENABLE_LUA_MODULES=ON" to enable support for
+  loading external Lua modules if the Lua engine is statically linked
+
+Plugins
+-------
+
+* New error code: DatabaseUnavailable
+
+Maintenance
+-----------
+
+* Orthanc now uses UTC (universal time) instead of local time in its database
+* Fix to allow creating DICOM instances with empty Specific Character Set (0008,0005)
+* Upgrade to curl 7.57.0 for static and Windows builds
+* Support of Linux Standard Base
+* Static linking against libuuid (from e2fsprogs)
+* Fix static build on CentOS 6
+* Upgrade to JsonCpp 1.8.4 for static builds
+* Possibility of using JsonCpp 0.10.6 if the compiler does not support C++11
+  with the "-DUSE_LEGACY_JSONCPP=ON" CMake option
+
+
+Version 1.3.1 (2017-11-29)
+==========================
+
+General
+-------
+
+* Built-in decoding of palette images
+
+REST API
+--------
+
+* New URI: "/instances/.../frames/.../raw.gz" to compress raw frames using gzip
+* New argument "ignore-length" to force the inclusion of too long tags in JSON
+* New argument "/.../media?extended" to include additional type-3 tags in DICOMDIR
+
+Plugins
+-------
+
+* New pixel formats exposed in SDK: BGRA32, Float32, Grayscale32, RGB48
+
+Maintenance
+-----------
+
+* Creation of ./Resources/CMake/OrthancFramework*.cmake to reuse the Orthanc
+  C++ framework in other projects
+* New security-related options: "DicomAlwaysAllowEcho"
+* Use "GBK" (frequently used in China) as an alias for "GB18030"
+* Experimental support of actively maintained Civetweb to replace Mongoose 3.8
+* Fix issue 31 for good (create new modality types for Philips ADW, GE Xeleris, GE AWServer)
+* Fix issue 64 (OpenBSD support)
+* Fix static compilation of DCMTK 3.6.2 on Fedora
+* Upgrade to Boost 1.65.1 in static builds
+* Upgrade to SQLite amalgamation 3.21.0 in static builds
+
+
+Version 1.3.0 (2017-07-19)
+==========================
+
+General
+-------
+
+* Orthanc now anonymizes according to Basic Profile of PS 3.15-2017c Table E.1-1
+* In the "DicomModalities" configuration:
+  - Manufacturer type MedInria is now obsolete
+  - Manufacturer types AgfaImpax and SyngoVia are obsolete too
+    (use GenericNoWildcardInDates instead)
+  - Obsolete manufacturers are still accepted but might disappear in the future
+  - Added new manufacturer: GenericNoUniversalWildcard to replace all '*' by '' in
+    outgoing C-Find requests
+* New security-related options: "DicomAlwaysAllowStore" and "DicomCheckModalityHost"
+
+REST API
+--------
+
+* Argument "Since" in URI "/tools/find" (related to issue 53)
+* Argument "DicomVersion" in URIs "/{...}/{...}/anonymization"
+
+Plugins
+-------
+
+* New function: "OrthancPluginRegisterIncomingHttpRequestFilter2()"
+
+Lua
+---
+
+* Added HTTP headers support for Lua HttpPost/HttpGet/HttpPut/HttpDelete
+
+Orthanc Explorer
+----------------
+
+* Query/retrieve: Added button for "DR" modality
+
+Maintenance
+-----------
+
+* Ability to retrieve raw frames encoded as unsigned 32-bits integers
+* Fix issue 29 (more consistent handling of the "--upgrade" argument)
+* Fix issue 31 (create new modality types for Philips ADW, GE Xeleris, GE AWServer)
+* Fix issue 35 (AET name is not transferred to Orthanc using DCMTK 3.6.0)
+* Fix issue 44 (bad interpretation of photometric interpretation MONOCHROME1)
+* Fix issue 45 (crash when providing a folder to "--config" command-line option)
+* Fix issue 46 (PHI remaining after anonymization)
+* Fix issue 49 (worklists: accentuated characters are removed from C-Find responses)
+* Fix issue 52 (DICOM level security association problems)
+* Fix issue 55 (modification/anonymization of tags that might break the database
+  model now requires the "Force" parameter to be set to "true" in the query)
+* Fix issue 56 (case-insensitive matching over accents)
+* Fix Debian #865606 (orthanc FTBFS with libdcmtk-dev 3.6.1~20170228-2)
+* Fix XSS inside DICOM in Orthanc Explorer (as reported by Victor Pasnkel, Morphus Labs)
+* Upgrade to DCMTK 3.6.2 in static builds (released on 2017-07-17)
+* Upgrade to Boost 1.64.0 in static builds
+* New advanced "Locale" configuration option
+* Removed configuration option "USE_DCMTK_361_PRIVATE_DIC"
+
+
+Version 1.2.0 (2016/12/13)
+==========================
+
+General
+-------
+
+* Handling of private tags/creators in the "Dictionary" configuration option
+* New configuration options: "LoadPrivateDictionary", "DicomScuTimeout" and "DicomScpTimeout"
+* New metadata automatically computed at the instance level: "TransferSyntax" and "SopClassUid"
+
+REST API
+--------
+
+* "/tools/invalidate-tags" to invalidate the JSON summary of all the DICOM files
+  (useful if private tags are registered, or if changing the default encoding)
+* "Permissive" flag for URI "/modalities/{...}/store" to ignore C-STORE transfer errors
+* "Asynchronous" flag for URIs "/modalities/{...}/store" and "/peers/{...}/store"
+  to avoid waiting for the completion of image transfers
+* Possibility to DELETE "dicom-as-json" attachments to reconstruct the JSON summaries
+  (useful if "Dictionary" has changed)
+* "Keep" option for modifications to keep original DICOM identifiers (advanced feature)
+* "/tools/default-encoding" to get or temporarily change the default encoding
+* "/{resource}/{id}/reconstruct" to reconstruct the main DICOM tags, the JSON summary and
+  the metadata of a resource (useful to compute new metadata, or if using "Keep" above)
+
+Plugins
+-------
+
+* New function: "OrthancPluginRegisterPrivateDictionaryTag()" to register private tags
+* More control over client cache in the ServeFolders plugin
+* New C++ help wrappers in "Plugins/Samples/Common/" to read DICOM datasets from REST API
+* New data structure: "OrthancPluginFindMatcher" to match DICOM against C-FIND queries
+
+Maintenance
+-----------
+
+* Fix handling of encodings in C-FIND requests (including for worklists)
+* Use of DCMTK 3.6.1 dictionary of private tags in standalone builds
+* Avoid hard crash if not enough memory (handling of std::bad_alloc)
+* Improved robustness of Orthanc Explorer wrt. query/retrieve (maybe fix issue 24)
+* Fix serious performance issue with C-FIND
+* Fix extraction of the symbolic name of the private tags
+* Performance warning if runtime debug assertions are turned on
+* Improved robustness against files with no PatientID
+* Upgrade to curl 7.50.3 for static and Windows builds
+* Content-Type for JSON documents is now "application/json; charset=utf-8"
+* Ignore "Group Length" tags in C-FIND queries
+* Fix handling of worklist SCP with ReferencedStudySequence and ReferencedPatientSequence
+* Fix handling of Move Originator AET and ID in C-MOVE SCP
+* Fix vulnerability ZSL-2016-5379 "Unquoted Service Path Privilege Escalation" in the
+  Windows service
+* Fix vulnerability ZSL-2016-5380 "Remote Memory Corruption Vulnerability" in DCMTK 3.6.0
+
+
+Version 1.1.0 (2016/06/27)
+==========================
+
+General
+-------
+
+* HTTPS client certificates can be associated with Orthanc peers to enhance security over Internet
+* Possibility to use PKCS#11 authentication for hardware security modules with Orthanc peers
+* New command-line option "--logfile" to output the Orthanc log to the given file
+* Support of SIGHUP signal (restart Orthanc only if the configuration files have changed)
+
+REST API
+--------
+
+* New URI: "/instances/.../frames/.../raw" to access the raw frames (bypass image decoding)
+* New URI "/modalities/.../move" to issue C-MOVE SCU requests
+* "MoveOriginatorID" can be specified for "/modalities/.../store"
+
+Dicom protocol
+--------------
+
+* Support of optional tags for counting resources in C-FIND:
+  0008-0061, 0008-0062, 0020-1200, 0020-1202, 0020-1204, 0020-1206, 0020-1208, 0020-1209
+* Support of Move Originator Message ID (0000,1031) in C-STORE responses driven by C-MOVE
+
+Plugins
+-------
+
+* Speedup in plugins by removing unnecessary locks
+* New callback to filter incoming HTTP requests: OrthancPluginRegisterIncomingHttpRequestFilter()
+* New callback to handle non-worklists C-FIND requests: OrthancPluginRegisterFindCallback()
+* New callback to handle C-MOVE requests: OrthancPluginRegisterMoveCallback()
+* New function: "OrthancPluginHttpClient()" to do HTTP requests with full control
+* New function: "OrthancPluginGenerateUuid()" to generate a UUID
+* More than one custom image decoder can be installed (e.g. to handle different transfer syntaxes)
+
+Lua
+---
+
+* Possibility to dynamically fix outgoing C-FIND requests using "OutgoingFindRequestFilter()"
+* Access to the HTTP headers in the "IncomingHttpRequestFilter()" callback
+
+Image decoding
+--------------
+
+* Huge speedup if decoding the family of JPEG transfer syntaxes
+* Refactoring leading to speedups with custom image decoders (including Web viewer plugin)
+* Support decoding of RLE Lossless transfer syntax
+* Support of signed 16bpp images in ParsedDicomFile
+
+Maintenance
+-----------
+
+* New logo of Orthanc
+* Fix issue 11 (is_regular_file() fails for FILE_ATTRIBUTE_REPARSE_POINT)
+* Fix issue 16 ("Limit" parameter error in REST API /tools/find method)
+* Fix of Debian bug #818512 ("FTBFS: Please install libdcmtk*-dev")
+* Fix of Debian bug #823139 ("orthanc: Please provide RecoverCompressedFile.cpp")
+* Replaced "localhost" by "127.0.0.1", as it might impact performance on Windows
+* Compatibility with CMake >= 3.5.0
+* Possibility to use forthcoming DCMTK 3.6.1 in static builds (instead of 3.6.0)
+* Upgrade to Boost 1.60.0 for static builds
+* Use of HTTP status 403 Forbidden (instead of 401) if access to a REST resource is disallowed
+* Option "HttpsVerifyPeers" can be used to connect against self-signed HTTPS certificates
+* New configuration option "AllowFindSopClassesInStudy"
+* Macro "__linux" (now obsolete) replaced by macro "__linux__" (maybe solves Debian bug #821011)
+* Modification of instances can now replace PixelData (resp. EncapsulatedDocument) with 
+  provided a PNG/JPEG image (resp. PDF file) if it is encoded using Data URI Scheme
+* Dropped support of Google Log
+
+
+Version 1.0.0 (2015/12/15)
+==========================
+
+* Lua: "IncomingFindRequestFilter()" to apply filters to incoming C-FIND requests
+* New function in plugin SDK: "OrthancPluginSendMultipartItem2()"
+* Fix of DICOMDIR generation with DCMTK 3.6.1, support of encodings
+* Fix range search if the lower or upper limit is absent
+* Fix modality worklists lookups if tags with UN (unknown) VR are present
+* Warn about badly formatted modality/peer definitions in configuration file at startup
+
+
+Version 0.9.6 (2015/12/08)
+==========================
+
+* Promiscuous mode (accept unknown SOP class UID) is now turned off by default
+* Fix serialization of DICOM buffers that might contain garbage trailing
+* Fix modality worklists server if some fields are null
+* More tolerant "/series/.../ordered-slices" with broken series
+* Improved logging information if upgrade fails
+* Fix formatting of multipart HTTP answers (bis)
+
+
+Version 0.9.5 (2015/12/02)
+==========================
+
+Major
+-----
+
+* Experimental support of DICOM C-FIND SCP for modality worklists through plugins
+* Support of DICOM C-FIND SCU for modality worklists ("/modalities/{dicom}/find-worklist")
+
+REST API
+--------
+
+* New URIs:
+  - "/series/.../ordered-slices" to order the slices of a 2D+t or 3D series
+  - "/tools/shutdown" to stop Orthanc from the REST API
+  - ".../compress", ".../uncompress" and ".../is-compressed" for attachments
+  - "/tools/create-archive" to create ZIP from a set of resources
+  - "/tools/create-media" to create ZIP+DICOMDIR from a set of resources
+  - "/instances/.../header" to get the meta information (header) of the DICOM instance
+* "/tools/create-dicom":
+  - Support of binary tags encoded using data URI scheme
+  - Support of hierarchical structures (creation of sequences)
+  - Create tags with unknown VR
+* "/modify" can insert/modify sequences
+* ".../preview" and ".../image-uint8" can return JPEG images if the HTTP Accept Header asks so
+* "Origin" metadata for the instances
+
+Minor
+-----
+
+* New configuration options:
+  - "UnknownSopClassAccepted" to disable promiscuous mode (accept unknown SOP class UID)
+  - New configuration option: "Dictionary" to declare custom DICOM tags
+* Add ".dcm" suffix to files in ZIP archives (cf. URI ".../archive")
+* MIME content type can be associated to custom attachments (cf. "UserContentType")
+
+Plugins
+-------
+
+* New functions:
+  - "OrthancPluginRegisterDecodeImageCallback()" to replace the built-in image decoder
+  - "OrthancPluginDicomInstanceToJson()" to convert DICOM to JSON
+  - "OrthancPluginDicomBufferToJson()" to convert DICOM to JSON
+  - "OrthancPluginRegisterErrorCode()" to declare custom error codes
+  - "OrthancPluginRegisterDictionaryTag()" to declare custom DICOM tags
+  - "OrthancPluginLookupDictionary()" to get information about some DICOM tag
+  - "OrthancPluginRestApiGet2()" to provide HTTP headers when calling Orthanc API
+  - "OrthancPluginGetInstanceOrigin()" to know through which mechanism an instance was received
+  - "OrthancPluginCreateImage()" and "OrthancPluginCreateImageAccessor()" to create images
+  - "OrthancPluginDecodeDicomImage()" to decode DICOM images
+  - "OrthancPluginComputeMd5()" and "OrthancPluginComputeSha1()" to compute MD5/SHA-1 hash
+* New events in change callbacks:
+  - "OrthancStarted"
+  - "OrthancStopped"
+  - "UpdatedAttachment" 
+  - "UpdatedMetadata"
+* "/system" URI gives information about the plugins used for storage area and DB back-end
+* Plugin callbacks must now return explicit "OrthancPluginErrorCode" (instead of integers)
+
+Lua
+---
+
+* Optional argument "keepStrings" in "DumpJson()"
+
+Maintenance
+-----------
+
+* Full indexation of the patient/study tags to speed up searches and C-FIND
+* Many refactorings, notably of the searching features and of the image decoding
+* C-MOVE SCP for studies using AccessionNumber tag
+* Fix issue 4 (C-STORE Association not renegotiated on Specific-to-specific transfer syntax change)
+* Fix formatting of multipart HTTP answers
+* "--logdir" flag creates a single log file instead of 3 separate files for errors/warnings/infos
+* "--errors" flag lists the error codes that could be returned by Orthanc
+* Under Windows, the exit status of Orthanc corresponds to the encountered error code
+* New "AgfaImpax", "EFilm2" and "Vitrea" modality manufacturers
+* C-FIND SCP will return tags with sequence value representation
+* Upgrade to Boost 1.59.0 for static builds
+
+
+Version 0.9.4 (2015/09/16)
+==========================
+
+* 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
+* Options to validate peers against CA certificates in HTTPS requests
+* New configuration option: "HttpTimeout" to set the default timeout for HTTP requests
+
+Lua
+---
+
+* More information about the origin request in the "OnStoredInstance()" and
+  "ReceivedInstanceFilter()" callbacks. WARNING: This can result in
+  incompatibilities wrt. previous versions of Orthanc.
+* New function "GetOrthancConfiguration()" to get the Orthanc configuration
+
+Plugins
+-------
+
+* New functions to compress/uncompress images using PNG and JPEG
+* New functions to issue HTTP requests from plugins
+* New function "OrthancPluginBufferCompression()" to (un)compress memory buffers
+* New function "OrthancPluginReadFile()" to read files from the filesystem
+* New function "OrthancPluginWriteFile()" to write files to the filesystem
+* New function "OrthancPluginGetErrorDescription()" to convert error codes to strings
+* New function "OrthancPluginSendHttpStatus()" to send HTTP status with a body
+* New function "OrthancPluginRegisterRestCallbackNoLock()" for high-performance plugins
+* Plugins have access to explicit error codes 
+* Improvements to the sample "ServeFolders" plugin
+* Primitives to upgrade the database version in plugins
+
+Maintenance
+-----------
+
+* Many code refactorings
+* Improved error codes (no more custom descriptions in exceptions)
+* If error while calling the REST API, the answer body contains description of the error
+  (this feature can be disabled with the "HttpDescribeErrors" option)
+* Upgrade to curl 7.44.0 for static and Windows builds
+* Upgrade to libcurl 1.0.2d for static and Windows builds
+* Depends on libjpeg 9a
+* Bypass zlib uncompression if "StorageCompression" is enabled and HTTP client supports deflate
+
+
+Version 0.9.3 (2015/08/07)
+==========================
+
+* C-Echo testing can be triggered from Orthanc Explorer (in the query/retrieve page)
+* Removal of the dependency upon Google Log, Orthanc now uses its internal logger 
+  (use -DENABLE_GOOGLE_LOG=ON to re-enable Google Log)
+* Upgrade to JsonCpp 0.10.5 for static and Windows builds
+
+
+Version 0.9.2 (2015/08/02)
+==========================
+
+* Upgrade to Boost 1.58.0 for static and Windows builds
+* Source code repository moved from Google Code to BitBucket
+* Inject version information into Windows binaries
+* Fix access to binary data in HTTP/REST requests by Lua scripts
+* Fix potential deadlock in the callbacks of plugins
+
+
+Version 0.9.1 (2015/07/02)
+==========================
+
+General
+-------
+
+* The configuration can be splitted into several files stored inside the same folder
+* Custom setting of the local AET during C-STORE SCU (both in Lua and in the REST API)
+* Many code refactorings
+
+Lua
+---
+
+* Access to the REST API of Orthanc (RestApiGet, RestApiPost, RestApiPut, RestApiDelete)
+* Functions to convert between Lua values and JSON strings: "ParseJson" and "DumpJson"
+* New events: "OnStablePatient", "OnStableStudy", "OnStableSeries", "Initialize", "Finalize"
+
+Plugins
+-------
+
+* Plugins can retrieve the configuration file directly as a JSON string
+* Plugins can send answers as multipart messages
+
+Fixes
+-----
+
+* Fix compatibility issues for C-FIND SCU to Siemens Syngo.Via modalities SCP
+* Fix issue 15 (Lua scripts making HTTP requests)
+* Fix issue 35 (Characters in PatientID string are not protected for C-FIND)
+* Fix issue 37 (Hyphens trigger range query even if datatype does not support ranges)
+
+
+Version 0.9.0 (2015/06/03)
+==========================
+
+Major
+-----
+
+* DICOM Query/Retrieve available from Orthanc Explorer
+* C-MOVE SCU and C-FIND SCU are accessible through the REST API
+* "?expand" flag for URIs "/patients", "/studies" and "/series"
+* "/tools/find" URI to search for DICOM resources from REST
+* Support of FreeBSD
+* The "Orthanc Client" SDK is now a separate project
+
+Minor
+-----
+
+* Speed-up in Orthanc Explorer for large amount of images
+* Speed-up of the C-FIND SCP server of Orthanc
+* Allow replacing PatientID/StudyInstanceUID/SeriesInstanceUID from Lua scripts
+* Option "CaseSensitivePN" to enable case-insensitive C-FIND SCP
+
+Fixes
+-----
+
+* Prevent freeze on C-FIND if no DICOM tag is to be returned
+* Fix slow C-STORE SCP on recent versions of GNU/Linux, if
+  USE_SYSTEM_DCMTK is set to OFF (http://forum.dcmtk.org/viewtopic.php?f=1&t=4009)
+* Fix issue 30 (QR response missing "Query/Retrieve Level" (008,0052))
+* Fix issue 32 (Cyrillic symbols): Introduction of the "Windows1251" encoding
+* Plugins now receive duplicated GET arguments in their REST callbacks
+
+
+Version 0.8.6 (2015/02/12)
+==========================
+
+Major
+-----
+
+* URIs to get all the parents of a given resource in a single REST call
+* Instances without PatientID are now allowed
+* Support of HTTP proxy to access Orthanc peers
+
+Minor
+-----
+
+* Support of Tudor DICOM in Query/Retrieve
+* More flexible "/modify" and "/anonymize" for single instance
+* Access to called AET and remote AET from Lua scripts ("OnStoredInstance")
+* Option "DicomAssociationCloseDelay" to set delay before closing DICOM association
+* ZIP archives now display the accession number of the studies
+
+Plugins
+-------
+
+* Introspection of plugins (cf. the "/plugins" URI)
+* Plugins can access the command-line arguments used to launch Orthanc
+* Plugins can extend Orthanc Explorer with custom JavaScript
+* Plugins can get/set global properties to save their configuration
+* Plugins can do REST calls to other plugins (cf. "xxxAfterPlugins()")
+* Scan of folders for plugins
+
+Fixes
+-----
+
+* Code refactorings
+* Fix issue 25 (AET with underscore not allowed)
+* Fix replacement and insertion of private DICOM tags
+* Fix anonymization generating non-portable DICOM files
+
+
+Version 0.8.5 (2014/11/04)
+==========================
+
+General
+-------
+
+* Major speed-up thanks to a new database schema
+* Plugins can monitor changes through callbacks
+* Download ZIP + DICOMDIR from Orthanc Explorer
+* Sample plugin framework to serve static resources (./Plugins/Samples/WebSkeleton/)
+
+Fixes
+-----
+
+* Fix issue 19 (YBR_FULL are decoded incorrectly)
+* Fix issue 21 (Microsoft Visual Studio precompiled headers)
+* Fix issue 22 (Error decoding multi-frame instances)
+* Fix issue 24 (Build fails on OSX when directory has .DS_Store files)
+* Fix crash when bad HTTP credentials are provided
+
+
+Version 0.8.4 (2014/09/19)
+==========================
+
+* "/instances-tags" to get the tags of all the child instances of a
+  patient/study/series with a single REST call (bulk tags retrieval)
+* Configuration/Lua to select the accepted C-STORE SCP transfer syntaxes
+* Fix reporting of errors in Orthanc Explorer when sending images to peers/modalities
+* Installation of plugin SDK in CMake
+
+
+Version 0.8.3 (2014/09/11)
+==========================
+
+Major
+-----
+
+* Creation of ZIP archives for media storage, with DICOMDIR
+* URIs to get all the children of a given resource in a single REST call
+* "/tools/lookup" URI to map DICOM UIDs to Orthanc identifiers
+* Support of index-only mode (using the "StoreDicom" option)
+* Plugins can implement a custom storage area
+
+Minor
+-----
+
+* Configuration option to enable HTTP Keep-Alive
+* Configuration option to disable the logging of exported resources in "/exports"
+* Plugins can retrieve the path to Orthanc and to its configuration file
+* "/tools/create-dicom" now accepts the "PatientID" DICOM tag (+ updated sample)
+* Possibility to set HTTP headers from plugins
+* "LastUpdate" metadata is now always returned for patients, studies and series
+
+Maintenance
+-----------
+
+* Refactoring of HttpOutput ("Content-Length" header is now always sent)
+* Upgrade to Mongoose 3.8
+* Fixes for Visual Studio 2013 and Windows 64bit
+* Fix issue 16: Handling of "AT" value representations in JSON
+* Fix issue 17
+
+
+Version 0.8.2 (2014/08/07)
+==========================
+
+* Support of the standard text encodings
+* Hot restart of Orthanc by posting to "/tools/reset"
+* More fault-tolerant commands in Lua scripts
+* Parameter to set the default encoding for DICOM files without SpecificCharacterSet
+* Fix of issue #14 (support of XCode 5.1)
+* Upgrade to Google Test 1.7.0
+
+
+Version 0.8.1 (2014/07/29)
+==========================
+
+General
+-------
+
+* Access patient module at the study level to cope with PatientID collisions
+* On-the-fly conversion of JSON to XML according to the HTTP Accept header
+* C-Echo SCU in the REST API
+* DICOM conformance statement available at URI "/tools/dicom-conformance"
+
+Lua scripts
+-----------
+
+* Lua scripts can do HTTP requests, and thus can call Web services
+* Lua scripts can invoke system commands, with CallSystem()
+
+Plugins
+-------
+
+* Lookup for DICOM UIDs in the plugin SDK
+* Plugins have access to the HTTP headers and can answer with HTTP status codes
+* Callback to react to the incoming of DICOM instances
+
+Fixes
+-----
+
+* Fix build of Google Log with Visual Studio >= 11.0
+* Fix automated generation of the list of resource children in the REST API
+
+
+Version 0.8.0 (2014/07/10)
+==========================
+
+Major changes
+-------------
+
+* Routing images with Lua scripts
+* Introduction of the Orthanc Plugin SDK
+* Official support of OS X (Darwin) 10.8
+
+Minor changes
+-------------
+
+* Extraction of tags for the patient/study/series/instance DICOM modules
+* Extraction of the tags shared by all the instances of a patient/study/series
+* Options to limit the number of results for an incoming C-FIND query
+* Support of kFreeBSD
+* Several code refactorings
+* Fix OrthancCppClient::GetVoxelSizeZ()
+
+
+Version 0.7.6 (2014/06/11)
+==========================
+
+* Support of JPEG and JPEG-LS decompression
+* Download DICOM images as Matlab/Octave arrays
+* Precompiled headers for Microsoft Visual Studio
+
+
+Version 0.7.5 (2014/05/08)
+==========================
+
+* Dynamic negotiation of SOP classes for C-STORE SCU
+* Creation of DICOM instances using the REST API
+* Embedding of images within DICOM instances
+* Adding/removal/modification of remote modalities/peers through REST
+* Reuse of the previous SCU connection to avoid unnecessary handshakes
+* Fix problems with anonymization and modification
+* Fix missing licensing terms about reuse of some code from DCMTK
+* Various code refactorings
+
+
+Version 0.7.4 (2014/04/16)
+==========================
+
+* Switch to openssl-1.0.1g in static builds (cf. Heartbleed exploit)
+* Switch to boost 1.55.0 in static builds (to solve compiling errors)
+* Better logging about nonexistent tags
+* Dcm4Chee manufacturer
+* Automatic discovering of the path to the DICOM dictionaries
+* In the "DicomModalities" config, the port number can be a string
+
+
+Version 0.7.3 (2014/02/14)
+==========================
+
+Major changes
+-------------
+
+* Fixes in the implementation of the C-FIND handler for Query/Retrieve
+* Custom attachment of files to patients, studies, series or instances
+* Access to lowlevel info about the attached files through the REST API
+* Recover pixel data for more transfer syntaxes (notably JPEG)
+
+Minor changes
+-------------
+
+* AET comparison is now case-insensitive by default
+* Possibility to disable the HTTP server or the DICOM server
+* Automatic computation of MD5 hashes for the stored DICOM files
+* Maintenance tool to recover DICOM files compressed by Orthanc
+* The newline characters in the configuration file are fixed for GNU/Linux
+* Capture of the SIGTERM signal in GNU/Linux
+
+
+Version 0.7.2 (2013/11/08)
+==========================
+
+* Support of Query/Retrieve from medInria
+* Accept more transfer syntaxes for C-STORE SCP and SCU (notably JPEG)
+* Create the meta-header when receiving files through C-STORE SCP
+* Fixes and improvements thanks to the static analyzer cppcheck
+
+
+Version 0.7.1 (2013/10/30)
+==========================
+
+* Use ZIP64 only when required to improve compatibility (cf. issue #7)
+* Refactoring of the CMake options
+* Fix for big-endian architectures (RedHat bug #985748)
+* Use filenames with 8 characters in ZIP files for maximum compatibility
+* Possibility to build Orthanc inplace (in the source directory)
+
+
+Version 0.7.0 (2013/10/25)
+==========================
+
+Major changes
+-------------
+
+* DICOM Query/Retrieve is supported
+
+Minor changes
+-------------
+
+* Possibility to keep the PatientID during an anonymization
+* Check whether "unzip", "tar" and/or "7-zip" are installed from CMake
+
+
+Version 0.6.2 (2013/10/04)
+==========================
+
+* Build of the C++ client as a shared library
+* Improvements and documentation of the C++ client API
+* Fix of Debian bug #724947 (licensing issue with the SHA-1 library)
+* Switch to Boost 1.54.0 (cf. issue #9)
+* "make uninstall" is now possible
+
+
+Version 0.6.1 (2013/09/16)
+==========================
+
+* Detection of stable patients/studies/series
+* C-FIND SCU at the instance level
+* Link from modified to original resource in Orthanc Explorer
+* Fix of issue #8
+* Anonymization of the medical alerts tag (0010,2000)
+
+
+Version 0.6.0 (2013/07/16)
+==========================
+
+Major changes
+-------------
+
+* Introduction of the C++ client
+* Send DICOM resources to other Orthanc instances through HTTP
+* Access to signed images (instances/.../image-int16)
+  (Closes: Debian #716958)
+
+Minor changes
+-------------
+
+* Export of DICOM files to the host filesystem (instances/.../export)
+* Statistics about patients, studies, series and instances
+* Link from anonymized to original resource in Orthanc Explorer
+* Fixes for Red Hat and Debian packaging
+* Fixes for history in Orthanc Explorer
+* Fixes for boost::thread, as reported by Cyril Paulus
+* Fix licensing (Closes: Debian #712038)
+
+Metadata
+--------
+
+* Access to the metadata through the REST API (.../metadata)
+* Support of user-defined metadata
+* "LastUpdate" metadata for patients, studies and series
+* "/tools/now" to be used in combination with "LastUpdate"
+* Improved support of series with temporal positions
+
+
+Version 0.5.2 (2013/05/07)
+==========================
+
+* "Bulk" Store-SCU (send several DICOM instances with the same
+  DICOM connection)
+* Store-SCU for patients and studies in Orthanc Explorer
+* Filtering of incoming DICOM instances (through Lua scripting)
+* Filtering of incoming HTTP requests (through Lua scripting)
+* Clearing of "/exports" and "/changes"
+* Check MD5 of third party downloads
+* Faking of the HTTP methods PUT and DELETE
+
+
+Version 0.5.1 (2013/04/17)
+==========================
+
+* Support of RGB images
+* Fix of store SCU in release builds
+* Possibility to store the SQLite index at another place than the
+  DICOM instances (for performance)
+
+
+Version 0.5.0 (2013/01/31)
+==========================
+
+Major changes
+-------------
+
+* Download of modified or anonymized DICOM instances
+* Inplace modification and anonymization of DICOM series, studies and patients
+
+Minor changes
+-------------
+
+* Support of private tags
+* Implementation of the PMSCT_RLE1 image decoding for Philips modalities
+* Generation of random DICOM UID through the REST API (/tools/generate-uid)
+
+
+Version 0.4.0 (2012/12/14)
+==========================
+
+Major changes
+-------------
+
+* Recycling of disk space
+* Raw access to the value of the DICOM tags in the REST API
+
+Minor changes
+-------------
+
+* Protection of patients against recycling (also in Orthanc Explorer)
+* The DICOM dictionaries are embedded in Windows builds
+
+
+Version 0.3.1 (2012/12/05)
+==========================
+
+* Download archives of patients, studies and series as ZIP files
+* Orthanc now checks the version of its database schema before starting
+
+
+Version 0.3.0 (2012/11/30)
+==========================
+
+Major changes
+-------------
+
+* Transparent compression of the DICOM instances on the disk
+* The patient/study/series/instances are now indexed by SHA-1 digests
+  of their DICOM Instance IDs (and not by UUIDs anymore): The same
+  DICOM objects are thus always identified by the same Orthanc IDs
+* Log of exported instances through DICOM C-STORE SCU ("/exported" URI)
+* Full refactoring of the DB schema and of the REST API
+* Introduction of generic classes for REST APIs (in Core/RestApi)
+
+Minor changes
+-------------
+
+* "/statistics" URI
+* "last" flag to retrieve the last change from the "/changes" URI
+* Generate a sample configuration file from command line
+* "CompletedSeries" event in the changes API
+* Thread to continuously flush DB to disk (SQLite checkpoints for
+  improved robustness)
+
+
+Version 0.2.3 (2012/10/26)
+==========================
+
+* Use HTTP Content-Disposition to set a filename when downloading JSON/DCM
+* URI "/system" for general information about Orthanc
+* Versioning info and help on the command line
+* Improved logging
+* Possibility of dynamic linking against jsoncpp, sqlite, boost and dmctk
+  for Debian packaging
+* Fix some bugs
+* Switch to default 8042 port for HTTP
+
+
+Version 0.2.2 (2012/10/04)
+==========================
+
+* Switch to Google Log
+* Fixes to Debian packaging
+
+
+Version 0.2.1 (2012/09/28)
+==========================
+
+* Status of series
+* Continuous Integration Server is up and running
+* Ready for Debian packaging
+
+
+Version 0.2.0 (2012/09/16)
+==========================
+
+Major changes
+-------------
+
+* Renaming to "Orthanc"
+* Focus on security: Support of SSL, HTTP Basic Authentication and
+  interdiction of remote access
+* Access to multi-frame images (for nuclear medicine)
+* Access to the raw PNG images (in 8bpp and 16bpp)
+
+Minor changes
+-------------
+
+* Change of the licensing of the "Core/SQLite" folder to BSD (to
+  reflect the original licensing terms of Chromium, from which the
+  code derives)
+* Standalone build for cross-compilation
+
+
+Version 0.1.1 (2012/07/20)
+==========================
+
+* Fix Windows version
+* Native Windows build with Microsoft Visual Studio 2005
+* Add path to storage in Configuration.json
+
+
+Version 0.1.0 (2012/07/19)
+==========================
+
+* Initial release
--- a/Orthanc/Plugins/Samples/GdcmDecoder/GdcmImageDecoder.cpp	Tue Mar 13 10:24:38 2018 +0100
+++ b/Orthanc/Plugins/Samples/GdcmDecoder/GdcmImageDecoder.cpp	Thu Mar 22 16:59:06 2018 +0100
@@ -265,6 +265,10 @@
     // http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.7.6.3.html#sect_C.7.6.3.1.2
     // https://en.wikipedia.org/wiki/YCbCr#JPEG_conversion
     
+    // TODO - Check out the outcome of Mathieu's discussion about
+    // truncation of YCbCr-to-RGB conversion:
+    // https://groups.google.com/forum/#!msg/comp.protocols.dicom/JHuGeyWbTz8/ARoTWrJzAQAJ
+
     const float Y  = ybr[0];
     const float Cb = ybr[1];
     const float Cr = ybr[2];
--- a/Orthanc/Resources/CMake/BoostConfiguration.cmake	Tue Mar 13 10:24:38 2018 +0100
+++ b/Orthanc/Resources/CMake/BoostConfiguration.cmake	Thu Mar 22 16:59:06 2018 +0100
@@ -11,10 +11,22 @@
     list(APPEND ORTHANC_BOOST_COMPONENTS locale)
   endif()
 
-  find_package(Boost
-    COMPONENTS filesystem thread system date_time regex ${ORTHANC_BOOST_COMPONENTS})
+  list(APPEND ORTHANC_BOOST_COMPONENTS filesystem thread system date_time regex)
+  find_package(Boost COMPONENTS "${ORTHANC_BOOST_COMPONENTS}")
 
   if (NOT Boost_FOUND)
+    foreach (item ${ORTHANC_BOOST_COMPONENTS})
+      string(TOUPPER ${item} tmp)
+
+      if (Boost_${tmp}_FOUND)
+        set(tmp2 "found")
+      else()
+        set(tmp2 "missing")
+      endif()
+      
+      message("Boost component ${item} - ${tmp2}")
+    endforeach()
+    
     message(FATAL_ERROR "Unable to locate Boost on this system")
   endif()
 
--- a/Orthanc/Resources/CMake/Compiler.cmake	Tue Mar 13 10:24:38 2018 +0100
+++ b/Orthanc/Resources/CMake/Compiler.cmake	Thu Mar 22 16:59:06 2018 +0100
@@ -180,10 +180,6 @@
 
 
 if (DEFINED ENABLE_PROFILING AND ENABLE_PROFILING)
-  if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
-    message(WARNING "Enabling profiling on a non-debug build will not produce full information")
-  endif()
-
   if (CMAKE_COMPILER_IS_GNUCXX)
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg")
     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pg")
--- a/Orthanc/Resources/CMake/JsonCppConfiguration.cmake	Tue Mar 13 10:24:38 2018 +0100
+++ b/Orthanc/Resources/CMake/JsonCppConfiguration.cmake	Thu Mar 22 16:59:06 2018 +0100
@@ -1,7 +1,18 @@
+set(JSONCPP_CXX11 OFF)
+
 if (STATIC_BUILD OR NOT USE_SYSTEM_JSONCPP)
-  set(JSONCPP_SOURCES_DIR ${CMAKE_BINARY_DIR}/jsoncpp-0.10.5)
-  set(JSONCPP_URL "http://www.orthanc-server.com/downloads/third-party/jsoncpp-0.10.5.tar.gz")
-  set(JSONCPP_MD5 "db146bac5a126ded9bd728ab7b61ed6b")
+  if (USE_LEGACY_JSONCPP)
+    set(JSONCPP_SOURCES_DIR ${CMAKE_BINARY_DIR}/jsoncpp-0.10.6)
+    set(JSONCPP_URL "http://www.orthanc-server.com/downloads/third-party/jsoncpp-0.10.6.tar.gz")
+    set(JSONCPP_MD5 "13d1991d79697df8cadbc25c93e37c83")
+    add_definitions(-DORTHANC_LEGACY_JSONCPP=1)
+  else()
+    set(JSONCPP_SOURCES_DIR ${CMAKE_BINARY_DIR}/jsoncpp-1.8.4)
+    set(JSONCPP_URL "http://www.orthanc-server.com/downloads/third-party/jsoncpp-1.8.4.tar.gz")
+    set(JSONCPP_MD5 "fa47a3ab6b381869b6a5f20811198662")
+    add_definitions(-DORTHANC_LEGACY_JSONCPP=0)
+    set(JSONCPP_CXX11 ON)
+  endif()
 
   DownloadPackage(${JSONCPP_MD5} ${JSONCPP_URL} "${JSONCPP_SOURCES_DIR}")
 
@@ -48,14 +59,24 @@
       JSONCPP_VERSION_MAJOR ${JSONCPP_VERSION_MAJOR1})
     message("JsonCpp major version: ${JSONCPP_VERSION_MAJOR}")
 
-    if ((CMAKE_COMPILER_IS_GNUCXX OR
-          "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") AND 
-        JSONCPP_VERSION_MAJOR GREATER 0)
-      message("Switching to C++11 standard in gcc/clang, as version of JsonCpp is >= 1.0.0")
-      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-deprecated-declarations")
+    if (JSONCPP_VERSION_MAJOR GREATER 0)
+      set(JSONCPP_CXX11 ON)
     endif()
   else()
     message("Unable to detect the major version of JsonCpp, assuming < 1.0.0")
   endif()
+endif()
 
+
+if (JSONCPP_CXX11)
+  # Osimis has encountered problems when this macro is left at its
+  # default value (1000), so we increase this limit
+  # https://gitlab.kitware.com/third-party/jsoncpp/commit/56df2068470241f9043b676bfae415ed62a0c172
+  add_definitions(-DJSONCPP_DEPRECATED_STACK_LIMIT=5000)
+
+  if (CMAKE_COMPILER_IS_GNUCXX OR
+      "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+    message("Switching to C++11 standard in gcc/clang, as version of JsonCpp is >= 1.0.0")
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-deprecated-declarations")
+  endif()
 endif()
--- a/Resources/SyncOrthancFolder.py	Tue Mar 13 10:24:38 2018 +0100
+++ b/Resources/SyncOrthancFolder.py	Thu Mar 22 16:59:06 2018 +0100
@@ -15,6 +15,7 @@
 REPOSITORY = 'https://bitbucket.org/sjodogne/orthanc/raw'
 
 FILES = [
+    'NEWS',
     'Core/ChunkedBuffer.cpp',
     'Core/ChunkedBuffer.h',
     'Core/Enumerations.cpp',
@@ -36,6 +37,7 @@
     'Core/Images/ImageBuffer.h',
     'Core/Images/ImageProcessing.cpp',
     'Core/Images/ImageProcessing.h',
+    'Core/Images/PixelTraits.h',
     'Core/Logging.h',
     'Core/MultiThreading/SharedMessageQueue.cpp',
     'Core/MultiThreading/SharedMessageQueue.h',