[med-svn] [Git][med-team/orthanc-dicomweb][upstream] New upstream version 1.2+dfsg

Sebastien Jodogne gitlab at salsa.debian.org
Wed May 27 15:05:00 BST 2020



Sebastien Jodogne pushed to branch upstream at Debian Med / orthanc-dicomweb


Commits:
c12a0b6a by jodogne-guest at 2020-05-27T15:21:37+02:00
New upstream version 1.2+dfsg
- - - - -


22 changed files:

- .hg_archival.txt
- CMakeLists.txt
- NEWS
- Plugin/Configuration.cpp
- Plugin/Configuration.h
- Plugin/DicomWebFormatter.cpp
- Plugin/DicomWebFormatter.h
- − Plugin/GdcmParsedDicomFile.cpp
- − Plugin/GdcmParsedDicomFile.h
- Plugin/Plugin.cpp
- Plugin/QidoRs.cpp
- Plugin/StowRs.cpp
- Plugin/WadoRs.cpp
- Plugin/WadoRs.h
- Plugin/WadoRsRetrieveFrames.cpp
- − Resources/CMake/GdcmConfiguration.cmake
- Resources/Orthanc/DownloadOrthancFramework.cmake
- Resources/Orthanc/LinuxStandardBaseToolchain.cmake
- − Resources/Orthanc/Sdk-1.5.4/orthanc/OrthancCPlugin.h
- Resources/Orthanc/Sdk-1.5.7/orthanc/OrthancCPlugin.h → Resources/Orthanc/Sdk-1.7.0/orthanc/OrthancCPlugin.h
- Resources/SyncOrthancFolder.py
- Status.txt


Changes:

=====================================
.hg_archival.txt
=====================================
@@ -1,6 +1,6 @@
 repo: d5f45924411123cfd02d035fd50b8e37536eadef
-node: 1e19bf059f49747d3f28ab8e3cf24607c7a64689
-branch: OrthancDicomWeb-1.1
+node: 76233f8f867fe027b31698fe8596e727d1e4dd67
+branch: OrthancDicomWeb-1.2
 latesttag: null
-latesttagdistance: 380
-changessincelatesttag: 398
+latesttagdistance: 400
+changessincelatesttag: 429


=====================================
CMakeLists.txt
=====================================
@@ -21,13 +21,13 @@ cmake_minimum_required(VERSION 2.8)
 
 project(OrthancDicomWeb)
 
-set(ORTHANC_DICOM_WEB_VERSION "1.1")
+set(ORTHANC_DICOM_WEB_VERSION "1.2")
 
 if (ORTHANC_DICOM_WEB_VERSION STREQUAL "mainline")
   set(ORTHANC_FRAMEWORK_DEFAULT_VERSION "mainline")
   set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "hg")
 else()
-  set(ORTHANC_FRAMEWORK_DEFAULT_VERSION "ae0e3fd609df")  # This is pre-1.6.0
+  set(ORTHANC_FRAMEWORK_DEFAULT_VERSION "1.7.0")
   set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "web")
 endif()
 
@@ -41,9 +41,8 @@ set(ORTHANC_FRAMEWORK_ARCHIVE "" CACHE STRING "Path to the Orthanc archive, if O
 set(ORTHANC_FRAMEWORK_ROOT "" CACHE STRING "Path to the Orthanc source directory, if ORTHANC_FRAMEWORK_SOURCE is \"path\"")
 
 # Advanced parameters to fine-tune linking against system libraries
-set(USE_SYSTEM_GDCM ON CACHE BOOL "Use the system version of Grassroot DICOM (GDCM)")
 set(USE_SYSTEM_ORTHANC_SDK ON CACHE BOOL "Use the system version of the Orthanc plugin SDK")
-set(ORTHANC_SDK_VERSION "1.5.7" CACHE STRING "Version of the Orthanc plugin SDK to use, if not using the system version (can be \"1.5.4\", \"1.5.7\", or \"framework\")")
+set(ORTHANC_SDK_VERSION "1.7.0" CACHE STRING "Version of the Orthanc plugin SDK to use, if not using the system version (can be \"1.7.0\", or \"framework\")")
 
 
 set(BUILD_BOOTSTRAP_VUE OFF CACHE BOOL "Compile Bootstrap-Vue from sources")
@@ -66,15 +65,12 @@ set(USE_BOOST_ICONV ON)
 include(${ORTHANC_ROOT}/Resources/CMake/OrthancFrameworkConfiguration.cmake)
 include_directories(${ORTHANC_ROOT})
 
-include(${CMAKE_SOURCE_DIR}/Resources/CMake/GdcmConfiguration.cmake)
 include(${CMAKE_SOURCE_DIR}/Resources/CMake/JavaScriptLibraries.cmake)
 
 
 if (STATIC_BUILD OR NOT USE_SYSTEM_ORTHANC_SDK)
-  if (ORTHANC_SDK_VERSION STREQUAL "1.5.4")
-    include_directories(${CMAKE_SOURCE_DIR}/Resources/Orthanc/Sdk-1.5.4)
-  elseif (ORTHANC_SDK_VERSION STREQUAL "1.5.7")
-    include_directories(${CMAKE_SOURCE_DIR}/Resources/Orthanc/Sdk-1.5.7)
+  if (ORTHANC_SDK_VERSION STREQUAL "1.7.0")
+    include_directories(${CMAKE_SOURCE_DIR}/Resources/Orthanc/Sdk-1.7.0)
   elseif (ORTHANC_SDK_VERSION STREQUAL "framework")
     include_directories(${ORTHANC_ROOT}/Plugins/Include)
   else()
@@ -146,7 +142,6 @@ add_definitions(
 
 set(CORE_SOURCES
   Plugin/Configuration.cpp
-  Plugin/GdcmParsedDicomFile.cpp
 
   ${ORTHANC_ROOT}/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
   ${ORTHANC_CORE_SOURCES}
@@ -166,8 +161,6 @@ add_library(OrthancDicomWeb SHARED ${CORE_SOURCES}
   ${AUTOGENERATED_SOURCES}
   )
 
-target_link_libraries(OrthancDicomWeb ${GDCM_LIBRARIES})
-
 message("Setting the version of the library to ${ORTHANC_DICOM_WEB_VERSION}")
 
 add_definitions(-DORTHANC_DICOM_WEB_VERSION="${ORTHANC_DICOM_WEB_VERSION}")
@@ -191,11 +184,5 @@ add_executable(UnitTests
   )
 
 target_link_libraries(UnitTests
-  ${GDCM_LIBRARIES}
   ${GOOGLE_TEST_LIBRARIES}
   )
-
-if (STATIC_BUILD OR NOT USE_SYSTEM_GDCM)
-  add_dependencies(OrthancDicomWeb GDCM)
-  add_dependencies(UnitTests GDCM)
-endif()


=====================================
NEWS
=====================================
@@ -2,6 +2,16 @@ Pending changes in the mainline
 ===============================
 
 
+
+Version 1.2 (2020-05-26)
+========================
+
+=> Minimum SDK version: 1.7.0 <=
+
+* Removed dependency on GDCM
+* "QidoCaseSensitive" defaults to "CaseSensitivePN" of Orthanc configuration (instead of "true")
+
+
 Version 1.1 (2020-03-04)
 ========================
 


=====================================
Plugin/Configuration.cpp
=====================================
@@ -334,6 +334,14 @@ namespace OrthancPlugins
     }
 
 
+    bool LookupBooleanValue(bool& target,
+                            const std::string& key)
+    {
+      assert(configuration_.get() != NULL);
+      return configuration_->LookupBooleanValue(target, key);
+    }
+
+
     unsigned int GetUnsignedIntegerValue(const std::string& key,
                                          unsigned int defaultValue)
     {


=====================================
Plugin/Configuration.h
=====================================
@@ -92,12 +92,14 @@ namespace OrthancPlugins
   {
     void Initialize();
 
-    std::string GetStringValue(const std::string& key,
-                               const std::string& defaultValue);
-
+    bool HasKey(const std::string& key);
+    
     bool GetBooleanValue(const std::string& key,
                          bool defaultValue);
 
+    bool LookupBooleanValue(bool& target,
+                            const std::string& key);
+
     unsigned int GetUnsignedIntegerValue(const std::string& key,
                                          unsigned int defaultValue);
 


=====================================
Plugin/DicomWebFormatter.cpp
=====================================
@@ -47,9 +47,10 @@ namespace OrthancPlugins
                                    const uint32_t *levelIndex,
                                    uint16_t tagGroup,
                                    uint16_t tagElement,
-                                   OrthancPluginValueRepresentation vr)
+                                   OrthancPluginValueRepresentation vr,
+                                   void* payload)
   {
-    const DicomWebFormatter& that = GetSingleton();
+    const DicomWebFormatter& that = *reinterpret_cast<const DicomWebFormatter*>(payload);
 
     switch (that.mode_)
     {
@@ -60,7 +61,7 @@ namespace OrthancPlugins
 
       case OrthancPluginDicomWebBinaryMode_BulkDataUri:
       {
-        std::string uri = GetSingleton().bulkRoot_;
+        std::string uri = that.bulkRoot_;
 
         for (size_t i = 0; i < levelDepth; i++)
         {
@@ -77,31 +78,25 @@ namespace OrthancPlugins
   }
 
 
-  DicomWebFormatter::Locker::Locker(OrthancPluginDicomWebBinaryMode mode,
-                                    const std::string& bulkRoot) :
-    that_(GetSingleton()),
-    lock_(that_.mutex_)
-  {
-    that_.mode_ = mode;
-    that_.bulkRoot_ = bulkRoot;
-  }
-
-
-  void DicomWebFormatter::Locker::Apply(std::string& target,
-                                        OrthancPluginContext* context,
-                                        const void* data,
-                                        size_t size,
-                                        bool xml)
+  void DicomWebFormatter::Apply(std::string& target,
+                                OrthancPluginContext* context,
+                                const void* data,
+                                size_t size,
+                                bool xml,
+                                OrthancPluginDicomWebBinaryMode mode,
+                                const std::string& bulkRoot)
   {
+    DicomWebFormatter payload(mode, bulkRoot);
+    
     OrthancString s;
 
     if (xml)
     {
-      s.Assign(OrthancPluginEncodeDicomWebXml(context, data, size, Callback));
+      s.Assign(OrthancPluginEncodeDicomWebXml2(context, data, size, Callback, &payload));
     }
     else
     {
-      s.Assign(OrthancPluginEncodeDicomWebJson(context, data, size, Callback));
+      s.Assign(OrthancPluginEncodeDicomWebJson2(context, data, size, Callback, &payload));
     }
 
     if (s.GetContent() == NULL)
@@ -116,14 +111,16 @@ namespace OrthancPlugins
   }
 
 
-  void DicomWebFormatter::Locker::Apply(std::string& target,
-                                        OrthancPluginContext* context,
-                                        const Json::Value& value,
-                                        bool xml)
+  void DicomWebFormatter::Apply(std::string& target,
+                                OrthancPluginContext* context,
+                                const Json::Value& value,
+                                bool xml,
+                                OrthancPluginDicomWebBinaryMode mode,
+                                const std::string& bulkRoot)
   {
     MemoryBuffer dicom;
     dicom.CreateDicom(value, OrthancPluginCreateDicomFlags_None);
-    Apply(target, context, dicom.GetData(), dicom.GetSize(), xml);
+    Apply(target, context, dicom.GetData(), dicom.GetSize(), xml, mode, bulkRoot);
   }
 
 
@@ -166,11 +163,8 @@ namespace OrthancPlugins
 
     std::string item;
 
-    {
-      // TODO - Avoid a global mutex => Need to change Orthanc SDK
-      OrthancPlugins::DicomWebFormatter::Locker locker(mode, bulkRoot);
-      locker.Apply(item, context_, dicom, size, isXml_);
-    }
+    OrthancPlugins::DicomWebFormatter::Apply(
+      item, context_, dicom, size, isXml_, mode, bulkRoot);
    
     if (isXml_)
     {


=====================================
Plugin/DicomWebFormatter.h
=====================================
@@ -29,7 +29,6 @@
 #include <json/value.h>
 
 #include <boost/noncopyable.hpp>
-#include <boost/thread/mutex.hpp>
 
 
 namespace OrthancPlugins
@@ -37,16 +36,9 @@ namespace OrthancPlugins
   class DicomWebFormatter : public boost::noncopyable
   {
   private:
-    boost::mutex                     mutex_;
     OrthancPluginDicomWebBinaryMode  mode_;
     std::string                      bulkRoot_;
 
-    static DicomWebFormatter& GetSingleton()
-    {
-      static DicomWebFormatter formatter;
-      return formatter;
-    }
-
     static void Callback(OrthancPluginDicomWebNode *node,
                          OrthancPluginDicomWebSetBinaryNode setter,
                          uint32_t levelDepth,
@@ -55,30 +47,31 @@ namespace OrthancPlugins
                          const uint32_t *levelIndex,
                          uint16_t tagGroup,
                          uint16_t tagElement,
-                         OrthancPluginValueRepresentation vr);
+                         OrthancPluginValueRepresentation vr,
+                         void* payload);
 
-  public:
-    class Locker : public boost::noncopyable
+    DicomWebFormatter(OrthancPluginDicomWebBinaryMode mode,
+                      const std::string& bulkRoot) :
+      mode_(mode),
+      bulkRoot_(bulkRoot)
     {
-    private:
-      DicomWebFormatter&         that_;
-      boost::mutex::scoped_lock  lock_;
-
-    public:
-      Locker(OrthancPluginDicomWebBinaryMode mode,
-             const std::string& bulkRoot);
-
-      void Apply(std::string& target,
-                 OrthancPluginContext* context,
-                 const void* data,
-                 size_t size,
-                 bool xml);
-
-      void Apply(std::string& target,
-                 OrthancPluginContext* context,
-                 const Json::Value& value,
-                 bool xml);
-    };
+    }
+    
+  public:
+    static void Apply(std::string& target,
+                      OrthancPluginContext* context,
+                      const void* data,
+                      size_t size,
+                      bool xml,
+                      OrthancPluginDicomWebBinaryMode mode,
+                      const std::string& bulkRoot);
+
+    static void Apply(std::string& target,
+                      OrthancPluginContext* context,
+                      const Json::Value& value,
+                      bool xml,
+                      OrthancPluginDicomWebBinaryMode mode,
+                      const std::string& bulkRoot);
 
     class HttpWriter : public boost::noncopyable
     {


=====================================
Plugin/GdcmParsedDicomFile.cpp deleted
=====================================
@@ -1,435 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * 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 "GdcmParsedDicomFile.h"
-
-#include "ChunkedBuffer.h"
-
-#include <Core/Toolbox.h>
-
-#include <gdcmDict.h>
-#include <gdcmDictEntry.h>
-#include <gdcmDicts.h>
-#include <gdcmGlobal.h>
-#include <gdcmStringFilter.h>
-
-#include <boost/lexical_cast.hpp>
-#include <json/writer.h>
-
-
-namespace OrthancPlugins
-{
-  static const gdcm::Dict* dictionary_ = NULL;
-
-  
-  void GdcmParsedDicomFile::Initialize()
-  {
-    if (dictionary_ != NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-    else
-    {
-      dictionary_ = &gdcm::Global::GetInstance().GetDicts().GetPublicDict();
-
-      if (dictionary_ == NULL)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError,
-                                        "Cannot initialize the DICOM dictionary of GDCM");
-      }
-    }
-  }
-  
-
-  static std::string MyStripSpaces(const std::string& source)
-  {
-    size_t first = 0;
-
-    while (first < source.length() &&
-           (isspace(source[first]) || 
-            source[first] == '\0'))
-    {
-      first++;
-    }
-
-    if (first == source.length())
-    {
-      // String containing only spaces
-      return "";
-    }
-
-    size_t last = source.length();
-    while (last > first &&
-           (isspace(source[last - 1]) ||
-            source[last - 1] == '\0'))
-    {
-      last--;
-    }          
-    
-    assert(first <= last);
-    return source.substr(first, last - first);
-  }
-
-
-  static const char* GetVRName(bool& isSequence,
-                               const gdcm::Tag& tag,
-                               gdcm::VR vr)
-  {
-    if (dictionary_ == NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls,
-                                      "GDCM has not been initialized");
-    }
-    
-    if (vr == gdcm::VR::INVALID)
-    {
-      const gdcm::DictEntry &entry = dictionary_->GetDictEntry(tag);
-      vr = entry.GetVR();
-
-      if (vr == gdcm::VR::OB_OW)
-      {
-        vr = gdcm::VR::OB;
-      }
-    }
-
-    isSequence = (vr == gdcm::VR::SQ);
-
-    const char* str = gdcm::VR::GetVRString(vr);
-    if (isSequence)
-    {
-      return str;
-    }
-
-    if (str == NULL ||
-        strlen(str) != 2 ||
-        !(str[0] >= 'A' && str[0] <= 'Z') ||
-        !(str[1] >= 'A' && str[1] <= 'Z'))
-    {
-      return "UN";
-    }
-    else
-    {
-      return str;
-    }
-  }
-
-
-  static const char* GetVRName(bool& isSequence,
-                               const gdcm::DataElement& element)
-  {
-    return GetVRName(isSequence, element.GetTag(), element.GetVR());
-  }
-
-
-  template <int T>
-  static void ConvertNumberTag(std::string& target,
-                               const gdcm::DataElement& source)
-  {
-    if (source.IsEmpty())
-    {
-      target.clear();
-    }
-    else
-    {
-      typename gdcm::Element<T, gdcm::VM::VM1_n> element;
-
-      element.Set(source.GetValue());
-
-      for (unsigned int i = 0; i < element.GetLength(); i++)
-      {
-        if (i != 0)
-        {
-          target += "\\";
-        }
-      
-        target = boost::lexical_cast<std::string>(element.GetValue());
-      }
-    }
-  }
-
-
-  static bool ConvertDicomStringToUtf8(std::string& result,
-                                       const gdcm::DataElement& element,
-                                       const Orthanc::Encoding sourceEncoding)
-  {
-    const gdcm::ByteValue* data = element.GetByteValue();
-    if (!data)
-    {
-      return false;
-    }
-
-    bool isSequence;
-    std::string vr = GetVRName(isSequence, element);
-
-    if (!isSequence)
-    {
-      if (vr == "FL")
-      {
-        ConvertNumberTag<gdcm::VR::FL>(result, element);
-        return true;
-      }
-      else if (vr == "FD")
-      {
-        ConvertNumberTag<gdcm::VR::FD>(result, element);
-        return true;
-      }
-      else if (vr == "SL")
-      {
-        ConvertNumberTag<gdcm::VR::SL>(result, element);
-        return true;
-      }
-      else if (vr == "SS")
-      {
-        ConvertNumberTag<gdcm::VR::SS>(result, element);
-        return true;
-      }
-      else if (vr == "UL")
-      {
-        ConvertNumberTag<gdcm::VR::UL>(result, element);
-        return true;
-      }
-      else if (vr == "US")
-      {
-        ConvertNumberTag<gdcm::VR::US>(result, element);
-        return true;
-      }
-    }
-
-    if (sourceEncoding == Orthanc::Encoding_Utf8)
-    {
-      result.assign(data->GetPointer(), data->GetLength());
-    }
-    else
-    {
-      std::string tmp(data->GetPointer(), data->GetLength());
-      result = Orthanc::Toolbox::ConvertToUtf8(tmp, sourceEncoding, false);
-    }
-
-    result = MyStripSpaces(result);
-    return true;
-  }
-
-
-
-  void GdcmParsedDicomFile::Setup(const std::string& dicom)
-  {
-    // Prepare a memory stream over the DICOM instance
-    std::stringstream stream(dicom);
-
-    // Parse the DICOM instance using GDCM
-    reader_.SetStream(stream);
-
-    if (!reader_.Read())
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
-                                      "GDCM cannot decode this DICOM instance of length " +
-                                      boost::lexical_cast<std::string>(dicom.size()));
-    }
-  }
-
-
-  GdcmParsedDicomFile::GdcmParsedDicomFile(const OrthancPlugins::MemoryBuffer& buffer)
-  {
-    // TODO Avoid this unnecessary memcpy by defining a stream over the MemoryBuffer
-    std::string dicom(buffer.GetData(), buffer.GetData() + buffer.GetSize());
-    Setup(dicom);
-  }
-
-
-  static bool GetRawTag(std::string& result,
-                        const gdcm::DataSet& dataset,
-                        const gdcm::Tag& tag,
-                        bool stripSpaces)
-  {
-    if (dataset.FindDataElement(tag))
-    {
-      const gdcm::ByteValue* value = dataset.GetDataElement(tag).GetByteValue();
-      if (value)
-      {
-        result.assign(value->GetPointer(), value->GetLength());
-
-        if (stripSpaces)
-        {
-          result = MyStripSpaces(result);
-        }
-
-        return true;
-      }
-    }
-
-    return false;
-  }
-
-
-  bool GdcmParsedDicomFile::GetRawTag(std::string& result,
-                                      const gdcm::Tag& tag,
-                                      bool stripSpaces) const
-  {
-    return OrthancPlugins::GetRawTag(result, GetDataSet(), tag, stripSpaces);
-  }
-
-
-  std::string GdcmParsedDicomFile::GetRawTagWithDefault(const gdcm::Tag& tag,
-                                                        const std::string& defaultValue,
-                                                        bool stripSpaces) const
-  {
-    std::string result;
-    if (!GetRawTag(result, tag, stripSpaces))
-    {
-      return defaultValue;
-    }
-    else
-    {
-      return result;
-    }
-  }
-
-
-  std::string GdcmParsedDicomFile::GetRawTagWithDefault(const Orthanc::DicomTag& tag,
-                                                        const std::string& defaultValue,
-                                                        bool stripSpaces) const
-  {
-    gdcm::Tag t(tag.GetGroup(), tag.GetElement());
-    return GetRawTagWithDefault(t, defaultValue, stripSpaces);
-  }
-
-
-  bool GdcmParsedDicomFile::GetStringTag(std::string& result,
-                                         const gdcm::Tag& tag,
-                                         bool stripSpaces) const
-  {
-    if (!GetDataSet().FindDataElement(tag))
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentTag);
-    }
-
-    const gdcm::DataElement& element = GetDataSet().GetDataElement(tag);
-
-    if (!ConvertDicomStringToUtf8(result, element, GetEncoding()))
-    {
-      return false;
-    }
-
-    if (stripSpaces)
-    {
-      result = MyStripSpaces(result);
-    }
-
-    return true;
-  }
-
-
-  bool GdcmParsedDicomFile::GetIntegerTag(int& result,
-                                          const gdcm::Tag& tag) const
-  {
-    std::string tmp;
-    if (!GetStringTag(tmp, tag, true))
-    {
-      return false;
-    }
-
-    try
-    {
-      result = boost::lexical_cast<int>(tmp);
-      return true;
-    }
-    catch (boost::bad_lexical_cast&)
-    {
-      return false;
-    }
-  }
-
-
-  std::string FormatTag(const gdcm::Tag& tag)
-  {
-    char tmp[16];
-    sprintf(tmp, "%04X%04X", tag.GetGroup(), tag.GetElement());
-    return std::string(tmp);
-  }
-
-
-  static std::string GetWadoUrl(const std::string& wadoBase,
-                                const gdcm::DataSet& dicom)
-  {
-    static const gdcm::Tag DICOM_TAG_STUDY_INSTANCE_UID(0x0020, 0x000d);
-    static const gdcm::Tag DICOM_TAG_SERIES_INSTANCE_UID(0x0020, 0x000e);
-    static const gdcm::Tag DICOM_TAG_SOP_INSTANCE_UID(0x0008, 0x0018);
-
-    std::string study, series, instance;
-
-    if (!GetRawTag(study, dicom, DICOM_TAG_STUDY_INSTANCE_UID, true) ||
-        !GetRawTag(series, dicom, DICOM_TAG_SERIES_INSTANCE_UID, true) ||
-        !GetRawTag(instance, dicom, DICOM_TAG_SOP_INSTANCE_UID, true))
-    {
-      return "";
-    }
-    else
-    {
-      return Configuration::GetWadoUrl(wadoBase, study, series, instance);
-    }
-  }
-
-
-  static Orthanc::Encoding DetectEncoding(const gdcm::DataSet& dicom)
-  {
-    static const gdcm::Tag DICOM_TAG_SPECIFIC_CHARACTER_SET(0x0008, 0x0005);
-
-    if (!dicom.FindDataElement(DICOM_TAG_SPECIFIC_CHARACTER_SET))
-    {
-      return Orthanc::Encoding_Ascii;
-    }
-
-    const gdcm::DataElement& element = 
-      dicom.GetDataElement(DICOM_TAG_SPECIFIC_CHARACTER_SET);
-
-    const gdcm::ByteValue* data = element.GetByteValue();
-    if (!data)
-    {
-      return Configuration::GetDefaultEncoding();
-    }
-
-    std::string tmp(data->GetPointer(), data->GetLength());
-    tmp = MyStripSpaces(tmp);
-
-    Orthanc::Encoding encoding;
-    if (Orthanc::GetDicomEncoding(encoding, tmp.c_str()))
-    {
-      return encoding;
-    }
-    else
-    {
-      return Configuration::GetDefaultEncoding();
-    }
-  }
-
-
-  Orthanc::Encoding  GdcmParsedDicomFile::GetEncoding() const
-  {
-    return DetectEncoding(GetDataSet());
-  }
-  
-
-  std::string GdcmParsedDicomFile::GetWadoUrl(const OrthancPluginHttpRequest* request) const
-  {
-    const std::string base = OrthancPlugins::Configuration::GetBaseUrl(request);
-    return OrthancPlugins::GetWadoUrl(base, GetDataSet());
-  }
-}


