changeset 262:6443aa133b6e

renamed Dicom.h to GdcmParsedDicomFile.h
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 27 Feb 2019 12:35:26 +0100
parents 69d8e34b04de
children 83cb0fdf4bd1
files CMakeLists.txt Plugin/Dicom.cpp Plugin/Dicom.h Plugin/GdcmParsedDicomFile.cpp Plugin/GdcmParsedDicomFile.h Plugin/WadoRsRetrieveFrames.cpp
diffstat 6 files changed, 507 insertions(+), 507 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Wed Feb 27 12:32:19 2019 +0100
+++ b/CMakeLists.txt	Wed Feb 27 12:35:26 2019 +0100
@@ -119,7 +119,7 @@
 
 set(CORE_SOURCES
   Plugin/Configuration.cpp
-  Plugin/Dicom.cpp
+  Plugin/GdcmParsedDicomFile.cpp
 
   ${ORTHANC_ROOT}/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
   ${ORTHANC_CORE_SOURCES}
--- a/Plugin/Dicom.cpp	Wed Feb 27 12:32:19 2019 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,409 +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-2019 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 "Dicom.h"
-
-#include "Plugin.h"
-#include "ChunkedBuffer.h"
-
-#include <Core/Toolbox.h>
-
-#include <gdcmDictEntry.h>
-#include <gdcmStringFilter.h>
-#include <boost/lexical_cast.hpp>
-#include <json/writer.h>
-
-
-namespace OrthancPlugins
-{
-  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::Dict& dictionary,
-                               const gdcm::Tag& tag,
-                               gdcm::VR vr)
-  {
-    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::Dict& dictionary,
-                               const gdcm::DataElement& element)
-  {
-    return GetVRName(isSequence, dictionary, 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::Dict& dictionary,
-                                       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, dictionary, 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 ParsedDicomFile::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()));
-    }
-  }
-
-
-  ParsedDicomFile::ParsedDicomFile(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 ParsedDicomFile::GetRawTag(std::string& result,
-                                  const gdcm::Tag& tag,
-                                  bool stripSpaces) const
-  {
-    return OrthancPlugins::GetRawTag(result, GetDataSet(), tag, stripSpaces);
-  }
-
-
-  std::string ParsedDicomFile::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 ParsedDicomFile::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 ParsedDicomFile::GetStringTag(std::string& result,
-                                     const gdcm::Dict& dictionary,
-                                     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, dictionary, element, GetEncoding()))
-    {
-      return false;
-    }
-
-    if (stripSpaces)
-    {
-      result = MyStripSpaces(result);
-    }
-
-    return true;
-  }
-
-
-  bool ParsedDicomFile::GetIntegerTag(int& result,
-                                      const gdcm::Dict& dictionary,
-                                      const gdcm::Tag& tag) const
-  {
-    std::string tmp;
-    if (!GetStringTag(tmp, dictionary, 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  ParsedDicomFile::GetEncoding() const
-  {
-    return DetectEncoding(GetDataSet());
-  }
-  
-
-  std::string ParsedDicomFile::GetWadoUrl(const OrthancPluginHttpRequest* request) const
-  {
-    const std::string base = OrthancPlugins::Configuration::GetBaseUrl(request);
-    return OrthancPlugins::GetWadoUrl(base, GetDataSet());
-  }
-}
--- a/Plugin/Dicom.h	Wed Feb 27 12:32:19 2019 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +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-2019 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 <gdcmDict.h>
-#include <list>
-
-
-namespace OrthancPlugins
-{
-  class ParsedDicomFile
-  {
-  private:
-    gdcm::Reader reader_;
-
-    void Setup(const std::string& dicom);
-
-    Orthanc::Encoding  GetEncoding() const;
-
-  public:
-    explicit ParsedDicomFile(const OrthancPlugins::MemoryBuffer& item);
-
-    explicit ParsedDicomFile(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::Dict& dictionary,
-                      const gdcm::Tag& tag,
-                      bool stripSpaces) const;
-
-    bool GetIntegerTag(int& result,
-                       const gdcm::Dict& dictionary,
-                       const gdcm::Tag& tag) const;
-
-    std::string GetWadoUrl(const OrthancPluginHttpRequest* request) const;
-  };
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugin/GdcmParsedDicomFile.cpp	Wed Feb 27 12:35:26 2019 +0100
@@ -0,0 +1,409 @@
+/**
+ * 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
+ *
+ * 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 "Plugin.h"
+#include "ChunkedBuffer.h"
+
+#include <Core/Toolbox.h>
+
+#include <gdcmDictEntry.h>
+#include <gdcmStringFilter.h>
+#include <boost/lexical_cast.hpp>
+#include <json/writer.h>
+
+
+namespace OrthancPlugins
+{
+  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::Dict& dictionary,
+                               const gdcm::Tag& tag,
+                               gdcm::VR vr)
+  {
+    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::Dict& dictionary,
+                               const gdcm::DataElement& element)
+  {
+    return GetVRName(isSequence, dictionary, 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::Dict& dictionary,
+                                       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, dictionary, 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::Dict& dictionary,
+                                         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, dictionary, element, GetEncoding()))
+    {
+      return false;
+    }
+
+    if (stripSpaces)
+    {
+      result = MyStripSpaces(result);
+    }
+
+    return true;
+  }
+
+
+  bool GdcmParsedDicomFile::GetIntegerTag(int& result,
+                                          const gdcm::Dict& dictionary,
+                                          const gdcm::Tag& tag) const
+  {
+    std::string tmp;
+    if (!GetStringTag(tmp, dictionary, 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());
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugin/GdcmParsedDicomFile.h	Wed Feb 27 12:35:26 2019 +0100
@@ -0,0 +1,90 @@
+/**
+ * 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
+ *
+ * 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 <gdcmDict.h>
+#include <list>
+
+
+namespace OrthancPlugins
+{
+  class GdcmParsedDicomFile : public boost::noncopyable
+  {
+  private:
+    gdcm::Reader reader_;
+
+    void Setup(const std::string& dicom);
+
+    Orthanc::Encoding  GetEncoding() const;
+
+  public:
+    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::Dict& dictionary,
+                      const gdcm::Tag& tag,
+                      bool stripSpaces) const;
+
+    bool GetIntegerTag(int& result,
+                       const gdcm::Dict& dictionary,
+                       const gdcm::Tag& tag) const;
+
+    std::string GetWadoUrl(const OrthancPluginHttpRequest* request) const;
+  };
+}
--- a/Plugin/WadoRsRetrieveFrames.cpp	Wed Feb 27 12:32:19 2019 +0100
+++ b/Plugin/WadoRsRetrieveFrames.cpp	Wed Feb 27 12:35:26 2019 +0100
@@ -21,7 +21,7 @@
 
 #include "WadoRs.h"
 
-#include "Dicom.h"
+#include "GdcmParsedDicomFile.h"
 #include "Plugin.h"
 
 #include <Core/Toolbox.h>
@@ -333,7 +333,7 @@
 
 static void AnswerSingleFrame(OrthancPluginRestOutput* output,
                               const OrthancPluginHttpRequest* request,
-                              const OrthancPlugins::ParsedDicomFile& dicom,
+                              const OrthancPlugins::GdcmParsedDicomFile& dicom,
                               const char* frame,
                               size_t size,
                               unsigned int frameIndex)
@@ -359,7 +359,7 @@
 
 static bool AnswerFrames(OrthancPluginRestOutput* output,
                          const OrthancPluginHttpRequest* request,
-                         const OrthancPlugins::ParsedDicomFile& dicom,
+                         const OrthancPlugins::GdcmParsedDicomFile& dicom,
                          const gdcm::TransferSyntax& syntax,
                          std::list<unsigned int>& frames)
 {
@@ -509,7 +509,7 @@
       OrthancPlugins::LogInfo(s);
     }
 
-    std::auto_ptr<OrthancPlugins::ParsedDicomFile> source;
+    std::auto_ptr<OrthancPlugins::GdcmParsedDicomFile> source;
 
     gdcm::TransferSyntax sourceSyntax;
 
@@ -520,7 +520,7 @@
     }
     else
     {
-      source.reset(new OrthancPlugins::ParsedDicomFile(content));
+      source.reset(new OrthancPlugins::GdcmParsedDicomFile(content));
       sourceSyntax = source->GetFile().GetHeader().GetDataSetTransferSyntax();
     }
 
@@ -532,7 +532,7 @@
 
       if (source.get() == NULL)
       {
-        source.reset(new OrthancPlugins::ParsedDicomFile(content));
+        source.reset(new OrthancPlugins::GdcmParsedDicomFile(content));
       }
 
       AnswerFrames(output, request, *source, targetSyntax, frames);
@@ -580,7 +580,7 @@
         throw Orthanc::OrthancException(Orthanc::ErrorCode_NotEnoughMemory);
       }
 
-      OrthancPlugins::ParsedDicomFile transcoded(ss.str());
+      OrthancPlugins::GdcmParsedDicomFile transcoded(ss.str());
       AnswerFrames(output, request, transcoded, targetSyntax, frames);
     }
   }