changeset 1308:adf234ecaa00 broker

Merge
author Benjamin Golinvaux <bgo@osimis.io>
date Wed, 04 Mar 2020 10:21:54 +0100
parents 8a28a9bf8876 (current diff) d6d56df61715 (diff)
children 1f877e0846fe
files Framework/Deprecated/Loaders/OrthancSeriesVolumeProgressiveLoader.h Framework/Scene2DViewport/LayerHolder.cpp Framework/Scene2DViewport/ViewportController.h Framework/Viewport/SdlViewport.h Framework/Viewport/WebAssemblyViewport.cpp Resources/CMake/OrthancStoneConfiguration.cmake
diffstat 164 files changed, 1639 insertions(+), 627 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/Generic/GuiAdapter.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Applications/Generic/GuiAdapter.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -34,13 +34,10 @@
 #  include "../../Framework/Deprecated/Messages/LockingEmitter.h"
 #endif
 
+#include <Core/Compatibility.h>
+
 namespace OrthancStone
 {
-  void GuiAdapter::RegisterWidget(boost::shared_ptr<IGuiAdapterWidget> widget)
-  {
-    widgets_.push_back(widget);
-  }
-
   std::ostream& operator<<(
     std::ostream& os, const GuiAdapterKeyboardEvent& event)
   {
@@ -200,7 +197,7 @@
     // userData is OnMouseWheelFuncAdapterPayload
     FuncAdapterPayload<GenericFunc>* payload =
       reinterpret_cast<FuncAdapterPayload<GenericFunc>*>(userData);
-    //std::auto_ptr< FuncAdapterPayload<GenericFunc> > deleter(payload);
+    //std::unique_ptr< FuncAdapterPayload<GenericFunc> > deleter(payload);
     bool ret = (*(payload->callback))(time, payload->userData);
     return static_cast<EM_BOOL>(ret);
   }
@@ -219,7 +216,7 @@
     // here
     FuncAdapterPayload<GenericFunc>* payload =
       new FuncAdapterPayload<GenericFunc>();
-    std::auto_ptr<FuncAdapterPayload<GenericFunc> > payloadP(payload);
+    std::unique_ptr<FuncAdapterPayload<GenericFunc> > payloadP(payload);
     payload->canvasId = canvasId;
     payload->callback = func;
     payload->userData = userData;
@@ -244,7 +241,7 @@
       EmscriptenSetCallbackFunc emFunc,
       std::string canvasId, void* userData, bool capture, GenericFunc func)
   {
-    std::auto_ptr<FuncAdapterPayload<GenericFunc> > payload(
+    std::unique_ptr<FuncAdapterPayload<GenericFunc> > payload(
       new FuncAdapterPayload<GenericFunc>()
     );
     payload->canvasId = canvasId;
@@ -267,7 +264,7 @@
       void* userData, GenericFunc func)
   {
     // LOG(ERROR) << "SetAnimationFrameCallback !!!!!! (RequestAnimationFrame)";
-    std::auto_ptr<FuncAdapterPayload<GenericFunc> > payload(
+    std::unique_ptr<FuncAdapterPayload<GenericFunc> > payload(
       new FuncAdapterPayload<GenericFunc>()
     );
     payload->canvasId = "UNDEFINED";
--- a/Applications/Generic/GuiAdapter.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Applications/Generic/GuiAdapter.h	Wed Mar 04 10:21:54 2020 +0100
@@ -233,8 +233,6 @@
       instanceCount = 1;
     }
 
-    void RegisterWidget(boost::shared_ptr<IGuiAdapterWidget> widget);
-    
     /**
       emscripten_set_resize_callback("#window", NULL, false, OnWindowResize);
 
@@ -359,21 +357,5 @@
     deals with this)
     */
     void ViewportsUpdateSize();
-
-    std::vector<boost::weak_ptr<IGuiAdapterWidget> > widgets_;
-
-    template<typename F> void VisitWidgets(F func)
-    {
-      for (size_t i = 0; i < widgets_.size(); i++)
-      {
-        boost::shared_ptr<IGuiAdapterWidget> widget = widgets_[i].lock();
-
-        // TODO: we need to clean widgets!
-        if (widget.get() != NULL)
-        {
-          func(widget);
-        }
-      }
-    }
   };
 }
--- a/Applications/Qt/QCairoWidget.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Applications/Qt/QCairoWidget.h	Wed Mar 04 10:21:54 2020 +0100
@@ -49,10 +49,10 @@
     }
   };
   
-  std::auto_ptr<QImage>         image_;
+  std::unique_ptr<QImage>         image_;
   OrthancStone::CairoSurface    surface_;
   OrthancStone::NativeStoneApplicationContext* context_;
-  std::auto_ptr<StoneObserver>  observer_;
+  std::unique_ptr<StoneObserver>  observer_;
 
 protected:
   virtual void paintEvent(QPaintEvent *event);