=====================================
Plugin/GdcmParsedDicomFile.h deleted
=====================================
@@ -1,89 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * 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 "Configuration.h"
-
-#include <Core/ChunkedBuffer.h>
-#include <Core/Enumerations.h>
-#include <Core/DicomFormat/DicomTag.h>
-#include <Plugins/Samples/Common/OrthancPluginCppWrapper.h>
-
-#include <gdcmReader.h>
-#include <gdcmDataSet.h>
-#include <pugixml.hpp>
-#include <list>
-
-
-namespace OrthancPlugins
-{
-  class GdcmParsedDicomFile : public boost::noncopyable
-  {
-  private:
-    gdcm::Reader reader_;
-
-    void Setup(const std::string& dicom);
-
-    Orthanc::Encoding  GetEncoding() const;
-
-  public:
-    static void Initialize();
-    
-    explicit GdcmParsedDicomFile(const OrthancPlugins::MemoryBuffer& item);
-
-    explicit GdcmParsedDicomFile(const std::string& dicom)
-    {
-      Setup(dicom);
-    }
-
-    const gdcm::File& GetFile() const
-    {
-      return reader_.GetFile();
-    }
-
-    const gdcm::DataSet& GetDataSet() const
-    {
-      return reader_.GetFile().GetDataSet();
-    }
-
-    bool GetRawTag(std::string& result,
-                   const gdcm::Tag& tag,
-                   bool stripSpaces) const;
-
-    std::string GetRawTagWithDefault(const gdcm::Tag& tag,
-                                     const std::string& defaultValue,
-                                     bool stripSpaces) const;
-
-    std::string GetRawTagWithDefault(const Orthanc::DicomTag& tag,
-                                     const std::string& defaultValue,
-                                     bool stripSpaces) const;
-
-    bool GetStringTag(std::string& result,
-                      const gdcm::Tag& tag,
-                      bool stripSpaces) const;
-
-    bool GetIntegerTag(int& result,
-                       const gdcm::Tag& tag) const;
-
-    std::string GetWadoUrl(const OrthancPluginHttpRequest* request) const;
-  };
-}


=====================================
Plugin/Plugin.cpp
=====================================
@@ -20,7 +20,6 @@
 
 #include "DicomWebClient.h"
 #include "DicomWebServers.h"
-#include "GdcmParsedDicomFile.h"
 #include "QidoRs.h"
 #include "StowRs.h"
 #include "WadoRs.h"
@@ -483,9 +482,6 @@ extern "C"
       // Read the configuration
       OrthancPlugins::Configuration::Initialize();
 
-      // Initialize GDCM
-      OrthancPlugins::GdcmParsedDicomFile::Initialize();
-
       // Configure the DICOMweb callbacks
       if (OrthancPlugins::Configuration::GetBooleanValue("Enable", true))
       {
@@ -513,8 +509,8 @@ extern "C"
         OrthancPlugins::RegisterRestCallback<RetrieveBulkData>(root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/bulk/(.*)", true);
         OrthancPlugins::RegisterRestCallback<RetrieveInstanceMetadata>(root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/metadata", true);
         OrthancPlugins::RegisterRestCallback<RetrieveSeriesMetadata>(root + "studies/([^/]*)/series/([^/]*)/metadata", true);
-        OrthancPlugins::RegisterRestCallback<RetrieveFrames>(root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/frames", true);
-        OrthancPlugins::RegisterRestCallback<RetrieveFrames>(root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/frames/([^/]*)", true);
+        OrthancPlugins::RegisterRestCallback<RetrieveAllFrames>(root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/frames", true);
+        OrthancPlugins::RegisterRestCallback<RetrieveSelectedFrames>(root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/frames/([^/]*)", true);
 
         OrthancPlugins::RegisterRestCallback<ListServers>(root + "servers", true);
         OrthancPlugins::RegisterRestCallback<ListServerOperations>(root + "servers/([^/]*)", true);


=====================================
Plugin/QidoRs.cpp
=====================================
@@ -265,8 +265,13 @@ namespace
           throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
       }
 
+      bool caseSensitive;
+      if (OrthancPlugins::Configuration::LookupBooleanValue(caseSensitive, "QidoCaseSensitive"))
+      {
+        result["CaseSensitive"] = caseSensitive;
+      }
+
       result["Expand"] = false;
-      result["CaseSensitive"] = OrthancPlugins::Configuration::GetBooleanValue("QidoCaseSensitive", true);
       result["Query"] = Json::objectValue;
       result["Limit"] = limit_;
       result["Since"] = offset_;
@@ -483,6 +488,8 @@ static void ApplyMatcher(OrthancPluginRestOutput* output,
   Json::Value find;
   matcher.ConvertToOrthanc(find, level);
 
+  LOG(INFO) << "Body of the call from QIDO-RS to /tools/find: " << find.toStyledString();
+  
   std::string body;
 
   {


=====================================
Plugin/StowRs.cpp
=====================================
@@ -191,10 +191,8 @@ namespace OrthancPlugins
     
     std::string answer;
     
-    {
-      DicomWebFormatter::Locker locker(OrthancPluginDicomWebBinaryMode_Ignore, "");
-      locker.Apply(answer, context_, result_, xml_);
-    }
+    DicomWebFormatter::Apply(answer, context_, result_, xml_,
+                             OrthancPluginDicomWebBinaryMode_Ignore, "");
       
     OrthancPluginAnswerBuffer(context_, output, answer.c_str(), answer.size(),
                               xml_ ? "application/dicom+xml" : "application/dicom+json");


=====================================
Plugin/WadoRs.cpp
=====================================
@@ -692,9 +692,9 @@ static void WriteInstanceMetadata(OrthancPlugins::DicomWebFormatter::HttpWriter&
       std::string dicomweb;
       {
         // TODO - Avoid a global mutex => Need to change Orthanc SDK
-        OrthancPlugins::DicomWebFormatter::Locker locker(OrthancPluginDicomWebBinaryMode_Ignore, "");
-        locker.Apply(dicomweb, OrthancPlugins::GetGlobalContext(),
-                     buffer.GetData(), buffer.GetSize(), false /* JSON */);
+        OrthancPlugins::DicomWebFormatter::Apply(
+          dicomweb, OrthancPlugins::GetGlobalContext(), buffer.GetData(), buffer.GetSize(),
+          false /* JSON */, OrthancPluginDicomWebBinaryMode_Ignore, "");
       }
 
       buffer.RestApiPut("/instances/" + orthancId + "/attachments/4444", dicomweb, false);


=====================================
Plugin/WadoRs.h
=====================================
@@ -70,9 +70,13 @@ void RetrieveBulkData(OrthancPluginRestOutput* output,
                       const char* url,
                       const OrthancPluginHttpRequest* request);
 
-void RetrieveFrames(OrthancPluginRestOutput* output,
-                    const char* url,
-                    const OrthancPluginHttpRequest* request);
+void RetrieveAllFrames(OrthancPluginRestOutput* output,
+                       const char* url,
+                       const OrthancPluginHttpRequest* request);
+
+void RetrieveSelectedFrames(OrthancPluginRestOutput* output,
+                            const char* url,
+                            const OrthancPluginHttpRequest* request);
 
 void RetrieveInstanceRendered(OrthancPluginRestOutput* output,
                               const char* url,


=====================================
Plugin/WadoRsRetrieveFrames.cpp
=====================================
@@ -21,21 +21,15 @@
 
 #include "WadoRs.h"
 
-#include "GdcmParsedDicomFile.h"
-
 #include <Core/Toolbox.h>
 #include <Plugins/Samples/Common/OrthancPluginCppWrapper.h>
 
 #include <memory>
 #include <list>
-#include <gdcmImageReader.h>
-#include <gdcmImageWriter.h>
-#include <gdcmImageChangeTransferSyntax.h>
 #include <boost/algorithm/string/replace.hpp>
 #include <boost/lexical_cast.hpp>
 
 
-
 static void TokenizeAndNormalize(std::vector<std::string>& tokens,
                                  const std::string& source,
                                  char separator)
@@ -62,8 +56,8 @@ static void RemoveSurroundingQuotes(std::string& value)
 
 
 
-static gdcm::TransferSyntax ParseTransferSyntax(const OrthancPluginHttpRequest* request,
-                                                gdcm::TransferSyntax sourceTransferSyntax)
+static bool ParseTransferSyntax(Orthanc::DicomTransferSyntax& syntax,
+                                const OrthancPluginHttpRequest* request)
 {
   for (uint32_t i = 0; i < request->headersCount; i++)
   {
@@ -78,7 +72,8 @@ static gdcm::TransferSyntax ParseTransferSyntax(const OrthancPluginHttpRequest*
       if (tokens.size() == 0 ||
           tokens[0] == "*/*")
       {
-        return gdcm::TransferSyntax::ExplicitVRLittleEndian;
+        syntax = Orthanc::DicomTransferSyntax_LittleEndianExplicit;
+        return true;
       }
 
       if (tokens[0] != "multipart/related")
@@ -114,14 +109,21 @@ static gdcm::TransferSyntax ParseTransferSyntax(const OrthancPluginHttpRequest*
 
       if (type == "application/octet-stream")
       {
-        if (transferSyntax.empty())
+        if (transferSyntax.empty() ||
+            transferSyntax == "1.2.840.10008.1.2.1")
         {
-          return gdcm::TransferSyntax(gdcm::TransferSyntax::ExplicitVRLittleEndian);
+          syntax = Orthanc::DicomTransferSyntax_LittleEndianExplicit;
+          return true;
+        }
+        else if (transferSyntax == "1.2.840.10008.1.2")
+        {
+          syntax = Orthanc::DicomTransferSyntax_LittleEndianImplicit;
+          return true;
         }
         else if (transferSyntax == "*")
         {
           // New in DICOMweb plugin 1.1.0
-          return sourceTransferSyntax;
+          return false;
         }
         else
         {
@@ -140,51 +142,62 @@ static gdcm::TransferSyntax ParseTransferSyntax(const OrthancPluginHttpRequest*
         if (type == "image/jpeg" && (transferSyntax.empty() ||  // Default
                                      transferSyntax == "1.2.840.10008.1.2.4.70"))
         {
-          return gdcm::TransferSyntax::JPEGLosslessProcess14_1;
+          syntax = Orthanc::DicomTransferSyntax_JPEGProcess14SV1;
+          return true;
         }
         else if (type == "image/jpeg" && transferSyntax == "1.2.840.10008.1.2.4.50")
         {
-          return gdcm::TransferSyntax::JPEGBaselineProcess1;
+          syntax = Orthanc::DicomTransferSyntax_JPEGProcess1;
+          return true;
         }
         else if (type == "image/jpeg" && transferSyntax == "1.2.840.10008.1.2.4.51")
         {
-          return gdcm::TransferSyntax::JPEGExtendedProcess2_4;
+          syntax = Orthanc::DicomTransferSyntax_JPEGProcess2_4;
+          return true;
         }
         else if (type == "image/jpeg" && transferSyntax == "1.2.840.10008.1.2.4.57")
         {
-          return gdcm::TransferSyntax::JPEGLosslessProcess14;
+          syntax = Orthanc::DicomTransferSyntax_JPEGProcess14;
+          return true;
         }
         else if (type == "image/x-dicom-rle" && (transferSyntax.empty() ||  // Default
                                                  transferSyntax == "1.2.840.10008.1.2.5"))
         {
-          return gdcm::TransferSyntax::RLELossless;
+          syntax = Orthanc::DicomTransferSyntax_RLELossless;
+          return true;
         }
         else if (type == "image/x-jls" && (transferSyntax.empty() ||  // Default
                                            transferSyntax == "1.2.840.10008.1.2.4.80"))
         {
-          return gdcm::TransferSyntax::JPEGLSLossless;
+          syntax = Orthanc::DicomTransferSyntax_JPEGLSLossless;
+          return true;
         }
         else if (type == "image/x-jls" && transferSyntax == "1.2.840.10008.1.2.4.81")
         {
-          return gdcm::TransferSyntax::JPEGLSNearLossless;
+          syntax = Orthanc::DicomTransferSyntax_JPEGLSLossy;
+          return true;
         }
         else if (type == "image/jp2" && (transferSyntax.empty() ||  // Default
                                          transferSyntax == "1.2.840.10008.1.2.4.90"))
         {
-          return gdcm::TransferSyntax::JPEG2000Lossless;
+          syntax = Orthanc::DicomTransferSyntax_JPEG2000LosslessOnly;
+          return true;
         }
         else if (type == "image/jp2" && transferSyntax == "1.2.840.10008.1.2.4.91")
         {
-          return gdcm::TransferSyntax::JPEG2000;
+          syntax = Orthanc::DicomTransferSyntax_JPEG2000;
+          return true;
         }
         else if (type == "image/jpx" && (transferSyntax.empty() ||  // Default
                                          transferSyntax == "1.2.840.10008.1.2.4.92"))
         {
-          return gdcm::TransferSyntax::JPEG2000Part2Lossless;
+          syntax = Orthanc::DicomTransferSyntax_JPEG2000MulticomponentLosslessOnly;
+          return true;
         }
         else if (type == "image/jpx" && transferSyntax == "1.2.840.10008.1.2.4.93")
         {
-          return gdcm::TransferSyntax::JPEG2000Part2;
+          syntax = Orthanc::DicomTransferSyntax_JPEG2000Multicomponent;
+          return true;
         }
 
 
@@ -194,52 +207,63 @@ static gdcm::TransferSyntax ParseTransferSyntax(const OrthancPluginHttpRequest*
          **/
         if (type == "image/dicom+jpeg" && transferSyntax == "1.2.840.10008.1.2.4.50")
         {
-          return gdcm::TransferSyntax::JPEGBaselineProcess1;
+          syntax = Orthanc::DicomTransferSyntax_JPEGProcess1;
+          return true;
         }
         else if (type == "image/dicom+jpeg" && transferSyntax == "1.2.840.10008.1.2.4.51")
         {
-          return gdcm::TransferSyntax::JPEGExtendedProcess2_4;
+          syntax = Orthanc::DicomTransferSyntax_JPEGProcess2_4;
+          return true;
         }
         else if (type == "image/dicom+jpeg" && transferSyntax == "1.2.840.10008.1.2.4.57")
         {
-          return gdcm::TransferSyntax::JPEGLosslessProcess14;
+          syntax = Orthanc::DicomTransferSyntax_JPEGProcess14;
+          return true;
         }
         else if (type == "image/dicom+jpeg" && (transferSyntax.empty() ||
                                                 transferSyntax == "1.2.840.10008.1.2.4.70"))
         {
-          return gdcm::TransferSyntax::JPEGLosslessProcess14_1;
+          syntax = Orthanc::DicomTransferSyntax_JPEGProcess14SV1;
+          return true;
         }
         else if (type == "image/dicom+rle" && (transferSyntax.empty() ||
                                                transferSyntax == "1.2.840.10008.1.2.5"))
         {
-          return gdcm::TransferSyntax::RLELossless;
+          syntax = Orthanc::DicomTransferSyntax_RLELossless;
+          return true;
         }
         else if (type == "image/dicom+jpeg-ls" && (transferSyntax.empty() ||
                                                    transferSyntax == "1.2.840.10008.1.2.4.80"))
         {
-          return gdcm::TransferSyntax::JPEGLSLossless;
+          syntax = Orthanc::DicomTransferSyntax_JPEGLSLossless;
+          return true;
         }
         else if (type == "image/dicom+jpeg-ls" && transferSyntax == "1.2.840.10008.1.2.4.81")
         {
-          return gdcm::TransferSyntax::JPEGLSNearLossless;
+          syntax = Orthanc::DicomTransferSyntax_JPEGLSLossy;
+          return true;
         }
         else if (type == "image/dicom+jp2" && (transferSyntax.empty() ||
                                                transferSyntax == "1.2.840.10008.1.2.4.90"))
         {
-          return gdcm::TransferSyntax::JPEG2000Lossless;
+          syntax = Orthanc::DicomTransferSyntax_JPEG2000LosslessOnly;
+          return true;
         }
         else if (type == "image/dicom+jp2" && transferSyntax == "1.2.840.10008.1.2.4.91")
         {
-          return gdcm::TransferSyntax::JPEG2000;
+          syntax = Orthanc::DicomTransferSyntax_JPEG2000;
+          return true;
         }
         else if (type == "image/dicom+jpx" && (transferSyntax.empty() ||
                                                transferSyntax == "1.2.840.10008.1.2.4.92"))
         {
-          return gdcm::TransferSyntax::JPEG2000Part2Lossless;
+          syntax = Orthanc::DicomTransferSyntax_JPEG2000MulticomponentLosslessOnly;
+          return true;
         }
         else if (type == "image/dicom+jpx" && transferSyntax == "1.2.840.10008.1.2.4.93")
         {
-          return gdcm::TransferSyntax::JPEG2000Part2;
+          syntax = Orthanc::DicomTransferSyntax_JPEG2000Multicomponent;
+          return true;
         }
 
         throw Orthanc::OrthancException(
@@ -251,7 +275,8 @@ static gdcm::TransferSyntax ParseTransferSyntax(const OrthancPluginHttpRequest*
   }
 
   // By default, DICOMweb expectes Little Endian uncompressed pixel data
-  return gdcm::TransferSyntax::ExplicitVRLittleEndian;
+  syntax = Orthanc::DicomTransferSyntax_LittleEndianExplicit;
+  return true;
 }
 
 
@@ -287,52 +312,51 @@ static void ParseFrameList(std::list<unsigned int>& frames,
 }                           
 
 
-
-static const char* GetMimeType(const gdcm::TransferSyntax& syntax)
+static const char* GetMimeType(const Orthanc::DicomTransferSyntax& syntax)
 {
   // http://dicom.nema.org/medical/dicom/current/output/html/part18.html#table_6.1.1.8-3b
   // http://dicom.nema.org/MEDICAL/dicom/2019a/output/chtml/part18/chapter_6.html#table_6.1.1.8-3b
 
   switch (syntax)
   {
-    case gdcm::TransferSyntax::ImplicitVRLittleEndian:
+    case Orthanc::DicomTransferSyntax_LittleEndianImplicit:
       // The "transfer-syntax" info was added in version 1.1 of the plugin
       return "application/octet-stream; transfer-syntax=1.2.840.10008.1.2";
 
-    case gdcm::TransferSyntax::ExplicitVRLittleEndian:
+    case Orthanc::DicomTransferSyntax_LittleEndianExplicit:
       return "application/octet-stream; transfer-syntax=1.2.840.10008.1.2.1";
 
-    case gdcm::TransferSyntax::JPEGBaselineProcess1:
+    case Orthanc::DicomTransferSyntax_JPEGProcess1:
       return "image/jpeg; transfer-syntax=1.2.840.10008.1.2.4.50";
 
-    case gdcm::TransferSyntax::JPEGExtendedProcess2_4:
+    case Orthanc::DicomTransferSyntax_JPEGProcess2_4:
       return "image/jpeg; transfer-syntax=1.2.840.10008.1.2.4.51";
     
-    case gdcm::TransferSyntax::JPEGLosslessProcess14:
+    case Orthanc::DicomTransferSyntax_JPEGProcess14:
       return "image/jpeg; transfer-syntax=1.2.840.10008.1.2.4.57";
 
-    case gdcm::TransferSyntax::JPEGLosslessProcess14_1:
-      return "image/jpeg; transferSyntax=1.2.840.10008.1.2.4.70";
+    case Orthanc::DicomTransferSyntax_JPEGProcess14SV1:
+      return "image/jpeg; transfer-syntax=1.2.840.10008.1.2.4.70";
     
-    case gdcm::TransferSyntax::RLELossless:
-      return "image/x-dicom-rle; transferSyntax=1.2.840.10008.1.2.5";
+    case Orthanc::DicomTransferSyntax_RLELossless:
+      return "image/x-dicom-rle; transfer-syntax=1.2.840.10008.1.2.5";
 
-    case gdcm::TransferSyntax::JPEGLSLossless:
-      return "image/x-jls; transferSyntax=1.2.840.10008.1.2.4.80";
+    case Orthanc::DicomTransferSyntax_JPEGLSLossless:
+      return "image/x-jls; transfer-syntax=1.2.840.10008.1.2.4.80";
 
-    case gdcm::TransferSyntax::JPEGLSNearLossless:
+    case Orthanc::DicomTransferSyntax_JPEGLSLossy:
       return "image/x-jls; transfer-syntax=1.2.840.10008.1.2.4.81";
 
-    case gdcm::TransferSyntax::JPEG2000Lossless:
-      return "image/jp2; transferSyntax=1.2.840.10008.1.2.4.90";
+    case Orthanc::DicomTransferSyntax_JPEG2000LosslessOnly:
+      return "image/jp2; transfer-syntax=1.2.840.10008.1.2.4.90";
 
-    case gdcm::TransferSyntax::JPEG2000:
+    case Orthanc::DicomTransferSyntax_JPEG2000:
       return "image/jp2; transfer-syntax=1.2.840.10008.1.2.4.91";
 
-    case gdcm::TransferSyntax::JPEG2000Part2Lossless:
-      return "image/jpx; transferSyntax=1.2.840.10008.1.2.4.92";
+    case Orthanc::DicomTransferSyntax_JPEG2000MulticomponentLosslessOnly:
+      return "image/jpx; transfer-syntax=1.2.840.10008.1.2.4.92";
 
-    case gdcm::TransferSyntax::JPEG2000Part2:
+    case Orthanc::DicomTransferSyntax_JPEG2000Multicomponent:
       return "image/jpx; transfer-syntax=1.2.840.10008.1.2.4.93";
 
     default:
@@ -341,278 +365,70 @@ static const char* GetMimeType(const gdcm::TransferSyntax& syntax)
 }
 
 
-
-static void ConvertYbrToRgb(uint8_t rgb[3],
-                            const uint8_t ybr[3])
-{
-  // http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.7.6.3.html#sect_C.7.6.3.1.2
-  // https://en.wikipedia.org/wiki/YCbCr#JPEG_conversion
-    
-  const float Y  = ybr[0];
-  const float Cb = ybr[1];
-  const float Cr = ybr[2];
-
-  const float result[3] = {
-    Y                             + 1.402f    * (Cr - 128.0f),
-    Y - 0.344136f * (Cb - 128.0f) - 0.714136f * (Cr - 128.0f),
-    Y + 1.772f    * (Cb - 128.0f)
-  };
-
-  for (uint8_t i = 0; i < 3 ; i++)
-  {
-    if (result[i] < 0)
-    {
-      rgb[i] = 0;
-    }
-    else if (result[i] > 255)
-    {
-      rgb[i] = 255;
-    }
-    else
-    {
-      rgb[i] = static_cast<uint8_t>(result[i]);
-    }
-  }    
-}
-
-
-static void AnswerSingleFrame(OrthancPluginRestOutput* output,
-                              const OrthancPluginHttpRequest* request,
-                              const OrthancPlugins::GdcmParsedDicomFile& dicom,
-                              const char* frame,
-                              size_t size,
-                              unsigned int frameIndex,
-                              bool convertYbr)
-{
-  /**
-   * Fix the photometric interpretation, typically needed for some
-   * multiframe US images (as the one in issue 164). Also check out
-   * the "Plugins/Samples/GdcmDecoder/GdcmImageDecoder.cpp" file in
-   * the source distribution of Orthanc, and Osimis issue WVB-319
-   * ("Some images are not loading in US_MF").
-   **/
-
-  std::vector<uint8_t> copied;  // Don't move this variable inside the
-                                // "if", as "frame" might point to it
-
-  if (convertYbr &&
-      size > 0)
-  {
-    copied.resize(size);
-    memcpy(&copied[0], frame, size);
-
-    uint8_t *p = &copied[0];
-    for (size_t i = 0; i < size / 3; i++)
-    {
-      uint8_t ybr[3], rgb[3];
-      ybr[0] = p[0];
-      ybr[1] = p[1];
-      ybr[2] = p[2];
-
-      ConvertYbrToRgb(rgb, ybr);
-      p[0] = rgb[0];
-      p[1] = rgb[1];
-      p[2] = rgb[2];
-
-      p += 3;
-    }
-
-    frame = reinterpret_cast<const char*>(&copied[0]);
-  }  
-
-
-  OrthancPluginErrorCode error;
-
-#if HAS_SEND_MULTIPART_ITEM_2 == 1
-  std::string location = dicom.GetWadoUrl(request) + "frames/" + boost::lexical_cast<std::string>(frameIndex + 1);
-  const char *keys[] = { "Content-Location" };
-  const char *values[] = { location.c_str() };
-  error = OrthancPluginSendMultipartItem2(OrthancPlugins::GetGlobalContext(), output, frame, size, 1, keys, values);
-#else
-  error = OrthancPluginSendMultipartItem(OrthancPlugins::GetGlobalContext(), output, frame, size);
-#endif
-
-  if (error != OrthancPluginErrorCode_Success)
-  {
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);      
-  }
-}
-
-
-static bool AnswerFrames(OrthancPluginRestOutput* output,
+static void AnswerFrames(OrthancPluginRestOutput* output,
                          const OrthancPluginHttpRequest* request,
-                         const OrthancPlugins::GdcmParsedDicomFile& dicom,
-                         const gdcm::TransferSyntax& syntax,
-                         std::list<unsigned int>& frames)
+                         const OrthancPlugins::DicomInstance& instance,
+                         const std::string& studyInstanceUid,
+                         const std::string& seriesInstanceUid,
+                         const std::string& sopInstanceUid,
+                         const std::list<unsigned int>& frames,
+                         Orthanc::DicomTransferSyntax outputSyntax)
 {
-  static const gdcm::Tag DICOM_TAG_BITS_ALLOCATED(0x0028, 0x0100);
-  static const gdcm::Tag DICOM_TAG_COLUMNS(0x0028, 0x0011);
-  static const gdcm::Tag DICOM_TAG_PIXEL_DATA(0x7fe0, 0x0010);
-  static const gdcm::Tag DICOM_TAG_ROWS(0x0028, 0x0010);
-  static const gdcm::Tag DICOM_TAG_SAMPLES_PER_PIXEL(0x0028, 0x0002);
-  static const gdcm::Tag DICOM_TAG_PHOTOMETRIC_INTERPRETATION(0x0028, 0x0004);
-
-  if (!dicom.GetDataSet().FindDataElement(DICOM_TAG_PIXEL_DATA))
+  if (OrthancPluginStartMultipartAnswer(
+        OrthancPlugins::GetGlobalContext(), 
+        output, "related", GetMimeType(outputSyntax)) != OrthancPluginErrorCode_Success)
   {
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
+    throw Orthanc::OrthancException(Orthanc::ErrorCode_Plugin,
+                                    "Cannot start a multipart answer");
   }
 
-  const gdcm::DataElement& pixelData = dicom.GetDataSet().GetDataElement(DICOM_TAG_PIXEL_DATA);
-  const gdcm::SequenceOfFragments* fragments = pixelData.GetSequenceOfFragments();
-
-  if (OrthancPluginStartMultipartAnswer(OrthancPlugins::GetGlobalContext(), 
-                                        output, "related", GetMimeType(syntax)) != OrthancPluginErrorCode_Success)
-  {
-    return false;
-  }
-
-  int samplesPerPixel;
-
-  if (!dicom.GetIntegerTag(samplesPerPixel, DICOM_TAG_SAMPLES_PER_PIXEL))
-  {
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
-  }
-  
-  bool convertYbr = false;
+  const std::string base = OrthancPlugins::Configuration::GetBaseUrl(request);
     
+  for (std::list<unsigned int>::const_iterator
+         frame = frames.begin(); frame != frames.end(); ++frame)
   {
-    std::string photometric;
-    if (samplesPerPixel == 3 &&
-        dicom.GetStringTag(photometric, DICOM_TAG_PHOTOMETRIC_INTERPRETATION, true) &&
-        photometric == "YBR_FULL")
-    {
-      convertYbr = true;
-    }
-  }  
-  
-  if (fragments == NULL)
-  {
-    // Single-fragment image
-
-    if (pixelData.GetByteValue() == NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError,
-                                      "Image was not properly decoded");
-    }
-
-    int width, height, bits;
-
-    if (!dicom.GetIntegerTag(height, DICOM_TAG_ROWS) ||
-        !dicom.GetIntegerTag(width, DICOM_TAG_COLUMNS) ||
-        !dicom.GetIntegerTag(bits, DICOM_TAG_BITS_ALLOCATED))
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
-    }
-
-    size_t frameSize = height * width * bits * samplesPerPixel / 8;
-
-    if (frameSize == 0)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
-    }
-
-    /**
-     * The number of bytes in "pixelData" might not be divisible by
-     * "frameSize", because "pixelData" might contain one padding byte
-     * to have an even number of bytes.
-     * https://bitbucket.org/sjodogne/orthanc/issues/164/
-     **/
-    
-    if (pixelData.GetByteValue()->GetLength() % frameSize != 0 &&
-        (/* allow one padding byte to be present */
-         pixelData.GetByteValue()->GetLength() % 2 == 0 &&
-         pixelData.GetByteValue()->GetLength() % frameSize != 1))
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);      
-    }
-
-    size_t framesCount = pixelData.GetByteValue()->GetLength() / frameSize;
+    std::string content;
+    instance.GetRawFrame(content, *frame);
 
-    if (frames.empty())
-    {
-      // If no frame is provided, return all the frames (this is an extension)
-      for (size_t i = 0; i < framesCount; i++)
-      {
-        frames.push_back(i);
-      }
-    }
-
-    const char* buffer = pixelData.GetByteValue()->GetPointer();
-    assert(sizeof(char) == 1);
-
-    for (std::list<unsigned int>::const_iterator 
-           frame = frames.begin(); frame != frames.end(); ++frame)
-    {
-      if (*frame >= framesCount)
-      {
-        throw Orthanc::OrthancException(
-          Orthanc::ErrorCode_ParameterOutOfRange,
-          "Trying to access frame number " + boost::lexical_cast<std::string>(*frame + 1) + 
-          " of an image with " + boost::lexical_cast<std::string>(framesCount) + " frames");
-      }
-      else
-      {
-        const char* p = buffer + (*frame) * frameSize;
-        AnswerSingleFrame(output, request, dicom, p, frameSize, *frame, convertYbr);
-      }
-    }
-  }
-  else
-  {
-    // Multi-fragment image, we assume that each fragment corresponds to one frame
+    const char* data = content.empty() ? NULL : content.c_str();
+    size_t size = content.size();
+        
+    OrthancPluginErrorCode error;
 
-    if (frames.empty())
-    {
-      // If no frame is provided, return all the frames (this is an extension)
-      for (size_t i = 0; i < fragments->GetNumberOfFragments(); i++)
-      {
-        frames.push_back(i);
-      }
-    }
+#if HAS_SEND_MULTIPART_ITEM_2 == 1
+    std::string location = (
+      OrthancPlugins::Configuration::GetWadoUrl(base, studyInstanceUid, seriesInstanceUid, sopInstanceUid) +
+      "frames/" + boost::lexical_cast<std::string>(*frame + 1));
+    const char *keys[] = { "Content-Location" };
+    const char *values[] = { location.c_str() };
+    error = OrthancPluginSendMultipartItem2(OrthancPlugins::GetGlobalContext(), output, data, size, 1, keys, values);
+#else
+    error = OrthancPluginSendMultipartItem(OrthancPlugins::GetGlobalContext(), output, data, size);
+#endif
 
-    for (std::list<unsigned int>::const_iterator 
-           frame = frames.begin(); frame != frames.end(); ++frame)
+    if (error != OrthancPluginErrorCode_Success)
     {
-      if (*frame >= fragments->GetNumberOfFragments())
-      {
-        // TODO A frame is not a fragment, looks like a bug
-        throw Orthanc::OrthancException(
-          Orthanc::ErrorCode_ParameterOutOfRange,
-          "Trying to access frame number " + 
-          boost::lexical_cast<std::string>(*frame + 1) + 
-          " of an image with " + 
-          boost::lexical_cast<std::string>(fragments->GetNumberOfFragments()) + 
-          " frames");
-      }
-      else
-      {
-        AnswerSingleFrame(output, request, dicom,
-                          fragments->GetFragment(*frame).GetByteValue()->GetPointer(),
-                          fragments->GetFragment(*frame).GetByteValue()->GetLength(),
-                          *frame, convertYbr);
-      }
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);      
     }
   }
-
-  return true;
 }
 
 
-
-void RetrieveFrames(OrthancPluginRestOutput* output,
-                    const char* url,
-                    const OrthancPluginHttpRequest* request)
+static void RetrieveFrames(OrthancPluginRestOutput* output,
+                           const OrthancPluginHttpRequest* request,
+                           bool allFrames,
+                           std::list<unsigned int>& frames)
 {
-  std::list<unsigned int> frames;
-  ParseFrameList(frames, request);
-
-  Json::Value header;
   std::string orthancId, studyInstanceUid, seriesInstanceUid, sopInstanceUid;
   OrthancPlugins::MemoryBuffer content;
   if (LocateInstance(output, orthancId, studyInstanceUid, seriesInstanceUid, sopInstanceUid, request) &&
-      content.RestApiGet("/instances/" + orthancId + "/file", false) &&
-      OrthancPlugins::RestApiGet(header, "/instances/" + orthancId + "/header?simplify", false))
+      content.RestApiGet("/instances/" + orthancId + "/file", false))
   {
+    if (allFrames)
+    {
+      OrthancPlugins::LogInfo("DICOMweb RetrieveFrames on " + orthancId + ", all frames");
+    }
+    else
     {
       std::string s = "DICOMweb RetrieveFrames on " + orthancId + ", frames: ";
       for (std::list<unsigned int>::const_iterator 
@@ -624,79 +440,56 @@ void RetrieveFrames(OrthancPluginRestOutput* output,
       OrthancPlugins::LogInfo(s);
     }
 
-    std::auto_ptr<OrthancPlugins::GdcmParsedDicomFile> source;
+    Orthanc::DicomTransferSyntax targetSyntax;
 
-    gdcm::TransferSyntax sourceSyntax;
-
-    if (header.type() == Json::objectValue &&
-        header.isMember("TransferSyntaxUID"))
+    std::unique_ptr<OrthancPlugins::DicomInstance> instance;
+    if (ParseTransferSyntax(targetSyntax, request))
     {
-      sourceSyntax = gdcm::TransferSyntax::GetTSType(header["TransferSyntaxUID"].asCString());
+      OrthancPlugins::LogInfo("DICOMweb RetrieveFrames: Transcoding instance " + orthancId + 
+                              " to transfer syntax " + Orthanc::GetTransferSyntaxUid(targetSyntax));
+
+      instance.reset(OrthancPlugins::DicomInstance::Transcode(
+                       content.GetData(), content.GetSize(), GetTransferSyntaxUid(targetSyntax)));
     }
     else
     {
-      source.reset(new OrthancPlugins::GdcmParsedDicomFile(content));
-      sourceSyntax = source->GetFile().GetHeader().GetDataSetTransferSyntax();
+      instance.reset(new OrthancPlugins::DicomInstance(content.GetData(), content.GetSize()));
     }
 
-    gdcm::TransferSyntax targetSyntax(ParseTransferSyntax(request, sourceSyntax));
-
-    if (sourceSyntax == targetSyntax)
+    if (instance.get() == NULL)
     {
-      // No need to change the transfer syntax
-
-      if (source.get() == NULL)
-      {
-        source.reset(new OrthancPlugins::GdcmParsedDicomFile(content));
-      }
-
-      AnswerFrames(output, request, *source, targetSyntax, frames);
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
     }
-    else
-    {
-      // Need to convert the transfer syntax
 
+    if (allFrames)
+    {
+      frames.clear();
+      for (unsigned int i = 0; i < instance->GetFramesCount(); i++)
       {
-        OrthancPlugins::LogInfo("DICOMweb RetrieveFrames: Transcoding instance " + orthancId + 
-                                " from transfer syntax " + std::string(sourceSyntax.GetString()) + 
-                                " to " + std::string(targetSyntax.GetString()));
+        frames.push_back(i + 1);  // Frames are numbered starting from 1
       }
+    }
 
-      gdcm::ImageChangeTransferSyntax change;
-      change.SetTransferSyntax(targetSyntax);
-
-      // TODO Avoid this unnecessary memcpy by defining a stream over the MemoryBuffer
-      std::string dicom(content.GetData(), content.GetData() + content.GetSize());
-      std::stringstream stream(dicom);
+    AnswerFrames(output, request, *instance, studyInstanceUid, seriesInstanceUid,
+                 sopInstanceUid, frames, targetSyntax);
+  }    
+}
 
-      gdcm::ImageReader reader;
-      reader.SetStream(stream);
-      if (!reader.Read())
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
-                                        "Cannot decode the image");
-      }
 
-      change.SetInput(reader.GetImage());
-      if (!change.Change())
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError,
-                                        "Cannot change the transfer syntax of the image");
-      }
+void RetrieveAllFrames(OrthancPluginRestOutput* output,
+                       const char* url,
+                       const OrthancPluginHttpRequest* request)
+{
+  std::list<unsigned int> frames;
+  RetrieveFrames(output, request, true, frames);
+}
 
-      gdcm::ImageWriter writer;
-      writer.SetImage(change.GetOutput());
-      writer.SetFile(reader.GetFile());
-      
-      std::stringstream ss;
-      writer.SetStream(ss);
-      if (!writer.Write())
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_NotEnoughMemory);
-      }
 
-      OrthancPlugins::GdcmParsedDicomFile transcoded(ss.str());
-      AnswerFrames(output, request, transcoded, targetSyntax, frames);
-    }
-  }    
+void RetrieveSelectedFrames(OrthancPluginRestOutput* output,
+                            const char* url,
+                            const OrthancPluginHttpRequest* request)
+{
+  std::list<unsigned int> frames;
+  ParseFrameList(frames, request);
+  RetrieveFrames(output, request, false, frames);
 }


=====================================
Resources/CMake/GdcmConfiguration.cmake deleted
=====================================
@@ -1,144 +0,0 @@
-# Orthanc - A Lightweight, RESTful DICOM Store
-# 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/>.
-
-
-if (STATIC_BUILD OR NOT USE_SYSTEM_GDCM)
-  if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR
-      ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR
-      ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD")
-    # If using gcc, build GDCM with the "-fPIC" argument to allow its
-    # embedding into the shared library containing the Orthanc plugin
-    set(AdditionalFlags "-fPIC")
-  elseif (${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
-    # This definition is necessary to compile
-    # "Source/MediaStorageAndFileFormat/gdcmFileStreamer.cxx"
-    set(AdditionalFlags "-Doff64_t=off_t") 
-  endif()
-  
-  set(Flags
-    "-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} ${AdditionalFlags}"
-    "-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} ${AdditionalFlags}"
-    -DCMAKE_C_FLAGS_DEBUG=${CMAKE_C_FLAGS_DEBUG}
-    -DCMAKE_CXX_FLAGS_DEBUG=${CMAKE_CXX_FLAGS_DEBUG}
-    -DCMAKE_C_FLAGS_RELEASE=${CMAKE_C_FLAGS_RELEASE}
-    -DCMAKE_CXX_FLAGS_RELEASE=${CMAKE_CXX_FLAGS_RELEASE}
-    -DCMAKE_C_FLAGS_MINSIZEREL=${CMAKE_C_FLAGS_MINSIZEREL}
-    -DCMAKE_CXX_FLAGS_MINSIZEREL=${CMAKE_CXX_FLAGS_MINSIZEREL} 
-    -DCMAKE_C_FLAGS_RELWITHDEBINFO=${CMAKE_C_FLAGS_RELWITHDEBINFO} 
-    -DCMAKE_CXX_FLAGS_RELWITHDEBINFO=${CMAKE_CXX_FLAGS_RELWITHDEBINFO}
-    )
-
-  if (CMAKE_TOOLCHAIN_FILE)
-    # Take absolute path to the toolchain
-    get_filename_component(TMP ${CMAKE_TOOLCHAIN_FILE} REALPATH BASE ${CMAKE_SOURCE_DIR})
-    list(APPEND Flags -DCMAKE_TOOLCHAIN_FILE=${TMP})
-  endif()
-
-  # Don't build manpages (since gdcm 2.8.4)
-  list(APPEND Flags -DGDCM_BUILD_DOCBOOK_MANPAGES=OFF)
-
-  if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase")
-    # Trick to disable the compilation of socket++ by gdcm, which is
-    # incompatible with LSB, but fortunately only required for DICOM
-    # Networking
-    list(APPEND Flags -DGDCM_USE_SYSTEM_SOCKETXX=ON)
-
-    # Detect the number of CPU cores to run "make" with as much
-    # parallelism as possible
-    include(ProcessorCount)
-    ProcessorCount(N)
-    if (NOT N EQUAL 0)
-      set(MAKE_PARALLEL -j${N})
-    endif()
-      
-    # For Linux Standard Base, avoid building incompatible target gdcmMEXD (*)
-    set(BUILD_COMMAND BUILD_COMMAND
-      ${CMAKE_MAKE_PROGRAM} ${MAKE_PARALLEL}
-      gdcmMSFF gdcmcharls gdcmDICT gdcmDSED gdcmIOD gdcmjpeg8
-      gdcmjpeg12 gdcmjpeg16 gdcmopenjp2 gdcmzlib gdcmCommon gdcmexpat gdcmuuid)
-  endif()
-
-  include(ExternalProject)
-  externalproject_add(GDCM
-    URL "http://orthanc.osimis.io/ThirdPartyDownloads/gdcm-3.0.4.tar.gz"
-    URL_MD5 "f12dbded708356d5fa0b5ed37ccdb66e"
-    TIMEOUT 60
-    CMAKE_ARGS -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} ${Flags}
-    ${BUILD_COMMAND}    # Customize "make", only for Linux Standard Base (*)
-    INSTALL_COMMAND ""  # Skip the install step
-    )
-
-  if(MSVC)
-    set(Suffix ".lib")
-    set(Prefix "")
-  else()
-    set(Suffix ".a")
-    list(GET CMAKE_FIND_LIBRARY_PREFIXES 0 Prefix)
-  endif()
-
-  set(GDCM_LIBRARIES
-    # WARNING: The order of the libraries below *is* important!
-    ${Prefix}gdcmMSFF${Suffix}
-    ${Prefix}gdcmcharls${Suffix}
-    ${Prefix}gdcmDICT${Suffix}
-    ${Prefix}gdcmDSED${Suffix}
-    ${Prefix}gdcmIOD${Suffix}
-    ${Prefix}gdcmjpeg8${Suffix}
-    ${Prefix}gdcmjpeg12${Suffix}
-    ${Prefix}gdcmjpeg16${Suffix}
-    ${Prefix}gdcmopenjp2${Suffix}
-    ${Prefix}gdcmzlib${Suffix}
-    ${Prefix}gdcmCommon${Suffix}
-    ${Prefix}gdcmexpat${Suffix}
-
-    #${Prefix}socketxx${Suffix}
-    #${Prefix}gdcmMEXD${Suffix}  # DICOM Networking, unneeded by Orthanc plugins
-    #${Prefix}gdcmgetopt${Suffix}
-    )
-
-  if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
-    list(APPEND GDCM_LIBRARIES
-      rpcrt4   # For UUID stuff
-      )
-  else()
-    list(APPEND GDCM_LIBRARIES
-      ${Prefix}gdcmuuid${Suffix}
-      )
-  endif()
-
-  ExternalProject_Get_Property(GDCM binary_dir)
-  include_directories(${binary_dir}/Source/Common)
-  link_directories(${binary_dir}/bin)
-
-  ExternalProject_Get_Property(GDCM source_dir)
-  include_directories(
-    ${source_dir}/Source/Common
-    ${source_dir}/Source/DataDictionary
-    ${source_dir}/Source/MediaStorageAndFileFormat
-    ${source_dir}/Source/DataStructureAndEncodingDefinition
-    )
-
-else()
-  find_package(GDCM REQUIRED)
-  if (GDCM_FOUND)
-    include(${GDCM_USE_FILE})
-    set(GDCM_LIBRARIES gdcmCommon gdcmMSFF)
-  else(GDCM_FOUND)
-    message(FATAL_ERROR "Cannot find GDCM, did you set GDCM_DIR?")
-  endif(GDCM_FOUND)
-endif()


=====================================
Resources/Orthanc/DownloadOrthancFramework.cmake
=====================================
@@ -112,6 +112,12 @@ if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "hg" OR
         set(ORTHANC_FRAMEWORK_MD5 "e1b76f01116d9b5d4ac8cc39980560e3")
       elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.5.8")
         set(ORTHANC_FRAMEWORK_MD5 "82323e8c49a667f658a3639ea4dbc336")
+      elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.6.0")
+        set(ORTHANC_FRAMEWORK_MD5 "eab428d6e53f61e847fa360bb17ebe25")
+      elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.6.1")
+        set(ORTHANC_FRAMEWORK_MD5 "3971f5de96ba71dc9d3f3690afeaa7c0")
+      elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.7.0")
+        set(ORTHANC_FRAMEWORK_MD5 "ce5f689e852b01d3672bd3d2f952a5ef")
 
       # Below this point are development snapshots that were used to
       # release some plugin, before an official release of the Orthanc
@@ -214,7 +220,7 @@ if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "hg")
   else()
     message("Forking the Orthanc source repository using Mercurial")
     execute_process(
-      COMMAND ${ORTHANC_FRAMEWORK_HG} clone "https://bitbucket.org/sjodogne/orthanc"
+      COMMAND ${ORTHANC_FRAMEWORK_HG} clone "https://hg.orthanc-server.com/orthanc/"
       WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
       RESULT_VARIABLE Failure
       )    


=====================================
Resources/Orthanc/LinuxStandardBaseToolchain.cmake
=====================================
@@ -1,11 +1,19 @@
-# LSB_CC=gcc-4.8 LSB_CXX=g++-4.8 cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=../Resources/LinuxStandardBaseToolchain.cmake -DUSE_LEGACY_JSONCPP=ON -DUSE_LEGACY_LIBICU=ON -DBOOST_LOCALE_BACKEND=icu
+#
+# Full build, as used on the BuildBot CIS:
+#
+#   $ LSB_CC=gcc-4.8 LSB_CXX=g++-4.8 cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=../Resources/LinuxStandardBaseToolchain.cmake -DUSE_LEGACY_JSONCPP=ON -DUSE_LEGACY_LIBICU=ON -DBOOST_LOCALE_BACKEND=icu -DENABLE_PKCS11=ON -G Ninja
+#
+# Or, more lightweight version (without libp11 and ICU):
+#
+#   $ LSB_CC=gcc-4.8 LSB_CXX=g++-4.8 cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=../Resources/LinuxStandardBaseToolchain.cmake -DUSE_LEGACY_JSONCPP=ON -G Ninja
+#
 
 INCLUDE(CMakeForceCompiler)
 
-SET(LSB_PATH $ENV{LSB_PATH})
-SET(LSB_CC $ENV{LSB_CC})
-SET(LSB_CXX $ENV{LSB_CXX})
-SET(LSB_TARGET_VERSION "4.0")
+SET(LSB_PATH $ENV{LSB_PATH} CACHE STRING "")
+SET(LSB_CC $ENV{LSB_CC} CACHE STRING "")
+SET(LSB_CXX $ENV{LSB_CXX} CACHE STRING "")
+SET(LSB_TARGET_VERSION "4.0" CACHE STRING "")
 
 IF ("${LSB_PATH}" STREQUAL "")
   SET(LSB_PATH "/opt/lsb")


=====================================
Resources/Orthanc/Sdk-1.5.4/orthanc/OrthancCPlugin.h deleted
=====================================
The diff for this file was not included because it is too large.

=====================================
Resources/Orthanc/Sdk-1.5.7/orthanc/OrthancCPlugin.h → Resources/Orthanc/Sdk-1.7.0/orthanc/OrthancCPlugin.h
=====================================
@@ -26,6 +26,9 @@
  *    - Possibly register a callback to unserialize jobs using OrthancPluginRegisterJobsUnserializer().
  *    - Possibly register a callback to refresh its metrics using OrthancPluginRegisterRefreshMetricsCallback().
  *    - Possibly register a callback to answer chunked HTTP transfers using ::OrthancPluginRegisterChunkedRestCallback().
+ *    - Possibly register a callback for Storage Commitment SCP using ::OrthancPluginRegisterStorageCommitmentScpCallback().
+ *    - Possibly register a callback to filter incoming DICOM instance using OrthancPluginRegisterIncomingDicomInstanceFilter().
+ *    - Possibly register a custom transcoder for DICOM images using OrthancPluginRegisterTranscoderCallback().
  * -# <tt>void OrthancPluginFinalize()</tt>:
  *    This function is invoked by Orthanc during its shutdown. The plugin
  *    must free all its memory.
@@ -58,10 +61,13 @@
  * @brief Functions to register and manage callbacks by the plugins.
  *
  * @defgroup DicomCallbacks DicomCallbacks
- * @brief Functions to register and manage DICOM callbacks (worklists, C-Find, C-MOVE).
+ * @brief Functions to register and manage DICOM callbacks (worklists, C-FIND, C-MOVE, storage commitment).
  *
  * @defgroup Orthanc Orthanc
  * @brief Functions to access the content of the Orthanc server.
+ *
+ * @defgroup DicomInstance DicomInstance
+ * @brief Functions to access DICOM images that are managed by the Orthanc core.
  **/
 
 
@@ -77,7 +83,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 Osimis S.A., 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 General Public License as
@@ -122,16 +128,16 @@
 #endif
 
 #define ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER     1
-#define ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER     5
-#define ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER  7
+#define ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER     7
+#define ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER  0
 
 
 #if !defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE)
-#define ORTHANC_PLUGINS_VERSION_IS_ABOVE(major, minor, revision) \
-  (ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER > major ||               \
-   (ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER == major &&             \
-    (ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER > minor ||             \
-     (ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER == minor &&           \
+#define ORTHANC_PLUGINS_VERSION_IS_ABOVE(major, minor, revision)        \
+  (ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER > major ||                      \
+   (ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER == major &&                    \
+    (ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER > minor ||                    \
+     (ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER == minor &&                  \
       ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER >= revision))))
 #endif
 
@@ -178,7 +184,7 @@
 /**
  * For Microsoft Visual Studio, a compatibility "stdint.h" can be
  * downloaded at the following URL:
- * https://bitbucket.org/sjodogne/orthanc/raw/default/Resources/ThirdParty/VisualStudio/stdint.h
+ * https://hg.orthanc-server.com/orthanc/raw-file/tip/Resources/ThirdParty/VisualStudio/stdint.h
  **/
 #include <stdint.h>
 
@@ -242,6 +248,7 @@ extern "C"
     OrthancPluginErrorCode_DatabaseUnavailable = 36    /*!< The database is currently not available (probably a transient situation) */,
     OrthancPluginErrorCode_CanceledJob = 37    /*!< This job was canceled */,
     OrthancPluginErrorCode_BadGeometry = 38    /*!< Geometry error encountered in Stone */,
+    OrthancPluginErrorCode_SslInitialization = 39    /*!< Cannot initialize SSL encryption, check out your certificates */,
     OrthancPluginErrorCode_SQLiteNotOpened = 1000    /*!< SQLite: The database is not opened */,
     OrthancPluginErrorCode_SQLiteAlreadyOpened = 1001    /*!< SQLite: Connection is already open */,
     OrthancPluginErrorCode_SQLiteCannotOpen = 1002    /*!< SQLite: Unable to open the database */,
@@ -301,6 +308,8 @@ extern "C"
     OrthancPluginErrorCode_CannotOrderSlices = 2040    /*!< Unable to order the slices of the series */,
     OrthancPluginErrorCode_NoWorklistHandler = 2041    /*!< No request handler factory for DICOM C-Find Modality SCP */,
     OrthancPluginErrorCode_AlreadyExistingTag = 2042    /*!< Cannot override the value of a tag that already exists */,
+    OrthancPluginErrorCode_NoStorageCommitmentHandler = 2043    /*!< No request handler factory for DICOM N-ACTION SCP (storage commitment) */,
+    OrthancPluginErrorCode_NoCGetHandler = 2044    /*!< No request handler factory for DICOM C-GET SCP */,
     OrthancPluginErrorCode_UnsupportedMediaType = 3000    /*!< Unsupported media type */,
 
     _OrthancPluginErrorCode_INTERNAL = 0x7fffffff
@@ -433,8 +442,11 @@ extern "C"
     _OrthancPluginService_SetMetricsValue = 31,
     _OrthancPluginService_EncodeDicomWebJson = 32,
     _OrthancPluginService_EncodeDicomWebXml = 33,
-    _OrthancPluginService_ChunkedHttpClient = 34,   /* New in Orthanc 1.5.7 */
-    _OrthancPluginService_GetTagName = 35,   /* New in Orthanc 1.5.7 */
+    _OrthancPluginService_ChunkedHttpClient = 34,    /* New in Orthanc 1.5.7 */
+    _OrthancPluginService_GetTagName = 35,           /* New in Orthanc 1.5.7 */
+    _OrthancPluginService_EncodeDicomWebJson2 = 36,  /* New in Orthanc 1.7.0 */
+    _OrthancPluginService_EncodeDicomWebXml2 = 37,   /* New in Orthanc 1.7.0 */
+    _OrthancPluginService_CreateMemoryBuffer = 38,   /* New in Orthanc 1.7.0 */
     
     /* Registration of callbacks */
     _OrthancPluginService_RegisterRestCallback = 1000,
@@ -450,7 +462,10 @@ extern "C"
     _OrthancPluginService_RegisterIncomingHttpRequestFilter2 = 1010,
     _OrthancPluginService_RegisterRefreshMetricsCallback = 1011,
     _OrthancPluginService_RegisterChunkedRestCallback = 1012,  /* New in Orthanc 1.5.7 */
-
+    _OrthancPluginService_RegisterStorageCommitmentScpCallback = 1013,
+    _OrthancPluginService_RegisterIncomingDicomInstanceFilter = 1014,
+    _OrthancPluginService_RegisterTranscoderCallback = 1015,   /* New in Orthanc 1.7.0 */
+    
     /* Sending answers to REST calls */
     _OrthancPluginService_AnswerBuffer = 2000,
     _OrthancPluginService_CompressAndAnswerPngImage = 2001,  /* Unused as of Orthanc 0.9.4 */
@@ -494,7 +509,19 @@ extern "C"
     _OrthancPluginService_HasInstanceMetadata = 4005,
     _OrthancPluginService_GetInstanceMetadata = 4006,
     _OrthancPluginService_GetInstanceOrigin = 4007,
-
+    _OrthancPluginService_GetInstanceTransferSyntaxUid = 4008,
+    _OrthancPluginService_HasInstancePixelData = 4009,
+    _OrthancPluginService_CreateDicomInstance = 4010,      /* New in Orthanc 1.7.0 */
+    _OrthancPluginService_FreeDicomInstance = 4011,        /* New in Orthanc 1.7.0 */
+    _OrthancPluginService_GetInstanceFramesCount = 4012,   /* New in Orthanc 1.7.0 */
+    _OrthancPluginService_GetInstanceRawFrame = 4013,      /* New in Orthanc 1.7.0 */
+    _OrthancPluginService_GetInstanceDecodedFrame = 4014,  /* New in Orthanc 1.7.0 */
+    _OrthancPluginService_TranscodeDicomInstance = 4015,   /* New in Orthanc 1.7.0 */
+    _OrthancPluginService_SerializeDicomInstance = 4016,   /* New in Orthanc 1.7.0 */
+    _OrthancPluginService_GetInstanceAdvancedJson = 4017,  /* New in Orthanc 1.7.0 */
+    _OrthancPluginService_GetInstanceDicomWebJson = 4018,  /* New in Orthanc 1.7.0 */
+    _OrthancPluginService_GetInstanceDicomWebXml = 4019,   /* New in Orthanc 1.7.0 */
+    
     /* Services for plugins implementing a database back-end */
     _OrthancPluginService_RegisterDatabaseBackend = 5000,
     _OrthancPluginService_DatabaseAnswer = 5001,
@@ -909,14 +936,14 @@ extern "C"
    **/
   typedef enum
   {
-    OrthancPluginMetricsType_Default,   /*!< Default metrics */
+    OrthancPluginMetricsType_Default = 0,   /*!< Default metrics */
 
     /**
      * This metrics represents a time duration. Orthanc will keep the
      * maximum value of the metrics over a sliding window of ten
      * seconds, which is useful if the metrics is sampled frequently.
      **/
-    OrthancPluginMetricsType_Timer
+    OrthancPluginMetricsType_Timer = 1
   } OrthancPluginMetricsType;
   
 
@@ -926,11 +953,47 @@ extern "C"
    **/
   typedef enum
   {
-    OrthancPluginDicomWebBinaryMode_Ignore,        /*!< Don't include binary tags */
-    OrthancPluginDicomWebBinaryMode_InlineBinary,  /*!< Inline encoding using Base64 */
-    OrthancPluginDicomWebBinaryMode_BulkDataUri    /*!< Use a bulk data URI field */
+    OrthancPluginDicomWebBinaryMode_Ignore = 0,        /*!< Don't include binary tags */
+    OrthancPluginDicomWebBinaryMode_InlineBinary = 1,  /*!< Inline encoding using Base64 */
+    OrthancPluginDicomWebBinaryMode_BulkDataUri = 2    /*!< Use a bulk data URI field */
   } OrthancPluginDicomWebBinaryMode;
 
+
+  /**
+   * The available values for the Failure Reason (0008,1197) during
+   * storage commitment.
+   * http://dicom.nema.org/medical/dicom/2019e/output/chtml/part03/sect_C.14.html#sect_C.14.1.1
+   **/
+  typedef enum
+  {
+    OrthancPluginStorageCommitmentFailureReason_Success = 0,
+    /*!< Success: The DICOM instance is properly stored in the SCP */
+
+    OrthancPluginStorageCommitmentFailureReason_ProcessingFailure = 1,
+    /*!< 0110H: A general failure in processing the operation was encountered */
+
+    OrthancPluginStorageCommitmentFailureReason_NoSuchObjectInstance = 2,
+    /*!< 0112H: One or more of the elements in the Referenced SOP
+      Instance Sequence was not available */
+
+    OrthancPluginStorageCommitmentFailureReason_ResourceLimitation = 3,
+    /*!< 0213H: The SCP does not currently have enough resources to
+      store the requested SOP Instance(s) */
+
+    OrthancPluginStorageCommitmentFailureReason_ReferencedSOPClassNotSupported = 4,
+    /*!< 0122H: Storage Commitment has been requested for a SOP
+      Instance with a SOP Class that is not supported by the SCP */
+
+    OrthancPluginStorageCommitmentFailureReason_ClassInstanceConflict = 5,
+    /*!< 0119H: The SOP Class of an element in the Referenced SOP
+      Instance Sequence did not correspond to the SOP class registered
+      for this SOP Instance at the SCP */
+
+    OrthancPluginStorageCommitmentFailureReason_DuplicateTransactionUID = 6
+    /*!< 0131H: The Transaction UID of the Storage Commitment Request
+      is already in use */
+  } OrthancPluginStorageCommitmentFailureReason;
+
   
 
   /**
@@ -965,7 +1028,8 @@ extern "C"
 
 
   /**
-   * @brief Opaque structure that represents a DICOM instance received by Orthanc.
+   * @brief Opaque structure that represents a DICOM instance that is managed by the Orthanc core.
+   * @ingroup DicomInstance
    **/
   typedef struct _OrthancPluginDicomInstance_t OrthancPluginDicomInstance;
 
@@ -1023,7 +1087,7 @@ extern "C"
    * @brief Opaque structure to an object that can be used to check whether a DICOM instance matches a C-Find query.
    * @ingroup Toolbox
    **/
-  typedef struct _OrthancPluginFindAnswers_t OrthancPluginFindMatcher;
+  typedef struct _OrthancPluginFindMatcher_t OrthancPluginFindMatcher;
 
 
   
@@ -1064,11 +1128,11 @@ extern "C"
 
 
   /**
-   * @brief Signature of a callback function that is triggered when Orthanc receives a DICOM instance.
+   * @brief Signature of a callback function that is triggered when Orthanc stores a new DICOM instance.
    * @ingroup Callbacks
    **/
   typedef OrthancPluginErrorCode (*OrthancPluginOnStoredInstanceCallback) (
-    OrthancPluginDicomInstance* instance,
+    const OrthancPluginDicomInstance* instance,
     const char* instanceId);
 
 
@@ -1148,6 +1212,12 @@ extern "C"
    * @param type The content type corresponding to this file. 
    * @return 0 if success, other value if error.
    * @ingroup Callbacks
+   * 
+   * @warning The "content" buffer *must* have been allocated using
+   * the "malloc()" function of your C standard library (i.e. nor
+   * "new[]", neither a pointer to a buffer). The "free()" function of
+   * your C standard library will automatically be invoked on the
+   * "content" pointer.
    **/
   typedef OrthancPluginErrorCode (*OrthancPluginStorageRead) (
     void** content,
@@ -1539,7 +1609,7 @@ extern "C"
    * "levelTagElement", and "levelIndex" arrays.
    * @param levelTagGroup The group of the parent DICOM tags in the hierarchy.
    * @param levelTagElement The element of the parent DICOM tags in the hierarchy.
-   * @param levelIndex The index of the node in the parent sequences of the hiearchy.
+   * @param levelIndex The index of the node in the parent sequences of the hierarchy.
    * @param tagGroup The group of the DICOM tag of interest.
    * @param tagElement The element of the DICOM tag of interest.
    * @param vr The value representation of the binary DICOM node.
@@ -1558,6 +1628,45 @@ extern "C"
 
 
 
+  /**
+   * @brief Callback executed to encode a binary tag in DICOMweb.
+   * 
+   * Signature of a callback function that is called by Orthanc
+   * whenever a DICOM tag that contains a binary value must be written
+   * to a JSON or XML node, while a DICOMweb document is being
+   * generated. The value representation (VR) of the DICOM tag can be
+   * OB, OD, OF, OL, OW, or UN.
+   * 
+   * @see OrthancPluginEncodeDicomWebJson() and OrthancPluginEncodeDicomWebXml()
+   * @param node The node being generated, as provided by Orthanc.
+   * @param setter The setter to be used to encode the content of the node. If
+   * the setter is not called, the binary tag is not written to the output document.
+   * @param levelDepth The depth of the node in the DICOM hierarchy of sequences.
+   * This parameter gives the number of elements in the "levelTagGroup", 
+   * "levelTagElement", and "levelIndex" arrays.
+   * @param levelTagGroup The group of the parent DICOM tags in the hierarchy.
+   * @param levelTagElement The element of the parent DICOM tags in the hierarchy.
+   * @param levelIndex The index of the node in the parent sequences of the hierarchy.
+   * @param tagGroup The group of the DICOM tag of interest.
+   * @param tagElement The element of the DICOM tag of interest.
+   * @param vr The value representation of the binary DICOM node.
+   * @param payload The user payload.
+   * @ingroup Callbacks
+   **/
+  typedef void (*OrthancPluginDicomWebBinaryCallback2) (
+    OrthancPluginDicomWebNode*          node,
+    OrthancPluginDicomWebSetBinaryNode  setter,
+    uint32_t                            levelDepth,
+    const uint16_t*                     levelTagGroup,
+    const uint16_t*                     levelTagElement,
+    const uint32_t*                     levelIndex,
+    uint16_t                            tagGroup,
+    uint16_t                            tagElement,
+    OrthancPluginValueRepresentation    vr,
+    void*                               payload);
+
+
+
   /**
    * @brief Data structure that contains information about the Orthanc core.
    **/
@@ -1652,7 +1761,8 @@ extern "C"
         sizeof(int32_t) != sizeof(OrthancPluginJobStepStatus) ||
         sizeof(int32_t) != sizeof(OrthancPluginConstraintType) ||
         sizeof(int32_t) != sizeof(OrthancPluginMetricsType) ||
-        sizeof(int32_t) != sizeof(OrthancPluginDicomWebBinaryMode))
+        sizeof(int32_t) != sizeof(OrthancPluginDicomWebBinaryMode) ||
+        sizeof(int32_t) != sizeof(OrthancPluginStorageCommitmentFailureReason))
     {
       /* Mismatch in the size of the enumerations */
       return 0;
@@ -1915,7 +2025,7 @@ extern "C"
   typedef struct
   {
     OrthancPluginRestOutput* output;
-    const char*              answer;
+    const void*              answer;
     uint32_t                 answerSize;
     const char*              mimeType;
   } _OrthancPluginAnswerBuffer;
@@ -1935,7 +2045,7 @@ extern "C"
   ORTHANC_PLUGIN_INLINE void OrthancPluginAnswerBuffer(
     OrthancPluginContext*    context,
     OrthancPluginRestOutput* output,
-    const char*              answer,
+    const void*              answer,
     uint32_t                 answerSize,
     const char*              mimeType)
   {
@@ -2646,12 +2756,12 @@ extern "C"
 
   typedef struct
   {
-    char**                       resultStringToFree;
-    const char**                 resultString;
-    int64_t*                     resultInt64;
-    const char*                  key;
-    OrthancPluginDicomInstance*  instance;
-    OrthancPluginInstanceOrigin* resultOrigin;   /* New in Orthanc 0.9.5 SDK */
+    char**                             resultStringToFree;
+    const char**                       resultString;
+    int64_t*                           resultInt64;
+    const char*                        key;
+    const OrthancPluginDicomInstance*  instance;
+    OrthancPluginInstanceOrigin*       resultOrigin;   /* New in Orthanc 0.9.5 SDK */
   } _OrthancPluginAccessDicomInstance;
 
 
@@ -2664,11 +2774,11 @@ extern "C"
    * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
    * @param instance The instance of interest.
    * @return The AET if success, NULL if error.
-   * @ingroup Callbacks
+   * @ingroup DicomInstance
    **/
   ORTHANC_PLUGIN_INLINE const char* OrthancPluginGetInstanceRemoteAet(
-    OrthancPluginContext*        context,
-    OrthancPluginDicomInstance*  instance)
+    OrthancPluginContext*              context,
+    const OrthancPluginDicomInstance*  instance)
   {
     const char* result;
 
@@ -2697,11 +2807,11 @@ extern "C"
    * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
    * @param instance The instance of interest.
    * @return The size of the file, -1 in case of error.
-   * @ingroup Callbacks
+   * @ingroup DicomInstance
    **/
   ORTHANC_PLUGIN_INLINE int64_t OrthancPluginGetInstanceSize(
-    OrthancPluginContext*       context,
-    OrthancPluginDicomInstance* instance)
+    OrthancPluginContext*             context,
+    const OrthancPluginDicomInstance* instance)
   {
     int64_t size;
 
@@ -2730,11 +2840,11 @@ extern "C"
    * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
    * @param instance The instance of interest.
    * @return The pointer to the DICOM data, NULL in case of error.
-   * @ingroup Callbacks
+   * @ingroup DicomInstance
    **/
-  ORTHANC_PLUGIN_INLINE const char* OrthancPluginGetInstanceData(
-    OrthancPluginContext*        context,
-    OrthancPluginDicomInstance*  instance)
+  ORTHANC_PLUGIN_INLINE const void* OrthancPluginGetInstanceData(
+    OrthancPluginContext*              context,
+    const OrthancPluginDicomInstance*  instance)
   {
     const char* result;
 
@@ -2766,11 +2876,11 @@ extern "C"
    * @param instance The instance of interest.
    * @return The NULL value in case of error, or a string containing the JSON file.
    * This string must be freed by OrthancPluginFreeString().
-   * @ingroup Callbacks
+   * @ingroup DicomInstance
    **/
   ORTHANC_PLUGIN_INLINE char* OrthancPluginGetInstanceJson(
-    OrthancPluginContext*        context,
-    OrthancPluginDicomInstance*  instance)
+    OrthancPluginContext*              context,
+    const OrthancPluginDicomInstance*  instance)
   {
     char* result;
 
@@ -2804,11 +2914,11 @@ extern "C"
    * @param instance The instance of interest.
    * @return The NULL value in case of error, or a string containing the JSON file.
    * This string must be freed by OrthancPluginFreeString().
-   * @ingroup Callbacks
+   * @ingroup DicomInstance
    **/
   ORTHANC_PLUGIN_INLINE char* OrthancPluginGetInstanceSimplifiedJson(
-    OrthancPluginContext*        context,
-    OrthancPluginDicomInstance*  instance)
+    OrthancPluginContext*              context,
+    const OrthancPluginDicomInstance*  instance)
   {
     char* result;
 
@@ -2843,12 +2953,12 @@ extern "C"
    * @param instance The instance of interest.
    * @param metadata The metadata of interest.
    * @return 1 if the metadata is present, 0 if it is absent, -1 in case of error.
-   * @ingroup Callbacks
+   * @ingroup DicomInstance
    **/
   ORTHANC_PLUGIN_INLINE int  OrthancPluginHasInstanceMetadata(
-    OrthancPluginContext*        context,
-    OrthancPluginDicomInstance*  instance,
-    const char*                  metadata)
+    OrthancPluginContext*              context,
+    const OrthancPluginDicomInstance*  instance,
+    const char*                        metadata)
   {
     int64_t result;
 
@@ -2880,13 +2990,16 @@ extern "C"
    * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
    * @param instance The instance of interest.
    * @param metadata The metadata of interest.
-   * @return The metadata value if success, NULL if error.
-   * @ingroup Callbacks
+   * @return The metadata value if success, NULL if error. Please note that the 
+   *         returned string belongs to the instance object and must NOT be 
+   *         deallocated. Please make a copy of the string if you wish to access 
+   *         it later.
+   * @ingroup DicomInstance
    **/
   ORTHANC_PLUGIN_INLINE const char* OrthancPluginGetInstanceMetadata(
-    OrthancPluginContext*        context,
-    OrthancPluginDicomInstance*  instance,
-    const char*                  metadata)
+    OrthancPluginContext*              context,
+    const OrthancPluginDicomInstance*  instance,
+    const char*                        metadata)
   {
     const char* result;
 
@@ -5053,11 +5166,11 @@ extern "C"
    * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
    * @param instance The instance of interest.
    * @return The origin of the instance.
-   * @ingroup Callbacks
+   * @ingroup DicomInstance
    **/
   ORTHANC_PLUGIN_INLINE OrthancPluginInstanceOrigin OrthancPluginGetInstanceOrigin(
-    OrthancPluginContext*       context,
-    OrthancPluginDicomInstance* instance)
+    OrthancPluginContext*             context,
+    const OrthancPluginDicomInstance* instance)
   {
     OrthancPluginInstanceOrigin origin;
 
@@ -5129,8 +5242,11 @@ extern "C"
   /**
    * @brief Register a callback to handle the decoding of DICOM images.
    *
-   * This function registers a custom callback to the decoding of
-   * DICOM images, replacing the built-in decoder of Orthanc.
+   * This function registers a custom callback to decode DICOM images,
+   * extending the built-in decoder of Orthanc that uses
+   * DCMTK. Starting with Orthanc 1.7.0, the exact behavior is
+   * affected by the configuration option
+   * "BuiltinDecoderTranscoderOrder" of Orthanc.
    *
    * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
    * @param callback The callback.
@@ -5262,6 +5378,7 @@ extern "C"
    * @param frameIndex The index of the frame of interest in a multi-frame image.
    * @return The uncompressed image. It must be freed with OrthancPluginFreeImage().
    * @ingroup Images
+   * @see OrthancPluginGetInstanceDecodedFrame()
    **/
   ORTHANC_PLUGIN_INLINE OrthancPluginImage* OrthancPluginDecodeDicomImage(
     OrthancPluginContext*  context,
@@ -6737,6 +6854,7 @@ extern "C"
    * @see OrthancPluginCreateDicom()
    * @return The NULL value in case of error, or the JSON document. This string must
    * be freed by OrthancPluginFreeString().
+   * @deprecated OrthancPluginEncodeDicomWebJson2()
    * @ingroup Toolbox
    **/
   ORTHANC_PLUGIN_INLINE char* OrthancPluginEncodeDicomWebJson(
@@ -6775,9 +6893,10 @@ extern "C"
    * @param dicom Pointer to the DICOM instance.
    * @param dicomSize Size of the DICOM instance.
    * @param callback Callback to set the value of the binary tags.
-   * @return The NULL value in case of error, or the JSON document. This string must
+   * @return The NULL value in case of error, or the XML document. This string must
    * be freed by OrthancPluginFreeString().
    * @see OrthancPluginCreateDicom()
+   * @deprecated OrthancPluginEncodeDicomWebXml2()
    * @ingroup Toolbox
    **/
   ORTHANC_PLUGIN_INLINE char* OrthancPluginEncodeDicomWebXml(
@@ -6807,6 +6926,104 @@ extern "C"
   
 
 
+  typedef struct
+  {
+    char**                                target;
+    const void*                           dicom;
+    uint32_t                              dicomSize;
+    OrthancPluginDicomWebBinaryCallback2  callback;
+    void*                                 payload;
+  } _OrthancPluginEncodeDicomWeb2;
+
+  /**
+   * @brief Convert a DICOM instance to DICOMweb JSON.
+   *
+   * This function converts a memory buffer containing a DICOM instance,
+   * into its DICOMweb JSON representation.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param dicom Pointer to the DICOM instance.
+   * @param dicomSize Size of the DICOM instance.
+   * @param callback Callback to set the value of the binary tags.
+   * @param payload User payload.
+   * @return The NULL value in case of error, or the JSON document. This string must
+   * be freed by OrthancPluginFreeString().
+   * @see OrthancPluginCreateDicom()
+   * @ingroup Toolbox
+   **/
+  ORTHANC_PLUGIN_INLINE char* OrthancPluginEncodeDicomWebJson2(
+    OrthancPluginContext*                 context,
+    const void*                           dicom,
+    uint32_t                              dicomSize,
+    OrthancPluginDicomWebBinaryCallback2  callback,
+    void*                                 payload)
+  {
+    char* target = NULL;
+    
+    _OrthancPluginEncodeDicomWeb2 params;
+    params.target = ⌖
+    params.dicom = dicom;
+    params.dicomSize = dicomSize;
+    params.callback = callback;
+    params.payload = payload;
+
+    if (context->InvokeService(context, _OrthancPluginService_EncodeDicomWebJson2, &params) != OrthancPluginErrorCode_Success)
+    {
+      /* Error */
+      return NULL;
+    }
+    else
+    {
+      return target;
+    }
+  }
+
+
+  /**
+   * @brief Convert a DICOM instance to DICOMweb XML.
+   *
+   * This function converts a memory buffer containing a DICOM instance,
+   * into its DICOMweb XML representation.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param dicom Pointer to the DICOM instance.
+   * @param dicomSize Size of the DICOM instance.
+   * @param callback Callback to set the value of the binary tags.
+   * @param payload User payload.
+   * @return The NULL value in case of error, or the XML document. This string must
+   * be freed by OrthancPluginFreeString().
+   * @see OrthancPluginCreateDicom()
+   * @ingroup Toolbox
+   **/
+  ORTHANC_PLUGIN_INLINE char* OrthancPluginEncodeDicomWebXml2(
+    OrthancPluginContext*                 context,
+    const void*                           dicom,
+    uint32_t                              dicomSize,
+    OrthancPluginDicomWebBinaryCallback2  callback,
+    void*                                 payload)
+  {
+    char* target = NULL;
+    
+    _OrthancPluginEncodeDicomWeb2 params;
+    params.target = ⌖
+    params.dicom = dicom;
+    params.dicomSize = dicomSize;
+    params.callback = callback;
+    params.payload = payload;
+
+    if (context->InvokeService(context, _OrthancPluginService_EncodeDicomWebXml2, &params) != OrthancPluginErrorCode_Success)
+    {
+      /* Error */
+      return NULL;
+    }
+    else
+    {
+      return target;
+    }
+  }
+  
+
+
   /**
    * @brief Callback executed when a HTTP header is received during a chunked transfer.
    *
@@ -7250,7 +7467,720 @@ extern "C"
   }
 
 
+
+  /**
+   * @brief Callback executed by the storage commitment SCP.
+   *
+   * Signature of a factory function that creates an object to handle
+   * one incoming storage commitment request.
+   *
+   * @remark The factory receives the list of the SOP class/instance
+   * UIDs of interest to the remote storage commitment SCU. This gives
+   * the factory the possibility to start some prefetch process
+   * upfront in the background, before the handler object is actually
+   * queried about the status of these DICOM instances.
+   *
+   * @param handler Output variable where the factory puts the handler object it created.
+   * @param jobId ID of the Orthanc job that is responsible for handling 
+   * the storage commitment request. This job will successively look for the
+   * status of all the individual queried DICOM instances.
+   * @param transactionUid UID of the storage commitment transaction
+   * provided by the storage commitment SCU. It contains the value of the
+   * (0008,1195) DICOM tag.
+   * @param sopClassUids Array of the SOP class UIDs (0008,0016) that are queried by the SCU.
+   * @param sopInstanceUids Array of the SOP instance UIDs (0008,0018) that are queried by the SCU.
+   * @param countInstances Number of DICOM instances that are queried. This is the size
+   * of the `sopClassUids` and `sopInstanceUids` arrays.
+   * @param remoteAet The AET of the storage commitment SCU.
+   * @param calledAet The AET used by the SCU to contact the storage commitment SCP (i.e. Orthanc).
+   * @return 0 if success, other value if error.
+   * @ingroup DicomCallbacks
+   **/
+  typedef OrthancPluginErrorCode (*OrthancPluginStorageCommitmentFactory) (
+    void**              handler /* out */,
+    const char*         jobId,
+    const char*         transactionUid,
+    const char* const*  sopClassUids,
+    const char* const*  sopInstanceUids,
+    uint32_t            countInstances,
+    const char*         remoteAet,
+    const char*         calledAet);
+
+  
+  /**
+   * @brief Callback to free one storage commitment SCP handler.
+   * 
+   * Signature of a callback function that releases the resources
+   * allocated by the factory of the storage commitment SCP. The
+   * handler is the return value of a previous call to the
+   * OrthancPluginStorageCommitmentFactory() callback.
+   *
+   * @param handler The handler object to be destructed.
+   * @ingroup DicomCallbacks
+   **/
+  typedef void (*OrthancPluginStorageCommitmentDestructor) (void* handler);
+
+
+  /**
+   * @brief Callback to get the status of one DICOM instance in the
+   * storage commitment SCP.
+   *
+   * Signature of a callback function that is successively invoked for
+   * each DICOM instance that is queried by the remote storage
+   * commitment SCU.  The function must be tought of as a method of
+   * the handler object that was created by a previous call to the
+   * OrthancPluginStorageCommitmentFactory() callback. After each call
+   * to this method, the progress of the associated Orthanc job is
+   * updated.
+   * 
+   * @param target Output variable where to put the status for the queried instance.
+   * @param handler The handler object associated with this storage commitment request.
+   * @param sopClassUid The SOP class UID (0008,0016) of interest.
+   * @param sopInstanceUid The SOP instance UID (0008,0018) of interest.
+   * @ingroup DicomCallbacks
+   **/
+  typedef OrthancPluginErrorCode (*OrthancPluginStorageCommitmentLookup) (
+    OrthancPluginStorageCommitmentFailureReason* target,
+    void* handler,
+    const char* sopClassUid,
+    const char* sopInstanceUid);
+    
+    
+  typedef struct
+  {
+    OrthancPluginStorageCommitmentFactory     factory;
+    OrthancPluginStorageCommitmentDestructor  destructor;
+    OrthancPluginStorageCommitmentLookup      lookup;
+  } _OrthancPluginRegisterStorageCommitmentScpCallback;
+
+  /**
+   * @brief Register a callback to handle incoming requests to the storage commitment SCP.
+   *
+   * This function registers a callback to handle storage commitment SCP requests.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param factory Factory function that creates the handler object
+   * for incoming storage commitment requests.
+   * @param destructor Destructor function to destroy the handler object..
+   * @param lookup Callback method to get the status of one DICOM instance.
+   * @return 0 if success, other value if error.
+   * @ingroup DicomCallbacks
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterStorageCommitmentScpCallback(
+    OrthancPluginContext*                     context,
+    OrthancPluginStorageCommitmentFactory     factory,
+    OrthancPluginStorageCommitmentDestructor  destructor,
+    OrthancPluginStorageCommitmentLookup      lookup)
+  {
+    _OrthancPluginRegisterStorageCommitmentScpCallback params;
+    params.factory = factory;
+    params.destructor = destructor;
+    params.lookup = lookup;
+    return context->InvokeService(context, _OrthancPluginService_RegisterStorageCommitmentScpCallback, &params);
+  }
   
+
+
+  /**
+   * @brief Callback to filter incoming DICOM instances received by Orthanc.
+   *
+   * Signature of a callback function that is triggered whenever
+   * Orthanc receives a new DICOM instance (e.g. through REST API or
+   * DICOM protocol), and that answers whether this DICOM instance
+   * should be accepted or discarded by Orthanc.
+   *
+   * Note that the metadata information is not available
+   * (i.e. GetInstanceMetadata() should not be used on "instance").
+   *
+   * @param instance The received DICOM instance.
+   * @return 0 to discard the instance, 1 to store the instance, -1 if error.
+   * @ingroup Callback
+   **/
+  typedef int32_t (*OrthancPluginIncomingDicomInstanceFilter) (
+    const OrthancPluginDicomInstance* instance);
+
+
+  typedef struct
+  {
+    OrthancPluginIncomingDicomInstanceFilter callback;
+  } _OrthancPluginIncomingDicomInstanceFilter;
+
+  /**
+   * @brief Register a callback to filter incoming DICOM instance.
+   *
+   * This function registers a custom callback to filter incoming
+   * DICOM instances received by Orthanc (either through the REST API
+   * or through the DICOM protocol).
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param callback The callback.
+   * @return 0 if success, other value if error.
+   * @ingroup Callbacks
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterIncomingDicomInstanceFilter(
+    OrthancPluginContext*                     context,
+    OrthancPluginIncomingDicomInstanceFilter  callback)
+  {
+    _OrthancPluginIncomingDicomInstanceFilter params;
+    params.callback = callback;
+
+    return context->InvokeService(context, _OrthancPluginService_RegisterIncomingDicomInstanceFilter, &params);
+  }
+
+
+  /**
+   * @brief Get the transfer syntax of a DICOM file.
+   *
+   * This function returns a pointer to a newly created string that
+   * contains the transfer syntax UID of the DICOM instance. The empty
+   * string might be returned if this information is unknown.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param instance The instance of interest.
+   * @return The NULL value in case of error, or a string containing the
+   * transfer syntax UID. This string must be freed by OrthancPluginFreeString().
+   * @ingroup DicomInstance
+   **/
+  ORTHANC_PLUGIN_INLINE char* OrthancPluginGetInstanceTransferSyntaxUid(
+    OrthancPluginContext*              context,
+    const OrthancPluginDicomInstance*  instance)
+  {
+    char* result;
+
+    _OrthancPluginAccessDicomInstance params;
+    memset(&params, 0, sizeof(params));
+    params.resultStringToFree = &result;
+    params.instance = instance;
+
+    if (context->InvokeService(context, _OrthancPluginService_GetInstanceTransferSyntaxUid, &params) != OrthancPluginErrorCode_Success)
+    {
+      /* Error */
+      return NULL;
+    }
+    else
+    {
+      return result;
+    }
+  }
+
+
+  /**
+   * @brief Check whether the DICOM file has pixel data.
+   *
+   * This function returns a Boolean value indicating whether the
+   * DICOM instance contains the pixel data (7FE0,0010) tag.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param instance The instance of interest.
+   * @return "1" if the DICOM instance contains pixel data, or "0" if
+   * the tag is missing, or "-1" in the case of an error.
+   * @ingroup DicomInstance
+   **/
+  ORTHANC_PLUGIN_INLINE int32_t OrthancPluginHasInstancePixelData(
+    OrthancPluginContext*             context,
+    const OrthancPluginDicomInstance* instance)
+  {
+    int64_t hasPixelData;
+
+    _OrthancPluginAccessDicomInstance params;
+    memset(&params, 0, sizeof(params));
+    params.resultInt64 = &hasPixelData;
+    params.instance = instance;
+
+    if (context->InvokeService(context, _OrthancPluginService_HasInstancePixelData, &params) != OrthancPluginErrorCode_Success ||
+        hasPixelData < 0 ||
+        hasPixelData > 1)
+    {
+      /* Error */
+      return -1;
+    }
+    else
+    {
+      return (hasPixelData != 0);
+    }
+  }
+
+
+
+
+
+
+  typedef struct
+  {
+    OrthancPluginDicomInstance**  target;
+    const void*                   buffer;
+    uint32_t                      size;
+    const char*                   transferSyntax;
+  } _OrthancPluginCreateDicomInstance;
+
+  /**
+   * @brief Parse a DICOM instance.
+   *
+   * This function parses a memory buffer that contains a DICOM
+   * file. The function returns a new pointer to a data structure that
+   * is managed by the Orthanc core.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param buffer The memory buffer containing the DICOM instance.
+   * @param size The size of the memory buffer.
+   * @return The newly allocated DICOM instance. It must be freed with OrthancPluginFreeDicomInstance().
+   * @ingroup DicomInstance
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginDicomInstance* OrthancPluginCreateDicomInstance(
+    OrthancPluginContext*  context,
+    const void*            buffer,
+    uint32_t               size)
+  {
+    OrthancPluginDicomInstance* target = NULL;
+
+    _OrthancPluginCreateDicomInstance params;
+    params.target = ⌖
+    params.buffer = buffer;
+    params.size = size;
+
+    if (context->InvokeService(context, _OrthancPluginService_CreateDicomInstance, &params) != OrthancPluginErrorCode_Success)
+    {
+      /* Error */
+      return NULL;
+    }
+    else
+    {
+      return target;
+    }
+  }
+
+  typedef struct
+  {
+    OrthancPluginDicomInstance*   dicom;
+  } _OrthancPluginFreeDicomInstance;
+
+  /**
+   * @brief Free a DICOM instance.
+   *
+   * This function frees a DICOM instance that was parsed using
+   * OrthancPluginCreateDicomInstance().
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param dicom The DICOM instance.
+   * @ingroup DicomInstance
+   **/
+  ORTHANC_PLUGIN_INLINE void  OrthancPluginFreeDicomInstance(
+    OrthancPluginContext*        context, 
+    OrthancPluginDicomInstance*  dicom)
+  {
+    _OrthancPluginFreeDicomInstance params;
+    params.dicom = dicom;
+
+    context->InvokeService(context, _OrthancPluginService_FreeDicomInstance, &params);
+  }
+
+
+  typedef struct
+  {
+    uint32_t*                             targetUint32;
+    OrthancPluginMemoryBuffer*            targetBuffer;
+    OrthancPluginImage**                  targetImage;
+    char**                                targetStringToFree;
+    const OrthancPluginDicomInstance*     instance;
+    uint32_t                              frameIndex;
+    OrthancPluginDicomToJsonFormat        format;
+    OrthancPluginDicomToJsonFlags         flags;
+    uint32_t                              maxStringLength;
+    OrthancPluginDicomWebBinaryCallback2  dicomWebCallback;
+    void*                                 dicomWebPayload;
+  } _OrthancPluginAccessDicomInstance2;
+
+  /**
+   * @brief Get the number of frames in a DICOM instance.
+   *
+   * This function returns the number of frames that are part of a
+   * DICOM image managed by the Orthanc core.
+   * 
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param instance The instance of interest.
+   * @return The number of frames (will be zero in the case of an error)..
+   * @ingroup DicomInstance
+   **/
+  ORTHANC_PLUGIN_INLINE uint32_t OrthancPluginGetInstanceFramesCount(
+    OrthancPluginContext*             context,
+    const OrthancPluginDicomInstance* instance)
+  {
+    uint32_t count;
+
+    _OrthancPluginAccessDicomInstance2 params;
+    memset(&params, 0, sizeof(params));
+    params.targetUint32 = &count;
+    params.instance = instance;
+
+    if (context->InvokeService(context, _OrthancPluginService_GetInstanceFramesCount, &params) != OrthancPluginErrorCode_Success)
+    {
+      /* Error */
+      return 0;
+    }
+    else
+    {
+      return count;
+    }
+  }
+
+
+  /**
+   * @brief Get the raw content of a frame in a DICOM instance.
+   *
+   * This function returns a memory buffer containing the raw content
+   * of a frame in a DICOM instance that is managed by the Orthanc
+   * core. This is notably useful for compressed transfer syntaxes, as
+   * it gives access to the embedded files (such as JPEG, JPEG-LS or
+   * JPEG2k). The Orthanc core transparently reassembles the fragments
+   * to extract the raw frame.
+   * 
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param target The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer().
+   * @param instance The instance of interest.
+   * @param frameIndex The index of the frame of interest.
+   * @return 0 if success, or the error code if failure.
+   * @ingroup DicomInstance
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginGetInstanceRawFrame(
+    OrthancPluginContext*             context,
+    OrthancPluginMemoryBuffer*        target,
+    const OrthancPluginDicomInstance* instance,
+    uint32_t                          frameIndex)
+  {
+    _OrthancPluginAccessDicomInstance2 params;
+    memset(&params, 0, sizeof(params));
+    params.targetBuffer = target;
+    params.instance = instance;
+    params.frameIndex = frameIndex;
+
+    return context->InvokeService(context, _OrthancPluginService_GetInstanceRawFrame, &params);
+  }
+
+
+  /**
+   * @brief Decode one frame from a DICOM instance.
+   *
+   * This function decodes one frame of a DICOM image that is managed
+   * by the Orthanc core.
+   * 
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param instance The instance of interest.
+   * @param frameIndex The index of the frame of interest.
+   * @return The uncompressed image. It must be freed with OrthancPluginFreeImage().
+   * @ingroup DicomInstance
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginImage* OrthancPluginGetInstanceDecodedFrame(
+    OrthancPluginContext*             context,
+    const OrthancPluginDicomInstance* instance,
+    uint32_t                          frameIndex)
+  {
+    OrthancPluginImage* target = NULL;
+
+    _OrthancPluginAccessDicomInstance2 params;
+    memset(&params, 0, sizeof(params));
+    params.targetImage = ⌖
+    params.instance = instance;
+    params.frameIndex = frameIndex;
+
+    if (context->InvokeService(context, _OrthancPluginService_GetInstanceDecodedFrame, &params) != OrthancPluginErrorCode_Success)
+    {
+      return NULL;
+    }
+    else
+    {
+      return target;
+    }
+  }
+
+  
+  /**
+   * @brief Parse and transcode a DICOM instance.
+   *
+   * This function parses a memory buffer that contains a DICOM file,
+   * then transcodes it to the given transfer syntax. The function
+   * returns a new pointer to a data structure that is managed by the
+   * Orthanc core.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param buffer The memory buffer containing the DICOM instance.
+   * @param size The size of the memory buffer.
+   * @param transferSyntax The transfer syntax UID for the transcoding.
+   * @return The newly allocated DICOM instance. It must be freed with OrthancPluginFreeDicomInstance().
+   * @ingroup DicomInstance
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginDicomInstance* OrthancPluginTranscodeDicomInstance(
+    OrthancPluginContext*  context,
+    const void*            buffer,
+    uint32_t               size,
+    const char*            transferSyntax)
+  {
+    OrthancPluginDicomInstance* target = NULL;
+
+    _OrthancPluginCreateDicomInstance params;
+    params.target = ⌖
+    params.buffer = buffer;
+    params.size = size;
+    params.transferSyntax = transferSyntax;
+
+    if (context->InvokeService(context, _OrthancPluginService_TranscodeDicomInstance, &params) != OrthancPluginErrorCode_Success)
+    {
+      /* Error */
+      return NULL;
+    }
+    else
+    {
+      return target;
+    }
+  }
+
+  /**
+   * @brief Writes a DICOM instance to a memory buffer.
+   *
+   * This function returns a memory buffer containing the
+   * serialization of a DICOM instance that is managed by the Orthanc
+   * core.
+   * 
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param target The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer().
+   * @param instance The instance of interest.
+   * @return 0 if success, or the error code if failure.
+   * @ingroup DicomInstance
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginSerializeDicomInstance(
+    OrthancPluginContext*             context,
+    OrthancPluginMemoryBuffer*        target,
+    const OrthancPluginDicomInstance* instance)
+  {
+    _OrthancPluginAccessDicomInstance2 params;
+    memset(&params, 0, sizeof(params));
+    params.targetBuffer = target;
+    params.instance = instance;
+
+    return context->InvokeService(context, _OrthancPluginService_SerializeDicomInstance, &params);
+  }
+  
+
+  /**
+   * @brief Format a DICOM memory buffer as a JSON string.
+   *
+   * This function takes as DICOM instance managed by the Orthanc
+   * core, and outputs a JSON string representing the tags of this
+   * DICOM file.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param instance The DICOM instance of interest.
+   * @param format The output format.
+   * @param flags Flags governing the output.
+   * @param maxStringLength The maximum length of a field. Too long fields will
+   * be output as "null". The 0 value means no maximum length.
+   * @return The NULL value if the case of an error, or the JSON
+   * string. This string must be freed by OrthancPluginFreeString().
+   * @ingroup DicomInstance
+   * @see OrthancPluginDicomBufferToJson
+   **/
+  ORTHANC_PLUGIN_INLINE char* OrthancPluginGetInstanceAdvancedJson(
+    OrthancPluginContext*              context,
+    const OrthancPluginDicomInstance*  instance,
+    OrthancPluginDicomToJsonFormat     format,
+    OrthancPluginDicomToJsonFlags      flags, 
+    uint32_t                           maxStringLength)
+  {
+    char* result = NULL;
+
+    _OrthancPluginAccessDicomInstance2 params;
+    memset(&params, 0, sizeof(params));
+    params.targetStringToFree = &result;
+    params.instance = instance;
+    params.format = format;
+    params.flags = flags;
+    params.maxStringLength = maxStringLength;
+
+    if (context->InvokeService(context, _OrthancPluginService_GetInstanceAdvancedJson, &params) != OrthancPluginErrorCode_Success)
+    {
+      /* Error */
+      return NULL;
+    }
+    else
+    {
+      return result;
+    }
+  }
+
+
+  /**
+   * @brief Convert a DICOM instance to DICOMweb JSON.
+   *
+   * This function converts a DICOM instance that is managed by the
+   * Orthanc core, into its DICOMweb JSON representation.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param instance The DICOM instance of interest.
+   * @param callback Callback to set the value of the binary tags.
+   * @param payload User payload.
+   * @return The NULL value in case of error, or the JSON document. This string must
+   * be freed by OrthancPluginFreeString().
+   * @ingroup DicomInstance
+   **/
+  ORTHANC_PLUGIN_INLINE char* OrthancPluginGetInstanceDicomWebJson(
+    OrthancPluginContext*                 context,
+    const OrthancPluginDicomInstance*     instance,
+    OrthancPluginDicomWebBinaryCallback2  callback,
+    void*                                 payload)
+  {
+    char* target = NULL;
+    
+    _OrthancPluginAccessDicomInstance2 params;
+    params.targetStringToFree = ⌖
+    params.instance = instance;
+    params.dicomWebCallback = callback;
+    params.dicomWebPayload = payload;
+
+    if (context->InvokeService(context, _OrthancPluginService_GetInstanceDicomWebJson, &params) != OrthancPluginErrorCode_Success)
+    {
+      /* Error */
+      return NULL;
+    }
+    else
+    {
+      return target;
+    }
+  }
+  
+
+  /**
+   * @brief Convert a DICOM instance to DICOMweb XML.
+   *
+   * This function converts a DICOM instance that is managed by the
+   * Orthanc core, into its DICOMweb XML representation.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param instance The DICOM instance of interest.
+   * @param callback Callback to set the value of the binary tags.
+   * @param payload User payload.
+   * @return The NULL value in case of error, or the XML document. This string must
+   * be freed by OrthancPluginFreeString().
+   * @ingroup DicomInstance
+   **/
+  ORTHANC_PLUGIN_INLINE char* OrthancPluginGetInstanceDicomWebXml(
+    OrthancPluginContext*                 context,
+    const OrthancPluginDicomInstance*     instance,
+    OrthancPluginDicomWebBinaryCallback2  callback,
+    void*                                 payload)
+  {
+    char* target = NULL;
+    
+    _OrthancPluginAccessDicomInstance2 params;
+    params.targetStringToFree = ⌖
+    params.instance = instance;
+    params.dicomWebCallback = callback;
+    params.dicomWebPayload = payload;
+
+    if (context->InvokeService(context, _OrthancPluginService_GetInstanceDicomWebXml, &params) != OrthancPluginErrorCode_Success)
+    {
+      /* Error */
+      return NULL;
+    }
+    else
+    {
+      return target;
+    }
+  }
+
+
+
+  /**
+   * @brief Signature of a callback function to transcode a DICOM instance.
+   * @param transcoded Target memory buffer. It must be allocated by the
+   * plugin using OrthancPluginCreateMemoryBuffer().
+   * @param buffer Memory buffer containing the source DICOM instance.
+   * @param size Size of the source memory buffer.
+   * @param allowedSyntaxes A C array of possible transfer syntaxes UIDs for the
+   * result of the transcoding. The plugin must choose by itself the 
+   * transfer syntax that will be used for the resulting DICOM image.
+   * @param countSyntaxes The number of transfer syntaxes that are contained
+   * in the "allowedSyntaxes" array.
+   * @param allowNewSopInstanceUid Whether the transcoding plugin can select
+   * a transfer syntax that will change the SOP instance UID (or, in other 
+   * terms, whether the plugin can transcode using lossy compression).
+   * @return 0 if success (i.e. image successfully transcoded and stored into
+   * "transcoded"), or the error code if failure.
+   * @ingroup Callbacks
+   **/
+  typedef OrthancPluginErrorCode (*OrthancPluginTranscoderCallback) (
+    OrthancPluginMemoryBuffer* transcoded /* out */,
+    const void*                buffer,
+    uint64_t                   size,
+    const char* const*         allowedSyntaxes,
+    uint32_t                   countSyntaxes,
+    uint8_t                    allowNewSopInstanceUid);
+
+
+  typedef struct
+  {
+    OrthancPluginTranscoderCallback callback;
+  } _OrthancPluginTranscoderCallback;
+
+  /**
+   * @brief Register a callback to handle the transcoding of DICOM images.
+   *
+   * This function registers a custom callback to transcode DICOM
+   * images, extending the built-in transcoder of Orthanc that uses
+   * DCMTK. The exact behavior is affected by the configuration option
+   * "BuiltinDecoderTranscoderOrder" of Orthanc.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param callback The callback.
+   * @return 0 if success, other value if error.
+   * @ingroup Callbacks
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterTranscoderCallback(
+    OrthancPluginContext*            context,
+    OrthancPluginTranscoderCallback  callback)
+  {
+    _OrthancPluginTranscoderCallback params;
+    params.callback = callback;
+
+    return context->InvokeService(context, _OrthancPluginService_RegisterTranscoderCallback, &params);
+  }
+  
+
+
+  typedef struct
+  {
+    OrthancPluginMemoryBuffer*  target;
+    uint32_t                    size;
+  } _OrthancPluginCreateMemoryBuffer;
+
+  /**
+   * @brief Create a memory buffer.
+   *
+   * This function creates a memory buffer that is managed by the
+   * Orthanc core. The main use case of this function is for plugins
+   * that act as DICOM transcoders.
+   * 
+   * Your plugin should never call "free()" on the resulting memory
+   * buffer, as the C library that is used by the plugin is in general
+   * not the same as the one used by the Orthanc core.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param target The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer().
+   * @param size Size of the memory buffer to be created.
+   * @return 0 if success, or the error code if failure.
+   * @ingroup Toolbox
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginCreateMemoryBuffer(
+    OrthancPluginContext*       context,
+    OrthancPluginMemoryBuffer*  target,
+    uint32_t                    size)
+  {
+    _OrthancPluginCreateMemoryBuffer params;
+    params.target = target;
+    params.size = size;
+
+    return context->InvokeService(context, _OrthancPluginService_CreateMemoryBuffer, &params);
+  }
+  
+
 #ifdef  __cplusplus
 }
 #endif


=====================================
Resources/SyncOrthancFolder.py
=====================================
@@ -11,8 +11,8 @@ import stat
 import urllib2
 
 TARGET = os.path.join(os.path.dirname(__file__), 'Orthanc')
-PLUGIN_SDK_VERSION = '1.5.7'
-REPOSITORY = 'https://bitbucket.org/sjodogne/orthanc/raw'
+PLUGIN_SDK_VERSION = '1.7.0'
+REPOSITORY = 'https://hg.orthanc-server.com/orthanc/raw-file'
 
 FILES = [
     'DownloadOrthancFramework.cmake',


=====================================
Status.txt
=====================================
@@ -1,5 +1,9 @@
 Reference: http://dicom.nema.org/MEDICAL/dicom/2019a/output/html/part18.html
 
+If you need some missing feature as an industrial player, please
+consider hiring the development team from Osimis by filling the
+dedicated form on the Orthanc Web site:
+https://www.orthanc-server.com/orthanc-pro.php
 
 
 =======================================
@@ -103,7 +107,6 @@ Not supported
 * GIF output
 * The following "Retrieve Rendered Query Parameters" (table 6.5.8-2):
   annotation, charset, iccprofile
-* URI "/studies/.../rendered" (only available for series, instances and frames)
 
 
 
@@ -148,6 +151,22 @@ Ignored
 
 
 
+===================
+6.8 RS Capabilities
+===================
+
+Not supported.
+
+
+
+===================
+6.9 UPS-RS Worklist
+===================
+
+Not supported.
+
+
+
 ==========================================================
 CP 1509 - Refactor media type description for web services
 ==========================================================



View it on GitLab: https://salsa.debian.org/med-team/orthanc-dicomweb/-/commit/c12a0b6ae2530e36dd2b20f6b293196a4937ddc1

-- 
View it on GitLab: https://salsa.debian.org/med-team/orthanc-dicomweb/-/commit/c12a0b6ae2530e36dd2b20f6b293196a4937ddc1
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20200527/42e97f8c/attachment-0001.html>


More information about the debian-med-commit mailing list