--- a/Applications/Qt/QtStoneApplicationRunner.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Applications/Qt/QtStoneApplicationRunner.h	Wed Mar 04 10:21:54 2020 +0100
@@ -33,7 +33,7 @@
   class QtStoneApplicationRunner : public NativeStoneApplicationRunner
   {
   protected:
-    std::auto_ptr<QStoneMainWindow> window_;
+    std::unique_ptr<QStoneMainWindow> window_;
 
   public:
     QtStoneApplicationRunner(MessageBroker& broker,
--- a/Applications/Samples/BasicPetCtFusionApplication.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Applications/Samples/BasicPetCtFusionApplication.h	Wed Mar 04 10:21:54 2020 +0100
@@ -179,9 +179,9 @@
         VolumeImage& petVolume = context.AddSeriesVolume(pet, true /* progressive download */, 1);
 
         // Take the PET volume as the reference for the slices
-        std::auto_ptr<Interactor> interactor(new Interactor(petVolume, VolumeProjection_Axial, false /* don't reverse normal */));
+        std::unique_ptr<Interactor> interactor(new Interactor(petVolume, VolumeProjection_Axial, false /* don't reverse normal */));
 
-        std::auto_ptr<LayeredSceneWidget> widget(new LayeredSceneWidget);
+        std::unique_ptr<LayeredSceneWidget> widget(new LayeredSceneWidget);
         widget->AddLayer(new VolumeImage::LayerFactory(ctVolume));
         widget->AddLayer(new VolumeImage::LayerFactory(petVolume));
         widget->SetSlice(interactor->GetCursor().GetCurrentSlice());
--- a/Applications/Samples/CMakeLists.txt	Wed Mar 04 10:07:37 2020 +0100
+++ b/Applications/Samples/CMakeLists.txt	Wed Mar 04 10:21:54 2020 +0100
@@ -251,6 +251,8 @@
   add_executable(UnitTests
     ${GOOGLE_TEST_SOURCES}
     ${ORTHANC_STONE_ROOT}/UnitTestsSources/GenericToolboxTests.cpp
+    ${ORTHANC_STONE_ROOT}/UnitTestsSources/ImageToolboxTests.cpp
+    ${ORTHANC_STONE_ROOT}/UnitTestsSources/PixelTestPatternsTests.cpp
     ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestCommands.cpp
     ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestMessageBroker.cpp
     ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestStrategy.cpp
--- a/Applications/Samples/LayoutPetCtFusionApplication.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Applications/Samples/LayoutPetCtFusionApplication.h	Wed Mar 04 10:21:54 2020 +0100
@@ -208,7 +208,7 @@
 
       LayeredSceneWidget* CreateWidget()
       {
-        std::auto_ptr<LayeredSceneWidget> widget(new LayeredSceneWidget);
+        std::unique_ptr<LayeredSceneWidget> widget(new LayeredSceneWidget);
         widget->Register(dynamic_cast<WorldSceneWidget::IWorldObserver&>(*this));
         widget->Register(dynamic_cast<LayeredSceneWidget::ISliceObserver&>(*this));
         return widget.release();
@@ -217,7 +217,7 @@
 
       void CreateLayout(BasicApplicationContext& context)
       {
-        std::auto_ptr<OrthancStone::LayoutWidget> layout(new OrthancStone::LayoutWidget);
+        std::unique_ptr<OrthancStone::LayoutWidget> layout(new OrthancStone::LayoutWidget);
         layout->SetBackgroundCleared(true);
         //layout->SetBackgroundColor(255,0,0);
         layout->SetPadding(5);
--- a/Applications/Samples/SampleInteractor.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Applications/Samples/SampleInteractor.h	Wed Mar 04 10:21:54 2020 +0100
@@ -47,7 +47,7 @@
                        VolumeProjection projection, 
                        bool reverse)
       {
-        std::auto_ptr<ParallelSlices> slices(volume.GetGeometry(projection, reverse));
+        std::unique_ptr<ParallelSlices> slices(volume.GetGeometry(projection, reverse));
         cursor_.SetGeometry(*slices);
       }
 
@@ -56,7 +56,7 @@
       {
         if (reverse)
         {
-          std::auto_ptr<ParallelSlices> slices(series.GetGeometry().Reverse());
+          std::unique_ptr<ParallelSlices> slices(series.GetGeometry().Reverse());
           cursor_.SetGeometry(*slices);
         }
         else
--- a/Applications/Samples/SimpleViewer/SimpleViewerApplication.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Applications/Samples/SimpleViewer/SimpleViewerApplication.h	Wed Mar 04 10:21:54 2020 +0100
@@ -81,8 +81,8 @@
   private:
     Tool                                currentTool_;
 
-    std::auto_ptr<MainWidgetInteractor> mainWidgetInteractor_;
-    std::auto_ptr<ThumbnailInteractor>  thumbnailInteractor_;
+    std::unique_ptr<MainWidgetInteractor> mainWidgetInteractor_;
+    std::unique_ptr<ThumbnailInteractor>  thumbnailInteractor_;
     Deprecated::LayoutWidget*                       mainLayout_;
     Deprecated::LayoutWidget*                       thumbnailsLayout_;
     Deprecated::SliceViewerWidget*                  mainWidget_;
@@ -94,7 +94,7 @@
     Deprecated::WidgetViewport*       wasmViewport2_;
 
     Deprecated::IStatusBar*                         statusBar_;
-    std::auto_ptr<Deprecated::SmartLoader>          smartLoader_;
+    std::unique_ptr<Deprecated::SmartLoader>          smartLoader_;
 
     Orthanc::Font                       font_;
 
--- a/Applications/Samples/SimpleViewerApplicationSingleFile.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Applications/Samples/SimpleViewerApplicationSingleFile.h	Wed Mar 04 10:21:54 2020 +0100
@@ -239,8 +239,8 @@
       };
 
       Tool                                 currentTool_;
-      std::auto_ptr<MainWidgetInteractor>  mainWidgetInteractor_;
-      std::auto_ptr<ThumbnailInteractor>   thumbnailInteractor_;
+      std::unique_ptr<MainWidgetInteractor>  mainWidgetInteractor_;
+      std::unique_ptr<ThumbnailInteractor>   thumbnailInteractor_;
       Deprecated::LayoutWidget*                        mainLayout_;
       Deprecated::LayoutWidget*                        thumbnailsLayout_;
       std::vector<boost::shared_ptr<Deprecated::SliceViewerWidget> >      thumbnails_;
@@ -253,7 +253,7 @@
       Deprecated::WidgetViewport*        wasmViewport2_;
 
       Deprecated::IStatusBar*                          statusBar_;
-      std::auto_ptr<Deprecated::SmartLoader>           smartLoader_;
+      std::unique_ptr<Deprecated::SmartLoader>           smartLoader_;
 
       Orthanc::Font                        font_;
 
--- a/Applications/Samples/SingleFrameApplication.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Applications/Samples/SingleFrameApplication.h	Wed Mar 04 10:21:54 2020 +0100
@@ -193,7 +193,7 @@
       }
 
       boost::shared_ptr<Deprecated::SliceViewerWidget>  widget_;
-      std::auto_ptr<Interactor>         mainWidgetInteractor_;
+      std::unique_ptr<Interactor>         mainWidgetInteractor_;
       boost::shared_ptr<Deprecated::DicomSeriesVolumeSlicer> source_;
       unsigned int                      slice_;
 
@@ -243,6 +243,7 @@
         boost::shared_ptr<Deprecated::DicomSeriesVolumeSlicer> layer(new Deprecated::DicomSeriesVolumeSlicer);
         layer->Connect(context->GetOrthancApiClient());
         source_ = layer;
+
         layer->LoadFrame(instance, frame);
         Register<Deprecated::IVolumeSlicer::GeometryReadyMessage>(*layer, &SingleFrameApplication::OnMainWidgetGeometryReady);
         widget_->AddLayer(layer);
--- a/Applications/Samples/SingleFrameEditorApplication.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Applications/Samples/SingleFrameEditorApplication.h	Wed Mar 04 10:21:54 2020 +0100
@@ -501,7 +501,7 @@
         interactor_.SetMaskLayer(maskLayer_);
 
         {
-          std::auto_ptr<Orthanc::ImageAccessor> renderedTextAlpha(TextRenderer::Render(Orthanc::EmbeddedResources::UBUNTU_FONT, 100,
+          std::unique_ptr<Orthanc::ImageAccessor> renderedTextAlpha(TextRenderer::Render(Orthanc::EmbeddedResources::UBUNTU_FONT, 100,
                                                                                     "%öÇaA&#"));
           RadiographyLayer& layer = scene_->LoadAlphaBitmap(renderedTextAlpha.release(), NULL);
           dynamic_cast<RadiographyAlphaLayer&>(layer).SetForegroundValue(200.0f * 256.0f);
--- a/Applications/Samples/SingleVolumeApplication.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Applications/Samples/SingleVolumeApplication.h	Wed Mar 04 10:21:54 2020 +0100
@@ -170,10 +170,10 @@
           throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
         }
 
-        std::auto_ptr<SliceViewerWidget> widget(new SliceViewerWidget);
+        std::unique_ptr<SliceViewerWidget> widget(new SliceViewerWidget);
 
 #if 1
-        std::auto_ptr<OrthancVolumeImage> volume(new OrthancVolumeImage(context.GetWebService(), true));
+        std::unique_ptr<OrthancVolumeImage> volume(new OrthancVolumeImage(context.GetWebService(), true));
         if (series.empty())
         {
           volume->ScheduleLoadInstance(instance);
@@ -206,14 +206,14 @@
           widget->SetLayerStyle(0, s);
         }
 #else
-        std::auto_ptr<OrthancVolumeImage> ct(new OrthancVolumeImage(context_->GetWebService(), false));
+        std::unique_ptr<OrthancVolumeImage> ct(new OrthancVolumeImage(context_->GetWebService(), false));
         //ct->ScheduleLoadSeries("15a6f44a-ac7b88fe-19c462d9-dddd918e-b01550d8");  // 0178023P
         //ct->ScheduleLoadSeries("dd069910-4f090474-7d2bba07-e5c10783-f9e4fb1d");
         //ct->ScheduleLoadSeries("a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa");  // IBA
         //ct->ScheduleLoadSeries("03677739-1d8bca40-db1daf59-d74ff548-7f6fc9c0");  // 0522c0001 TCIA
         ct->ScheduleLoadSeries("295e8a13-dfed1320-ba6aebb2-9a13e20f-1b3eb953");  // Captain
         
-        std::auto_ptr<OrthancVolumeImage> pet(new OrthancVolumeImage(context_->GetWebService(), true));
+        std::unique_ptr<OrthancVolumeImage> pet(new OrthancVolumeImage(context_->GetWebService(), true));
         //pet->ScheduleLoadSeries("48d2997f-8e25cd81-dd715b64-bd79cdcc-e8fcee53");  // 0178023P
         //pet->ScheduleLoadSeries("aabad2e7-80702b5d-e599d26c-4f13398e-38d58a9e");
         //pet->ScheduleLoadInstance("830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb"); // IBA 1
@@ -223,7 +223,7 @@
         pet->ScheduleLoadInstance("f080888c-0ab7528a-f7d9c28c-84980eb1-ff3b0ae6");  // Captain 1
         //pet->ScheduleLoadInstance("4f78055b-6499a2c5-1e089290-394acc05-3ec781c1");  // Captain 2
 
-        std::auto_ptr<StructureSetLoader> rtStruct(new StructureSetLoader(context_->GetWebService()));
+        std::unique_ptr<StructureSetLoader> rtStruct(new StructureSetLoader(context_->GetWebService()));
         //rtStruct->ScheduleLoadInstance("c2ebc17b-6b3548db-5e5da170-b8ecab71-ea03add3");  // 0178023P
         //rtStruct->ScheduleLoadInstance("54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9");  // IBA
         //rtStruct->ScheduleLoadInstance("17cd032b-ad92a438-ca05f06a-f9e96668-7e3e9e20");  // 0522c0001 TCIA
--- a/Applications/Samples/StoneSampleCommands_generated.hpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Applications/Samples/StoneSampleCommands_generated.hpp	Wed Mar 04 10:21:54 2020 +0100
@@ -18,7 +18,7 @@
 //#define STONEGEN_NO_CPP11 1
 
 #ifdef STONEGEN_NO_CPP11
-#define StoneSmartPtr std::auto_ptr
+#define StoneSmartPtr std::unique_ptr
 #else 
 #define StoneSmartPtr std::unique_ptr
 #endif 
--- a/Applications/Samples/SynchronizedSeriesApplication.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Applications/Samples/SynchronizedSeriesApplication.h	Wed Mar 04 10:21:54 2020 +0100
@@ -40,12 +40,12 @@
       LayeredSceneWidget* CreateSeriesWidget(BasicApplicationContext& context,
                                              const std::string& series)
       {
-        std::auto_ptr<ISeriesLoader> loader
+        std::unique_ptr<ISeriesLoader> loader
           (new OrthancSeriesLoader(context.GetWebService().GetConnection(), series));
 
-        std::auto_ptr<SampleInteractor> interactor(new SampleInteractor(*loader, false));
+        std::unique_ptr<SampleInteractor> interactor(new SampleInteractor(*loader, false));
 
-        std::auto_ptr<LayeredSceneWidget> widget(new LayeredSceneWidget);
+        std::unique_ptr<LayeredSceneWidget> widget(new LayeredSceneWidget);
         widget->AddLayer(new SeriesFrameRendererFactory(loader.release(), false));
         widget->SetSlice(interactor->GetCursor().GetCurrentSlice());
         widget->SetInteractor(*interactor);
@@ -83,19 +83,19 @@
           throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
         }
 
-        std::auto_ptr<LayeredSceneWidget> a(CreateSeriesWidget(context, parameters["a"].as<std::string>()));
-        std::auto_ptr<LayeredSceneWidget> b(CreateSeriesWidget(context, parameters["b"].as<std::string>()));
-        std::auto_ptr<LayeredSceneWidget> c(CreateSeriesWidget(context, parameters["c"].as<std::string>()));
+        std::unique_ptr<LayeredSceneWidget> a(CreateSeriesWidget(context, parameters["a"].as<std::string>()));
+        std::unique_ptr<LayeredSceneWidget> b(CreateSeriesWidget(context, parameters["b"].as<std::string>()));
+        std::unique_ptr<LayeredSceneWidget> c(CreateSeriesWidget(context, parameters["c"].as<std::string>()));
 
         ReferenceLineFactory::Configure(*a, *b);
         ReferenceLineFactory::Configure(*a, *c);
         ReferenceLineFactory::Configure(*b, *c);
 
-        std::auto_ptr<LayoutWidget> layout(new LayoutWidget);
+        std::unique_ptr<LayoutWidget> layout(new LayoutWidget);
         layout->SetPadding(5);
         layout->AddWidget(a.release());
 
-        std::auto_ptr<LayoutWidget> layoutB(new LayoutWidget);
+        std::unique_ptr<LayoutWidget> layoutB(new LayoutWidget);
         layoutB->SetVertical();
         layoutB->SetPadding(5);
         layoutB->AddWidget(b.release());
--- a/Applications/Samples/TestPatternApplication.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Applications/Samples/TestPatternApplication.h	Wed Mar 04 10:21:54 2020 +0100
@@ -49,7 +49,7 @@
       {
         using namespace OrthancStone;
 
-        std::auto_ptr<LayoutWidget> layout(new LayoutWidget);
+        std::unique_ptr<LayoutWidget> layout(new LayoutWidget);
         layout->SetPadding(10);
         layout->SetBackgroundCleared(true);
         layout->AddWidget(new TestCairoWidget(parameters["animate"].as<bool>()));
--- a/Applications/Samples/rt-viewer-demo/main.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Applications/Samples/rt-viewer-demo/main.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -506,14 +506,14 @@
         SliceViewerWidget& widget, StructureSetLoader& loader);
 
       SliceViewerWidget* CreateDoseCtWidget(
-        std::auto_ptr<OrthancVolumeImage>& ct,
-        std::auto_ptr<OrthancVolumeImage>& dose,
-        std::auto_ptr<StructureSetLoader>& structLoader,
+        std::unique_ptr<OrthancVolumeImage>& ct,
+        std::unique_ptr<OrthancVolumeImage>& dose,
+        std::unique_ptr<StructureSetLoader>& structLoader,
         VolumeProjection projection);
 
       void AddCtLayer(SliceViewerWidget& widget, OrthancVolumeImage& volume);
 
-      std::auto_ptr<Interactor>         mainWidgetInteractor_;
+      std::unique_ptr<Interactor>         mainWidgetInteractor_;
       const DicomSeriesVolumeSlicer*    source_;
       unsigned int                      slice_;
 
@@ -521,9 +521,9 @@
       std::string                                        doseInstance_;
       std::string                                        doseSeries_;
       std::string                                        structInstance_;
-      std::auto_ptr<OrthancStone::OrthancVolumeImage>    dose_;
-      std::auto_ptr<OrthancStone::OrthancVolumeImage>    ct_;
-      std::auto_ptr<OrthancStone::StructureSetLoader>    struct_;
+      std::unique_ptr<OrthancStone::OrthancVolumeImage>    dose_;
+      std::unique_ptr<OrthancStone::OrthancVolumeImage>    ct_;
+      std::unique_ptr<OrthancStone::StructureSetLoader>    struct_;
 
     public:
       RtViewerDemoApplication(MessageBroker& broker) :
@@ -729,7 +729,7 @@
         (ct_, dose_, struct_, OrthancStone::VolumeProjection_Axial);
         mainWidget_->AddWidget(axialWidget);
                
-        std::auto_ptr<OrthancStone::LayoutWidget> subLayout(
+        std::unique_ptr<OrthancStone::LayoutWidget> subLayout(
           new OrthancStone::LayoutWidget("main-layout"));
         subLayout->SetVertical();
         subLayout->SetPadding(5);
@@ -774,12 +774,12 @@
     }
 
     SliceViewerWidget* RtViewerDemoApplication::CreateDoseCtWidget(
-      std::auto_ptr<OrthancVolumeImage>& ct,
-      std::auto_ptr<OrthancVolumeImage>& dose,
-      std::auto_ptr<StructureSetLoader>& structLoader,
+      std::unique_ptr<OrthancVolumeImage>& ct,
+      std::unique_ptr<OrthancVolumeImage>& dose,
+      std::unique_ptr<StructureSetLoader>& structLoader,
       VolumeProjection projection)
     {
-      std::auto_ptr<OrthancStone::SliceViewerWidget> widget(
+      std::unique_ptr<OrthancStone::SliceViewerWidget> widget(
         new OrthancStone::SliceViewerWidget(IObserver::GetBroker(),
           "ct-dose-widget"));
 
--- a/Applications/Sdl/SdlCairoSurface.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Applications/Sdl/SdlCairoSurface.h	Wed Mar 04 10:21:54 2020 +0100
@@ -27,8 +27,9 @@
 #include "../../Framework/Wrappers/CairoSurface.h"
 #include "../../Framework/Deprecated/Viewport/IViewport.h"
 
+#include <Core/Compatibility.h>
+
 #include <SDL_render.h>
-
 #include <boost/thread/mutex.hpp>
 
 namespace OrthancStone
@@ -36,7 +37,7 @@
   class SdlCairoSurface : public boost::noncopyable
   {
   private:
-    std::auto_ptr<CairoSurface>  cairoSurface_;
+    std::unique_ptr<CairoSurface>  cairoSurface_;
     SdlWindow&                   window_;
     SDL_Surface*                 sdlSurface_;
 
--- a/Applications/Sdl/SdlOrthancSurface.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Applications/Sdl/SdlOrthancSurface.h	Wed Mar 04 10:21:54 2020 +0100
@@ -25,7 +25,9 @@
 
 #include "../../Framework/Viewport/SdlWindow.h"
 
+#include <Core/Compatibility.h>
 #include <Core/Images/ImageAccessor.h>
+
 #include <boost/thread/mutex.hpp>
 
 namespace OrthancStone
@@ -33,7 +35,7 @@
   class SdlOrthancSurface : public boost::noncopyable
   {
   private:
-    std::auto_ptr<Orthanc::ImageAccessor>  image_;
+    std::unique_ptr<Orthanc::ImageAccessor>  image_;
     SdlWindow&                             window_;
     SDL_Surface*                           sdlSurface_;
 
--- a/Framework/Deprecated/Layers/ColorFrameRenderer.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Layers/ColorFrameRenderer.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -29,7 +29,7 @@
 {
   OrthancStone::CairoSurface* ColorFrameRenderer::GenerateDisplay(const RenderStyle& style)
   {
-    std::auto_ptr<OrthancStone::CairoSurface> display
+    std::unique_ptr<OrthancStone::CairoSurface> display
       (new OrthancStone::CairoSurface(frame_->GetWidth(), frame_->GetHeight(), false /* no alpha */));
 
     Orthanc::ImageAccessor target;
--- a/Framework/Deprecated/Layers/ColorFrameRenderer.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Layers/ColorFrameRenderer.h	Wed Mar 04 10:21:54 2020 +0100
@@ -28,7 +28,7 @@
   class ColorFrameRenderer : public FrameRenderer
   {
   private:
-    std::auto_ptr<Orthanc::ImageAccessor>   frame_;  // In RGB24
+    std::unique_ptr<Orthanc::ImageAccessor>   frame_;  // In RGB24
 
   protected:
     virtual OrthancStone::CairoSurface* GenerateDisplay(const RenderStyle& style);
--- a/Framework/Deprecated/Layers/FrameRenderer.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Layers/FrameRenderer.h	Wed Mar 04 10:21:54 2020 +0100
@@ -35,7 +35,7 @@
     double                        pixelSpacingY_;
     RenderStyle                   style_;
     bool                          isFullQuality_;
-    std::auto_ptr<OrthancStone::CairoSurface>   display_;
+    std::unique_ptr<OrthancStone::CairoSurface>   display_;
 
   protected:
     virtual OrthancStone::CairoSurface* GenerateDisplay(const RenderStyle& style) = 0;
--- a/Framework/Deprecated/Layers/GrayscaleFrameRenderer.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Layers/GrayscaleFrameRenderer.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -30,7 +30,7 @@
   {
     assert(frame_->GetFormat() == Orthanc::PixelFormat_Float32);
 
-    std::auto_ptr<OrthancStone::CairoSurface> result;
+    std::unique_ptr<OrthancStone::CairoSurface> result;
 
     float windowCenter, windowWidth;
     style.ComputeWindowing(windowCenter, windowWidth,
--- a/Framework/Deprecated/Layers/GrayscaleFrameRenderer.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Layers/GrayscaleFrameRenderer.h	Wed Mar 04 10:21:54 2020 +0100
@@ -29,7 +29,7 @@
   class GrayscaleFrameRenderer : public FrameRenderer
   {
   private:
-    std::auto_ptr<Orthanc::ImageAccessor>   frame_;  // In Float32
+    std::unique_ptr<Orthanc::ImageAccessor>   frame_;  // In Float32
     float                                   defaultWindowCenter_;
     float                                   defaultWindowWidth_;
     Orthanc::PhotometricInterpretation      photometric_;
--- a/Framework/Deprecated/Layers/SeriesFrameRendererFactory.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Layers/SeriesFrameRendererFactory.h	Wed Mar 04 10:21:54 2020 +0100
@@ -30,11 +30,11 @@
   class SeriesFrameRendererFactory : public ILayerRendererFactory
   {
   private:
-    std::auto_ptr<ISeriesLoader>  loader_;
+    std::unique_ptr<ISeriesLoader>  loader_;
     size_t                        currentFrame_;
     bool                          fast_;
 
-    std::auto_ptr<OrthancPlugins::IDicomDataset>  currentDataset_;
+    std::unique_ptr<OrthancPlugins::IDicomDataset>  currentDataset_;
 
     void ReadCurrentFrameDataset(size_t frame);
 
--- a/Framework/Deprecated/Layers/SingleFrameRendererFactory.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Layers/SingleFrameRendererFactory.h	Wed Mar 04 10:21:54 2020 +0100
@@ -30,7 +30,7 @@
   {
   private:
     OrthancPlugins::IOrthancConnection&           orthanc_;
-    std::auto_ptr<OrthancPlugins::IDicomDataset>  dicom_;
+    std::unique_ptr<OrthancPlugins::IDicomDataset>  dicom_;
 
     std::string           instance_;
     unsigned int          frame_;
--- a/Framework/Deprecated/Loaders/DicomStructureSetLoader.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Loaders/DicomStructureSetLoader.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -140,7 +140,7 @@
       const std::string instanceId = lookup[0]["ID"].asString();
 
       {
-        std::auto_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand);
+        std::unique_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand);
         command->SetHttpHeader("Accept-Encoding", "gzip");
         std::string uri = "/instances/" + instanceId + "/tags";
         command->SetUri(uri);
@@ -227,7 +227,7 @@
       for (std::set<std::string>::const_iterator
         it = nonEmptyInstances.begin(); it != nonEmptyInstances.end(); ++it)
       {
-        std::auto_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand);
+        std::unique_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand);
         command->SetUri("/tools/lookup");
         command->SetMethod(Orthanc::HttpMethod_Post);
         command->SetBody(*it);
@@ -293,7 +293,7 @@
     {
       assert(isValid_);
 
-      std::auto_ptr<OrthancStone::PolylineSceneLayer> layer(new OrthancStone::PolylineSceneLayer);
+      std::unique_ptr<OrthancStone::PolylineSceneLayer> layer(new OrthancStone::PolylineSceneLayer);
       layer->SetThickness(2);
 
       for (size_t i = 0; i < content_.GetStructuresCount(); i++)
@@ -377,7 +377,7 @@
     initiallyVisibleStructures_ = initiallyVisibleStructures;
 
     {
-      std::auto_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand);
+      std::unique_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand);
       command->SetHttpHeader("Accept-Encoding", "gzip");
 
       std::string uri = "/instances/" + instanceId + "/tags?ignore-length=3006-0050";
--- a/Framework/Deprecated/Loaders/DicomStructureSetLoader.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Loaders/DicomStructureSetLoader.h	Wed Mar 04 10:21:54 2020 +0100
@@ -42,7 +42,7 @@
     class LookupInstance;          // 2nd state
     class LoadStructure;           // 1st state
     
-    std::auto_ptr<OrthancStone::DicomStructureSet>  content_;
+    std::unique_ptr<OrthancStone::DicomStructureSet>  content_;
     uint64_t                          revision_;
     std::string                       instanceId_;
     unsigned int                      countProcessedInstances_;
--- a/Framework/Deprecated/Loaders/DicomStructureSetLoader2.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Loaders/DicomStructureSetLoader2.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -81,7 +81,7 @@
 
   void DicomStructureSetLoader2::LoadInstance(const std::string& instanceId)
   {
-    std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand);
+    std::unique_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand);
     command->SetHttpHeader("Accept-Encoding", "gzip");
 
     std::string uri = "/instances/" + instanceId + "/tags?ignore-length=3006-0050";
--- a/Framework/Deprecated/Loaders/LoaderStateMachine.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Loaders/LoaderStateMachine.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -47,7 +47,7 @@
   {
     LOG(TRACE) << "LoaderStateMachine(" << std::hex << this << std::dec << ")::Schedule()";
 
-    std::auto_ptr<OrthancStone::OracleCommandBase> protection(command);
+    std::unique_ptr<OrthancStone::OracleCommandBase> protection(command);
 
     if (command == NULL)
     {
--- a/Framework/Deprecated/Loaders/OrthancMultiframeVolumeLoader.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Loaders/OrthancMultiframeVolumeLoader.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -29,7 +29,7 @@
   class OrthancMultiframeVolumeLoader::LoadRTDoseGeometry : public LoaderStateMachine::State
   {
   private:
-    std::auto_ptr<Orthanc::DicomMap>  dicom_;
+    std::unique_ptr<Orthanc::DicomMap>  dicom_;
 
   public:
     LoadRTDoseGeometry(OrthancMultiframeVolumeLoader& that,
@@ -90,7 +90,7 @@
         throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
       }
 
-      std::auto_ptr<Orthanc::DicomMap> dicom(new Orthanc::DicomMap);
+      std::unique_ptr<Orthanc::DicomMap> dicom(new Orthanc::DicomMap);
       dicom->FromDicomAsJson(body);
 
       if (OrthancStone::StringToSopClassUid(GetSopClassUid(*dicom)) == OrthancStone::SopClassUid_RTDose)
@@ -98,7 +98,7 @@
         // Download the "Grid Frame Offset Vector" DICOM tag, that is
         // mandatory for RT-DOSE, but is too long to be returned by default
           
-        std::auto_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand);
+        std::unique_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand);
         command->SetUri("/instances/" + loader.GetInstanceId() + "/content/" +
                         Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR.Format());
         command->AcquirePayload(new LoadRTDoseGeometry(loader, dicom.release()));
@@ -171,7 +171,7 @@
         transferSyntaxUid_ == "1.2.840.10008.1.2.1" ||
         transferSyntaxUid_ == "1.2.840.10008.1.2.2")
     {
-      std::auto_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand);
+      std::unique_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand);
       command->SetHttpHeader("Accept-Encoding", "gzip");
       command->SetUri("/instances/" + instanceId_ + "/content/" +
                       Orthanc::DICOM_TAG_PIXEL_DATA.Format() + "/0");
@@ -345,7 +345,6 @@
     {
       OrthancStone::ImageBuffer3D& target = volume_->GetPixelData();
 
-      const uint64_t bpp = target.GetBytesPerPixel();
       const uint64_t width = target.GetWidth();
       const uint64_t height = target.GetHeight();
       const uint64_t depth = target.GetDepth();
@@ -563,7 +562,7 @@
     instanceId_ = instanceId;
 
     {
-      std::auto_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand);
+      std::unique_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand);
       command->SetHttpHeader("Accept-Encoding", "gzip");
       command->SetUri("/instances/" + instanceId + "/tags");
       command->AcquirePayload(new LoadGeometry(*this));
@@ -571,7 +570,7 @@
     }
 
     {
-      std::auto_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand);
+      std::unique_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand);
       command->SetUri("/instances/" + instanceId + "/metadata/TransferSyntax");
       command->AcquirePayload(new LoadTransferSyntax(*this));
       Schedule(command.release());
--- a/Framework/Deprecated/Loaders/OrthancSeriesVolumeProgressiveLoader.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Loaders/OrthancSeriesVolumeProgressiveLoader.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -271,11 +271,11 @@
         throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
       }
 
-      std::auto_ptr<OrthancStone::OracleCommandBase> command;
+      std::unique_ptr<OrthancStone::OracleCommandBase> command;
         
       if (quality == BEST_QUALITY)
       {
-        std::auto_ptr<OrthancStone::GetOrthancImageCommand> tmp(new OrthancStone::GetOrthancImageCommand);
+        std::unique_ptr<OrthancStone::GetOrthancImageCommand> tmp(new OrthancStone::GetOrthancImageCommand);
         // TODO: review the following comment. 
         // - Commented out by bgo on 2019-07-19 | reason: Alain has seen cases 
         //   where gzipping the uint16 image took 11 sec to produce 5mb. 
@@ -291,7 +291,7 @@
       }
       else
       {
-        std::auto_ptr<OrthancStone::GetOrthancWebViewerJpegCommand> tmp(new OrthancStone::GetOrthancWebViewerJpegCommand);
+        std::unique_ptr<OrthancStone::GetOrthancWebViewerJpegCommand> tmp(new OrthancStone::GetOrthancWebViewerJpegCommand);
         // TODO: review the following comment. Commented out by bgo on 2019-07-19
         // (gzip for jpeg seems overkill)
         //tmp->SetHttpHeader("Accept-Encoding", "gzip");
@@ -337,7 +337,7 @@
         Orthanc::DicomMap dicom;
         dicom.FromDicomAsJson(body[instances[i]]);
 
-        std::auto_ptr<OrthancStone::DicomInstanceParameters> instance(new OrthancStone::DicomInstanceParameters(dicom));
+        std::unique_ptr<OrthancStone::DicomInstanceParameters> instance(new OrthancStone::DicomInstanceParameters(dicom));
         instance->SetOrthancInstanceIdentifier(instances[i]);
 
         // the 3D plane corresponding to the slice
@@ -487,7 +487,7 @@
     {
       active_ = true;
 
-      std::auto_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand);
+      std::unique_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand);
       command->SetUri("/series/" + seriesId + "/instances-tags");
 
 //      LOG(TRACE) << "OrthancSeriesVolumeProgressiveLoader::LoadSeries about to call oracle_.Schedule";
--- a/Framework/Deprecated/Loaders/OrthancSeriesVolumeProgressiveLoader.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Loaders/OrthancSeriesVolumeProgressiveLoader.h	Wed Mar 04 10:21:54 2020 +0100
@@ -70,7 +70,7 @@
 
       void CheckSliceIndex(size_t index) const;
 
-      std::auto_ptr<OrthancStone::VolumeImageGeometry>     geometry_;
+      std::unique_ptr<OrthancStone::VolumeImageGeometry>     geometry_;
       std::vector<OrthancStone::DicomInstanceParameters*>  slices_;
       std::vector<uint64_t>                  slicesRevision_;
 
@@ -113,8 +113,8 @@
     unsigned int                                  simultaneousDownloads_;
     SeriesGeometry                                seriesGeometry_;
     boost::shared_ptr<OrthancStone::DicomVolumeImage>           volume_;
-    std::auto_ptr<OrthancStone::IFetchingItemsSorter::IFactory> sorter_;
-    std::auto_ptr<OrthancStone::IFetchingStrategy>              strategy_;
+    std::unique_ptr<OrthancStone::IFetchingItemsSorter::IFactory> sorter_;
+    std::unique_ptr<OrthancStone::IFetchingStrategy>              strategy_;
     std::vector<unsigned int>                     slicesQuality_;
     bool                                          volumeImageReadyInHighQuality_;
 
--- a/Framework/Deprecated/SmartLoader.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/SmartLoader.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -61,7 +61,7 @@
     };
     
     unsigned int                    sliceIndex_;
-    std::auto_ptr<Slice>            slice_;
+    std::unique_ptr<Slice>            slice_;
     boost::shared_ptr<Orthanc::ImageAccessor>   image_;
     SliceImageQuality               effectiveQuality_;
     CachedSliceStatus               status_;
@@ -191,7 +191,7 @@
 
     cachedSlices_[sliceKeyId] = boost::shared_ptr<CachedSlice>(cachedSlice);
 
-    std::auto_ptr<IVolumeSlicer> layerSource(new DicomSeriesVolumeSlicer);
+    std::unique_ptr<IVolumeSlicer> layerSource(new DicomSeriesVolumeSlicer);
     dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->Connect(orthancApiClient_);
     dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->SetImageQuality(imageQuality_);
     Register<IVolumeSlicer::GeometryReadyMessage>(*layerSource, &SmartLoader::OnLayerGeometryReady);
--- a/Framework/Deprecated/Toolbox/BaseWebService.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Toolbox/BaseWebService.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -37,9 +37,9 @@
   class BaseWebService::BaseWebServicePayload : public Orthanc::IDynamicObject
   {
   private:
-    std::auto_ptr< MessageHandler<IWebService::HttpRequestSuccessMessage> >   userSuccessHandler_;
-    std::auto_ptr< MessageHandler<IWebService::HttpRequestErrorMessage> >     userFailureHandler_;
-    std::auto_ptr< Orthanc::IDynamicObject>                                   userPayload_;
+    std::unique_ptr< MessageHandler<IWebService::HttpRequestSuccessMessage> >   userSuccessHandler_;
+    std::unique_ptr< MessageHandler<IWebService::HttpRequestErrorMessage> >     userFailureHandler_;
+    std::unique_ptr< Orthanc::IDynamicObject>                                   userPayload_;
 
   public:
     BaseWebServicePayload(MessageHandler<IWebService::HttpRequestSuccessMessage>* userSuccessHandler,
--- a/Framework/Deprecated/Toolbox/DicomFrameConverter.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Toolbox/DicomFrameConverter.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -174,7 +174,7 @@
   }
     
 
-  void DicomFrameConverter::ConvertFrameInplace(std::auto_ptr<Orthanc::ImageAccessor>& source) const
+  void DicomFrameConverter::ConvertFrameInplace(std::unique_ptr<Orthanc::ImageAccessor>& source) const
   {
     assert(sizeof(float) == 4);
 
@@ -210,7 +210,7 @@
     if (sourceFormat == Orthanc::PixelFormat_RGB24)
     {
       // This is the case of a color image. No conversion has to be done (*)
-      std::auto_ptr<Orthanc::Image> converted(new Orthanc::Image(Orthanc::PixelFormat_RGB24, 
+      std::unique_ptr<Orthanc::Image> converted(new Orthanc::Image(Orthanc::PixelFormat_RGB24, 
                                                                  source.GetWidth(), 
                                                                  source.GetHeight(),
                                                                  false));
@@ -224,7 +224,7 @@
              sourceFormat == Orthanc::PixelFormat_SignedGrayscale16);
 
       // This is the case of a grayscale frame. Convert it to Float32.
-      std::auto_ptr<Orthanc::Image> converted(new Orthanc::Image(Orthanc::PixelFormat_Float32, 
+      std::unique_ptr<Orthanc::Image> converted(new Orthanc::Image(Orthanc::PixelFormat_Float32, 
                                                                  source.GetWidth(), 
                                                                  source.GetHeight(),
                                                                  false));
--- a/Framework/Deprecated/Toolbox/DicomFrameConverter.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Toolbox/DicomFrameConverter.h	Wed Mar 04 10:21:54 2020 +0100
@@ -22,6 +22,7 @@
 #pragma once
 
 #include <Plugins/Samples/Common/IDicomDataset.h>
+#include <Core/Compatibility.h>
 #include <Core/DicomFormat/DicomMap.h>
 #include <Core/Images/ImageAccessor.h>
 
@@ -63,7 +64,7 @@
     {
       // TODO: check whether this dtor is called or not
       // An MSVC warning explains that declaring an
-      // std::auto_ptr with a forward-declared type
+      // std::unique_ptr with a forward-declared type
       // prevents its dtor from being called. Does not
       // seem an issue here (only POD types inside), but
       // definitely something to keep an eye on.
@@ -157,7 +158,7 @@
       return rescaleSlope_;
     }
 
-    void ConvertFrameInplace(std::auto_ptr<Orthanc::ImageAccessor>& source) const;
+    void ConvertFrameInplace(std::unique_ptr<Orthanc::ImageAccessor>& source) const;
 
     Orthanc::ImageAccessor* ConvertFrame(const Orthanc::ImageAccessor& source) const;
 
--- a/Framework/Deprecated/Toolbox/MessagingToolbox.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Toolbox/MessagingToolbox.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -251,7 +251,7 @@
           throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
       }
       
-      std::auto_ptr<Orthanc::PngReader> result(new Orthanc::PngReader);
+      std::unique_ptr<Orthanc::PngReader> result(new Orthanc::PngReader);
       result->ReadFromMemory(compressed);
 
       if (targetFormat == Orthanc::PixelFormat_SignedGrayscale16)
@@ -328,7 +328,7 @@
       std::string jpeg;
       Orthanc::Toolbox::DecodeBase64(jpeg, info["PixelData"].asString());
 
-      std::auto_ptr<Orthanc::JpegReader> reader(new Orthanc::JpegReader);
+      std::unique_ptr<Orthanc::JpegReader> reader(new Orthanc::JpegReader);
       reader->ReadFromMemory(jpeg);
 
       if (reader->GetFormat() == Orthanc::PixelFormat_RGB24)  // This is a color image
@@ -386,7 +386,7 @@
       }
 
       // Decode a grayscale JPEG 8bpp image coming from the Web viewer
-      std::auto_ptr<Orthanc::ImageAccessor> image
+      std::unique_ptr<Orthanc::ImageAccessor> image
         (new Orthanc::Image(targetFormat, reader->GetWidth(), reader->GetHeight(), false));
 
       float scaling = static_cast<float>(stretchHigh - stretchLow) / 255.0f;
--- a/Framework/Deprecated/Toolbox/OrthancApiClient.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Toolbox/OrthancApiClient.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -68,11 +68,12 @@
   class OrthancApiClient::WebServicePayload : public Orthanc::IDynamicObject
   {
   private:
-    std::auto_ptr< MessageHandler<EmptyResponseReadyMessage> >             emptyHandler_;
-    std::auto_ptr< MessageHandler<JsonResponseReadyMessage> >              jsonHandler_;
-    std::auto_ptr< MessageHandler<BinaryResponseReadyMessage> >            binaryHandler_;
-    std::auto_ptr< MessageHandler<IWebService::HttpRequestErrorMessage> >  failureHandler_;
-    std::auto_ptr< Orthanc::IDynamicObject >                               userPayload_;
+    std::unique_ptr< MessageHandler<EmptyResponseReadyMessage> >             emptyHandler_;
+    std::unique_ptr< MessageHandler<JsonResponseReadyMessage> >              jsonHandler_;
+    std::unique_ptr< MessageHandler<BinaryResponseReadyMessage> >            binaryHandler_;
+    std::unique_ptr< MessageHandler<IWebService::HttpRequestErrorMessage> >  failureHandler_;
+    std::unique_ptr< Orthanc::IDynamicObject >                               userPayload_;
+
     void NotifyConversionError(const IWebService::HttpRequestSuccessMessage& message) const
     {
       if (failureHandler_.get() != NULL)
--- a/Framework/Deprecated/Toolbox/OrthancSlicesLoader.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Toolbox/OrthancSlicesLoader.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -128,7 +128,7 @@
 
     static Operation* DownloadInstanceGeometry(const std::string& instanceId)
     {
-      std::auto_ptr<Operation> operation(new Operation(Mode_InstanceGeometry));
+      std::unique_ptr<Operation> operation(new Operation(Mode_InstanceGeometry));
       operation->instanceId_ = instanceId;
       return operation.release();
     }
@@ -136,7 +136,7 @@
     static Operation* DownloadFrameGeometry(const std::string& instanceId,
                                             unsigned int frame)
     {
-      std::auto_ptr<Operation> operation(new Operation(Mode_FrameGeometry));
+      std::unique_ptr<Operation> operation(new Operation(Mode_FrameGeometry));
       operation->instanceId_ = instanceId;
       operation->frame_ = frame;
       return operation.release();
@@ -146,7 +146,7 @@
                                          const Slice&  slice,
                                          SliceImageQuality quality)
     {
-      std::auto_ptr<Operation> tmp(new Operation(Mode_LoadImage));
+      std::unique_ptr<Operation> tmp(new Operation(Mode_LoadImage));
       tmp->sliceIndex_ = sliceIndex;
       tmp->slice_ = &slice;
       tmp->quality_ = quality;
@@ -156,7 +156,7 @@
     static Operation* DownloadSliceRawImage(unsigned int  sliceIndex,
                                             const Slice&  slice)
     {
-      std::auto_ptr<Operation> tmp(new Operation(Mode_LoadRawImage));
+      std::unique_ptr<Operation> tmp(new Operation(Mode_LoadRawImage));
       tmp->sliceIndex_ = sliceIndex;
       tmp->slice_ = &slice;
       tmp->quality_ = SliceImageQuality_InternalRaw;
@@ -165,7 +165,7 @@
 
     static Operation* DownloadDicomFile(const Slice&  slice)
     {
-      std::auto_ptr<Operation> tmp(new Operation(Mode_LoadDicomFile));
+      std::unique_ptr<Operation> tmp(new Operation(Mode_LoadDicomFile));
       tmp->slice_ = &slice;
       return tmp.release();
     }
@@ -241,7 +241,7 @@
       
       for (unsigned int frame = 0; frame < frames; frame++)
       {
-        std::auto_ptr<Slice> slice(new Slice);
+        std::unique_ptr<Slice> slice(new Slice);
         if (slice->ParseOrthancFrame(dicom, instances[i], frame))
         {
           OrthancStone::CoordinateSystem3D geometry = slice->GetGeometry();
@@ -277,7 +277,7 @@
     
     for (unsigned int frame = 0; frame < frames; frame++)
     {
-      std::auto_ptr<Slice> slice(new Slice);
+      std::unique_ptr<Slice> slice(new Slice);
       if (slice->ParseOrthancFrame(dicom, instanceId, frame))
       {
         OrthancStone::CoordinateSystem3D geometry = slice->GetGeometry();
@@ -308,7 +308,7 @@
     Orthanc::DicomMap dicom;
     MessagingToolbox::ConvertDataset(dicom, dataset);
     
-    std::auto_ptr<Slice> slice(new Slice);
+    std::unique_ptr<Slice> slice(new Slice);
     if (slice->ParseOrthancFrame(dicom, instanceId, frame))
     {
       LOG(INFO) << "Loaded instance geometry " << instanceId;
@@ -329,7 +329,7 @@
   void OrthancSlicesLoader::ParseSliceImagePng(const OrthancApiClient::BinaryResponseReadyMessage& message)
   {
     const Operation& operation = dynamic_cast<const OrthancSlicesLoader::Operation&>(message.GetPayload());
-    std::auto_ptr<Orthanc::ImageAccessor>  image;
+    std::unique_ptr<Orthanc::ImageAccessor>  image;
     
     try
     {
@@ -369,7 +369,7 @@
   void OrthancSlicesLoader::ParseSliceImagePam(const OrthancApiClient::BinaryResponseReadyMessage& message)
   {
     const Operation& operation = dynamic_cast<const OrthancSlicesLoader::Operation&>(message.GetPayload());
-    std::auto_ptr<Orthanc::ImageAccessor>  image;
+    std::unique_ptr<Orthanc::ImageAccessor>  image;
 
     try
     {
@@ -449,7 +449,7 @@
       }
     }
     
-    std::auto_ptr<Orthanc::ImageAccessor> reader;
+    std::unique_ptr<Orthanc::ImageAccessor> reader;
     
     {
       std::string jpeg;
@@ -536,7 +536,7 @@
     }
     
     // Decode a grayscale JPEG 8bpp image coming from the Web viewer
-    std::auto_ptr<Orthanc::ImageAccessor> image
+    std::unique_ptr<Orthanc::ImageAccessor> image
       (new Orthanc::Image(expectedFormat, reader->GetWidth(), reader->GetHeight(), false));
 
     Orthanc::ImageProcessing::Convert(*image, *reader);
@@ -599,7 +599,7 @@
     {
       // This is the case of RT-DOSE (uint32_t values)
       
-      std::auto_ptr<Orthanc::ImageAccessor> image
+      std::unique_ptr<Orthanc::ImageAccessor> image
         (new StringImage(Orthanc::PixelFormat_Grayscale32, info.GetWidth(),
                          info.GetHeight(), raw));
       
@@ -623,7 +623,7 @@
              info.GetPhotometricInterpretation() == Orthanc::PhotometricInterpretation_Monochrome2 &&
              raw.size() == info.GetWidth() * info.GetHeight() * 2)
     {
-      std::auto_ptr<Orthanc::ImageAccessor> image
+      std::unique_ptr<Orthanc::ImageAccessor> image
         (new StringImage(Orthanc::PixelFormat_Grayscale16, info.GetWidth(),
                          info.GetHeight(), raw));
       
--- a/Framework/Deprecated/Toolbox/ParallelSlices.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Toolbox/ParallelSlices.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -143,7 +143,7 @@
 
   ParallelSlices* ParallelSlices::Reverse() const
   {
-    std::auto_ptr<ParallelSlices> reversed(new ParallelSlices);
+    std::unique_ptr<ParallelSlices> reversed(new ParallelSlices);
 
     for (size_t i = slices_.size(); i > 0; i--)
     {
@@ -164,7 +164,7 @@
     const OrthancStone::Vector dimensions = geometry.GetVoxelDimensions(OrthancStone::VolumeProjection_Axial);
     const OrthancStone::CoordinateSystem3D& axial = geometry.GetAxialGeometry();
     
-    std::auto_ptr<ParallelSlices> result(new ParallelSlices);
+    std::unique_ptr<ParallelSlices> result(new ParallelSlices);
 
     switch (projection)
     {
--- a/Framework/Deprecated/Toolbox/ParallelSlicesCursor.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Toolbox/ParallelSlicesCursor.h	Wed Mar 04 10:21:54 2020 +0100
@@ -24,12 +24,14 @@
 #include "ParallelSlices.h"
 #include "../../StoneEnumerations.h"
 
+#include <Core/Compatibility.h>
+
 namespace Deprecated
 {
   class ParallelSlicesCursor : public boost::noncopyable
   {
   private:
-    std::auto_ptr<ParallelSlices>  slices_;
+    std::unique_ptr<ParallelSlices>  slices_;
     size_t                         currentSlice_;
 
     size_t GetDefaultSlice();
--- a/Framework/Deprecated/Toolbox/Slice.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Toolbox/Slice.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -48,7 +48,7 @@
 
   Slice* Slice::Clone() const
   {
-    std::auto_ptr<Slice> target(new Slice());
+    std::unique_ptr<Slice> target(new Slice());
 
     target->type_ = type_;
     target->orthancInstanceId_ = orthancInstanceId_;
--- a/Framework/Deprecated/Toolbox/Slice.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Toolbox/Slice.h	Wed Mar 04 10:21:54 2020 +0100
@@ -59,7 +59,7 @@
     unsigned int         height_;   // TODO : Redundant with "imageInformation_"
     DicomFrameConverter  converter_;   // TODO : Partially redundant with "imageInformation_"
 
-    std::auto_ptr<Orthanc::DicomImageInformation>  imageInformation_;
+    std::unique_ptr<Orthanc::DicomImageInformation>  imageInformation_;
 
   public:
     Slice() :
--- a/Framework/Deprecated/Viewport/WidgetViewport.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Viewport/WidgetViewport.h	Wed Mar 04 10:21:54 2020 +0100
@@ -24,6 +24,8 @@
 #include "IViewport.h"
 #include "../Widgets/IWidget.h"
 
+#include <Core/Compatibility.h>
+
 #include <memory>
 
 namespace Deprecated
@@ -33,7 +35,7 @@
   private:
     boost::shared_ptr<IWidget>    centralWidget_;
     IStatusBar*                   statusBar_;
-    std::auto_ptr<IMouseTracker>  mouseTracker_;
+    std::unique_ptr<IMouseTracker>  mouseTracker_;
     bool                          isMouseOver_;
     int                           lastMouseX_;
     int                           lastMouseY_;
--- a/Framework/Deprecated/Volumes/StructureSetLoader.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Volumes/StructureSetLoader.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -119,7 +119,7 @@
     const std::string uri = "/instances/" + instanceId + "/tags?ignore-length=3006-0050";
     OrthancPlugins::FullOrthancDataset dataset(orthanc, uri);
 
-    std::auto_ptr<OrthancStone::DicomStructureSet> result
+    std::unique_ptr<OrthancStone::DicomStructureSet> result
       (new OrthancStone::DicomStructureSet(dataset));
 
     std::set<std::string> instances;
--- a/Framework/Deprecated/Volumes/StructureSetLoader.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Volumes/StructureSetLoader.h	Wed Mar 04 10:21:54 2020 +0100
@@ -26,6 +26,8 @@
 #include "../Toolbox/OrthancApiClient.h"
 #include "IVolumeLoader.h"
 
+#include <Core/Compatibility.h>
+
 namespace Deprecated
 {
   class StructureSetLoader :
@@ -34,7 +36,7 @@
   {
   private:
     OrthancApiClient&                 orthanc_;
-    std::auto_ptr<OrthancStone::DicomStructureSet>  structureSet_;
+    std::unique_ptr<OrthancStone::DicomStructureSet>  structureSet_;
 
     void OnReferencedSliceLoaded(const OrthancApiClient::JsonResponseReadyMessage& message);
 
--- a/Framework/Deprecated/Widgets/LayoutWidget.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Widgets/LayoutWidget.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -31,7 +31,7 @@
   class LayoutWidget::LayoutMouseTracker : public IMouseTracker
   {
   private:
-    std::auto_ptr<IMouseTracker>   tracker_;
+    std::unique_ptr<IMouseTracker>   tracker_;
     int                            left_;
     int                            top_;
     unsigned int                   width_;
--- a/Framework/Deprecated/Widgets/LayoutWidget.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Widgets/LayoutWidget.h	Wed Mar 04 10:21:54 2020 +0100
@@ -38,7 +38,7 @@
     bool                          isHorizontal_;
     unsigned int                  width_;
     unsigned int                  height_;
-    std::auto_ptr<IMouseTracker>  mouseTracker_;
+    std::unique_ptr<IMouseTracker>  mouseTracker_;
     unsigned int                  paddingLeft_;
     unsigned int                  paddingTop_;
     unsigned int                  paddingRight_;
--- a/Framework/Deprecated/Widgets/SliceViewerWidget.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Widgets/SliceViewerWidget.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -35,206 +35,174 @@
 
 namespace Deprecated
 {
-  class SliceViewerWidget::Scene : public boost::noncopyable
+  void SliceViewerWidget::Scene::DeleteLayer(size_t index)
+  {
+    if (index >= renderers_.size())
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    assert(countMissing_ <= renderers_.size());
+
+    if (renderers_[index] != NULL)
+    {
+      assert(countMissing_ < renderers_.size());
+      delete renderers_[index];
+      renderers_[index] = NULL;
+      countMissing_++;
+    }
+  }
+
+  
+  SliceViewerWidget::Scene::Scene(const OrthancStone::CoordinateSystem3D& plane,
+                                  double thickness,
+                                  size_t countLayers) :
+    plane_(plane),
+    thickness_(thickness),
+    countMissing_(countLayers),
+    renderers_(countLayers, NULL)
+  {
+    if (thickness <= 0)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+  }
+
+  
+  SliceViewerWidget::Scene::~Scene()
+  {
+    for (size_t i = 0; i < renderers_.size(); i++)
+    {
+      DeleteLayer(i);
+    }
+  }
+
+  void SliceViewerWidget::Scene::SetLayer(size_t index,
+                                          ILayerRenderer* renderer)  // Takes ownership
   {
-  private:
-    OrthancStone::CoordinateSystem3D            plane_;
-    double                        thickness_;
-    size_t                        countMissing_;
-    std::vector<ILayerRenderer*>  renderers_;
+    if (renderer == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+    }
+
+    DeleteLayer(index);
+
+    renderers_[index] = renderer;
+    countMissing_--;
+  }
+
+
+  bool SliceViewerWidget::Scene::RenderScene(OrthancStone::CairoContext& context,
+                                             const ViewportGeometry& view,
+                                             const OrthancStone::CoordinateSystem3D& viewportPlane)
+  {
+    bool fullQuality = true;
+    cairo_t *cr = context.GetObject();
 
-  public:
-    void DeleteLayer(size_t index)
+    for (size_t i = 0; i < renderers_.size(); i++)
     {
-      if (index >= renderers_.size())
+      if (renderers_[i] != NULL)
       {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+        const OrthancStone::CoordinateSystem3D& framePlane = renderers_[i]->GetLayerPlane();
+          
+        double x0, y0, x1, y1, x2, y2;
+        viewportPlane.ProjectPoint(x0, y0, framePlane.GetOrigin());
+        viewportPlane.ProjectPoint(x1, y1, framePlane.GetOrigin() + framePlane.GetAxisX());
+        viewportPlane.ProjectPoint(x2, y2, framePlane.GetOrigin() + framePlane.GetAxisY());
+
+        /**
+         * Now we solve the system of linear equations Ax + b = x', given:
+         *   A [0 ; 0] + b = [x0 ; y0]
+         *   A [1 ; 0] + b = [x1 ; y1]
+         *   A [0 ; 1] + b = [x2 ; y2]
+         * <=>
+         *   b = [x0 ; y0]
+         *   A [1 ; 0] = [x1 ; y1] - b = [x1 - x0 ; y1 - y0]
+         *   A [0 ; 1] = [x2 ; y2] - b = [x2 - x0 ; y2 - y0]
+         * <=>
+         *   b = [x0 ; y0]
+         *   [a11 ; a21] = [x1 - x0 ; y1 - y0]
+         *   [a12 ; a22] = [x2 - x0 ; y2 - y0]
+         **/
+
+        cairo_matrix_t transform;
+        cairo_matrix_init(&transform, x1 - x0, y1 - y0, x2 - x0, y2 - y0, x0, y0);
+
+        cairo_save(cr);
+        cairo_transform(cr, &transform);
+          
+        if (!renderers_[i]->RenderLayer(context, view))
+        {
+          cairo_restore(cr);
+          return false;
+        }
+
+        cairo_restore(cr);
       }
 
-      assert(countMissing_ <= renderers_.size());
-
-      if (renderers_[index] != NULL)
+      if (renderers_[i] != NULL &&
+          !renderers_[i]->IsFullQuality())
       {
-        assert(countMissing_ < renderers_.size());
-        delete renderers_[index];
-        renderers_[index] = NULL;
-        countMissing_++;
-      }
-    }
-
-    Scene(const OrthancStone::CoordinateSystem3D& plane,
-          double thickness,
-          size_t countLayers) :
-      plane_(plane),
-      thickness_(thickness),
-      countMissing_(countLayers),
-      renderers_(countLayers, NULL)
-    {
-      if (thickness <= 0)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-      }
-    }
-
-    ~Scene()
-    {
-      for (size_t i = 0; i < renderers_.size(); i++)
-      {
-        DeleteLayer(i);
+        fullQuality = false;
       }
     }
 
-    void SetLayer(size_t index,
-                  ILayerRenderer* renderer)  // Takes ownership
-    {
-      if (renderer == NULL)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
-      }
-
-      DeleteLayer(index);
-
-      renderers_[index] = renderer;
-      countMissing_--;
-    }
-
-    const OrthancStone::CoordinateSystem3D& GetPlane() const
+    if (!fullQuality)
     {
-      return plane_;
-    }
+      double x, y;
+      view.MapDisplayToScene(x, y, static_cast<double>(view.GetDisplayWidth()) / 2.0, 10);
 
-    bool HasRenderer(size_t index)
-    {
-      return renderers_[index] != NULL;
-    }
+      cairo_translate(cr, x, y);
 
-    bool IsComplete() const
-    {
-      return countMissing_ == 0;
-    }
-
-    unsigned int GetCountMissing() const
-    {
-      return static_cast<unsigned int>(countMissing_);
+#if 1
+      double s = 5.0 / view.GetZoom();
+      cairo_rectangle(cr, -s, -s, 2.0 * s, 2.0 * s);
+#else
+      // TODO Drawing filled circles makes WebAssembly crash!
+      cairo_arc(cr, 0, 0, 5.0 / view.GetZoom(), 0, 2.0 * boost::math::constants::pi<double>());
+#endif
+        
+      cairo_set_line_width(cr, 2.0 / view.GetZoom());
+      cairo_set_source_rgb(cr, 1, 1, 1);
+      cairo_stroke_preserve(cr);
+      cairo_set_source_rgb(cr, 1, 0, 0);
+      cairo_fill(cr);
     }
 
-    bool RenderScene(OrthancStone::CairoContext& context,
-                     const ViewportGeometry& view,
-                     const OrthancStone::CoordinateSystem3D& viewportPlane)
-    {
-      bool fullQuality = true;
-      cairo_t *cr = context.GetObject();
+    return true;
+  }
 
-      for (size_t i = 0; i < renderers_.size(); i++)
-      {
-        if (renderers_[i] != NULL)
-        {
-          const OrthancStone::CoordinateSystem3D& framePlane = renderers_[i]->GetLayerPlane();
-          
-          double x0, y0, x1, y1, x2, y2;
-          viewportPlane.ProjectPoint(x0, y0, framePlane.GetOrigin());
-          viewportPlane.ProjectPoint(x1, y1, framePlane.GetOrigin() + framePlane.GetAxisX());
-          viewportPlane.ProjectPoint(x2, y2, framePlane.GetOrigin() + framePlane.GetAxisY());
+  void SliceViewerWidget::Scene::SetLayerStyle(size_t index,
+                                               const RenderStyle& style)
+  {
+    if (renderers_[index] != NULL)
+    {
+      renderers_[index]->SetLayerStyle(style);
+    }
+  }
 
-          /**
-           * Now we solve the system of linear equations Ax + b = x', given:
-           *   A [0 ; 0] + b = [x0 ; y0]
-           *   A [1 ; 0] + b = [x1 ; y1]
-           *   A [0 ; 1] + b = [x2 ; y2]
-           * <=>
-           *   b = [x0 ; y0]
-           *   A [1 ; 0] = [x1 ; y1] - b = [x1 - x0 ; y1 - y0]
-           *   A [0 ; 1] = [x2 ; y2] - b = [x2 - x0 ; y2 - y0]
-           * <=>
-           *   b = [x0 ; y0]
-           *   [a11 ; a21] = [x1 - x0 ; y1 - y0]
-           *   [a12 ; a22] = [x2 - x0 ; y2 - y0]
-           **/
-
-          cairo_matrix_t transform;
-          cairo_matrix_init(&transform, x1 - x0, y1 - y0, x2 - x0, y2 - y0, x0, y0);
+  bool SliceViewerWidget::Scene::ContainsPlane(const OrthancStone::CoordinateSystem3D& plane) const
+  {
+    bool isOpposite;
+    if (!OrthancStone::GeometryToolbox::IsParallelOrOpposite(isOpposite,
+                                                             plane.GetNormal(),
+                                                             plane_.GetNormal()))
+    {
+      return false;
+    }
+    else
+    {
+      double z = (plane_.ProjectAlongNormal(plane.GetOrigin()) -
+                  plane_.ProjectAlongNormal(plane_.GetOrigin()));
 
-          cairo_save(cr);
-          cairo_transform(cr, &transform);
-          
-          if (!renderers_[i]->RenderLayer(context, view))
-          {
-            cairo_restore(cr);
-            return false;
-          }
-
-          cairo_restore(cr);
-        }
-
-        if (renderers_[i] != NULL &&
-            !renderers_[i]->IsFullQuality())
-        {
-          fullQuality = false;
-        }
+      if (z < 0)
+      {
+        z = -z;
       }
 
-      if (!fullQuality)
-      {
-        double x, y;
-        view.MapDisplayToScene(x, y, static_cast<double>(view.GetDisplayWidth()) / 2.0, 10);
-
-        cairo_translate(cr, x, y);
-
-#if 1
-        double s = 5.0 / view.GetZoom();
-        cairo_rectangle(cr, -s, -s, 2.0 * s, 2.0 * s);
-#else
-        // TODO Drawing filled circles makes WebAssembly crash!
-        cairo_arc(cr, 0, 0, 5.0 / view.GetZoom(), 0, 2.0 * boost::math::constants::pi<double>());
-#endif
-        
-        cairo_set_line_width(cr, 2.0 / view.GetZoom());
-        cairo_set_source_rgb(cr, 1, 1, 1);
-        cairo_stroke_preserve(cr);
-        cairo_set_source_rgb(cr, 1, 0, 0);
-        cairo_fill(cr);
-      }
-
-      return true;
+      return z <= thickness_;
     }
-
-    void SetLayerStyle(size_t index,
-                       const RenderStyle& style)
-    {
-      if (renderers_[index] != NULL)
-      {
-        renderers_[index]->SetLayerStyle(style);
-      }
-    }
-
-    bool ContainsPlane(const OrthancStone::CoordinateSystem3D& plane) const
-    {
-      bool isOpposite;
-      if (!OrthancStone::GeometryToolbox::IsParallelOrOpposite(isOpposite,
-                                                               plane.GetNormal(),
-                                                               plane_.GetNormal()))
-      {
-        return false;
-      }
-      else
-      {
-        double z = (plane_.ProjectAlongNormal(plane.GetOrigin()) -
-                    plane_.ProjectAlongNormal(plane_.GetOrigin()));
-
-        if (z < 0)
-        {
-          z = -z;
-        }
-
-        return z <= thickness_;
-      }
-    }
-
-    double GetThickness() const
-    {
-      return thickness_;
-    }
-  };
+  }
 
   
   bool SliceViewerWidget::LookupLayer(size_t& index /* out */,
@@ -327,7 +295,7 @@
   {
     LOG(INFO) << "Updating layer " << index;
     
-    std::auto_ptr<ILayerRenderer> tmp(renderer);
+    std::unique_ptr<ILayerRenderer> tmp(renderer);
 
     if (renderer == NULL)
     {
@@ -357,7 +325,12 @@
           !currentScene_->IsComplete() ||
           pendingScene_->IsComplete())
       {
-        currentScene_ = pendingScene_;
+#if __cplusplus < 201103L
+        currentScene_.reset(pendingScene_.release());
+#else
+        currentScene_ = std::move(pendingScene_);
+#endif
+
         NotifyContentChanged();
       }
     }
@@ -503,7 +476,11 @@
           (pendingScene_.get() != NULL &&
            pendingScene_->IsComplete()))
       {
-        currentScene_ = pendingScene_;
+#if __cplusplus < 201103L
+        currentScene_.reset(pendingScene_.release());
+#else
+        currentScene_ = std::move(pendingScene_);
+#endif
       }
 
       plane_ = plane;
--- a/Framework/Deprecated/Widgets/SliceViewerWidget.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Widgets/SliceViewerWidget.h	Wed Mar 04 10:21:54 2020 +0100
@@ -66,7 +66,61 @@
     SliceViewerWidget(const SliceViewerWidget&);
     SliceViewerWidget& operator=(const SliceViewerWidget&);
 
-    class Scene;
+    class Scene : public boost::noncopyable
+    {
+    private:
+      OrthancStone::CoordinateSystem3D  plane_;
+      double                            thickness_;
+      size_t                            countMissing_;
+      std::vector<ILayerRenderer*>      renderers_;
+
+    public:
+      void DeleteLayer(size_t index);
+
+      Scene(const OrthancStone::CoordinateSystem3D& plane,
+            double thickness,
+            size_t countLayers);
+
+      ~Scene();
+
+      void SetLayer(size_t index,
+                    ILayerRenderer* renderer);  // Takes ownership
+
+      const OrthancStone::CoordinateSystem3D& GetPlane() const
+      {
+        return plane_;
+      }
+
+      bool HasRenderer(size_t index)
+      {
+        return renderers_[index] != NULL;
+      }
+
+      bool IsComplete() const
+      {
+        return countMissing_ == 0;
+      }
+
+      unsigned int GetCountMissing() const
+      {
+        return static_cast<unsigned int>(countMissing_);
+      }
+
+      bool RenderScene(OrthancStone::CairoContext& context,
+                       const ViewportGeometry& view,
+                       const OrthancStone::CoordinateSystem3D& viewportPlane);
+
+      void SetLayerStyle(size_t index,
+                         const RenderStyle& style);
+
+      bool ContainsPlane(const OrthancStone::CoordinateSystem3D& plane) const;
+
+      double GetThickness() const
+      {
+        return thickness_;
+      }
+    };
+
     
     typedef std::map<const IVolumeSlicer*, size_t>  LayersIndex;
 
@@ -75,8 +129,8 @@
     std::vector<boost::shared_ptr<IVolumeSlicer> >  layers_;
     std::vector<RenderStyle>     styles_;
     OrthancStone::CoordinateSystem3D           plane_;
-    std::auto_ptr<Scene>         currentScene_;
-    std::auto_ptr<Scene>         pendingScene_;
+    std::unique_ptr<Scene>         currentScene_;
+    std::unique_ptr<Scene>         pendingScene_;
     std::vector<bool>            changedLayers_;
 
     bool LookupLayer(size_t& index /* out */,
--- a/Framework/Deprecated/Widgets/TestWorldSceneWidget.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Widgets/TestWorldSceneWidget.h	Wed Mar 04 10:21:54 2020 +0100
@@ -34,7 +34,7 @@
     private:
       class Interactor;
 
-      std::auto_ptr<Interactor>   interactor_;
+      std::unique_ptr<Interactor>   interactor_;
       bool                        animate_;
       unsigned int                count_;
 
--- a/Framework/Deprecated/Widgets/WorldSceneWidget.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/Widgets/WorldSceneWidget.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -42,7 +42,7 @@
   {
   private:
     ViewportGeometry                        view_;
-    std::auto_ptr<IWorldSceneMouseTracker>  tracker_;
+    std::unique_ptr<IWorldSceneMouseTracker>  tracker_;
 
   public:
     SceneMouseTracker(const ViewportGeometry& view,
@@ -166,7 +166,7 @@
     view_.MapPixelCenterToScene(sceneX, sceneY, x, y);
 
     // asks the Widget Interactor to provide a mouse tracker
-    std::auto_ptr<IWorldSceneMouseTracker> tracker;
+    std::unique_ptr<IWorldSceneMouseTracker> tracker;
 
     if (interactor_)
     {
--- a/Framework/Deprecated/dev.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Deprecated/dev.h	Wed Mar 04 10:21:54 2020 +0100
@@ -47,8 +47,8 @@
   {
   private:
     OrthancSlicesLoader           loader_;
-    std::auto_ptr<OrthancStone::ImageBuffer3D>  image_;
-    std::auto_ptr<DownloadStack>  downloadStack_;
+    std::unique_ptr<OrthancStone::ImageBuffer3D>  image_;
+    std::unique_ptr<DownloadStack>  downloadStack_;
     bool                          computeRange_;
     size_t                        pendingSlices_;
 
@@ -521,9 +521,9 @@
 
 
     OrthancVolumeImage&                 volume_;
-    std::auto_ptr<VolumeImageGeometry>  axialGeometry_;
-    std::auto_ptr<VolumeImageGeometry>  coronalGeometry_;
-    std::auto_ptr<VolumeImageGeometry>  sagittalGeometry_;
+    std::unique_ptr<VolumeImageGeometry>  axialGeometry_;
+    std::unique_ptr<VolumeImageGeometry>  coronalGeometry_;
+    std::unique_ptr<VolumeImageGeometry>  sagittalGeometry_;
 
 
     bool IsGeometryReady() const
@@ -662,7 +662,7 @@
       {
         // As the slices of the volumic image are arranged in a box,
         // we only consider one single reference slice (the one with index 0).
-        std::auto_ptr<Slice> slice(GetProjectionGeometry(projection).GetSlice(0));
+        std::unique_ptr<Slice> slice(GetProjectionGeometry(projection).GetSlice(0));
         slice->GetExtent(points);
 
         return true;
@@ -684,7 +684,7 @@
         {
           bool isFullQuality = true;  // TODO
 
-          std::auto_ptr<Orthanc::Image> frame;
+          std::unique_ptr<Orthanc::Image> frame;
 
           {
             OrthancStone::ImageBuffer3D::SliceReader reader(volume_.GetImage(), projection, static_cast<unsigned int>(closest));
@@ -693,7 +693,7 @@
             frame.reset(Orthanc::Image::Clone(reader.GetAccessor()));
           }
 
-          std::auto_ptr<Slice> slice(geometry.GetSlice(closest));
+          std::unique_ptr<Slice> slice(geometry.GetSlice(closest));
 
           RendererFactory factory(*frame, *slice, isFullQuality);
 
@@ -716,7 +716,7 @@
   private:
     SliceViewerWidget&                  widget_;
     OrthancStone::VolumeProjection      projection_;
-    std::auto_ptr<VolumeImageGeometry>  slices_;
+    std::unique_ptr<VolumeImageGeometry>  slices_;
     size_t                              slice_;
 
   protected:
@@ -858,7 +858,7 @@
       {
         slice_ = slice;
 
-        std::auto_ptr<Slice> tmp(slices_->GetSlice(slice_));
+        std::unique_ptr<Slice> tmp(slices_->GetSlice(slice_));
         widget_.SetSlice(tmp->GetGeometry());
       }
     }
--- a/Framework/Fonts/FontRenderer.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Fonts/FontRenderer.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -141,7 +141,7 @@
                               face_->glyph->bitmap.pitch,
                               face_->glyph->bitmap.buffer);
 
-        std::auto_ptr<Glyph> glyph(
+        std::unique_ptr<Glyph> glyph(
           new Glyph(bitmap.GetWidth(),
                     bitmap.GetHeight(),
                     face_->glyph->bitmap_left,
--- a/Framework/Fonts/Glyph.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Fonts/Glyph.h	Wed Mar 04 10:21:54 2020 +0100
@@ -21,6 +21,7 @@
 
 #pragma once
 
+#include <Core/Compatibility.h>
 #include <Core/IDynamicObject.h>
 
 #include <memory>
@@ -38,7 +39,7 @@
     int            advanceX_;
     unsigned int   lineHeight_;
       
-    std::auto_ptr<Orthanc::IDynamicObject>  payload_;
+    std::unique_ptr<Orthanc::IDynamicObject>  payload_;
 
   public:
     // WARNING: This does not copy the payload
--- a/Framework/Fonts/GlyphAlphabet.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Fonts/GlyphAlphabet.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -43,12 +43,12 @@
                                const Glyph& glyph,
                                Orthanc::IDynamicObject* payload)
   {
-    std::auto_ptr<Orthanc::IDynamicObject> protection(payload);
+    std::unique_ptr<Orthanc::IDynamicObject> protection(payload);
       
     // Don't add twice the same character
     if (content_.find(unicode) == content_.end())
     {
-      std::auto_ptr<Glyph> raii(new Glyph(glyph));
+      std::unique_ptr<Glyph> raii(new Glyph(glyph));
         
       if (payload != NULL)
       {
@@ -65,7 +65,7 @@
   void GlyphAlphabet::Register(FontRenderer& renderer,
                                uint32_t unicode)
   {
-    std::auto_ptr<Glyph>  glyph(renderer.Render(unicode));
+    std::unique_ptr<Glyph>  glyph(renderer.Render(unicode));
       
     if (glyph.get() != NULL)
     {
--- a/Framework/Fonts/GlyphBitmapAlphabet.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Fonts/GlyphBitmapAlphabet.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -98,7 +98,7 @@
   {
     TextBoundingBox box(alphabet_, utf8);
 
-    std::auto_ptr<Orthanc::ImageAccessor> bitmap(
+    std::unique_ptr<Orthanc::ImageAccessor> bitmap(
       new Orthanc::Image(Orthanc::PixelFormat_Grayscale8,
                          box.GetWidth(), box.GetHeight(),
                          true /* force minimal pitch */));
--- a/Framework/Fonts/GlyphTextureAlphabet.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Fonts/GlyphTextureAlphabet.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -77,7 +77,7 @@
   class GlyphTextureAlphabet::TextureGenerator : public GlyphAlphabet::IGlyphVisitor
   {
   private:
-    std::auto_ptr<Orthanc::ImageAccessor>  texture_;
+    std::unique_ptr<Orthanc::ImageAccessor>  texture_;
 
     unsigned int    countColumns_;
     unsigned int    countRows_;
@@ -289,7 +289,7 @@
   {
     TextBoundingBox box(alphabet_, utf8);
 
-    std::auto_ptr<Orthanc::ImageAccessor> bitmap(
+    std::unique_ptr<Orthanc::ImageAccessor> bitmap(
       new Orthanc::Image(Orthanc::PixelFormat_RGBA32,
                          box.GetWidth(), box.GetHeight(),
                          true /* force minimal pitch */));
--- a/Framework/Fonts/GlyphTextureAlphabet.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Fonts/GlyphTextureAlphabet.h	Wed Mar 04 10:21:54 2020 +0100
@@ -61,7 +61,7 @@
     class RenderTextVisitor;
     
     GlyphAlphabet                          alphabet_;
-    std::auto_ptr<Orthanc::ImageAccessor>  texture_;
+    std::unique_ptr<Orthanc::ImageAccessor>  texture_;
     unsigned int                           textureWidth_;
     unsigned int                           textureHeight_;
     
--- a/Framework/Loaders/BasicFetchingStrategy.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Loaders/BasicFetchingStrategy.h	Wed Mar 04 10:21:54 2020 +0100
@@ -24,6 +24,8 @@
 #include "IFetchingItemsSorter.h"
 #include "IFetchingStrategy.h"
 
+#include <Core/Compatibility.h>
+
 #include <memory>
 
 namespace OrthancStone
@@ -56,7 +58,7 @@
       }
     };
 
-    std::auto_ptr<IFetchingItemsSorter>  sorter_;
+    std::unique_ptr<IFetchingItemsSorter>  sorter_;
     std::vector<unsigned int>            nextQuality_;
     unsigned int                         maxQuality_;
     std::vector<ContentItem>             content_;
--- a/Framework/Loaders/DicomResourcesLoader.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Loaders/DicomResourcesLoader.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -417,7 +417,7 @@
 
     for (;;)
     {
-      std::auto_ptr<Orthanc::DicomMap> current(dicomDir.GetItem(index).Clone());
+      std::unique_ptr<Orthanc::DicomMap> current(dicomDir.GetItem(index).Clone());
       current->RemoveBinaryTags();
       current->Merge(parent);
 
@@ -556,13 +556,13 @@
                                                              boost::shared_ptr<unsigned int> remainingCommands,
                                                              boost::shared_ptr<Orthanc::IDynamicObject> userPayload)
   {
-    std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand);
+    std::unique_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand);
     command->SetUri("/instances/" + instanceId + "/tags");
     command->AcquirePayload(new OrthancInstanceTagsHandler(shared_from_this(), target, priority,
                                                            source, remainingCommands, userPayload));
 
     {
-      std::auto_ptr<ILoadersContext::ILock> lock(context_.Lock());
+      std::unique_ptr<ILoadersContext::ILock> lock(context_.Lock());
       lock->Schedule(GetSharedObserver(), priority, command.release());
     }
   }
@@ -576,13 +576,13 @@
                                                                  boost::shared_ptr<unsigned int> remainingCommands,
                                                                  boost::shared_ptr<Orthanc::IDynamicObject> userPayload)
   {
-    std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand);
+    std::unique_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand);
     command->SetUri("/" + GetUri(level) + "/" + id + "/instances");
     command->AcquirePayload(new OrthancOneChildInstanceHandler(shared_from_this(), target, priority,
                                                                source, remainingCommands, userPayload));
 
     {
-      std::auto_ptr<ILoadersContext::ILock> lock(context_.Lock());
+      std::unique_ptr<ILoadersContext::ILock> lock(context_.Lock());
       lock->Schedule(GetSharedObserver(), priority, command.release());
     }
   }
@@ -665,12 +665,12 @@
     std::map<std::string, std::string> arguments, headers;
     SetIncludeTags(arguments, includeTags);
   
-    std::auto_ptr<IOracleCommand> command(
+    std::unique_ptr<IOracleCommand> command(
       source.CreateDicomWebCommand(uri, arguments, headers, 
                                    new DicomWebHandler(shared_from_this(), target, priority, source, protection)));
       
     {
-      std::auto_ptr<ILoadersContext::ILock> lock(context_.Lock());
+      std::unique_ptr<ILoadersContext::ILock> lock(context_.Lock());
       lock->Schedule(GetSharedObserver(), priority, command.release());
     }
   }
@@ -728,13 +728,13 @@
 
     SetIncludeTags(arguments, includeTags);
 
-    std::auto_ptr<IOracleCommand> command(
+    std::unique_ptr<IOracleCommand> command(
       source.CreateDicomWebCommand(uri, arguments, headers, 
                                    new DicomWebHandler(shared_from_this(), target, priority, source, protection)));
 
 
     {
-      std::auto_ptr<ILoadersContext::ILock> lock(context_.Lock());
+      std::unique_ptr<ILoadersContext::ILock> lock(context_.Lock());
       lock->Schedule(GetSharedObserver(), priority, command.release());
     }
   }
@@ -802,14 +802,14 @@
     }
     else 
     {
-      std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand);
+      std::unique_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand);
       command->SetUri("/" + GetUri(topLevel) + "/" + topId + "/" + GetUri(bottomLevel));
       command->AcquirePayload(new OrthancAllChildrenInstancesHandler
                               (shared_from_this(), target, priority, source,
                                remainingCommands, bottomLevel, protection));
 
       {
-        std::auto_ptr<ILoadersContext::ILock> lock(context_.Lock());
+        std::unique_ptr<ILoadersContext::ILock> lock(context_.Lock());
         lock->Schedule(GetSharedObserver(), priority, command.release());
       }
     }
@@ -836,11 +836,11 @@
     }
 
 #if ORTHANC_ENABLE_DCMTK == 1
-    std::auto_ptr<ReadFileCommand> command(new ReadFileCommand(path));
+    std::unique_ptr<ReadFileCommand> command(new ReadFileCommand(path));
     command->AcquirePayload(new DicomDirHandler(shared_from_this(), target, priority, source, protection));
 
     {
-      std::auto_ptr<ILoadersContext::ILock> lock(context_.Lock());      
+      std::unique_ptr<ILoadersContext::ILock> lock(context_.Lock());      
       lock->Schedule(GetSharedObserver(), priority, command.release());
     }
 #else
@@ -860,12 +860,12 @@
     boost::shared_ptr<Orthanc::IDynamicObject> protection(userPayload);
     
 #if ORTHANC_ENABLE_DCMTK == 1
-    std::auto_ptr<ParseDicomFromFileCommand> command(new ParseDicomFromFileCommand(path));
+    std::unique_ptr<ParseDicomFromFileCommand> command(new ParseDicomFromFileCommand(path));
     command->SetPixelDataIncluded(includePixelData);
     command->AcquirePayload(new Handler(shared_from_this(), target, priority, source, protection));
 
     {
-      std::auto_ptr<ILoadersContext::ILock> lock(context_.Lock());
+      std::unique_ptr<ILoadersContext::ILock> lock(context_.Lock());
       lock->Schedule(GetSharedObserver(), priority, command.release());
     }
 #else
@@ -883,7 +883,7 @@
                                                    bool includePixelData,
                                                    Orthanc::IDynamicObject* userPayload)
   {
-    std::auto_ptr<Orthanc::IDynamicObject> protection(userPayload);
+    std::unique_ptr<Orthanc::IDynamicObject> protection(userPayload);
     
 #if ORTHANC_ENABLE_DCMTK == 1
     std::string file;
--- a/Framework/Loaders/DicomSource.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Loaders/DicomSource.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -144,13 +144,13 @@
                                                      const std::map<std::string, std::string>& headers,
                                                      Orthanc::IDynamicObject* payload) const
   {
-    std::auto_ptr<Orthanc::IDynamicObject> protection(payload);
+    std::unique_ptr<Orthanc::IDynamicObject> protection(payload);
 
     switch (type_)
     {
       case DicomSourceType_DicomWeb:
       {
-        std::auto_ptr<HttpCommand> command(new HttpCommand);
+        std::unique_ptr<HttpCommand> command(new HttpCommand);
         
         command->SetMethod(Orthanc::HttpMethod_Get);
         command->SetUrl(webService_.GetUrl() + "/" + EncodeGetArguments(uri, arguments));
@@ -196,7 +196,7 @@
         body["Arguments"] = args;
         body["Headers"] = h;
 
-        std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand);
+        std::unique_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand);
         command->SetMethod(Orthanc::HttpMethod_Post);
         command->SetUri(orthancDicomWebRoot_ + "/servers/" + serverName_ + "/get");
         command->SetBody(body);
--- a/Framework/Loaders/GenericLoadersContext.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Loaders/GenericLoadersContext.h	Wed Mar 04 10:21:54 2020 +0100
@@ -44,7 +44,7 @@
     boost::recursive_mutex  mutex_;
 
     IObservable                         oracleObservable_;
-    std::auto_ptr<ThreadedOracle>       oracle_;
+    std::unique_ptr<ThreadedOracle>       oracle_;
     boost::shared_ptr<OracleScheduler>  scheduler_;
 
     // Necessary to keep the loaders persistent (including global
--- a/Framework/Loaders/OracleScheduler.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Loaders/OracleScheduler.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -30,7 +30,7 @@
   private:
     Priority   priority_;
     boost::weak_ptr<IObserver>  receiver_;
-    std::auto_ptr<IOracleCommand>  command_;
+    std::unique_ptr<IOracleCommand>  command_;
 
   public:
     ReceiverPayload(Priority priority,
@@ -68,7 +68,7 @@
   {
   private:
     boost::weak_ptr<IObserver>     receiver_;
-    std::auto_ptr<IOracleCommand>  command_;
+    std::unique_ptr<IOracleCommand>  command_;
 
   public:
     ScheduledCommand(boost::shared_ptr<IObserver> receiver,
@@ -103,7 +103,7 @@
       }
       else
       {
-        std::auto_ptr<IOracleCommand> wrapped(command_->Clone());
+        std::unique_ptr<IOracleCommand> wrapped(command_->Clone());
         dynamic_cast<OracleCommandBase&>(*wrapped).AcquirePayload(new ReceiverPayload(priority, receiver_, command_.release()));
         return wrapped.release();
       }
@@ -198,7 +198,7 @@
     Queue::iterator item = queue.begin();
     assert(item != queue.end());
 
-    std::auto_ptr<ScheduledCommand> command(dynamic_cast<ScheduledCommand*>(item->second));
+    std::unique_ptr<ScheduledCommand> command(dynamic_cast<ScheduledCommand*>(item->second));
     queue.erase(item);
 
     if (command.get() != NULL)
@@ -522,7 +522,7 @@
                                  int priority,
                                  IOracleCommand* command /* Takes ownership */)
   {
-    std::auto_ptr<ScheduledCommand> pending(new ScheduledCommand(receiver, dynamic_cast<IOracleCommand*>(command)));
+    std::unique_ptr<ScheduledCommand> pending(new ScheduledCommand(receiver, dynamic_cast<IOracleCommand*>(command)));
 
     /**
      * Safeguard to remember that a new "Handle()" method and a call
--- a/Framework/Loaders/SeriesFramesLoader.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Loaders/SeriesFramesLoader.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -47,7 +47,7 @@
     bool          hasWindowing_;
     float         windowingCenter_;
     float         windowingWidth_;
-    std::auto_ptr<Orthanc::IDynamicObject>  userPayload_;
+    std::unique_ptr<Orthanc::IDynamicObject>  userPayload_;
 
   public:
     Payload(const DicomSource& source,
@@ -169,7 +169,7 @@
   {     
     size_t frameIndex = frames_.GetFrameIndex(payload.GetSeriesIndex());
 
-    std::auto_ptr<Orthanc::ImageAccessor> decoded;
+    std::unique_ptr<Orthanc::ImageAccessor> decoded;
     decoded.reset(Orthanc::DicomImageDecoder::Decode(dicom, frameIndex));
 
     if (decoded.get() == NULL)
@@ -381,7 +381,7 @@
                                              unsigned int quality,
                                              Orthanc::IDynamicObject* userPayload)
   {
-    std::auto_ptr<Orthanc::IDynamicObject> protection(userPayload);
+    std::unique_ptr<Orthanc::IDynamicObject> protection(userPayload);
     
     if (index >= frames_.GetFramesCount() ||
         quality >= source.GetQualityCount())
@@ -413,12 +413,12 @@
       std::string file;
       if (dicomDir_->LookupStringValue(file, sopInstanceUid, Orthanc::DICOM_TAG_REFERENCED_FILE_ID))
       {
-        std::auto_ptr<ParseDicomFromFileCommand> command(new ParseDicomFromFileCommand(dicomDirPath_, file));
+        std::unique_ptr<ParseDicomFromFileCommand> command(new ParseDicomFromFileCommand(dicomDirPath_, file));
         command->SetPixelDataIncluded(true);
         command->AcquirePayload(new Payload(source, index, sopInstanceUid, quality, protection.release()));
 
         {
-          std::auto_ptr<ILoadersContext::ILock> lock(context_.Lock());
+          std::unique_ptr<ILoadersContext::ILock> lock(context_.Lock());
           lock->Schedule(GetSharedObserver(), priority, command.release());
         }
       }
@@ -452,11 +452,11 @@
                                boost::lexical_cast<std::string>(w) + ",linear");
         headers["Accept"] = "image/jpeg";
 
-        std::auto_ptr<Payload> payload(new Payload(source, index, sopInstanceUid, quality, protection.release()));
+        std::unique_ptr<Payload> payload(new Payload(source, index, sopInstanceUid, quality, protection.release()));
         payload->SetWindowing(c, w);
 
         {
-          std::auto_ptr<ILoadersContext::ILock> lock(context_.Lock());
+          std::unique_ptr<ILoadersContext::ILock> lock(context_.Lock());
           lock->Schedule(GetSharedObserver(), priority,
                          source.CreateDicomWebCommand(uri + "/rendered", arguments, headers, payload.release()));
         }
@@ -467,16 +467,16 @@
                (!source.HasDicomWebRendered() && quality == 0));
 
 #if ORTHANC_ENABLE_DCMTK == 1
-        std::auto_ptr<Payload> payload(new Payload(source, index, sopInstanceUid, quality, protection.release()));
+        std::unique_ptr<Payload> payload(new Payload(source, index, sopInstanceUid, quality, protection.release()));
 
         const std::map<std::string, std::string> empty;
 
-        std::auto_ptr<ParseDicomFromWadoCommand> command(
+        std::unique_ptr<ParseDicomFromWadoCommand> command(
           new ParseDicomFromWadoCommand(sopInstanceUid, source.CreateDicomWebCommand(uri, empty, empty, NULL)));
         command->AcquirePayload(payload.release());
 
         {
-          std::auto_ptr<ILoadersContext::ILock> lock(context_.Lock());
+          std::unique_ptr<ILoadersContext::ILock> lock(context_.Lock());
           lock->Schedule(GetSharedObserver(), priority, command.release());
         }
 #else
@@ -507,13 +507,13 @@
 
       if (quality == 0 && source.HasOrthancWebViewer1())
       {
-        std::auto_ptr<GetOrthancWebViewerJpegCommand> command(new GetOrthancWebViewerJpegCommand);
+        std::unique_ptr<GetOrthancWebViewerJpegCommand> command(new GetOrthancWebViewerJpegCommand);
         command->SetInstance(orthancId);
         command->SetExpectedPixelFormat(parameters.GetExpectedPixelFormat());
         command->AcquirePayload(new Payload(source, index, sopInstanceUid, quality, protection.release()));
 
         {
-          std::auto_ptr<ILoadersContext::ILock> lock(context_.Lock());
+          std::unique_ptr<ILoadersContext::ILock> lock(context_.Lock());
           lock->Schedule(GetSharedObserver(), priority, command.release());
         }
       }
@@ -528,14 +528,14 @@
                source.HasOrthancWebViewer1() || 
                source.HasOrthancAdvancedPreview());
 
-        std::auto_ptr<GetOrthancImageCommand> command(new GetOrthancImageCommand);
+        std::unique_ptr<GetOrthancImageCommand> command(new GetOrthancImageCommand);
         command->SetFrameUri(orthancId, frames_.GetFrameIndex(index), parameters.GetExpectedPixelFormat());
         command->SetExpectedPixelFormat(parameters.GetExpectedPixelFormat());
         command->SetHttpHeader("Accept", Orthanc::MIME_PAM);
         command->AcquirePayload(new Payload(source, index, sopInstanceUid, quality, protection.release()));
 
         {
-          std::auto_ptr<ILoadersContext::ILock> lock(context_.Lock());
+          std::unique_ptr<ILoadersContext::ILock> lock(context_.Lock());
           lock->Schedule(GetSharedObserver(), priority, command.release());
         }
       }
--- a/Framework/Loaders/SeriesOrderedFrames.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Loaders/SeriesOrderedFrames.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -29,7 +29,7 @@
   class SeriesOrderedFrames::Instance : public boost::noncopyable
   {
   private:
-    std::auto_ptr<Orthanc::DicomMap>  dicom_;
+    std::unique_ptr<Orthanc::DicomMap>  dicom_;
     DicomInstanceParameters           parameters_;
 
   public:
@@ -276,7 +276,7 @@
     {
       try
       {
-        std::auto_ptr<Instance> instance(new Instance(instances.GetResource(i)));
+        std::unique_ptr<Instance> instance(new Instance(instances.GetResource(i)));
         numberOfFrames += instance->GetInstanceParameters().GetImageInformation().GetNumberOfFrames();
         instances_.push_back(instance.release());
       }
--- a/Framework/Loaders/SeriesThumbnailsLoader.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Loaders/SeriesThumbnailsLoader.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -78,7 +78,7 @@
   {
     assert(thumbnail != NULL);
   
-    std::auto_ptr<Thumbnail> protection(thumbnail);
+    std::unique_ptr<Thumbnail> protection(thumbnail);
   
     Thumbnails::iterator found = thumbnails_.find(seriesInstanceUid);
     if (found == thumbnails_.end())
@@ -254,7 +254,7 @@
       arguments["0020000E"] = GetSeriesInstanceUid();
       arguments["includefield"] = "00080016";
 
-      std::auto_ptr<IOracleCommand> command(
+      std::unique_ptr<IOracleCommand> command(
         GetSource().CreateDicomWebCommand(
           "/instances", arguments, headers, new DicomWebSopClassHandler(
             GetLoader(), GetSource(), GetStudyInstanceUid(), GetSeriesInstanceUid())));
@@ -326,7 +326,7 @@
       }
       else
       {
-        std::auto_ptr<GetOrthancImageCommand> command(new GetOrthancImageCommand);
+        std::unique_ptr<GetOrthancImageCommand> command(new GetOrthancImageCommand);
         command->SetUri("/instances/" + instanceId_ + "/preview");
         command->SetHttpHeader("Accept", Orthanc::MIME_JPEG);
         command->AcquirePayload(new ThumbnailInformation(
@@ -375,7 +375,7 @@
 
           const std::string instance = json[INSTANCES][index].asString();
 
-          std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand);
+          std::unique_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand);
           command->SetUri("/instances/" + instance + "/metadata/SopClassUid");
           command->AcquirePayload(
             new OrthancSopClassHandler(
@@ -389,7 +389,7 @@
     
   void SeriesThumbnailsLoader::Schedule(IOracleCommand* command)
   {
-    std::auto_ptr<ILoadersContext::ILock> lock(context_.Lock());
+    std::unique_ptr<ILoadersContext::ILock> lock(context_.Lock());
     lock->Schedule(GetSharedObserver(), priority_, command);
   }    
 
@@ -412,7 +412,7 @@
   {
     assert(message.GetOrigin().HasPayload());
 
-    std::auto_ptr<Orthanc::ImageAccessor> resized(Orthanc::ImageProcessing::FitSize(message.GetImage(), width_, height_));
+    std::unique_ptr<Orthanc::ImageAccessor> resized(Orthanc::ImageProcessing::FitSize(message.GetImage(), width_, height_));
 
     std::string jpeg;
     Orthanc::JpegWriter writer;
@@ -540,7 +540,7 @@
       // https://github.com/emscripten-core/emscripten/pull/8486
       headers["Accept"] = Orthanc::MIME_JPEG;
 
-      std::auto_ptr<IOracleCommand> command(
+      std::unique_ptr<IOracleCommand> command(
         source.CreateDicomWebCommand(
           uri, arguments, headers, new DicomWebThumbnailHandler(
             shared_from_this(), source, studyInstanceUid, seriesInstanceUid)));
@@ -551,7 +551,7 @@
       // Dummy SOP Instance UID, as we are working at the "series" level
       Orthanc::DicomInstanceHasher hasher(patientId, studyInstanceUid, seriesInstanceUid, "dummy");
 
-      std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand);
+      std::unique_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand);
       command->SetUri("/series/" + hasher.HashSeries());
       command->AcquirePayload(new SelectOrthancInstanceHandler(
                                 shared_from_this(), source, studyInstanceUid, seriesInstanceUid));
--- a/Framework/Oracle/GenericOracleRunner.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Oracle/GenericOracleRunner.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -314,7 +314,7 @@
 
     if (ok)
     {
-      std::auto_ptr<Orthanc::ParsedDicomFile> result(new Orthanc::ParsedDicomFile(dicom));
+      std::unique_ptr<Orthanc::ParsedDicomFile> result(new Orthanc::ParsedDicomFile(dicom));
 
       boost::posix_time::ptime end = boost::posix_time::microsec_clock::local_time();
       LOG(TRACE) << path << ": parsed in " << (end-start).total_milliseconds() << " ms";
@@ -352,7 +352,7 @@
     }
 
     uint64_t fileSize;
-    std::auto_ptr<Orthanc::ParsedDicomFile> parsed(ParseDicom(fileSize, path, command.IsPixelDataIncluded()));
+    std::unique_ptr<Orthanc::ParsedDicomFile> parsed(ParseDicom(fileSize, path, command.IsPixelDataIncluded()));
 
     if (fileSize != static_cast<size_t>(fileSize))
     {
@@ -418,7 +418,7 @@
     }
 
     size_t fileSize;
-    std::auto_ptr<Orthanc::ParsedDicomFile> parsed(ParseDicomSuccessMessage::ParseWadoAnswer(fileSize, answer, answerHeaders));
+    std::unique_ptr<Orthanc::ParsedDicomFile> parsed(ParseDicomSuccessMessage::ParseWadoAnswer(fileSize, answer, answerHeaders));
 
     {
       ParseDicomSuccessMessage message(command, *parsed, fileSize,
--- a/Framework/Oracle/GetOrthancImageCommand.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Oracle/GetOrthancImageCommand.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -112,7 +112,7 @@
       }
     }
 
-    std::auto_ptr<Orthanc::ImageAccessor> image;
+    std::unique_ptr<Orthanc::ImageAccessor> image;
 
     switch (contentType)
     {
--- a/Framework/Oracle/GetOrthancWebViewerJpegCommand.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Oracle/GetOrthancWebViewerJpegCommand.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -114,7 +114,7 @@
       }
     }
     
-    std::auto_ptr<Orthanc::ImageAccessor> reader;
+    std::unique_ptr<Orthanc::ImageAccessor> reader;
     
     {
       std::string jpeg;
@@ -185,7 +185,7 @@
     }
     
     // Decode a grayscale JPEG 8bpp image coming from the Web viewer
-    std::auto_ptr<Orthanc::ImageAccessor> image
+    std::unique_ptr<Orthanc::ImageAccessor> image
       (new Orthanc::Image(expectedFormat_, reader->GetWidth(), reader->GetHeight(), false));
 
     Orthanc::ImageProcessing::Convert(*image, *reader);
--- a/Framework/Oracle/OracleCommandBase.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Oracle/OracleCommandBase.h	Wed Mar 04 10:21:54 2020 +0100
@@ -23,6 +23,9 @@
 
 #include "IOracleCommand.h"
 
+#include <Core/Compatibility.h>
+#include <Core/IDynamicObject.h>
+
 #include <memory>
 
 namespace OrthancStone
@@ -30,7 +33,7 @@
   class OracleCommandBase : public IOracleCommand
   {
   private:
-    std::auto_ptr<Orthanc::IDynamicObject>  payload_;
+    std::unique_ptr<Orthanc::IDynamicObject>  payload_;
 
   public:
     void AcquirePayload(Orthanc::IDynamicObject* payload);
--- a/Framework/Oracle/ParseDicomFromWadoCommand.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Oracle/ParseDicomFromWadoCommand.h	Wed Mar 04 10:21:54 2020 +0100
@@ -31,7 +31,7 @@
   {
   private:
     std::string                    sopInstanceUid_;
-    std::auto_ptr<IOracleCommand>  restCommand_;
+    std::unique_ptr<IOracleCommand>  restCommand_;
 
   public:
     ParseDicomFromWadoCommand(const std::string& sopInstanceUid,
--- a/Framework/Oracle/ParseDicomSuccessMessage.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Oracle/ParseDicomSuccessMessage.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -30,7 +30,7 @@
   class MultipartHandler : public Orthanc::MultipartStreamReader::IHandler
   {
   private:
-    std::auto_ptr<Orthanc::ParsedDicomFile>  dicom_;
+    std::unique_ptr<Orthanc::ParsedDicomFile>  dicom_;
     size_t                                   size_;
 
   public:
--- a/Framework/Oracle/ThreadedOracle.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Oracle/ThreadedOracle.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -32,7 +32,7 @@
   {
   private:
     boost::weak_ptr<IObserver>      receiver_;
-    std::auto_ptr<IOracleCommand>   command_;
+    std::unique_ptr<IOracleCommand>   command_;
 
   public:
     Item(boost::weak_ptr<IObserver> receiver,
@@ -66,7 +66,7 @@
     {
     private:
       boost::weak_ptr<IObserver>         receiver_;
-      std::auto_ptr<SleepOracleCommand>  command_;
+      std::unique_ptr<SleepOracleCommand>  command_;
       boost::posix_time::ptime           expiration_;
 
     public:
@@ -154,7 +154,7 @@
 
   void ThreadedOracle::Step()
   {
-    std::auto_ptr<Orthanc::IDynamicObject>  object(queue_.Dequeue(100));
+    std::unique_ptr<Orthanc::IDynamicObject>  object(queue_.Dequeue(100));
 
     if (object.get() != NULL)
     {
@@ -164,7 +164,7 @@
       {
         SleepOracleCommand& command = dynamic_cast<SleepOracleCommand&>(item.GetCommand());
           
-        std::auto_ptr<SleepOracleCommand> copy(new SleepOracleCommand(command.GetDelay()));
+        std::unique_ptr<SleepOracleCommand> copy(new SleepOracleCommand(command.GetDelay()));
           
         if (command.HasPayload())
         {
@@ -412,7 +412,7 @@
   bool ThreadedOracle::Schedule(boost::shared_ptr<IObserver> receiver,
                                 IOracleCommand* command)
   {
-    std::auto_ptr<Item> item(new Item(receiver, command));
+    std::unique_ptr<Item> item(new Item(receiver, command));
 
     {
       boost::mutex::scoped_lock lock(mutex_);
--- a/Framework/Oracle/WebAssemblyOracle.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Oracle/WebAssemblyOracle.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -43,7 +43,7 @@
   private:
     WebAssemblyOracle&                 oracle_;
     boost::weak_ptr<IObserver>         receiver_;
-    std::auto_ptr<SleepOracleCommand>  command_;
+    std::unique_ptr<SleepOracleCommand>  command_;
 
   public:
     TimeoutContext(WebAssemblyOracle& oracle,
@@ -72,7 +72,7 @@
 
     static void Callback(void *userData)
     {
-      std::auto_ptr<TimeoutContext> context(reinterpret_cast<TimeoutContext*>(userData));
+      std::unique_ptr<TimeoutContext> context(reinterpret_cast<TimeoutContext*>(userData));
       context->EmitMessage();
     }
   };
@@ -92,7 +92,7 @@
   private:
     WebAssemblyOracle&             oracle_;
     boost::weak_ptr<IObserver>     receiver_;
-    std::auto_ptr<IOracleCommand>  command_;
+    std::unique_ptr<IOracleCommand>  command_;
     std::string                    expectedContentType_;
 
   public:
@@ -149,7 +149,7 @@
 
 #if ORTHANC_ENABLE_DCMTK == 1
     void StoreInCache(const std::string& sopInstanceUid,
-                      std::auto_ptr<Orthanc::ParsedDicomFile>& dicom,
+                      std::unique_ptr<Orthanc::ParsedDicomFile>& dicom,
                       size_t fileSize)
     {
       if (oracle_.dicomCache_.get())
@@ -174,7 +174,7 @@
         return;
       }
 
-      std::auto_ptr<FetchContext> context(reinterpret_cast<FetchContext*>(fetch->userData));
+      std::unique_ptr<FetchContext> context(reinterpret_cast<FetchContext*>(fetch->userData));
 
       std::string answer;
       if (fetch->numBytes > 0)
@@ -292,7 +292,7 @@
                 context->GetTypedCommand<ParseDicomFromWadoCommand>();
               
               size_t fileSize;
-              std::auto_ptr<Orthanc::ParsedDicomFile> dicom
+              std::unique_ptr<Orthanc::ParsedDicomFile> dicom
                 (ParseDicomSuccessMessage::ParseWadoAnswer(fileSize, answer, headers));
 
               {
@@ -327,7 +327,7 @@
 
     static void FailureCallback(emscripten_fetch_t *fetch)
     {
-      std::auto_ptr<FetchContext> context(reinterpret_cast<FetchContext*>(fetch->userData));
+      std::unique_ptr<FetchContext> context(reinterpret_cast<FetchContext*>(fetch->userData));
 
       {
         const size_t kEmscriptenStatusTextSize = sizeof(emscripten_fetch_t::statusText);
@@ -364,7 +364,7 @@
   private:
     WebAssemblyOracle&             oracle_;
     boost::weak_ptr<IObserver>     receiver_;
-    std::auto_ptr<IOracleCommand>  command_;
+    std::unique_ptr<IOracleCommand>  command_;
     Orthanc::HttpMethod            method_;
     std::string                    url_;
     std::string                    body_;
@@ -655,7 +655,7 @@
   void WebAssemblyOracle::Execute(boost::weak_ptr<IObserver> receiver,
                                   ParseDicomFromWadoCommand* command)
   {
-    std::auto_ptr<ParseDicomFromWadoCommand> protection(command);
+    std::unique_ptr<ParseDicomFromWadoCommand> protection(command);
     
 #if ORTHANC_ENABLE_DCMTK == 1
     if (dicomCache_.get())
@@ -733,7 +733,7 @@
     LOG(TRACE) << "WebAssemblyOracle::Schedule : receiver = "
                << std::hex << &receiver;
     
-    std::auto_ptr<IOracleCommand> protection(command);
+    std::unique_ptr<IOracleCommand> protection(command);
 
     if (command == NULL)
     {
--- a/Framework/Oracle/WebAssemblyOracle.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Oracle/WebAssemblyOracle.h	Wed Mar 04 10:21:54 2020 +0100
@@ -81,7 +81,7 @@
     Orthanc::WebServiceParameters  remoteOrthanc_;
 
 #if ORTHANC_ENABLE_DCMTK == 1
-    std::auto_ptr<ParsedDicomCache>  dicomCache_;
+    std::unique_ptr<ParsedDicomCache>  dicomCache_;
 #endif
 
   public:
--- a/Framework/Radiography/RadiographyAlphaLayer.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Radiography/RadiographyAlphaLayer.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -23,8 +23,10 @@
 
 #include "RadiographyScene.h"
 
+#include <Core/Compatibility.h>
 #include <Core/Images/Image.h>
 #include <Core/OrthancException.h>
+
 #include "../Toolbox/ImageGeometry.h"
 
 namespace OrthancStone
@@ -32,7 +34,7 @@
 
   void RadiographyAlphaLayer::SetAlpha(Orthanc::ImageAccessor* image)
   {
-    std::auto_ptr<Orthanc::ImageAccessor> raii(image);
+    std::unique_ptr<Orthanc::ImageAccessor> raii(image);
 
     if (image == NULL)
     {
@@ -45,7 +47,12 @@
     }
 
     SetSize(image->GetWidth(), image->GetHeight());
-    alpha_ = raii;
+
+#if __cplusplus < 201103L
+    alpha_.reset(raii.release());
+#else
+    alpha_ = std::move(raii);
+#endif
 
     BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this));
   }
--- a/Framework/Radiography/RadiographyAlphaLayer.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Radiography/RadiographyAlphaLayer.h	Wed Mar 04 10:21:54 2020 +0100
@@ -23,6 +23,8 @@
 
 #include "RadiographyLayer.h"
 
+#include <Core/Compatibility.h>
+
 namespace OrthancStone
 {
   class RadiographyScene;
@@ -33,7 +35,7 @@
   class RadiographyAlphaLayer : public RadiographyLayer
   {
   private:
-    std::auto_ptr<Orthanc::ImageAccessor>  alpha_;       // Grayscale8 in the range [0, 255]  0 = transparent, 255 = opaque -> the foreground value will be displayed
+    std::unique_ptr<Orthanc::ImageAccessor>  alpha_;       // Grayscale8 in the range [0, 255]  0 = transparent, 255 = opaque -> the foreground value will be displayed
     float                                  foreground_;  // in the range [0.0, 65535.0]
 
   public:
--- a/Framework/Radiography/RadiographyDicomLayer.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Radiography/RadiographyDicomLayer.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -98,7 +98,7 @@
 
   void RadiographyDicomLayer::SetSourceImage(Orthanc::ImageAccessor* image)   // Takes ownership
   {
-    std::auto_ptr<Orthanc::ImageAccessor> raii(image);
+    std::unique_ptr<Orthanc::ImageAccessor> raii(image);
 
     if (image == NULL)
     {
@@ -107,7 +107,12 @@
 
     SetSize(image->GetWidth(), image->GetHeight());
 
-    source_ = raii;
+#if __cplusplus < 201103L
+    source_.reset(raii.release());
+#else
+    source_ = std::move(raii);
+#endif
+
     ApplyConverter();
 
     BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this));
@@ -115,7 +120,7 @@
 
   void RadiographyDicomLayer::SetSourceImage(Orthanc::ImageAccessor* image, double newPixelSpacingX, double newPixelSpacingY, bool emitLayerEditedEvent)   // Takes ownership
   {
-    std::auto_ptr<Orthanc::ImageAccessor> raii(image);
+    std::unique_ptr<Orthanc::ImageAccessor> raii(image);
 
     if (image == NULL)
     {
@@ -124,7 +129,12 @@
 
     SetSize(image->GetWidth(), image->GetHeight(), false);
 
-    source_ = raii;
+#if __cplusplus < 201103L
+    source_.reset(raii.release());
+#else
+    source_ = std::move(raii);
+#endif
+
     ApplyConverter();
 
     SetPixelSpacing(newPixelSpacingX, newPixelSpacingY, false);
--- a/Framework/Radiography/RadiographyDicomLayer.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Radiography/RadiographyDicomLayer.h	Wed Mar 04 10:21:54 2020 +0100
@@ -33,9 +33,9 @@
   class RadiographyDicomLayer : public RadiographyLayer
   {
   private:
-    std::auto_ptr<Orthanc::ImageAccessor>  source_;  // Content of PixelData
-    std::auto_ptr<Deprecated::DicomFrameConverter>     converter_;
-    std::auto_ptr<Orthanc::ImageAccessor>  converted_;  // Float32
+    std::unique_ptr<Orthanc::ImageAccessor>  source_;  // Content of PixelData
+    std::unique_ptr<Deprecated::DicomFrameConverter>     converter_;
+    std::unique_ptr<Orthanc::ImageAccessor>  converted_;  // Float32
     std::string                            instanceId_;
     unsigned int                           frame_;
 
--- a/Framework/Radiography/RadiographyMaskLayer.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Radiography/RadiographyMaskLayer.h	Wed Mar 04 10:21:54 2020 +0100
@@ -22,8 +22,10 @@
 #pragma once
 
 #include "RadiographyLayer.h"
-#include "Core/Images/Image.h"
-#include "Core/Images/ImageProcessing.h"
+
+#include <Core/Compatibility.h>
+#include <Core/Images/Image.h>
+#include <Core/Images/ImageProcessing.h>
 
 namespace OrthancStone
 {
@@ -38,7 +40,7 @@
     mutable bool                      invalidated_;
     float                             foreground_;
 
-    mutable std::auto_ptr<Orthanc::ImageAccessor>  mask_;
+    mutable std::unique_ptr<Orthanc::ImageAccessor>  mask_;
   public:
     RadiographyMaskLayer(const RadiographyScene& scene, const RadiographyDicomLayer& dicomLayer,
                          float foreground) :
--- a/Framework/Radiography/RadiographyScene.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Radiography/RadiographyScene.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -127,7 +127,7 @@
 
   void RadiographyScene::_RegisterLayer(RadiographyLayer* layer)
   {
-    std::auto_ptr<RadiographyLayer> raii(layer);
+    std::unique_ptr<RadiographyLayer> raii(layer);
 
     // LOG(INFO) << "Registering layer: " << countLayers_;
 
@@ -324,7 +324,7 @@
                                                RadiographyLayer::Geometry* centerGeometry,
                                                bool isCenterGeometry)
   {
-    std::auto_ptr<RadiographyTextLayer>  alpha(new RadiographyTextLayer(*this));
+    std::unique_ptr<RadiographyTextLayer>  alpha(new RadiographyTextLayer(*this));
     alpha->SetText(utf8, font, fontSize, foreground);
     if (centerGeometry != NULL)
     {
@@ -352,7 +352,7 @@
                                                     unsigned int height,
                                                     RadiographyLayer::Geometry* geometry)
   {
-    std::auto_ptr<Orthanc::Image>  block(new Orthanc::Image(Orthanc::PixelFormat_Grayscale8, width, height, false));
+    std::unique_ptr<Orthanc::Image>  block(new Orthanc::Image(Orthanc::PixelFormat_Grayscale8, width, height, false));
 
     for (unsigned int padding = 0;
          (width > 2 * padding) && (height > 2 * padding);
@@ -381,7 +381,7 @@
                                                float foreground,
                                                RadiographyLayer::Geometry* geometry)
   {
-    std::auto_ptr<RadiographyMaskLayer>  mask(new RadiographyMaskLayer(*this, dicomLayer, foreground));
+    std::unique_ptr<RadiographyMaskLayer>  mask(new RadiographyMaskLayer(*this, dicomLayer, foreground));
     mask->SetCorners(corners);
     if (geometry != NULL)
     {
@@ -394,7 +394,7 @@
 
   RadiographyLayer& RadiographyScene::LoadAlphaBitmap(Orthanc::ImageAccessor* bitmap, RadiographyLayer::Geometry *geometry)
   {
-    std::auto_ptr<RadiographyAlphaLayer>  alpha(new RadiographyAlphaLayer(*this));
+    std::unique_ptr<RadiographyAlphaLayer>  alpha(new RadiographyAlphaLayer(*this));
     alpha->SetAlpha(bitmap);
     if (geometry != NULL)
     {
@@ -490,8 +490,8 @@
     size_t index = dynamic_cast<const Orthanc::SingleValueObject<size_t>&>
         (message.GetPayload()).GetValue();
 
-    LOG(INFO) << "JSON received: " << message.GetUri().c_str()
-              << " (" << message.GetAnswerSize() << " bytes) for layer " << index;
+    VLOG(1) << "JSON received: " << message.GetUri().c_str()
+            << " (" << message.GetAnswerSize() << " bytes) for layer " << index;
 
     Layers::iterator layer = layers_.find(index);
     if (layer != layers_.end())
@@ -519,8 +519,8 @@
   {
     size_t index = dynamic_cast<const Orthanc::SingleValueObject<size_t>&>(message.GetPayload()).GetValue();
 
-    LOG(INFO) << "DICOM frame received: " << message.GetUri().c_str()
-              << " (" << message.GetAnswerSize() << " bytes) for layer " << index;
+    VLOG(1) << "DICOM frame received: " << message.GetUri().c_str()
+            << " (" << message.GetAnswerSize() << " bytes) for layer " << index;
 
     Layers::iterator layer = layers_.find(index);
     if (layer != layers_.end())
@@ -533,7 +533,7 @@
         content.assign(reinterpret_cast<const char*>(message.GetAnswer()), message.GetAnswerSize());
       }
 
-      std::auto_ptr<Orthanc::PamReader> reader(new Orthanc::PamReader);
+      std::unique_ptr<Orthanc::PamReader> reader(new Orthanc::PamReader);
       reader->ReadFromMemory(content);
       dynamic_cast<RadiographyDicomLayer*>(layer->second)->SetSourceImage(reader.release());
 
@@ -724,7 +724,7 @@
 
     Render(layers, view, interpolation, applyWindowing);
 
-    std::auto_ptr<Orthanc::Image> rendered(new Orthanc::Image(Orthanc::PixelFormat_Grayscale16,
+    std::unique_ptr<Orthanc::Image> rendered(new Orthanc::Image(Orthanc::PixelFormat_Grayscale16,
                                                               layers.GetWidth(), layers.GetHeight(), false));
 
     Orthanc::ImageProcessing::Convert(*rendered, layers);
@@ -745,7 +745,7 @@
   {
     LOG(INFO) << "Exporting RadiographyScene to DICOM";
 
-    std::auto_ptr<Orthanc::Image> rendered(ExportToImage(pixelSpacingX, pixelSpacingY, interpolation, false)); // note: we don't invert the image in the pixels data because we'll set the PhotometricDisplayMode correctly in the DICOM tags
+    std::unique_ptr<Orthanc::Image> rendered(ExportToImage(pixelSpacingX, pixelSpacingY, interpolation, false)); // note: we don't invert the image in the pixels data because we'll set the PhotometricDisplayMode correctly in the DICOM tags
 
     createDicomRequestContent["Tags"] = dicomTags;
 
@@ -800,7 +800,7 @@
     LOG(INFO) << "Exporting RadiographyScene to DICOM";
     VLOG(1) << "Exporting RadiographyScene to: export to image";
 
-    std::auto_ptr<Orthanc::Image> rendered(ExportToCreateDicomRequestAndImage(createDicomRequestContent, dicomTags, parentOrthancId, pixelSpacingX, pixelSpacingY, invert, interpolation));
+    std::unique_ptr<Orthanc::Image> rendered(ExportToCreateDicomRequestAndImage(createDicomRequestContent, dicomTags, parentOrthancId, pixelSpacingX, pixelSpacingY, invert, interpolation));
 
     // convert the image into base64 for inclusing in the createDicomRequest
     std::string base64;
--- a/Framework/Radiography/RadiographySceneReader.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Radiography/RadiographySceneReader.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -55,7 +55,7 @@
 
   RadiographyDicomLayer* RadiographySceneGeometryReader::LoadDicom(const std::string& instanceId, unsigned int frame, RadiographyLayer::Geometry* geometry)
   {
-    std::auto_ptr<RadiographyPlaceholderLayer>  layer(new RadiographyPlaceholderLayer(scene_));
+    std::unique_ptr<RadiographyPlaceholderLayer>  layer(new RadiographyPlaceholderLayer(scene_));
     layer->SetGeometry(*geometry);
     layer->SetSize(dicomImageWidth_, dicomImageHeight_);
     scene_.RegisterLayer(layer.get());
@@ -119,7 +119,7 @@
         std::string mimeType;
         Orthanc::Toolbox::DecodeDataUriScheme(mimeType, pngContent, pngContentBase64);
 
-        std::auto_ptr<Orthanc::ImageAccessor>  image;
+        std::unique_ptr<Orthanc::ImageAccessor>  image;
         if (mimeType == "image/png")
         {
           image.reset(new Orthanc::PngReader());
--- a/Framework/Radiography/RadiographySceneReader.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Radiography/RadiographySceneReader.h	Wed Mar 04 10:21:54 2020 +0100
@@ -52,8 +52,8 @@
   {
   protected:
     RadiographyScene&                               scene_;
-    std::auto_ptr<Orthanc::ImageAccessor>           dicomImage_;
-    std::auto_ptr<Deprecated::DicomFrameConverter>  dicomFrameConverter_;
+    std::unique_ptr<Orthanc::ImageAccessor>           dicomImage_;
+    std::unique_ptr<Deprecated::DicomFrameConverter>  dicomFrameConverter_;
     RadiographyPhotometricDisplayMode               preferredPhotometricDisplayMode_;
 
   public:
--- a/Framework/Radiography/RadiographyWidget.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Radiography/RadiographyWidget.h	Wed Mar 04 10:21:54 2020 +0100
@@ -40,8 +40,8 @@
 
   private:
     boost::shared_ptr<RadiographyScene>    scene_;
-    std::auto_ptr<Orthanc::ImageAccessor>  floatBuffer_;
-    std::auto_ptr<CairoSurface>            cairoBuffer_;
+    std::unique_ptr<Orthanc::ImageAccessor>  floatBuffer_;
+    std::unique_ptr<CairoSurface>            cairoBuffer_;
     bool                                   invert_;
     ImageInterpolation                     interpolation_;
     bool                                   hasSelection_;
--- a/Framework/Scene2D/CairoCompositor.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/CairoCompositor.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -117,7 +117,7 @@
     }
     else
     {
-      std::auto_ptr<GlyphBitmapAlphabet> protection(dict);
+      std::unique_ptr<GlyphBitmapAlphabet> protection(dict);
       
       Fonts::iterator found = fonts_.find(index);
 
@@ -145,7 +145,7 @@
     FontRenderer renderer;
     renderer.LoadFont(resource, fontSize);
 
-    std::auto_ptr<GlyphBitmapAlphabet> alphabet(new GlyphBitmapAlphabet);
+    std::unique_ptr<GlyphBitmapAlphabet> alphabet(new GlyphBitmapAlphabet);
     alphabet->LoadCodepage(renderer, codepage);
 
     SetFont(index, alphabet.release());
--- a/Framework/Scene2D/CairoCompositor.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/CairoCompositor.h	Wed Mar 04 10:21:54 2020 +0100
@@ -37,12 +37,12 @@
   private:
     typedef std::map<size_t, GlyphBitmapAlphabet*>   Fonts;
 
-    std::auto_ptr<Internals::CompositorHelper>  helper_;
+    std::unique_ptr<Internals::CompositorHelper>  helper_;
     CairoSurface                 canvas_;
     Fonts                        fonts_;
 
     // Only valid during a call to "Refresh()"
-    std::auto_ptr<CairoContext>  context_;
+    std::unique_ptr<CairoContext>  context_;
 
     virtual cairo_t* GetCairoContext() ORTHANC_OVERRIDE;
 
--- a/Framework/Scene2D/ColorTextureSceneLayer.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/ColorTextureSceneLayer.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -42,7 +42,7 @@
 
   ISceneLayer* ColorTextureSceneLayer::Clone() const
   {
-    std::auto_ptr<ColorTextureSceneLayer> cloned(new ColorTextureSceneLayer(GetTexture()));
+    std::unique_ptr<ColorTextureSceneLayer> cloned(new ColorTextureSceneLayer(GetTexture()));
     cloned->CopyParameters(*this);
     return cloned.release();
   }
--- a/Framework/Scene2D/FloatTextureSceneLayer.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/FloatTextureSceneLayer.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -21,6 +21,8 @@
 
 #include "FloatTextureSceneLayer.h"
 
+#include "../Toolbox/ImageToolbox.h"
+
 #include <Core/Images/Image.h>
 #include <Core/Images/ImageProcessing.h>
 #include <Core/OrthancException.h>
@@ -32,13 +34,14 @@
     applyLog_(false)
   {
     {
-      std::auto_ptr<Orthanc::ImageAccessor> t(
+      std::unique_ptr<Orthanc::ImageAccessor> t(
         new Orthanc::Image(Orthanc::PixelFormat_Float32, 
                            texture.GetWidth(), 
                            texture.GetHeight(), 
                            false));
 
       Orthanc::ImageProcessing::Convert(*t, texture);
+
       SetTexture(t.release());
     }
 
@@ -124,7 +127,7 @@
     
   ISceneLayer* FloatTextureSceneLayer::Clone() const
   {
-    std::auto_ptr<FloatTextureSceneLayer> cloned
+    std::unique_ptr<FloatTextureSceneLayer> cloned
       (new FloatTextureSceneLayer(GetTexture()));
 
     cloned->CopyParameters(*this);
--- a/Framework/Scene2D/GrayscaleStyleConfigurator.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/GrayscaleStyleConfigurator.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -88,7 +88,7 @@
     const Orthanc::ImageAccessor& frame,
     const DicomInstanceParameters& parameters) const
   {
-    std::auto_ptr<TextureBaseSceneLayer> layer(parameters.CreateTexture(frame));
+    std::unique_ptr<TextureBaseSceneLayer> layer(parameters.CreateTexture(frame));
 
     if (layer.get() == NULL ||
         layer->GetTexture().GetFormat() != Orthanc::PixelFormat_Float32)
--- a/Framework/Scene2D/InfoPanelSceneLayer.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/InfoPanelSceneLayer.h	Wed Mar 04 10:21:54 2020 +0100
@@ -24,6 +24,7 @@
 #include "ISceneLayer.h"
 #include "../StoneEnumerations.h"
 
+#include <Core/Compatibility.h>
 #include <Core/Images/ImageAccessor.h>
 
 #include <memory>
@@ -33,7 +34,7 @@
   class InfoPanelSceneLayer : public ISceneLayer
   {
   private:
-    std::auto_ptr<Orthanc::ImageAccessor>  texture_;
+    std::unique_ptr<Orthanc::ImageAccessor>  texture_;
     BitmapAnchor                           anchor_;
     bool                                   isLinearInterpolation_;
 
--- a/Framework/Scene2D/Internals/CairoBaseRenderer.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/Internals/CairoBaseRenderer.h	Wed Mar 04 10:21:54 2020 +0100
@@ -24,6 +24,8 @@
 #include "ICairoContextProvider.h"
 #include "CompositorHelper.h"
 
+#include <Core/Compatibility.h>
+
 namespace OrthancStone
 {
   namespace Internals
@@ -32,7 +34,7 @@
     {
     private:
       ICairoContextProvider&      target_;
-      std::auto_ptr<ISceneLayer>  layer_;
+      std::unique_ptr<ISceneLayer>  layer_;
 
     protected:
       template<typename T>
--- a/Framework/Scene2D/Internals/CairoTextRenderer.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/Internals/CairoTextRenderer.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -32,7 +32,7 @@
                                          const TextSceneLayer& layer) :
       CairoBaseRenderer(target, layer)
     {
-      std::auto_ptr<Orthanc::ImageAccessor> source(alphabet.RenderText(layer.GetText()));
+      std::unique_ptr<Orthanc::ImageAccessor> source(alphabet.RenderText(layer.GetText()));
 
       if (source.get() != NULL)
       {
--- a/Framework/Scene2D/Internals/CompositorHelper.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/Internals/CompositorHelper.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -30,7 +30,7 @@
     class CompositorHelper::Item : public boost::noncopyable
     {
     private:
-      std::auto_ptr<ILayerRenderer>  renderer_;
+      std::unique_ptr<ILayerRenderer>  renderer_;
       const ISceneLayer&             layer_;
       uint64_t                       layerIdentifier_;
       uint64_t                       lastRevision_;
@@ -104,7 +104,7 @@
           content_.erase(found);
         }
 
-        std::auto_ptr<ILayerRenderer> renderer(factory_.Create(layer));
+        std::unique_ptr<ILayerRenderer> renderer(factory_.Create(layer));
 
         if (renderer.get() != NULL)
         {
--- a/Framework/Scene2D/Internals/OpenGLAdvancedPolylineRenderer.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/Internals/OpenGLAdvancedPolylineRenderer.h	Wed Mar 04 10:21:54 2020 +0100
@@ -34,7 +34,7 @@
     private:
       OpenGL::IOpenGLContext&                  context_;
       OpenGLLinesProgram&                      program_;
-      std::auto_ptr<OpenGLLinesProgram::Data>  data_;
+      std::unique_ptr<OpenGLLinesProgram::Data>  data_;
 
       void LoadLayer(const PolylineSceneLayer& layer);
 
--- a/Framework/Scene2D/Internals/OpenGLBasicPolylineRenderer.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/Internals/OpenGLBasicPolylineRenderer.h	Wed Mar 04 10:21:54 2020 +0100
@@ -25,6 +25,8 @@
 #include "../PolylineSceneLayer.h"
 #include "CompositorHelper.h"
 
+#include <Core/Compatibility.h>
+
 namespace OrthancStone
 {
   namespace Internals
--- a/Framework/Scene2D/Internals/OpenGLColorTextureRenderer.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/Internals/OpenGLColorTextureRenderer.h	Wed Mar 04 10:21:54 2020 +0100
@@ -34,7 +34,7 @@
     private:
       OpenGL::IOpenGLContext&               context_;
       OpenGLColorTextureProgram&            program_;
-      std::auto_ptr<OpenGL::OpenGLTexture>  texture_;
+      std::unique_ptr<OpenGL::OpenGLTexture>  texture_;
       AffineTransform2D                     layerTransform_;
 
       void LoadTexture(const ColorTextureSceneLayer& layer);
--- a/Framework/Scene2D/Internals/OpenGLFloatTextureRenderer.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/Internals/OpenGLFloatTextureRenderer.h	Wed Mar 04 10:21:54 2020 +0100
@@ -34,7 +34,7 @@
     private:
       OpenGL::IOpenGLContext&                         context_;
       OpenGLFloatTextureProgram&                      program_;
-      std::auto_ptr<OpenGLFloatTextureProgram::Data>  texture_;
+      std::unique_ptr<OpenGLFloatTextureProgram::Data>  texture_;
       AffineTransform2D                               layerTransform_;
       float                                           windowCenter_;
       float                                           windowWidth_;
--- a/Framework/Scene2D/Internals/OpenGLInfoPanelRenderer.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/Internals/OpenGLInfoPanelRenderer.h	Wed Mar 04 10:21:54 2020 +0100
@@ -34,7 +34,7 @@
     private:
       OpenGL::IOpenGLContext&               context_;
       OpenGLColorTextureProgram&            program_;
-      std::auto_ptr<OpenGL::OpenGLTexture>  texture_;
+      std::unique_ptr<OpenGL::OpenGLTexture>  texture_;
       BitmapAnchor                          anchor_;
 
       void LoadTexture(const InfoPanelSceneLayer& layer);
--- a/Framework/Scene2D/Internals/OpenGLLinesProgram.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/Internals/OpenGLLinesProgram.h	Wed Mar 04 10:21:54 2020 +0100
@@ -26,6 +26,8 @@
 #include "../../Toolbox/AffineTransform2D.h"
 #include "../PolylineSceneLayer.h"
 
+#include <Core/Compatibility.h>
+
 namespace OrthancStone
 {
   namespace Internals
@@ -73,7 +75,7 @@
       
     private:
       OpenGL::IOpenGLContext&               context_;
-      std::auto_ptr<OpenGL::OpenGLProgram>  program_;
+      std::unique_ptr<OpenGL::OpenGLProgram>  program_;
 
     public:
       OpenGLLinesProgram(OpenGL::IOpenGLContext&  context);
--- a/Framework/Scene2D/Internals/OpenGLLookupTableTextureRenderer.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/Internals/OpenGLLookupTableTextureRenderer.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -21,6 +21,9 @@
 
 #include "OpenGLLookupTableTextureRenderer.h"
 
+#include "../../Toolbox/ImageToolbox.h"
+
+
 #include <Core/OrthancException.h>
 
 namespace OrthancStone
--- a/Framework/Scene2D/Internals/OpenGLLookupTableTextureRenderer.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/Internals/OpenGLLookupTableTextureRenderer.h	Wed Mar 04 10:21:54 2020 +0100
@@ -36,8 +36,8 @@
     private:
       OpenGL::IOpenGLContext&                context_;
       OpenGLColorTextureProgram&             program_;
-      std::auto_ptr<OpenGL::OpenGLTexture>   glTexture_;
-      std::auto_ptr<Orthanc::Image>          texture_;
+      std::unique_ptr<OpenGL::OpenGLTexture>   glTexture_;
+      std::unique_ptr<Orthanc::Image>          texture_;
       AffineTransform2D                      layerTransform_;
 
       void LoadTexture(const LookupTableTextureSceneLayer& layer);
--- a/Framework/Scene2D/Internals/OpenGLTextProgram.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/Internals/OpenGLTextProgram.h	Wed Mar 04 10:21:54 2020 +0100
@@ -28,6 +28,8 @@
 #include "../../Toolbox/AffineTransform2D.h"
 #include "../TextSceneLayer.h"
 
+#include <Core/Compatibility.h>
+
 namespace OrthancStone
 {
   namespace Internals
@@ -120,7 +122,7 @@
       
     private:
       OpenGL::IOpenGLContext&               context_;
-      std::auto_ptr<OpenGL::OpenGLProgram>  program_;
+      std::unique_ptr<OpenGL::OpenGLProgram>  program_;
       GLint                                 positionLocation_;
       GLint                                 textureLocation_;
 
--- a/Framework/Scene2D/Internals/OpenGLTextRenderer.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/Internals/OpenGLTextRenderer.h	Wed Mar 04 10:21:54 2020 +0100
@@ -35,7 +35,7 @@
       OpenGLTextProgram&                      program_;
       const GlyphTextureAlphabet&             alphabet_;
       OpenGL::OpenGLTexture&                  texture_;
-      std::auto_ptr<OpenGLTextProgram::Data>  data_;
+      std::unique_ptr<OpenGLTextProgram::Data>  data_;
 
       void LoadLayer(const TextSceneLayer& layer);
 
--- a/Framework/Scene2D/Internals/OpenGLTextureProgram.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/Internals/OpenGLTextureProgram.h	Wed Mar 04 10:21:54 2020 +0100
@@ -26,6 +26,8 @@
 #include "../../OpenGL/OpenGLTexture.h"
 #include "../../Toolbox/AffineTransform2D.h"
 
+#include <Core/Compatibility.h>
+
 namespace OrthancStone
 {
   namespace Internals
@@ -34,7 +36,7 @@
     {
     private:
       OpenGL::IOpenGLContext&               context_;
-      std::auto_ptr<OpenGL::OpenGLProgram>  program_;
+      std::unique_ptr<OpenGL::OpenGLProgram>  program_;
       GLint                                 positionLocation_;
       GLint                                 textureLocation_;
       GLuint                                buffers_[2];
--- a/Framework/Scene2D/LookupTableTextureSceneLayer.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/LookupTableTextureSceneLayer.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -31,7 +31,7 @@
     applyLog_(false)
   {
     {
-      std::auto_ptr<Orthanc::ImageAccessor> t(
+      std::unique_ptr<Orthanc::ImageAccessor> t(
         new Orthanc::Image(Orthanc::PixelFormat_Float32, 
                            texture.GetWidth(), 
                            texture.GetHeight(), 
@@ -153,7 +153,7 @@
     
   ISceneLayer* LookupTableTextureSceneLayer::Clone() const
   {
-    std::auto_ptr<LookupTableTextureSceneLayer> cloned
+    std::unique_ptr<LookupTableTextureSceneLayer> cloned
       (new LookupTableTextureSceneLayer(GetTexture()));
 
 
--- a/Framework/Scene2D/OpenGLCompositor.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/OpenGLCompositor.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -33,8 +33,8 @@
   class OpenGLCompositor::Font : public boost::noncopyable
   {
   private:
-    std::auto_ptr<GlyphTextureAlphabet>   alphabet_;
-    std::auto_ptr<OpenGL::OpenGLTexture>  texture_;
+    std::unique_ptr<GlyphTextureAlphabet>   alphabet_;
+    std::unique_ptr<OpenGL::OpenGLTexture>  texture_;
 
   public:
     Font(OpenGL::IOpenGLContext& context, const GlyphBitmapAlphabet& dict)
@@ -42,7 +42,7 @@
       alphabet_.reset(new GlyphTextureAlphabet(dict));
       texture_.reset(new OpenGL::OpenGLTexture(context));
 
-      std::auto_ptr<Orthanc::ImageAccessor> bitmap(alphabet_->ReleaseTexture());
+      std::unique_ptr<Orthanc::ImageAccessor> bitmap(alphabet_->ReleaseTexture());
       texture_->Load(*bitmap, true /* enable linear interpolation */);
     }
 
@@ -185,7 +185,7 @@
     {
       context_.MakeCurrent(); // this can throw if context lost
 
-      std::auto_ptr<Font> font(new Font(context_, dict));
+      std::unique_ptr<Font> font(new Font(context_, dict));
 
       Fonts::iterator found = fonts_.find(index);
 
--- a/Framework/Scene2D/OpenGLCompositor.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/OpenGLCompositor.h	Wed Mar 04 10:21:54 2020 +0100
@@ -39,7 +39,7 @@
 
     OpenGL::IOpenGLContext&                     context_;
     Fonts                                       fonts_;
-    std::auto_ptr<Internals::CompositorHelper>  helper_;
+    std::unique_ptr<Internals::CompositorHelper>  helper_;
     Internals::OpenGLColorTextureProgram        colorTextureProgram_;
     Internals::OpenGLFloatTextureProgram        floatTextureProgram_;
     Internals::OpenGLLinesProgram               linesProgram_;
--- a/Framework/Scene2D/PolylineSceneLayer.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/PolylineSceneLayer.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -35,7 +35,7 @@
   
   ISceneLayer* PolylineSceneLayer::Clone() const
   {
-    std::auto_ptr<PolylineSceneLayer> cloned(new PolylineSceneLayer);
+    std::unique_ptr<PolylineSceneLayer> cloned(new PolylineSceneLayer);
     cloned->Copy(*this);
     return cloned.release();
   }
--- a/Framework/Scene2D/Scene2D.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/Scene2D.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -29,7 +29,7 @@
   class Scene2D::Item
   {
   private:
-    std::auto_ptr<ISceneLayer>  layer_;
+    std::unique_ptr<ISceneLayer>  layer_;
     uint64_t                    identifier_;
 
   public:
@@ -105,7 +105,7 @@
                          ISceneLayer* layer)  // Takes ownership
   {
     LOG(TRACE) << "SetLayer(" << depth << ", " << reinterpret_cast<intptr_t>(layer) << ")";
-    std::auto_ptr<Item> item(new Item(layer, layerCounter_++));
+    std::unique_ptr<Item> item(new Item(layer, layerCounter_++));
 
     if (layer == NULL)
     {
@@ -193,7 +193,7 @@
     {
       assert(found->second != NULL);
 
-      std::auto_ptr<ISceneLayer> layer(found->second->ReleaseLayer());
+      std::unique_ptr<ISceneLayer> layer(found->second->ReleaseLayer());
       assert(layer.get() != NULL);
 
       content_.erase(found);
--- a/Framework/Scene2D/TextSceneLayer.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/TextSceneLayer.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -21,6 +21,8 @@
 
 #include "TextSceneLayer.h"
 
+#include <Core/Compatibility.h>
+
 namespace OrthancStone
 {
   TextSceneLayer::TextSceneLayer() :
@@ -36,7 +38,7 @@
 
   ISceneLayer* TextSceneLayer::Clone() const
   {
-    std::auto_ptr<TextSceneLayer> cloned(new TextSceneLayer);
+    std::unique_ptr<TextSceneLayer> cloned(new TextSceneLayer);
     cloned->SetColor(GetColor());
     cloned->x_ = x_;
     cloned->y_ = y_;
--- a/Framework/Scene2D/TextureBaseSceneLayer.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2D/TextureBaseSceneLayer.h	Wed Mar 04 10:21:54 2020 +0100
@@ -24,6 +24,7 @@
 #include "ISceneLayer.h"
 #include "../Toolbox/AffineTransform2D.h"
 
+#include <Core/Compatibility.h>
 #include <Core/Images/ImageAccessor.h>
 
 namespace OrthancStone
@@ -31,7 +32,7 @@
   class TextureBaseSceneLayer : public ISceneLayer
   {
   private:
-    std::auto_ptr<Orthanc::ImageAccessor>  texture_;
+    std::unique_ptr<Orthanc::ImageAccessor>  texture_;
     double                                 originX_;
     double                                 originY_;
     double                                 pixelSpacingX_;
--- a/Framework/Scene2DViewport/LayerHolder.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2DViewport/LayerHolder.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -44,23 +44,23 @@
   void LayerHolder::CreateLayers()
   {
     std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+    ViewportController& controller = lock->GetController();
+    Scene2D& scene = controller.GetScene();
 
     assert(baseLayerIndex_ == -1);
 
-    baseLayerIndex_ = lock->GetController().GetScene().GetMaxDepth() + 100;
+    baseLayerIndex_ = scene.GetMaxDepth() + 100;
 
     for (int i = 0; i < polylineLayerCount_; ++i)
     {
-      std::auto_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer());
-      lock->GetController().GetScene().SetLayer(baseLayerIndex_ + i, layer.release());
+      std::unique_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer());
+      scene.SetLayer(baseLayerIndex_ + i, layer.release());
     }
 
     for (int i = 0; i < textLayerCount_; ++i)
     {
-      std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer());
-      lock->GetController().GetScene().SetLayer(
-        baseLayerIndex_ + polylineLayerCount_ + i,
-        layer.release());
+      std::unique_ptr<TextSceneLayer> layer(new TextSceneLayer());
+      scene.SetLayer(baseLayerIndex_ + polylineLayerCount_ + i, layer.release());
     }
     lock->Invalidate();
   }
--- a/Framework/Scene2DViewport/ViewportController.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Scene2DViewport/ViewportController.h	Wed Mar 04 10:21:54 2020 +0100
@@ -26,6 +26,8 @@
 #include "../Scene2D/Scene2D.h"
 #include "../Scene2DViewport/IFlexiblePointerTracker.h"
 
+#include <Core/Compatibility.h>
+
 #include <boost/enable_shared_from_this.hpp>
 #include <stack>
 
@@ -232,9 +234,9 @@
     IViewport&                                    viewport_;
     boost::weak_ptr<UndoStack>                    undoStackW_;  // Global stack, possibly shared by all viewports
     std::vector<boost::shared_ptr<MeasureTool> >  measureTools_;
-    boost::shared_ptr<IFlexiblePointerTracker>    activeTracker_;  // TODO - Couldn't this be a "std::auto_ptr"?
+    boost::shared_ptr<IFlexiblePointerTracker>    activeTracker_;  // TODO - Couldn't this be a "std::unique_ptr"?
 
-    std::auto_ptr<Scene2D>   scene_;
+    std::unique_ptr<Scene2D>   scene_;
 
     // this is cached
     double  canvasToSceneFactor_;    
--- a/Framework/StoneInitialization.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/StoneInitialization.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -62,7 +62,7 @@
 
 #if ORTHANC_ENABLE_WASM == 1
 static double viewportsTimeout_ = 1000;
-static std::auto_ptr<OrthancStone::WebGLViewportsRegistry>  viewportsRegistry_;
+static std::unique_ptr<OrthancStone::WebGLViewportsRegistry>  viewportsRegistry_;
 #endif
 
 #include "Toolbox/LinearAlgebra.h"
--- a/Framework/Toolbox/DicomInstanceParameters.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Toolbox/DicomInstanceParameters.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -24,6 +24,7 @@
 #include "../Scene2D/ColorTextureSceneLayer.h"
 #include "../Scene2D/FloatTextureSceneLayer.h"
 #include "../Toolbox/GeometryToolbox.h"
+#include "../Toolbox/ImageToolbox.h"
 
 #include <Core/Images/Image.h>
 #include <Core/Images/ImageProcessing.h>
@@ -263,7 +264,6 @@
             distance <= thickness_ / 2.0);
   }
 
-      
   void DicomInstanceParameters::Data::ApplyRescaleAndDoseScaling(Orthanc::ImageAccessor& image,
                                                                  bool useDouble) const
   {
@@ -369,12 +369,13 @@
 
   Orthanc::ImageAccessor* DicomInstanceParameters::ConvertToFloat(const Orthanc::ImageAccessor& pixelData) const
   {
-    std::auto_ptr<Orthanc::Image> converted(new Orthanc::Image(Orthanc::PixelFormat_Float32, 
+    std::unique_ptr<Orthanc::Image> converted(new Orthanc::Image(Orthanc::PixelFormat_Float32, 
                                                                pixelData.GetWidth(), 
                                                                pixelData.GetHeight(),
                                                                false));
     Orthanc::ImageProcessing::Convert(*converted, pixelData);
 
+                                                   
     // Correct rescale slope/intercept if need be
     //data_.ApplyRescaleAndDoseScaling(*converted, (pixelData.GetFormat() == Orthanc::PixelFormat_Grayscale32));
     data_.ApplyRescaleAndDoseScaling(*converted, false);
@@ -403,7 +404,7 @@
     else
     {
       // This is the case of a grayscale frame. Convert it to Float32.
-      std::auto_ptr<FloatTextureSceneLayer> texture;
+      std::unique_ptr<FloatTextureSceneLayer> texture;
 
       if (pixelData.GetFormat() == Orthanc::PixelFormat_Float32)
       {
@@ -411,7 +412,7 @@
       }
       else
       {
-        std::auto_ptr<Orthanc::ImageAccessor> converted(ConvertToFloat(pixelData));
+        std::unique_ptr<Orthanc::ImageAccessor> converted(ConvertToFloat(pixelData));
         texture.reset(new FloatTextureSceneLayer(*converted));
       }
 
@@ -441,7 +442,7 @@
   LookupTableTextureSceneLayer* DicomInstanceParameters::CreateLookupTableTexture
   (const Orthanc::ImageAccessor& pixelData) const
   {
-    std::auto_ptr<FloatTextureSceneLayer> texture;
+    std::unique_ptr<FloatTextureSceneLayer> texture;
 
     if (pixelData.GetFormat() == Orthanc::PixelFormat_Float32)
     {
@@ -449,7 +450,7 @@
     }
     else
     {
-      std::auto_ptr<Orthanc::ImageAccessor> converted(ConvertToFloat(pixelData));
+      std::unique_ptr<Orthanc::ImageAccessor> converted(ConvertToFloat(pixelData));
       return new LookupTableTextureSceneLayer(*converted);
     }
   }
--- a/Framework/Toolbox/DynamicBitmap.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Toolbox/DynamicBitmap.h	Wed Mar 04 10:21:54 2020 +0100
@@ -21,6 +21,7 @@
 
 #pragma once
 
+#include <Core/Compatibility.h>
 #include <Core/IDynamicObject.h>
 #include <Core/Images/ImageAccessor.h>
 
@@ -31,7 +32,7 @@
   class DynamicBitmap : public Orthanc::IDynamicObject
   {
   private:
-    std::auto_ptr<Orthanc::ImageAccessor>  bitmap_;
+    std::unique_ptr<Orthanc::ImageAccessor>  bitmap_;
 
   public:
     DynamicBitmap(const Orthanc::ImageAccessor& bitmap);
--- a/Framework/Toolbox/FiniteProjectiveCamera.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Toolbox/FiniteProjectiveCamera.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -434,7 +434,7 @@
     // to the line joining the camera center and the principal point
     const VolumeProjection projection = VolumeProjection_Axial;
 
-    std::auto_ptr<Orthanc::ImageAccessor> target
+    std::unique_ptr<Orthanc::ImageAccessor> target
       (new Orthanc::Image(targetFormat, targetWidth, targetHeight, false));
     
     if (targetFormat == Orthanc::PixelFormat_Grayscale16 &&
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Toolbox/ImageToolbox.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -0,0 +1,292 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * 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
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "ImageToolbox.h"
+
+#include "../StoneException.h"
+
+#include <Core/Images/ImageProcessing.h>
+#include <Core/Images/PixelTraits.h>
+
+#include <Core/Logging.h>
+#include <Core/OrthancException.h>
+
+#include <boost/static_assert.hpp>
+#include <boost/type_traits.hpp>
+
+#include <vector>
+
+namespace OrthancStone
+{
+  namespace
+  {
+    using Orthanc::PixelTraits;
+    using Orthanc::PixelFormat;
+    using Orthanc::ImageAccessor;
+    using Orthanc::PixelFormat;
+
+    template<typename Orthanc::PixelFormat Format>
+    class PixelBinner
+    {
+      // "PixelBinner requires an arithmetic (integer or floating-point) pixel format"
+      typedef typename Orthanc::PixelTraits<Format>::PixelType PixelType;
+      BOOST_STATIC_ASSERT(boost::is_arithmetic<PixelType>::value);
+    
+    public:
+      PixelBinner(HistogramData& hd, double minValue, double maxValue)
+        : hd_(hd)
+        , minValue_(minValue)
+        , maxValue_(maxValue)
+        , division_(1.0 / hd_.binSize)
+      {
+        ORTHANC_ASSERT(hd_.bins.size() > 0);
+        ORTHANC_ASSERT(maxValue > minValue);
+      }
+
+      ORTHANC_FORCE_INLINE void AddPixel(PixelType p)
+      {
+        if (p <= minValue_)
+        {
+          hd_.bins[0] += 1;
+        }
+        else if (p >= maxValue_)
+        {
+          hd_.bins.back() += 1;
+        }
+        else
+        {
+          double distanceFromMin = p - minValue_;
+          size_t binIndex = static_cast<size_t>(
+            std::floor(distanceFromMin * division_));
+          if (binIndex >= hd_.bins.size())
+            binIndex = hd_.bins.size() - 1;
+          hd_.bins[binIndex] += 1;
+        }
+      }
+    private:
+      HistogramData&        hd_;
+      double                minValue_;
+      double                maxValue_;
+      double                division_;
+    };
+
+    template<PixelFormat Format>
+    struct Histogram
+    {
+      typedef typename PixelTraits<Format>::PixelType PixelType;
+
+      static void Apply(const Orthanc::ImageAccessor& img, HistogramData& hd,
+                        double minValue = 0, 
+                        double maxValue = 0)
+      {
+        ORTHANC_ASSERT(Format == img.GetFormat(), 
+                       "Internal error. Wrong template histogram type");
+    
+        const size_t height = img.GetHeight();
+        const size_t width = img.GetHeight();
+
+        if ((minValue == 0) && (maxValue == 0))
+        {
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
+          //ORTHANC_ASSERT(boost::is_integral<PixelType>::value, 
+          //  "Min and max values must be supplied for float-based histogram");
+          //
+          //PixelTraits<Format>::SetMinValue(minValue);
+          //PixelTraits<Format>::SetMaxValue(maxValue);
+        }
+
+        hd.minValue = minValue;
+
+        // the following code is not really pretty but ensures 
+        size_t numBins = static_cast<size_t>(
+          std::ceil((maxValue - minValue) / hd.binSize));
+
+        hd.bins.resize(numBins);
+        std::fill(hd.bins.begin(), hd.bins.end(), 0);
+
+        PixelBinner<Format> binner(hd, minValue, maxValue);
+        for (uint32_t y = 0; y < height; ++y)
+        {
+          const PixelType* curPix = reinterpret_cast<const PixelType*>(
+            img.GetConstRow(y));
+          
+          for (uint32_t x = 0; x < width; x++, curPix++)
+          {
+            binner.AddPixel(*curPix);
+          }
+        }
+      }
+    };
+
+
+    template<PixelFormat Format>
+    struct ComputeMinMax__
+    {
+      typedef typename PixelTraits<Format>::PixelType PixelType;
+
+      static void Apply(const Orthanc::ImageAccessor& img,
+                        PixelType& minValue, PixelType& maxValue)
+      {
+        ORTHANC_ASSERT(Format == img.GetFormat(), 
+                       "Internal error. Wrong template histogram type");
+
+        const size_t height = img.GetHeight();
+        const size_t width = img.GetHeight();
+
+        if (height * width == 0)
+        {
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
+        }
+
+        // min and max are crossed below. Think about it. This is OK :)
+        PixelTraits<Format>::SetMaxValue(minValue);
+        PixelTraits<Format>::SetMinValue(maxValue);
+
+        for (uint32_t y = 0; y < height; ++y)
+        {
+          const PixelType* curPix = reinterpret_cast<const PixelType*>(
+            img.GetConstRow(y));
+
+          for (uint32_t x = 0; x < width; x++, curPix++)
+          {
+            if (*curPix <= minValue)
+              minValue = *curPix;
+            if (*curPix >= maxValue)
+              maxValue = *curPix;
+          }
+        }
+      }
+    };
+
+    template<PixelFormat Format>
+    void ComputeMinMax_(const Orthanc::ImageAccessor& img, 
+                        double& minValue, double& maxValue)
+    {
+      typedef typename PixelTraits<Format>::PixelType PixelType;
+      PixelType minValuePix = PixelType();
+      PixelType maxValuePix = PixelType();
+      ComputeMinMax__<Format>::Apply(img, minValuePix, maxValuePix);
+      minValue = static_cast<double>(minValuePix);
+      maxValue = static_cast<double>(maxValuePix);
+    }
+    
+    template<PixelFormat Format>
+    void ComputeHistogram_(const Orthanc::ImageAccessor& img, HistogramData& hd)
+    {
+      typedef typename PixelTraits<Format>::PixelType PixelType;
+      PixelType minValue = PixelType();
+      PixelType maxValue = PixelType();
+      ComputeMinMax__<Format>::Apply(img, minValue, maxValue);
+      
+      // make bins a little bigger to center integer pixel values
+      Histogram<Format>::Apply(img, hd, 
+                               static_cast<double>(minValue) - 0.5, 
+                               static_cast<double>(maxValue) + 0.5);
+    }
+  }
+
+  void ComputeHistogram(const Orthanc::ImageAccessor& img,
+                        HistogramData& hd, double binSize)
+  {
+    using namespace Orthanc;
+
+    hd.binSize = binSize;
+
+    // dynamic/static bridge
+    switch (img.GetFormat())
+    {
+    case PixelFormat_Grayscale8:
+      ComputeHistogram_<PixelFormat_Grayscale8>       (img, hd);
+      break;
+    case PixelFormat_Grayscale16:
+      ComputeHistogram_<PixelFormat_Grayscale16>      (img, hd);
+      break;
+    case PixelFormat_SignedGrayscale16:
+      ComputeHistogram_<PixelFormat_SignedGrayscale16>(img, hd);
+      break;
+    case PixelFormat_Float32:
+      ComputeHistogram_<PixelFormat_Float32>          (img, hd);
+      break;
+    case PixelFormat_Grayscale32:
+      ComputeHistogram_<PixelFormat_Grayscale32>      (img, hd);
+      break;
+    case PixelFormat_Grayscale64:
+      ComputeHistogram_<PixelFormat_Grayscale64>      (img, hd);
+      break;
+    default:
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
+    }
+  }
+
+  void ComputeMinMax(const Orthanc::ImageAccessor& img,
+                     double& minValue, double& maxValue)
+  {
+    using namespace Orthanc;
+
+    // dynamic/static bridge
+    switch (img.GetFormat())
+    {
+    case PixelFormat_Grayscale8:
+      ComputeMinMax_<PixelFormat_Grayscale8>       (img, minValue, maxValue);
+      break;                                                
+    case PixelFormat_Grayscale16:                           
+      ComputeMinMax_<PixelFormat_Grayscale16>      (img, minValue, maxValue);
+      break;                                                
+    case PixelFormat_SignedGrayscale16:                     
+      ComputeMinMax_<PixelFormat_SignedGrayscale16>(img, minValue, maxValue);
+      break;                                                
+    case PixelFormat_Float32:                               
+      ComputeMinMax_<PixelFormat_Float32>          (img, minValue, maxValue);
+      break;                                                
+    case PixelFormat_Grayscale32:                           
+      ComputeMinMax_<PixelFormat_Grayscale32>      (img, minValue, maxValue);
+      break;                                                
+    case PixelFormat_Grayscale64:                           
+      ComputeMinMax_<PixelFormat_Grayscale64>      (img, minValue, maxValue);
+      break;
+    default:
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
+    }
+
+  }
+
+  void DumpHistogramResult(std::string& s, const HistogramData& hd)
+  {
+    std::stringstream ss;
+    ss << "Histogram:\n";
+    ss << "==========\n";
+    ss << "\n";
+    ss << "minValue        : " << hd.minValue << "\n";
+    ss << "binSize         : " << hd.binSize << "\n";
+    ss << "bins.size()     : " << hd.bins.size() << "\n";
+    ss << "bins            :\n";
+    double curBinStart = hd.minValue;
+    size_t pixCount = 0;
+    for (size_t i = 0; i < hd.bins.size(); ++i)
+    {
+      ss << "index: " << i << " (from " << curBinStart << " to "
+        << curBinStart + hd.binSize << ") : " << hd.bins[i] << " pixels\n";
+      curBinStart += hd.binSize;
+      pixCount += hd.bins[i];
+    }
+    ss << "total pix. count: " << pixCount << "\n";
+    s = ss.str();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Toolbox/ImageToolbox.h	Wed Mar 04 10:21:54 2020 +0100
@@ -0,0 +1,76 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * 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
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "../StoneEnumerations.h"
+#include "LinearAlgebra.h"
+
+#include <Core/Images/ImageAccessor.h>
+
+namespace OrthancStone
+{
+
+  /**
+  This structure represents the result of an histogram computation
+
+  bins[0]   contains the values in [minValue                , minValue +   binSize [
+  bins[1]   contains the values in [minValue +       binSize, minValue + 2*binSize [
+  bins[2]   contains the values in [minValue +     2*binSize, minValue + 3*binSize [
+  ...
+  bins[N-1] contains the values in [minValue + (N-1)*binSize, minValue + N*binSize [
+
+  */
+  struct HistogramData
+  {
+    std::vector<size_t> bins;
+    double minValue;
+    double binSize;
+  };
+
+  /**
+  Dumps the supplied histogram to the supplied strings
+  */
+  void DumpHistogramResult(std::string& s, const HistogramData& hd);
+  
+  /**
+  This will compute the histogram of the supplied image (count the number of 
+  pixels).
+
+  The image must contain arithmetic pixels (that is, having a single component,
+  integer or float). Compound pixel types like RGB, YUV are not supported and
+  will cause this function to throw an exception.
+
+  The range of available values will be split in sets of size `binSize`, and 
+  each set will contain the number of pixels in the given bin 
+  (see HistogramResult above).
+  */
+  void ComputeHistogram(const Orthanc::ImageAccessor& img,
+                        HistogramData& hd, double binSize);
+
+
+  /**
+  Computes the min max values in an image
+  */
+  void ComputeMinMax(const Orthanc::ImageAccessor& img, 
+                     double& minValue, double& maxValue);
+
+}
--- a/Framework/Toolbox/ParsedDicomCache.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Toolbox/ParsedDicomCache.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -26,7 +26,7 @@
   class ParsedDicomCache::Item : public Orthanc::ICacheable
   {
   private:
-    std::auto_ptr<Orthanc::ParsedDicomFile>  dicom_;
+    std::unique_ptr<Orthanc::ParsedDicomFile>  dicom_;
     size_t                                   fileSize_;
     bool                                     hasPixelData_;
     
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Toolbox/PixelTestPatterns.h	Wed Mar 04 10:21:54 2020 +0100
@@ -0,0 +1,130 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * 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
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+// PixelTestPatterns.h
+
+#pragma once
+
+#include "../StoneException.h"
+
+#include <Core/Images/ImageAccessor.h>
+
+#include <string>
+#include <stdint.h>
+#include <math.h>
+
+namespace OrthancStone
+{
+  namespace PixelTestPatterns
+  {
+    template<typename T, typename U>
+    inline uint8_t byteAddClip(T v1, U v2)
+    {
+      double tmp = static_cast<double>(v1) + static_cast<double>(v2);
+      if (tmp > 255.0)
+        tmp = 255;
+      if (tmp < 0.0)
+        tmp = 0;
+      return static_cast<uint8_t>(tmp+0.5);
+    }
+
+    // fills the area with a horizontal gradient.
+    // leftmost pixels are filled with r0 g0 b0
+    // rightmost pixels are filled with r1 g1 b1
+    // linear interpolation in-between
+    inline void fillWithHGradient(Orthanc::ImageAccessor& target,
+      uint8_t r0, uint8_t g0, uint8_t b0,
+      uint8_t r1, uint8_t g1, uint8_t b1)
+    {
+      if (target.GetFormat() != Orthanc::PixelFormat_RGBA32) {
+        ORTHANC_ASSERT(false, "Wrong pixel format");
+      }
+      const unsigned int width = target.GetWidth();
+      const unsigned int height = target.GetHeight();
+
+      ORTHANC_ASSERT(width > 0);
+      ORTHANC_ASSERT(height > 0);
+
+      double invWidth = 1.0 / static_cast<double>(target.GetWidth());
+      double rIncr = (static_cast<double>(r1) - static_cast<double>(r0))* invWidth;
+      double gIncr = (static_cast<double>(g1) - static_cast<double>(g0))* invWidth;
+      double bIncr = (static_cast<double>(b1) - static_cast<double>(b0))* invWidth;
+
+      for (unsigned int y = 0; y < height; y++)
+      {
+        uint8_t r = r0;
+        uint8_t g = g0;
+        uint8_t b = b0;
+        uint8_t* q = reinterpret_cast<uint8_t*>(target.GetRow(y));
+        for (unsigned int x = 0; x < width; x++)
+        {
+          q[0] = r;
+          q[1] = g;
+          q[2] = b;
+          q[3] = 255;
+          r = byteAddClip(r, rIncr);
+          g = byteAddClip(g, gIncr);
+          b = byteAddClip(b, bIncr);
+          q += 4;
+        }
+      }
+    }
+
+    inline void fillWithVGradient(Orthanc::ImageAccessor& target,
+      uint8_t r0, uint8_t g0, uint8_t b0,
+      uint8_t r1, uint8_t g1, uint8_t b1)
+    {
+      if (target.GetFormat() != Orthanc::PixelFormat_RGBA32) {
+        ORTHANC_ASSERT(false, "Wrong pixel format");
+      }
+      const unsigned int width = target.GetWidth();
+      const unsigned int height = target.GetHeight();
+
+      ORTHANC_ASSERT(width > 0);
+      ORTHANC_ASSERT(height > 0);
+
+      double invHeight = 1.0 / static_cast<double>(target.GetHeight());
+      double rIncr = (static_cast<double>(r1) - static_cast<double>(r0))* invHeight;
+      double gIncr = (static_cast<double>(g1) - static_cast<double>(g0))* invHeight;
+      double bIncr = (static_cast<double>(b1) - static_cast<double>(b0))* invHeight;
+
+      uint8_t r = r0;
+      uint8_t g = g0;
+      uint8_t b = b0;
+      for (unsigned int y = 0; y < height; y++)
+      {
+        uint8_t* q = reinterpret_cast<uint8_t*>(target.GetRow(y));
+        for (unsigned int x = 0; x < width; x++)
+        {
+          q[0] = r;
+          q[1] = g;
+          q[2] = b;
+          q[3] = 255;
+          q += 4;
+        }
+        r = byteAddClip(r, rIncr);
+        g = byteAddClip(g, gIncr);
+        b = byteAddClip(b, bIncr);
+      }
+    }
+
+  }
+}
+
--- a/Framework/Toolbox/ShearWarpProjectiveTransform.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Toolbox/ShearWarpProjectiveTransform.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -414,7 +414,7 @@
      * for each pixel is stored in the "counter" image.
      **/
 
-    std::auto_ptr<Orthanc::ImageAccessor> accumulator, counter, intermediate;
+    std::unique_ptr<Orthanc::ImageAccessor> accumulator, counter, intermediate;
 
     accumulator.reset(new Orthanc::Image(Orthanc::PixelFormat_Float32,
                                          intermediateWidth, intermediateHeight, false));
@@ -635,7 +635,7 @@
                                            ImageInterpolation shearInterpolation,
                                            ImageInterpolation warpInterpolation)
   {
-    std::auto_ptr<Orthanc::ImageAccessor> target
+    std::unique_ptr<Orthanc::ImageAccessor> target
       (new Orthanc::Image(targetFormat, targetWidth, targetHeight, false));
     
     if (source.GetFormat() == Orthanc::PixelFormat_Grayscale16 &&
--- a/Framework/Toolbox/SlicesSorter.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Toolbox/SlicesSorter.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -33,7 +33,7 @@
     CoordinateSystem3D  geometry_;
     double              depth_;
 
-    std::auto_ptr<Orthanc::IDynamicObject>   payload_;
+    std::unique_ptr<Orthanc::IDynamicObject>   payload_;
 
   public:
     SliceWithDepth(const CoordinateSystem3D& geometry,
--- a/Framework/Toolbox/TextRenderer.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Toolbox/TextRenderer.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -44,7 +44,7 @@
     renderer.LoadFont(font, fontSize);
 
     // add each char to be rendered to the alphabet
-    std::auto_ptr<GlyphBitmapAlphabet> alphabet(new GlyphBitmapAlphabet);
+    std::unique_ptr<GlyphBitmapAlphabet> alphabet(new GlyphBitmapAlphabet);
 
     size_t posInString = 0;
     uint32_t unicode;
@@ -58,10 +58,10 @@
     }
 
 
-    std::auto_ptr<Orthanc::ImageAccessor> renderedText(alphabet->RenderText(utf8String));
+    std::unique_ptr<Orthanc::ImageAccessor> renderedText(alphabet->RenderText(utf8String));
 
     // add a blank line on top of the text (to improve bilinear filtering of the topmost line)
-    std::auto_ptr<Orthanc::Image> renderedTextExtended(new Orthanc::Image(renderedText->GetFormat(), renderedText->GetWidth(), renderedText->GetHeight() + 1, true));
+    std::unique_ptr<Orthanc::Image> renderedTextExtended(new Orthanc::Image(renderedText->GetFormat(), renderedText->GetWidth(), renderedText->GetHeight() + 1, true));
 
     Orthanc::ImageAccessor textRegion;
     Orthanc::ImageAccessor firstLineRegion;
@@ -81,8 +81,8 @@
                                                         const std::string& utf8String,
                                                         uint8_t foreground)
   {
-    std::auto_ptr<Orthanc::ImageAccessor> renderedText8(Render(resource, fontSize, utf8String));
-    std::auto_ptr<Orthanc::Image> target(new Orthanc::Image(Orthanc::PixelFormat_RGBA32, renderedText8->GetWidth(), renderedText8->GetHeight(), true));
+    std::unique_ptr<Orthanc::ImageAccessor> renderedText8(Render(resource, fontSize, utf8String));
+    std::unique_ptr<Orthanc::Image> target(new Orthanc::Image(Orthanc::PixelFormat_RGBA32, renderedText8->GetWidth(), renderedText8->GetHeight(), true));
 
     Orthanc::ImageProcessing::Set(*target, foreground, foreground, foreground, *renderedText8);
     return target.release();
@@ -98,18 +98,18 @@
   //                                                        uint8_t foreground,
   //                                                        uint8_t borderColor)
   //  {
-  //    std::auto_ptr<Orthanc::ImageAccessor> renderedBorderAlpha(RenderWithAlpha(resource, fontSize, utf8String, borderColor));
-  //    std::auto_ptr<Orthanc::ImageAccessor> renderedTextAlpha(RenderWithAlpha(resource, fontSize, utf8String, foreground));
+  //    std::unique_ptr<Orthanc::ImageAccessor> renderedBorderAlpha(RenderWithAlpha(resource, fontSize, utf8String, borderColor));
+  //    std::unique_ptr<Orthanc::ImageAccessor> renderedTextAlpha(RenderWithAlpha(resource, fontSize, utf8String, foreground));
 
   //    unsigned int textWidth = renderedBorderAlpha->GetWidth();
   //    unsigned int textHeight = renderedBorderAlpha->GetHeight();
 
   //    Scene2D targetScene;
-  //    std::auto_ptr<ColorTextureSceneLayer> borderLayerLeft(new ColorTextureSceneLayer(*renderedBorderAlpha));
-  //    std::auto_ptr<ColorTextureSceneLayer> borderLayerRight(new ColorTextureSceneLayer(*renderedBorderAlpha));
-  //    std::auto_ptr<ColorTextureSceneLayer> borderLayerTop(new ColorTextureSceneLayer(*renderedBorderAlpha));
-  //    std::auto_ptr<ColorTextureSceneLayer> borderLayerBottom(new ColorTextureSceneLayer(*renderedBorderAlpha));
-  //    std::auto_ptr<ColorTextureSceneLayer> textLayerCenter(new ColorTextureSceneLayer(*renderedTextAlpha));
+  //    std::unique_ptr<ColorTextureSceneLayer> borderLayerLeft(new ColorTextureSceneLayer(*renderedBorderAlpha));
+  //    std::unique_ptr<ColorTextureSceneLayer> borderLayerRight(new ColorTextureSceneLayer(*renderedBorderAlpha));
+  //    std::unique_ptr<ColorTextureSceneLayer> borderLayerTop(new ColorTextureSceneLayer(*renderedBorderAlpha));
+  //    std::unique_ptr<ColorTextureSceneLayer> borderLayerBottom(new ColorTextureSceneLayer(*renderedBorderAlpha));
+  //    std::unique_ptr<ColorTextureSceneLayer> textLayerCenter(new ColorTextureSceneLayer(*renderedTextAlpha));
 
   //    borderLayerLeft->SetOrigin(0, 1);
   //    borderLayerRight->SetOrigin(2, 1);
@@ -129,7 +129,7 @@
   //    Orthanc::ImageAccessor canvas;
   //    compositor.GetCanvas().GetReadOnlyAccessor(canvas);
 
-  //    std::auto_ptr<Orthanc::Image> output(new Orthanc::Image(Orthanc::PixelFormat_RGBA32, canvas.GetWidth(), canvas.GetHeight(), false));
+  //    std::unique_ptr<Orthanc::Image> output(new Orthanc::Image(Orthanc::PixelFormat_RGBA32, canvas.GetWidth(), canvas.GetHeight(), false));
   //    Orthanc::ImageProcessing::Convert(*output, canvas);
   //    return output.release();
   //  }
--- a/Framework/Viewport/SdlViewport.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Viewport/SdlViewport.h	Wed Mar 04 10:21:54 2020 +0100
@@ -59,7 +59,7 @@
     boost::recursive_mutex                 mutex_;
     uint32_t                               refreshEvent_;
     boost::shared_ptr<ViewportController>  controller_;
-    std::auto_ptr<ICompositor>             compositor_;
+    std::unique_ptr<ICompositor>             compositor_;
 
     void SendRefreshEvent();
 
--- a/Framework/Viewport/WebAssemblyCairoViewport.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Viewport/WebAssemblyCairoViewport.h	Wed Mar 04 10:21:54 2020 +0100
@@ -28,7 +28,7 @@
   class WebAssemblyCairoViewport : public WebAssemblyViewport
   {
   private:
-    std::auto_ptr<Orthanc::ImageAccessor>  javascript_;
+    std::unique_ptr<Orthanc::ImageAccessor>  javascript_;
         
     void GetCanvasSize(unsigned int& width,
                        unsigned int& height);
--- a/Framework/Viewport/WebAssemblyViewport.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Viewport/WebAssemblyViewport.h	Wed Mar 04 10:21:54 2020 +0100
@@ -43,9 +43,9 @@
     
     std::string                            shortCanvasId_;
     std::string                            fullCanvasId_;
-    std::auto_ptr<ICompositor>             compositor_;
+    std::unique_ptr<ICompositor>             compositor_;
     boost::shared_ptr<ViewportController>  controller_;
-    std::auto_ptr<IViewportInteractor>     interactor_;
+    std::unique_ptr<IViewportInteractor>     interactor_;
 
     static EM_BOOL OnRequestAnimationFrame(double time, void *userData);
     
--- a/Framework/Viewport/WebGLViewportsRegistry.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Viewport/WebGLViewportsRegistry.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -63,7 +63,7 @@
         boost::shared_ptr<WebGLViewport> viewport;
           
         {
-          std::auto_ptr<IViewport::ILock> lock(it->second->Lock());
+          std::unique_ptr<IViewport::ILock> lock(it->second->Lock());
           viewport = boost::make_shared<WebGLViewport>(it->first, lock->GetController().GetScene());
         }
 
@@ -72,7 +72,7 @@
 
         // Tag the fresh canvas as needing a repaint
         {
-          std::auto_ptr<IViewport::ILock> lock(it->second->Lock());
+          std::unique_ptr<IViewport::ILock> lock(it->second->Lock());
           lock->Invalidate();
         }
       }
--- a/Framework/Viewport/WebGLViewportsRegistry.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Viewport/WebGLViewportsRegistry.h	Wed Mar 04 10:21:54 2020 +0100
@@ -65,7 +65,7 @@
     {
     private:
       WebGLViewportsRegistry&          that_;
-      std::auto_ptr<IViewport::ILock>  lock_;
+      std::unique_ptr<IViewport::ILock>  lock_;
 
     public:
       Accessor(WebGLViewportsRegistry& that,
--- a/Framework/Volumes/DicomStructureSetSlicer2.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Volumes/DicomStructureSetSlicer2.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -78,7 +78,7 @@
   {
     assert(isValid_);
 
-    std::auto_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer);
+    std::unique_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer);
     layer->SetThickness(2); // thickness of the on-screen line
 
     for (size_t i = 0; i < structureSet_->GetStructuresCount(); i++)
--- a/Framework/Volumes/DicomVolumeImage.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Volumes/DicomVolumeImage.h	Wed Mar 04 10:21:54 2020 +0100
@@ -42,9 +42,9 @@
 
   private:
     uint64_t                                revision_;
-    std::auto_ptr<VolumeImageGeometry>      geometry_;
-    std::auto_ptr<ImageBuffer3D>            image_;
-    std::auto_ptr<DicomInstanceParameters>  parameters_;
+    std::unique_ptr<VolumeImageGeometry>      geometry_;
+    std::unique_ptr<ImageBuffer3D>            image_;
+    std::unique_ptr<DicomInstanceParameters>  parameters_;
 
     void CheckHasGeometry() const;
     
--- a/Framework/Volumes/DicomVolumeImageMPRSlicer.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Volumes/DicomVolumeImageMPRSlicer.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -23,6 +23,8 @@
 
 #include "../StoneException.h"
 
+#include "../Toolbox/ImageToolbox.h"
+
 #include <Core/OrthancException.h>
 //#include <Core/Images/PngWriter.h>
 #include <Core/Images/JpegWriter.h>
@@ -74,11 +76,12 @@
                                       "A style configurator is mandatory for textures");
     }
 
-    std::auto_ptr<TextureBaseSceneLayer> texture;
+    std::unique_ptr<TextureBaseSceneLayer> texture;
       
     {
       const DicomInstanceParameters& parameters = volume_.GetDicomParameters();
       ImageBuffer3D::SliceReader reader(volume_.GetPixelData(), projection_, sliceIndex_);
+
       texture.reset(dynamic_cast<TextureBaseSceneLayer*>
                     (configurator->CreateTextureFromDicom(reader.GetAccessor(), parameters)));
     }
@@ -102,7 +105,7 @@
     {
       texture->SetAngle(atan2(dy, dx));
     }
-        
+
     Vector tmp = volume_.GetGeometry().GetVoxelDimensions(projection_);
     texture->SetPixelSpacing(tmp[0], tmp[1]);
 
--- a/Framework/Volumes/DicomVolumeImageReslicer.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Volumes/DicomVolumeImageReslicer.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -67,7 +67,7 @@
 
       if (reslicer.IsSuccess())
       {
-        std::auto_ptr<TextureBaseSceneLayer> layer
+        std::unique_ptr<TextureBaseSceneLayer> layer
           (configurator->CreateTextureFromDicom(reslicer.GetOutputSlice(),
                                                 that_.volume_->GetDicomParameters()));
         if (layer.get() == NULL)
--- a/Framework/Volumes/ImageBuffer3D.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Volumes/ImageBuffer3D.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -81,7 +81,7 @@
       throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
 
-    std::auto_ptr<Orthanc::Image> result(new Orthanc::Image(format_, height_, depth_, false));
+    std::unique_ptr<Orthanc::Image> result(new Orthanc::Image(format_, height_, depth_, false));
     //LOG(TRACE) << "ImageBuffer3D::ExtractSagittalSlice result will be an image of WIDTH = " << height_ << " and HEIGHT = " << depth_;
 
     unsigned int bytesPerPixel = Orthanc::GetBytesPerPixel(format_);
--- a/Framework/Volumes/ImageBuffer3D.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Volumes/ImageBuffer3D.h	Wed Mar 04 10:21:54 2020 +0100
@@ -24,6 +24,7 @@
 #include "../StoneEnumerations.h"
 #include "../Toolbox/LinearAlgebra.h"
 
+#include <Core/Compatibility.h>
 #include <Core/Images/Image.h>
 
 namespace OrthancStone
@@ -143,7 +144,7 @@
     {
     private:
       Orthanc::ImageAccessor         accessor_;
-      std::auto_ptr<Orthanc::Image>  sagittal_;  // Unused for axial and coronal
+      std::unique_ptr<Orthanc::Image>  sagittal_;  // Unused for axial and coronal
 
     public:
       SliceReader(const ImageBuffer3D& that,
@@ -163,7 +164,7 @@
       ImageBuffer3D&                 that_;
       bool                           modified_;
       Orthanc::ImageAccessor         accessor_;
-      std::auto_ptr<Orthanc::Image>  sagittal_;  // Unused for axial and coronal
+      std::unique_ptr<Orthanc::Image>  sagittal_;  // Unused for axial and coronal
 
       void Flush();
 
--- a/Framework/Volumes/VolumeReslicer.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Volumes/VolumeReslicer.h	Wed Mar 04 10:21:54 2020 +0100
@@ -42,7 +42,7 @@
     // Output of reslicing
     bool                           success_;
     Extent2D                       extent_;
-    std::auto_ptr<Orthanc::Image>  slice_;
+    std::unique_ptr<Orthanc::Image>  slice_;
     double                         pixelSpacing_;
 
     void CheckIterators(const ImageBuffer3D& source,
--- a/Framework/Volumes/VolumeSceneLayerSource.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Volumes/VolumeSceneLayerSource.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -96,7 +96,7 @@
   void VolumeSceneLayerSource::Update(const CoordinateSystem3D& plane)
   {
     assert(slicer_.get() != NULL);
-    std::auto_ptr<IVolumeSlicer::IExtractedSlice> slice(slicer_->ExtractSlice(plane));
+    std::unique_ptr<IVolumeSlicer::IExtractedSlice> slice(slicer_->ExtractSlice(plane));
 
     if (slice.get() == NULL)
     {
@@ -129,7 +129,7 @@
       lastPlane_.reset(new CoordinateSystem3D(plane));
       lastRevision_ = slice->GetRevision();
 
-      std::auto_ptr<ISceneLayer> layer(slice->CreateSceneLayer(configurator_.get(), plane));
+      std::unique_ptr<ISceneLayer> layer(slice->CreateSceneLayer(configurator_.get(), plane));
       if (layer.get() == NULL)
       {
         LOG(TRACE) << "VolumeSceneLayerSource::Update -- (layer.get() == NULL)";
--- a/Framework/Volumes/VolumeSceneLayerSource.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Framework/Volumes/VolumeSceneLayerSource.h	Wed Mar 04 10:21:54 2020 +0100
@@ -41,8 +41,8 @@
     Scene2D&                                scene_;
     int                                     layerDepth_;
     boost::shared_ptr<IVolumeSlicer>        slicer_;
-    std::auto_ptr<ILayerStyleConfigurator>  configurator_;
-    std::auto_ptr<CoordinateSystem3D>       lastPlane_;
+    std::unique_ptr<ILayerStyleConfigurator>  configurator_;
+    std::unique_ptr<CoordinateSystem3D>       lastPlane_;
     uint64_t                                lastRevision_;
     uint64_t                                lastConfiguratorRevision_;
 
--- a/Platforms/Generic/DelayedCallCommand.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Platforms/Generic/DelayedCallCommand.h	Wed Mar 04 10:21:54 2020 +0100
@@ -35,8 +35,8 @@
   class DelayedCallCommand : public IOracleCommand, OrthancStone::IObservable
   {
   protected:
-    std::auto_ptr<MessageHandler<IDelayedCallExecutor::TimeoutMessage> >  callback_;
-    std::auto_ptr<Orthanc::IDynamicObject>  payload_;
+    std::unique_ptr<MessageHandler<IDelayedCallExecutor::TimeoutMessage> >  callback_;
+    std::unique_ptr<Orthanc::IDynamicObject>  payload_;
     OrthancStone::NativeStoneApplicationContext&          context_;
     boost::posix_time::ptime                expirationTimePoint_;
     unsigned int                            timeoutInMs_;
--- a/Platforms/Generic/Oracle.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Platforms/Generic/Oracle.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -62,7 +62,7 @@
           break;
         }
 
-        std::auto_ptr<Orthanc::IDynamicObject> item(that->queue_.Dequeue(100));
+        std::unique_ptr<Orthanc::IDynamicObject> item(that->queue_.Dequeue(100));
         if (item.get() != NULL)
         {
           IOracleCommand& command = dynamic_cast<IOracleCommand&>(*item);
@@ -107,7 +107,7 @@
 
     void Submit(IOracleCommand* command)
     {
-      std::auto_ptr<IOracleCommand> protection(command);
+      std::unique_ptr<IOracleCommand> protection(command);
 
       if (command == NULL)
       {
--- a/Platforms/Generic/OracleWebService.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Platforms/Generic/OracleWebService.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -29,8 +29,8 @@
   class OracleWebService::WebServiceCachedGetCommand : public IOracleCommand, OrthancStone::IObservable
   {
   protected:
-    std::auto_ptr<MessageHandler<IWebService::HttpRequestSuccessMessage> >  successCallback_;
-    std::auto_ptr<Orthanc::IDynamicObject>                                  payload_;
+    std::unique_ptr<MessageHandler<IWebService::HttpRequestSuccessMessage> >  successCallback_;
+    std::unique_ptr<Orthanc::IDynamicObject>                                  payload_;
     boost::shared_ptr<BaseWebService::CachedHttpRequestSuccessMessage>      cachedMessage_;
     OrthancStone::NativeStoneApplicationContext&                                          context_;
 
--- a/Platforms/Generic/WebServiceCommandBase.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Platforms/Generic/WebServiceCommandBase.h	Wed Mar 04 10:21:54 2020 +0100
@@ -37,12 +37,12 @@
   class WebServiceCommandBase : public IOracleCommand, OrthancStone::IObservable
   {
   protected:
-    std::auto_ptr<MessageHandler<IWebService::HttpRequestSuccessMessage> >  successCallback_;
-    std::auto_ptr<MessageHandler<IWebService::HttpRequestErrorMessage> >    failureCallback_;
+    std::unique_ptr<MessageHandler<IWebService::HttpRequestSuccessMessage> >  successCallback_;
+    std::unique_ptr<MessageHandler<IWebService::HttpRequestErrorMessage> >    failureCallback_;
     Orthanc::WebServiceParameters           parameters_;
     std::string                             url_;
     IWebService::HttpHeaders                headers_;
-    std::auto_ptr<Orthanc::IDynamicObject>  payload_;
+    std::unique_ptr<Orthanc::IDynamicObject>  payload_;
     bool                                    success_;
     Orthanc::HttpStatus                     httpStatus_;
     std::string                             answer_;
--- a/Platforms/Wasm/WasmWebService.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Platforms/Wasm/WasmWebService.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -7,7 +7,7 @@
 struct CachedSuccessNotification
 {
   boost::shared_ptr<Deprecated::BaseWebService::CachedHttpRequestSuccessMessage>    cachedMessage;
-  std::auto_ptr<Orthanc::IDynamicObject>                                              payload;
+  std::unique_ptr<Orthanc::IDynamicObject>                                              payload;
   OrthancStone::MessageHandler<Deprecated::IWebService::HttpRequestSuccessMessage>* successCallback;
 };
 
@@ -56,7 +56,7 @@
   void EMSCRIPTEN_KEEPALIVE WasmWebService_NotifyCachedSuccess(void* notification_)
   {
     // notification has been allocated in C++ and passed to JS.  It must be deleted by this method
-    std::auto_ptr<CachedSuccessNotification> notification(reinterpret_cast<CachedSuccessNotification*>(notification_));
+    std::unique_ptr<CachedSuccessNotification> notification(reinterpret_cast<CachedSuccessNotification*>(notification_));
 
     notification->successCallback->Apply(Deprecated::IWebService::HttpRequestSuccessMessage(
       notification->cachedMessage->GetUri(), 
--- a/Resources/CMake/OrthancStoneConfiguration.cmake	Wed Mar 04 10:07:37 2020 +0100
+++ b/Resources/CMake/OrthancStoneConfiguration.cmake	Wed Mar 04 10:21:54 2020 +0100
@@ -646,8 +646,12 @@
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/GeometryToolbox.h
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ImageGeometry.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ImageGeometry.h
+  ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ImageToolbox.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ImageToolbox.h
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/LinearAlgebra.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/LinearAlgebra.h
+  ${ORTHANC_STONE_ROOT}/Framework/Toolbox/PixelTestPatterns.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Toolbox/PixelTestPatterns.h
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ShearWarpProjectiveTransform.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ShearWarpProjectiveTransform.h
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/SlicesSorter.cpp
@@ -665,6 +669,7 @@
   ${ORTHANC_STONE_ROOT}/Framework/Volumes/IVolumeSlicer.h
   ${ORTHANC_STONE_ROOT}/Framework/Volumes/OrientedVolumeBoundingBox.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Volumes/OrientedVolumeBoundingBox.h
+
   ${ORTHANC_STONE_ROOT}/Framework/Volumes/VolumeImageGeometry.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Volumes/VolumeImageGeometry.h
   ${ORTHANC_STONE_ROOT}/Framework/Volumes/VolumeReslicer.cpp
--- a/Resources/CMake/OrthancStoneParameters.cmake	Wed Mar 04 10:07:37 2020 +0100
+++ b/Resources/CMake/OrthancStoneParameters.cmake	Wed Mar 04 10:21:54 2020 +0100
@@ -52,6 +52,6 @@
 ## the Stone of Orthanc
 #####################################################################
 
-set(ENABLE_OPENGL ON CACHE INTERNAL "Enable support of OpenGL")
+set(ENABLE_OPENGL ON CACHE BOOL "Enable support of OpenGL")
 set(ENABLE_WASM OFF CACHE INTERNAL "Enable support of WebAssembly")
 set(ENABLE_STONE_DEPRECATED OFF CACHE INTERNAL "Enable backward compatibility with deprecated Stone classes")
--- a/Resources/CodeGeneration/template.in.h.j2	Wed Mar 04 10:07:37 2020 +0100
+++ b/Resources/CodeGeneration/template.in.h.j2	Wed Mar 04 10:21:54 2020 +0100
@@ -19,7 +19,7 @@
 //#define STONEGEN_NO_CPP11 1
 
 #ifdef STONEGEN_NO_CPP11
-#define StoneSmartPtr std::auto_ptr
+#define StoneSmartPtr std::unique_ptr
 #else 
 #define StoneSmartPtr std::unique_ptr
 #endif 
--- a/Resources/CodeGeneration/testWasmIntegrated/jsoncpp-1.8.4/jsoncpp.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Resources/CodeGeneration/testWasmIntegrated/jsoncpp-1.8.4/jsoncpp.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -287,7 +287,7 @@
 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
 typedef std::unique_ptr<CharReader> CharReaderPtr;
 #else
-typedef std::auto_ptr<CharReader> CharReaderPtr;
+typedef std::unique_ptr<CharReader> CharReaderPtr;
 #endif
 
 // Implementation of class Features
@@ -4242,7 +4242,7 @@
 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
 typedef std::unique_ptr<StreamWriter> StreamWriterPtr;
 #else
-typedef std::auto_ptr<StreamWriter> StreamWriterPtr;
+typedef std::unique_ptr<StreamWriter> StreamWriterPtr;
 #endif
 
 String valueToString(LargestInt value) {
--- a/Resources/Conventions.txt	Wed Mar 04 10:07:37 2020 +0100
+++ b/Resources/Conventions.txt	Wed Mar 04 10:21:54 2020 +0100
@@ -62,14 +62,14 @@
 --------
 
 * As we are targeting C++03 (for VS2008 and LSB compatibility), use
-  "std::auto_ptr<>" and "boost::shared_ptr<>" (*not*
+  "std::unique_ptr<>" and "boost::shared_ptr<>" (*not*
   "std::shared_ptr<>").
 
 * The fact of transfering the ownership of one object to another must
   be tagged by naming the method "Acquire...()", and by providing a
   raw pointer.
 
-* Use "std::auto_ptr<>" if the goal is to internally store a pointer
+* Use "std::unique_ptr<>" if the goal is to internally store a pointer
   whose lifetime corresponds to the host object.
 
 * The use of "boost::weak_ptr<>" should be restricted to
--- a/Resources/Graveyard/ReferenceLineFactory.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Resources/Graveyard/ReferenceLineFactory.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -101,7 +101,7 @@
                                              x1, y1, x2, y2,
                                              sx1, sy1, sx2, sy2))
     {
-      std::auto_ptr<ILayerRenderer> layer(new LineLayerRenderer(x1, y1, x2, y2));
+      std::unique_ptr<ILayerRenderer> layer(new LineLayerRenderer(x1, y1, x2, y2));
       layer->SetLayerStyle(style_);
       return layer.release();
     }
--- a/Resources/Graveyard/Threading/SdlBuffering.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Resources/Graveyard/Threading/SdlBuffering.h	Wed Mar 04 10:21:54 2020 +0100
@@ -35,8 +35,8 @@
   {
   private:
     boost::mutex                 mutex_;
-    std::auto_ptr<CairoSurface>  offscreenSurface_;
-    std::auto_ptr<CairoSurface>  onscreenSurface_;
+    std::unique_ptr<CairoSurface>  offscreenSurface_;
+    std::unique_ptr<CairoSurface>  onscreenSurface_;
     SDL_Surface*                 sdlSurface_;
     bool                         pendingFrame_;
 
--- a/Samples/MultiPlatform/BasicScene/BasicScene.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Samples/MultiPlatform/BasicScene/BasicScene.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -69,7 +69,7 @@
 
     scene.SetLayer(12, new ColorTextureSceneLayer(i));
 
-    std::auto_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i));
+    std::unique_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i));
     l->SetOrigin(-3, 2);
     l->SetPixelSpacing(1.5, 1);
     l->SetAngle(20.0 / 180.0 * 3.14);
@@ -85,7 +85,7 @@
     p[1] = 0;
     p[2] = 0;
 
-    std::auto_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i));
+    std::unique_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i));
     l->SetOrigin(-2, 1);
     l->SetAngle(20.0 / 180.0 * 3.14);
     scene.SetLayer(13, l.release());
@@ -93,7 +93,7 @@
 
   // Some lines
   {
-    std::auto_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer);
+    std::unique_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer);
 
     layer->SetThickness(1);
 
@@ -125,7 +125,7 @@
 
   // Some text
   {
-    std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer);
+    std::unique_ptr<TextSceneLayer> layer(new TextSceneLayer);
     layer->SetText("Hello");
     scene.SetLayer(100, layer.release());
   }
@@ -170,7 +170,7 @@
   }
   else
   {
-    std::auto_ptr<TextSceneLayer>
+    std::unique_ptr<TextSceneLayer>
         layer(new TextSceneLayer);
     layer->SetColor(0, 255, 0);
     layer->SetText(buf);
--- a/Samples/Sdl/BasicScene.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Samples/Sdl/BasicScene.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -78,7 +78,7 @@
 
     scene.SetLayer(12, new ColorTextureSceneLayer(i));
 
-    std::auto_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i));
+    std::unique_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i));
     l->SetOrigin(-3, 2);
     l->SetPixelSpacing(1.5, 1);
     l->SetAngle(20.0 / 180.0 * M_PI);
@@ -94,7 +94,7 @@
     p[1] = 0;
     p[2] = 0;
 
-    std::auto_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i));
+    std::unique_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i));
     l->SetOrigin(-2, 1);
     l->SetAngle(20.0 / 180.0 * M_PI);
     scene.SetLayer(13, l.release());
@@ -102,7 +102,7 @@
 
   // Some lines
   {
-    std::auto_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer);
+    std::unique_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer);
 
     layer->SetThickness(10);
 
@@ -133,7 +133,7 @@
 
   // Some text
   {
-    std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer);
+    std::unique_ptr<TextSceneLayer> layer(new TextSceneLayer);
     layer->SetText("Hello");
     scene.SetLayer(100, layer.release());
   }
@@ -199,7 +199,7 @@
       }
       else
       {
-        std::auto_ptr<TextSceneLayer> 
+        std::unique_ptr<TextSceneLayer> 
           layer(new TextSceneLayer);
         layer->SetColor(0, 255, 0);
         layer->SetText(buf);
--- a/Samples/Sdl/FusionMprSdl.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Samples/Sdl/FusionMprSdl.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -125,7 +125,7 @@
     }
     else
     {
-      std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer);
+      std::unique_ptr<TextSceneLayer> layer(new TextSceneLayer);
       layerP = layer.get();
       layer->SetColor(0, 255, 0);
       layer->SetFontIndex(1);
@@ -160,7 +160,7 @@
     }
     else
     {
-      std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer);
+      std::unique_ptr<TextSceneLayer> layer(new TextSceneLayer);
       layer->SetColor(0, 255, 0);
       layer->SetText(buf);
       layer->SetBorder(20);
@@ -635,7 +635,7 @@
     this->SetVolume1(0, ctLoader, new GrayscaleStyleConfigurator);
 
     {
-      std::auto_ptr<LookupTableStyleConfigurator> config(new LookupTableStyleConfigurator);
+      std::unique_ptr<LookupTableStyleConfigurator> config(new LookupTableStyleConfigurator);
       config->SetLookupTable(Orthanc::EmbeddedResources::COLORMAP_HOT);
 
       boost::shared_ptr<DicomVolumeImageMPRSlicer> tmp(new DicomVolumeImageMPRSlicer(dose));
--- a/Samples/Sdl/Loader.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Samples/Sdl/Loader.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -120,7 +120,7 @@
   OrthancStone::CoordinateSystem3D  plane_;
   OrthancStone::IOracle&            oracle_;
   OrthancStone::Scene2D             scene_;
-  std::auto_ptr<OrthancStone::VolumeSceneLayerSource>  source1_, source2_, source3_;
+  std::unique_ptr<OrthancStone::VolumeSceneLayerSource>  source1_, source2_, source3_;
 
 
   void Refresh()
@@ -342,7 +342,7 @@
   
 
   {
-    std::auto_ptr<OrthancStone::LookupTableStyleConfigurator> config(new OrthancStone::LookupTableStyleConfigurator);
+    std::unique_ptr<OrthancStone::LookupTableStyleConfigurator> config(new OrthancStone::LookupTableStyleConfigurator);
     config->SetLookupTable(Orthanc::EmbeddedResources::COLORMAP_HOT);
 
     boost::shared_ptr<OrthancStone::DicomVolumeImageMPRSlicer> tmp(new OrthancStone::DicomVolumeImageMPRSlicer(dose));
@@ -359,7 +359,7 @@
     v["Level"] = "Series";
     v["Query"] = Json::objectValue;
 
-    std::auto_ptr<OrthancStone::OrthancRestApiCommand>  command(new OrthancStone::OrthancRestApiCommand);
+    std::unique_ptr<OrthancStone::OrthancRestApiCommand>  command(new OrthancStone::OrthancRestApiCommand);
     command->SetMethod(Orthanc::HttpMethod_Post);
     command->SetUri("/tools/find");
     command->SetBody(v);
@@ -371,7 +371,7 @@
   {
     if (0)
     {
-      std::auto_ptr<OrthancStone::GetOrthancImageCommand>  command(new OrthancStone::GetOrthancImageCommand);
+      std::unique_ptr<OrthancStone::GetOrthancImageCommand>  command(new OrthancStone::GetOrthancImageCommand);
       command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Jpeg)));
       command->SetUri("/instances/6687cc73-07cae193-52ff29c8-f646cb16-0753ed92/preview");
       oracle.Schedule(*toto, command.release());
@@ -379,7 +379,7 @@
     
     if (0)
     {
-      std::auto_ptr<OrthancStone::GetOrthancImageCommand>  command(new OrthancStone::GetOrthancImageCommand);
+      std::unique_ptr<OrthancStone::GetOrthancImageCommand>  command(new OrthancStone::GetOrthancImageCommand);
       command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Png)));
       command->SetUri("/instances/6687cc73-07cae193-52ff29c8-f646cb16-0753ed92/preview");
       oracle.Schedule(*toto, command.release());
@@ -387,7 +387,7 @@
     
     if (0)
     {
-      std::auto_ptr<OrthancStone::GetOrthancImageCommand>  command(new OrthancStone::GetOrthancImageCommand);
+      std::unique_ptr<OrthancStone::GetOrthancImageCommand>  command(new OrthancStone::GetOrthancImageCommand);
       command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Png)));
       command->SetUri("/instances/6687cc73-07cae193-52ff29c8-f646cb16-0753ed92/image-uint16");
       oracle.Schedule(*toto, command.release());
@@ -395,7 +395,7 @@
     
     if (0)
     {
-      std::auto_ptr<OrthancStone::GetOrthancImageCommand>  command(new OrthancStone::GetOrthancImageCommand);
+      std::unique_ptr<OrthancStone::GetOrthancImageCommand>  command(new OrthancStone::GetOrthancImageCommand);
       command->SetHttpHeader("Accept-Encoding", "gzip");
       command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Pam)));
       command->SetUri("/instances/6687cc73-07cae193-52ff29c8-f646cb16-0753ed92/image-uint16");
@@ -404,7 +404,7 @@
     
     if (0)
     {
-      std::auto_ptr<OrthancStone::GetOrthancImageCommand>  command(new OrthancStone::GetOrthancImageCommand);
+      std::unique_ptr<OrthancStone::GetOrthancImageCommand>  command(new OrthancStone::GetOrthancImageCommand);
       command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Pam)));
       command->SetUri("/instances/6687cc73-07cae193-52ff29c8-f646cb16-0753ed92/image-uint16");
       oracle.Schedule(*toto, command.release());
@@ -412,7 +412,7 @@
 
     if (0)
     {
-      std::auto_ptr<OrthancStone::GetOrthancWebViewerJpegCommand>  command(new OrthancStone::GetOrthancWebViewerJpegCommand);
+      std::unique_ptr<OrthancStone::GetOrthancWebViewerJpegCommand>  command(new OrthancStone::GetOrthancWebViewerJpegCommand);
       command->SetHttpHeader("Accept-Encoding", "gzip");
       command->SetInstance("e6c7c20b-c9f65d7e-0d76f2e2-830186f2-3e3c600e");
       command->SetQuality(90);
@@ -424,7 +424,7 @@
     {
       for (unsigned int i = 0; i < 10; i++)
       {
-        std::auto_ptr<OrthancStone::SleepOracleCommand> command(new OrthancStone::SleepOracleCommand(i * 1000));
+        std::unique_ptr<OrthancStone::SleepOracleCommand> command(new OrthancStone::SleepOracleCommand(i * 1000));
         command->SetPayload(new Orthanc::SingleValueObject<unsigned int>(42 * i));
         oracle.Schedule(*toto, command.release());
       }
--- a/Samples/Sdl/RadiographyEditor.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Samples/Sdl/RadiographyEditor.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -179,7 +179,7 @@
     glEnable(GL_DEBUG_OUTPUT);
     glDebugMessageCallback(OpenGLMessageCallback, 0);
 
-    std::auto_ptr<OpenGlSdlCompositorFactory> compositorFactory(new OpenGlSdlCompositorFactory(window));
+    std::unique_ptr<OpenGlSdlCompositorFactory> compositorFactory(new OpenGlSdlCompositorFactory(window));
     boost::shared_ptr<RadiographyEditorApp> app(new RadiographyEditorApp(oracle, lock.GetOracleObservable(), compositorFactory.release()));
     app->PrepareScene();
     app->FitContent(window.GetCanvasWidth(), window.GetCanvasHeight());
--- a/Samples/Sdl/TrackerSampleApp.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Samples/Sdl/TrackerSampleApp.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -96,7 +96,7 @@
     }
     else
     {
-      std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer);
+      std::unique_ptr<TextSceneLayer> layer(new TextSceneLayer);
       layerP = layer.get();
       layer->SetColor(0, 255, 0);
       layer->SetFontIndex(1);
@@ -131,7 +131,7 @@
     }
     else
     {
-      std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer);
+      std::unique_ptr<TextSceneLayer> layer(new TextSceneLayer);
       layer->SetColor(0, 255, 0);
       layer->SetText(buf);
       layer->SetBorder(20);
@@ -516,7 +516,7 @@
 
       controller_->GetScene().SetLayer(TEXTURE_2x2_1_ZINDEX, new ColorTextureSceneLayer(i));
 
-      std::auto_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i));
+      std::unique_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i));
       l->SetOrigin(-3, 2);
       l->SetPixelSpacing(1.5, 1);
       l->SetAngle(20.0 / 180.0 * M_PI);
@@ -532,7 +532,7 @@
       p[1] = 0;
       p[2] = 0;
 
-      std::auto_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i));
+      std::unique_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i));
       l->SetOrigin(-2, 1);
       l->SetAngle(20.0 / 180.0 * M_PI);
       controller_->GetScene().SetLayer(TEXTURE_1x1_ZINDEX, l.release());
@@ -540,7 +540,7 @@
 
     // Some lines
     {
-      std::auto_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer);
+      std::unique_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer);
 
       layer->SetThickness(1);
 
@@ -571,7 +571,7 @@
 
     // Some text
     {
-      std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer);
+      std::unique_ptr<TextSceneLayer> layer(new TextSceneLayer);
       layer->SetText("Hello");
       controller_->GetScene().SetLayer(LINESET_2_ZINDEX, layer.release());
     }
--- a/Samples/WebAssembly/BasicMPR.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Samples/WebAssembly/BasicMPR.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -38,7 +38,7 @@
   {
   private:
     OrthancStone::WebAssemblyViewport      viewport_;
-    std::auto_ptr<VolumeSceneLayerSource>  source_;
+    std::unique_ptr<VolumeSceneLayerSource>  source_;
     VolumeProjection                       projection_;
     std::vector<CoordinateSystem3D>        planes_;
     size_t                                 currentPlane_;
@@ -155,9 +155,9 @@
 
 boost::shared_ptr<OrthancStone::OrthancSeriesVolumeProgressiveLoader>  loader_;
 
-std::auto_ptr<OrthancStone::VolumeSlicerWidget>  widget1_;
-std::auto_ptr<OrthancStone::VolumeSlicerWidget>  widget2_;
-std::auto_ptr<OrthancStone::VolumeSlicerWidget>  widget3_;
+std::unique_ptr<OrthancStone::VolumeSlicerWidget>  widget1_;
+std::unique_ptr<OrthancStone::VolumeSlicerWidget>  widget2_;
+std::unique_ptr<OrthancStone::VolumeSlicerWidget>  widget3_;
 
 OrthancStone::MessageBroker  broker_;
 OrthancStone::WebAssemblyOracle  oracle_(broker_);
@@ -371,7 +371,7 @@
     
       widget1_.reset(new OrthancStone::VolumeSlicerWidget(broker_, "mycanvas1", OrthancStone::VolumeProjection_Axial));
       {
-        std::auto_ptr<OrthancStone::GrayscaleStyleConfigurator> style(new OrthancStone::GrayscaleStyleConfigurator);
+        std::unique_ptr<OrthancStone::GrayscaleStyleConfigurator> style(new OrthancStone::GrayscaleStyleConfigurator);
         style->SetLinearInterpolation(true);
         style->SetWindowing(OrthancStone::ImageWindowing_Bone);
         widget1_->SetSlicer(0, loader_, *loader_, style.release());
@@ -380,7 +380,7 @@
 
       widget2_.reset(new OrthancStone::VolumeSlicerWidget(broker_, "mycanvas2", OrthancStone::VolumeProjection_Coronal));
       {
-        std::auto_ptr<OrthancStone::GrayscaleStyleConfigurator> style(new OrthancStone::GrayscaleStyleConfigurator);
+        std::unique_ptr<OrthancStone::GrayscaleStyleConfigurator> style(new OrthancStone::GrayscaleStyleConfigurator);
         style->SetLinearInterpolation(true);
         style->SetWindowing(OrthancStone::ImageWindowing_Bone);
         widget2_->SetSlicer(0, loader_, *loader_, style.release());
@@ -389,7 +389,7 @@
 
       widget3_.reset(new OrthancStone::VolumeSlicerWidget(broker_, "mycanvas3", OrthancStone::VolumeProjection_Sagittal));
       {
-        std::auto_ptr<OrthancStone::GrayscaleStyleConfigurator> style(new OrthancStone::GrayscaleStyleConfigurator);
+        std::unique_ptr<OrthancStone::GrayscaleStyleConfigurator> style(new OrthancStone::GrayscaleStyleConfigurator);
         style->SetLinearInterpolation(true);
         style->SetWindowing(OrthancStone::ImageWindowing_Bone);
         widget3_->SetSlicer(0, loader_, *loader_, style.release());
--- a/Samples/WebAssembly/BasicScene.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/Samples/WebAssembly/BasicScene.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -62,7 +62,7 @@
 
     scene.SetLayer(12, new ColorTextureSceneLayer(i));
 
-    std::auto_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i));
+    std::unique_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i));
     l->SetOrigin(-3, 2);
     l->SetPixelSpacing(1.5, 1);
     l->SetAngle(20.0 / 180.0 * M_PI);
@@ -79,7 +79,7 @@
     p[1] = 0;
     p[2] = 0;
 
-    std::auto_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i));
+    std::unique_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i));
     l->SetOrigin(-2, 1);
     l->SetAngle(20.0 / 180.0 * M_PI);
     scene.SetLayer(13, l.release());
@@ -88,7 +88,7 @@
   // Some lines
   if (1)
   {
-    std::auto_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer);
+    std::unique_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer);
 
     layer->SetThickness(1);
 
@@ -120,16 +120,16 @@
   // Some text
   if (1)
   {
-    std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer);
+    std::unique_ptr<TextSceneLayer> layer(new TextSceneLayer);
     layer->SetText("Hello");
     scene.SetLayer(100, layer.release());
   }
 }
 
 
-std::auto_ptr<OrthancStone::WebAssemblyViewport>  viewport1_;
-std::auto_ptr<OrthancStone::WebAssemblyViewport>  viewport2_;
-std::auto_ptr<OrthancStone::WebAssemblyViewport>  viewport3_;
+std::unique_ptr<OrthancStone::WebAssemblyViewport>  viewport1_;
+std::unique_ptr<OrthancStone::WebAssemblyViewport>  viewport2_;
+std::unique_ptr<OrthancStone::WebAssemblyViewport>  viewport3_;
 boost::shared_ptr<OrthancStone::ViewportController>   controller1_;
 boost::shared_ptr<OrthancStone::ViewportController>   controller2_;
 boost::shared_ptr<OrthancStone::ViewportController>   controller3_;
--- a/Samples/WebAssembly/dev.h	Wed Mar 04 10:07:37 2020 +0100
+++ b/Samples/WebAssembly/dev.h	Wed Mar 04 10:21:54 2020 +0100
@@ -79,7 +79,7 @@
   const EmscriptenMouseEvent&        source,
   OrthancStone::IViewport& viewport)
 {
-  std::auto_ptr<OrthancStone::PointerEvent> target(
+  std::unique_ptr<OrthancStone::PointerEvent> target(
     new OrthancStone::PointerEvent);
 
   target->AddPosition(viewport.GetPixelCenterCoordinates(
@@ -91,7 +91,7 @@
   return target.release();
 }
 
-std::auto_ptr<OrthancStone::ActiveTracker> tracker_;
+std::unique_ptr<OrthancStone::ActiveTracker> tracker_;
 
 EM_BOOL OnMouseEvent(int eventType, 
                      const EmscriptenMouseEvent *mouseEvent, 
@@ -111,7 +111,7 @@
         char buf[64];
         sprintf(buf, "click %d", count++);
 
-        std::auto_ptr<OrthancStone::TextSceneLayer> layer(new OrthancStone::TextSceneLayer);
+        std::unique_ptr<OrthancStone::TextSceneLayer> layer(new OrthancStone::TextSceneLayer);
         layer->SetText(buf);
         controller->GetViewport().GetScene().SetLayer(100, layer.release());
         controller->GetViewport().Refresh();
@@ -123,7 +123,7 @@
         boost::shared_ptr<OrthancStone::IFlexiblePointerTracker> t;
 
         {
-          std::auto_ptr<OrthancStone::PointerEvent> event(
+          std::unique_ptr<OrthancStone::PointerEvent> event(
             ConvertMouseEvent(*mouseEvent, controller->GetViewport()));
 
           switch (mouseEvent->button)
@@ -165,7 +165,7 @@
       case EMSCRIPTEN_EVENT_MOUSEMOVE:
         if (tracker_.get() != NULL)
         {
-          std::auto_ptr<OrthancStone::PointerEvent> event(
+          std::unique_ptr<OrthancStone::PointerEvent> event(
             ConvertMouseEvent(*mouseEvent, controller->GetViewport()));
           tracker_->PointerMove(*event);
           controller->GetViewport().Refresh();
@@ -175,7 +175,7 @@
       case EMSCRIPTEN_EVENT_MOUSEUP:
         if (tracker_.get() != NULL)
         {
-          std::auto_ptr<OrthancStone::PointerEvent> event(
+          std::unique_ptr<OrthancStone::PointerEvent> event(
             ConvertMouseEvent(*mouseEvent, controller->GetViewport()));
           tracker_->PointerUp(*event);
           controller->GetViewport().Refresh();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UnitTestsSources/ImageToolboxTests.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -0,0 +1,260 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * 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
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include <Framework/Toolbox/ImageToolbox.h>
+
+// #include <boost/chrono.hpp>
+// #include <boost/lexical_cast.hpp>
+
+#include <Core/Compatibility.h>
+#include <Core/Images/Image.h>
+#include <Core/Images/PixelTraits.h>
+
+#include "stdint.h"
+
+#include "gtest/gtest.h"
+
+#include <cmath>
+
+
+TEST(ImageToolbox, SimpleHisto_Grayscale8_BinSize1)
+{
+  using OrthancStone::HistogramData;
+  using OrthancStone::DumpHistogramResult;
+  using OrthancStone::ComputeHistogram;
+
+  const unsigned int W = 16;
+  const unsigned int H = 16;
+
+  // 256/17 = 15,...
+  // 256 % 17 = 1
+  // 0 will be 16 times
+  // 1 will be 15 times
+  // 2 will be 15 times
+  // ...
+  // 16 will be 15 times
+
+  size_t pixCounter = 0;
+
+  std::unique_ptr<Orthanc::Image> image(new Orthanc::Image(
+    Orthanc::PixelFormat_Grayscale8, W, H, false));
+
+  for (unsigned int y = 0; y < H; ++y)
+  {
+    uint8_t* buffer = reinterpret_cast<uint8_t*>(image->GetRow(y));
+    for (unsigned int x = 0; x < W; ++x, ++buffer, ++pixCounter)
+    {
+      *buffer = static_cast<uint8_t>(pixCounter % 17);
+    }
+  }
+
+  HistogramData hd;
+  ComputeHistogram(*image, hd, 1);
+  ASSERT_EQ(-0.5, hd.minValue);
+  ASSERT_EQ(17u, hd.bins.size());
+  ASSERT_EQ(16u, hd.bins[0]);
+  for (size_t i = 1; i < hd.bins.size(); ++i)
+    ASSERT_EQ(15u, hd.bins[i]);
+}
+
+TEST(ImageToolbox, SimpleHisto_Grayscale8_BinSize1_FormatString)
+{
+  using OrthancStone::HistogramData;
+  using OrthancStone::DumpHistogramResult;
+  using OrthancStone::ComputeHistogram;
+
+  const unsigned int W = 16;
+  const unsigned int H = 16;
+
+  // 256/17 = 15,...
+  // 256 % 17 = 1
+  // 0 will be 16 times
+  // 1 will be 15 times
+  // 2 will be 15 times
+  // ...
+  // 16 will be 15 times
+
+  size_t pixCounter = 0;
+
+  std::unique_ptr<Orthanc::Image> image(new Orthanc::Image(
+    Orthanc::PixelFormat_Grayscale8, W, H, false));
+
+  for (unsigned int y = 0; y < H; ++y)
+  {
+    uint8_t* buffer = reinterpret_cast<uint8_t*>(image->GetRow(y));
+    for (unsigned int x = 0; x < W; ++x, ++buffer, ++pixCounter)
+    {
+      *buffer = static_cast<uint8_t>(pixCounter % 17);
+    }
+  }
+
+  HistogramData hd;
+  ComputeHistogram(*image, hd, 1);
+
+  // void DumpHistogramResult(std::string& s, const HistogramData& hd)
+  std::string s;
+  DumpHistogramResult(s, hd);
+  std::cout << s;
+}
+
+template<Orthanc::PixelFormat Format>
+void SimpleHisto_T_BinSize1_2()
+{
+  using OrthancStone::HistogramData;
+  using OrthancStone::DumpHistogramResult;
+  using OrthancStone::ComputeHistogram;
+
+  const unsigned int W = 16;
+  const unsigned int H = 16;
+
+  // 256/17 = 15,...
+  // 256 % 17 = 1
+  // 0 will be 16 times
+  // 1 will be 15 times
+  // 2 will be 15 times
+  // ...
+  // 16 will be 15 times
+
+  size_t pixCounter = 0;
+
+  std::unique_ptr<Orthanc::Image> image(new Orthanc::Image(
+    Format, W, H, false));
+
+  typedef typename Orthanc::PixelTraits<Format>::PixelType PixelType;
+
+  PixelType pixValue = 0;
+
+  for (unsigned int y = 0; y < H; ++y)
+  {
+    PixelType* buffer = reinterpret_cast<PixelType*>(image->GetRow(y));
+    for (unsigned int x = 0; x < W; ++x, ++buffer, ++pixCounter)
+    {
+      // 0..99 0..99 0..55
+      *buffer = pixValue;
+      pixValue++;
+      if (pixValue >= 100)
+        pixValue = 0;
+    }
+  }
+
+  HistogramData hd;
+  ComputeHistogram(*image, hd, 1);
+  ASSERT_EQ(-0.5, hd.minValue);
+  ASSERT_EQ(100u, hd.bins.size());
+  for (size_t i = 0; i <= 55; ++i)
+    ASSERT_EQ(3u, hd.bins[i]);
+  for (size_t i = 56; i <= 99; ++i)
+    ASSERT_EQ(2u, hd.bins[i]);
+}
+
+TEST(ImageToolbox, SimpleHisto_Grayscale8_BinSize1_2)
+{               
+  SimpleHisto_T_BinSize1_2<Orthanc::PixelFormat_Grayscale8>();
+}
+
+TEST(ImageToolbox, SimpleHisto_Grayscale16_BinSize1_2)
+{
+  SimpleHisto_T_BinSize1_2<Orthanc::PixelFormat_Grayscale16>();
+}
+
+TEST(ImageToolbox, SimpleHisto_SignedGrayscale16_BinSize1_2)
+{
+  SimpleHisto_T_BinSize1_2<Orthanc::PixelFormat_SignedGrayscale16>();
+}
+
+TEST(ImageToolbox, SimpleHisto_Grayscale32_BinSize1_2)
+{
+  SimpleHisto_T_BinSize1_2<Orthanc::PixelFormat_Grayscale32>();
+}
+
+template<Orthanc::PixelFormat Format>
+void SimpleHisto_T_BinSize10_2()
+{
+  using OrthancStone::HistogramData;
+  using OrthancStone::DumpHistogramResult;
+  using OrthancStone::ComputeHistogram;
+
+  const unsigned int W = 16;
+  const unsigned int H = 16;
+
+  // 256/17 = 15,...
+  // 256 % 17 = 1
+  // 0 will be 16 times
+  // 1 will be 15 times
+  // 2 will be 15 times
+  // ...
+  // 16 will be 15 times
+
+  size_t pixCounter = 0;
+
+  std::unique_ptr<Orthanc::Image> image(new Orthanc::Image(
+    Format, W, H, false));
+
+  typedef typename Orthanc::PixelTraits<Format>::PixelType PixelType;
+
+  PixelType pixValue = 0;
+
+  for (unsigned int y = 0; y < H; ++y)
+  {
+    PixelType* buffer = reinterpret_cast<PixelType*>(image->GetRow(y));
+    for (unsigned int x = 0; x < W; ++x, ++buffer, ++pixCounter)
+    {
+      // 0..99 0..99 0..55
+      *buffer = pixValue;
+      pixValue++;
+      if (pixValue >= 100)
+        pixValue = 0;
+    }
+  }
+
+  HistogramData hd;
+  ComputeHistogram(*image, hd, 10);
+  ASSERT_EQ(-0.5, hd.minValue);
+  ASSERT_EQ(10u, hd.bins.size());
+
+  for (size_t i = 0; i <= 4; ++i)
+    ASSERT_EQ(30u, hd.bins[i]);
+
+  ASSERT_EQ(26u, hd.bins[5]);
+
+  for (size_t i = 6; i <= 9; ++i)
+    ASSERT_EQ(20u, hd.bins[i]);
+}
+
+TEST(ImageToolbox, SimpleHisto_Grayscale8_BinSize10_2)
+{
+  SimpleHisto_T_BinSize10_2<Orthanc::PixelFormat_Grayscale8>();
+}
+
+TEST(ImageToolbox, SimpleHisto_Grayscale16_BinSize10_2)
+{
+  SimpleHisto_T_BinSize10_2<Orthanc::PixelFormat_Grayscale16>();
+}
+
+TEST(ImageToolbox, SimpleHisto_SignedGrayscale16_BinSize10_2)
+{
+  SimpleHisto_T_BinSize10_2<Orthanc::PixelFormat_SignedGrayscale16>();
+}
+
+TEST(ImageToolbox, SimpleHisto_Grayscale32_BinSize10_2)
+{
+  SimpleHisto_T_BinSize10_2<Orthanc::PixelFormat_Grayscale32>();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UnitTestsSources/PixelTestPatternsTests.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -0,0 +1,171 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * 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
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include <Core/Images/Image.h>
+#include <Core/Images/PngWriter.h>
+#include <Framework/Toolbox/PixelTestPatterns.h>
+
+#include <boost/chrono.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include "gtest/gtest.h"
+
+#include "stdint.h"
+
+#include <cmath>
+
+ /* Autogenerated from prout.png */
+static const unsigned char bin2c_SimpleRedBlueHGradient_png[391] = "\211PNG\15\12\32\12\0\0\0\15IHDR\0\0\0\200\0\0\0\200\10\6\0\0\0\303>a\313\0\0\1MIDATx\234\355\322\1\15\3000\0\303\260~\3741o\7\342X\12\203|o{wgev\26Z\3\340\32\0\327\0\270\6\3005\0\256\1p\15\200k\0\\\3\340\32\0\327\0\270\6\3005\0\256\1p\15\200k\0\\\3\340\32\0\327\0\270\6\3005\0\256\1p\15\200k\0\\\3\340\32\0\327\0\270\6\3005\0\256\1p\15\200k\0\\\3\340\32\0\327\0\270\6\3005\0\256\1p\15\200k\0\\\3\340\32\0\327\0\270\6\3005\0\256\1p\15\200k\0\\\3\340\32\0\327\0\270\6\3005\0\256\1p\15\200k\0\\\3\340\32\0\327\0\270\6\3005\0\256\1p\15\200k\0\\\3\340\32\0\327\0\270\6\3005\0\256\1p\15\200k\0\\\3\340\32\0\327\0\270\6\3005\0\256\1p\15\200k\0\\\3\340\32\0\327\0\270\6\3005\0\256\1p\15\200k\0\\\3\340\32\0\327\0\270\6\3005\0\256\1p\15\200k\0\\\3\340\32\0\327\0\270\6\3005\0\256\1p\15\200k\0\\\3\340\32\0\327\0\270\6\3005\0\256\1p\15\200k\0\\\3\340\32\0\327\0\270\6\3005\0\256\1p\15\200k\0\\\3\340\32\0\327\0\270\6\3005\0\256\1p?\314\262\201\3760\355r\262\0\0\0\0IEND\256B`\202";
+
+TEST(PixelTestPatterns, SimpleRedHGradient)
+{
+  std::unique_ptr<Orthanc::Image> texture;
+
+  texture.reset(new Orthanc::Image(
+    Orthanc::PixelFormat_RGBA32,
+    128,
+    128,
+    /*forceMinimalPitch*/false));
+
+  Orthanc::ImageAccessor target;
+  texture->GetWriteableAccessor(target);
+
+  OrthancStone::PixelTestPatterns::fillWithHGradient(target,255,0,0,0,0,255);
+
+  Orthanc::PngWriter writer;
+#if 0
+  writer.WriteToFile("SimpleRedBlueHGradient.png", *texture);
+#else
+  std::string contents;
+  writer.WriteToMemory(contents, *texture);
+
+  ASSERT_EQ(1u, sizeof(unsigned char));
+  ASSERT_EQ(391u, sizeof(bin2c_SimpleRedBlueHGradient_png));
+  ASSERT_EQ(390u, contents.size());
+
+  char* resultPngBytes = &(contents[0]);
+
+  int result = memcmp(resultPngBytes, bin2c_SimpleRedBlueHGradient_png, 390);
+  ASSERT_EQ(0, result);
+#endif
+}
+
+static const unsigned char bin2c_SimpleRedBlueVGradient_png[400] = "\211PNG\15\12\32\12\0\0\0\15IHDR\0\0\0\200\0\0\0\200\10\6\0\0\0\303>a\313\0\0\1VIDATx\234\355\322A\21\3000\14\300\260t7\376\220\327\301\310\303\22\2?|\356\314\35\262\336o\236\355\6\26\31 \316\0q\6\2103@\234\1\342\14\20g\2008\3\304\31 \316\0q\6\2103@\234\1\342\14\20g\2008\3\304\31 \316\0q\6\2103@\234\1\342\14\20g\2008\3\304\31 \316\0q\6\2103@\234\1\342\14\20g\2008\3\304\31 \316\0q\6\2103@\234\1\342\14\20g\2008\3\304\31 \316\0q\6\2103@\234\1\342\14\20g\2008\3\304\31 \316\0q\6\2103@\234\1\342\14\20g\2008\3\304\31 \316\0q\6\2103@\234\1\342\14\20g\2008\3\304\31 \316\0q\6\2103@\234\1\342\14\20g\2008\3\304\31 \316\0q\6\2103@\234\1\342\14\20g\2008\3\304\31 \316\0q\6\2103@\234\1\342\14\20g\2008\3\304\31 \316\0q\6\2103@\234\1\342\14\20g\2008\3\304\31 \316\0q\6\2103@\234\1\342\14\20g\2008\3\304\31 \316\0q\6\2103@\234\1\342\14\20g\2008\3\304\31 \316\0q\6\2103@\234\1\342\14\20g\2008\3\304\31 \316\0q\6\2103@\234\1\342\316\231\357nG\260\347\7\221\255\203\367~A)\36\0\0\0\0IEND\256B`\202";
+
+
+TEST(PixelTestPatterns, SimpleRedBlueVGradient)
+{
+  std::unique_ptr<Orthanc::Image> texture;
+
+  texture.reset(new Orthanc::Image(
+    Orthanc::PixelFormat_RGBA32,
+    128,
+    128,
+    /*forceMinimalPitch*/false));
+
+  Orthanc::ImageAccessor target;
+  texture->GetWriteableAccessor(target);
+
+  OrthancStone::PixelTestPatterns::fillWithVGradient(target, 255, 0, 0, 0, 0, 255);
+
+  Orthanc::PngWriter writer;
+#if 0
+  writer.WriteToFile("SimpleRedBlueVGradient.png", *texture);
+#else
+  std::string contents;
+  writer.WriteToMemory(contents, *texture);
+
+  ASSERT_EQ(1u, sizeof(unsigned char));
+  ASSERT_EQ(400u, sizeof(bin2c_SimpleRedBlueVGradient_png));
+  ASSERT_EQ(399u, contents.size());
+
+  char* resultPngBytes = &(contents[0]);
+
+  int result = memcmp(resultPngBytes, bin2c_SimpleRedBlueVGradient_png, 399);
+  ASSERT_EQ(0, result);
+#endif
+}
+
+
+/* Autogenerated from MultiGradient.png */
+static const unsigned char bin2c_MultiGradient_png[774] = "\211PNG\15\12\32\12\0\0\0\15IHDR\0\0\1\0\0\0\0\200\10\6\0\0\0\344\265\267\12\0\0\2\314IDATx\234\355\325\301\11\3030\24\5\301/\242\376+6(E$ \314\354\30\337\215\364X\2573s\6\266\316\314\226\237\365\271}\5\227\255\331{\273\357s\373\374sY\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\25\0^\13\220\2559\347\354\231Q\337\317\372\303)\276\331Ys\377\26\256.\340\3673|\261}\373\3n{\360?\240>\200\347\351\376i\5\300V\0pz\0t\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0l\5\0W\0lz\0\276!\352\302\35+U\244b\0\0\0\0IEND\256B`\202";
+
+TEST(PixelTestPatterns, MultiGradient)
+{
+  std::unique_ptr<Orthanc::Image> texture;
+
+  const int CELLW = 64;
+  const int CELLH = 64;
+  const int NHCELLS = 4;
+  const int NVCELLS = 2;
+  const int NCELLS = NHCELLS * NVCELLS;
+
+  texture.reset(new Orthanc::Image(
+    Orthanc::PixelFormat_RGBA32,
+    NHCELLS * CELLW,
+    NVCELLS * CELLH,
+    /*forceMinimalPitch*/false));
+
+  // H:R->K, V:G->W, H:B->K
+
+  //                    R   G   B   K   C   M   Y   W
+  uint8_t startR[NCELLS] = {255,000,000,000,000,255,255,255};
+  uint8_t startG[NCELLS] = {000,255,000,000,255,000,255,255};
+  uint8_t startB[NCELLS] = {000,000,255,000,255,255,000,255};
+  
+  //                  K   W   K   W   W   K   W   K
+  uint8_t eeendR[NCELLS] = {000,255,000,255,255,000,255,000};
+  uint8_t eeendG[NCELLS] = {000,255,000,255,255,000,255,000 };
+  uint8_t eeendB[NCELLS] = {000,255,000,255,255,000,255,000 };
+
+  // vertical?
+  bool verticality[NCELLS] = { false,true,false,true,true,false,true,false };
+
+  for(size_t slot = 0; slot < NCELLS; ++slot)
+  {
+    int x0 = (slot % 4) * CELLW;
+    bool vertical = (((slot / NHCELLS) % 2) == 0) ? (slot % 2 == 0) : (slot % 2 == 1);
+    int y0 = static_cast<int>(slot / NHCELLS) * CELLH;
+    Orthanc::ImageAccessor target;
+    texture->GetRegion(target, x0, y0, CELLW, CELLH);
+    if (vertical)
+      OrthancStone::PixelTestPatterns::fillWithVGradient(target, startR[slot], startG[slot], startB[slot], eeendR[slot], eeendG[slot], eeendB[slot]);
+    else 
+      OrthancStone::PixelTestPatterns::fillWithHGradient(target, startR[slot], startG[slot], startB[slot], eeendR[slot], eeendG[slot], eeendB[slot]);
+  }
+ 
+  Orthanc::PngWriter writer;
+#if 0
+  writer.WriteToFile("MultiGradient.png", *texture);
+#else
+  std::string contents;
+  writer.WriteToMemory(contents, *texture);
+
+  ASSERT_EQ(1u, sizeof(unsigned char));
+  ASSERT_EQ(774u, sizeof(bin2c_MultiGradient_png));
+  ASSERT_EQ(773u, contents.size());
+
+  char* resultPngBytes = &(contents[0]);
+
+  int result = memcmp(resultPngBytes, bin2c_MultiGradient_png, 773);
+  ASSERT_EQ(0, result);
+#endif
+}
+
--- a/UnitTestsSources/TestCommands.cpp	Wed Mar 04 10:07:37 2020 +0100
+++ b/UnitTestsSources/TestCommands.cpp	Wed Mar 04 10:21:54 2020 +0100
@@ -60,7 +60,7 @@
 //  Json::Value cmdJson;
 //  cmdJson["command"] = "noop";
 
-//  std::auto_ptr<OrthancStone::ICommand> command(factory.CreateFromJson(cmdJson));
+//  std::unique_ptr<OrthancStone::ICommand> command(factory.CreateFromJson(cmdJson));
 
 //  ASSERT_TRUE(command.get() != NULL);
 //  ASSERT_EQ("noop", command->GetName());
@@ -77,7 +77,7 @@
 //  cmdJson["command"] = "increment";
 //  cmdJson["args"]["increment"] = 2;
 
-//  std::auto_ptr<OrthancStone::ICommand> command(factory.CreateFromJson(cmdJson));
+//  std::unique_ptr<OrthancStone::ICommand> command(factory.CreateFromJson(cmdJson));
 
 //  ASSERT_TRUE(command.get() != NULL);
 //  CommandIncrement::counter = 0;
@@ -93,7 +93,7 @@
 //  Json::Value cmdJson;
 //  cmdJson["command"] = "unknown";
 
-//  ASSERT_THROW(std::auto_ptr<OrthancStone::ICommand> command(factory.CreateFromJson(cmdJson)), Orthanc::OrthancException);
+//  ASSERT_THROW(std::unique_ptr<OrthancStone::ICommand> command(factory.CreateFromJson(cmdJson)), Orthanc::OrthancException);
 //}
 
 //TEST(Commands, TryCreateCommandFromInvalidJson)
@@ -104,5 +104,5 @@
 //  Json::Value cmdJson;
 //  cmdJson["command-name"] = "noop";
 
-//  ASSERT_THROW(std::auto_ptr<OrthancStone::ICommand> command(factory.CreateFromJson(cmdJson)), Orthanc::OrthancException);
+//  ASSERT_THROW(std::unique_ptr<OrthancStone::ICommand> command(factory.CreateFromJson(cmdJson)), Orthanc::OrthancException);
 //}