Mercurial > hg > orthanc-dicomweb
changeset 434:9a0457a3ca19 transcoding
integration mainline->transcoding
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 26 May 2020 11:06:13 +0200 |
parents | d575f05723eb (diff) ad671caa2dcf (current diff) |
children | d9f2b8280f86 |
files | CMakeLists.txt Resources/Orthanc/DownloadOrthancFramework.cmake |
diffstat | 15 files changed, 171 insertions(+), 1347 deletions(-) [+] |
line wrap: on
line diff
--- a/CMakeLists.txt Tue May 26 11:05:10 2020 +0200 +++ b/CMakeLists.txt Tue May 26 11:06:13 2020 +0200 @@ -24,8 +24,7 @@ set(ORTHANC_DICOM_WEB_VERSION "mainline") if (ORTHANC_DICOM_WEB_VERSION STREQUAL "mainline") - # TODO - Switch to "mainline" after "transcoding" is made the new "default" - set(ORTHANC_FRAMEWORK_DEFAULT_VERSION "1.6.1") + set(ORTHANC_FRAMEWORK_DEFAULT_VERSION "mainline") set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "hg") else() set(ORTHANC_FRAMEWORK_DEFAULT_VERSION "1.6.1") @@ -42,7 +41,6 @@ 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\")") @@ -67,7 +65,6 @@ 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) @@ -147,7 +144,6 @@ set(CORE_SOURCES Plugin/Configuration.cpp - Plugin/GdcmParsedDicomFile.cpp ${ORTHANC_ROOT}/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp ${ORTHANC_CORE_SOURCES} @@ -167,8 +163,6 @@ ${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}") @@ -192,11 +186,5 @@ ) 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()
--- a/NEWS Tue May 26 11:05:10 2020 +0200 +++ b/NEWS Tue May 26 11:06:13 2020 +0200 @@ -2,6 +2,11 @@ =============================== +=> Minimum SDK version: 1.7.0 <= + + +* Removed dependency on GDCM + Maintenance -----------
--- a/Plugin/DicomWebFormatter.cpp Tue May 26 11:05:10 2020 +0200 +++ b/Plugin/DicomWebFormatter.cpp Tue May 26 11:06:13 2020 +0200 @@ -47,9 +47,10 @@ 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 @@ 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 @@ } - DicomWebFormatter::Locker::Locker(OrthancPluginDicomWebBinaryMode mode, - const std::string& bulkRoot) : - that_(GetSingleton()), - lock_(that_.mutex_) + void DicomWebFormatter::Apply(std::string& target, + OrthancPluginContext* context, + const void* data, + size_t size, + bool xml, + OrthancPluginDicomWebBinaryMode mode, + const std::string& bulkRoot) { - that_.mode_ = mode; - that_.bulkRoot_ = bulkRoot; - } - - - void DicomWebFormatter::Locker::Apply(std::string& target, - OrthancPluginContext* context, - const void* data, - size_t size, - bool xml) - { + 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 @@ } - 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 @@ 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_) {
--- a/Plugin/DicomWebFormatter.h Tue May 26 11:05:10 2020 +0200 +++ b/Plugin/DicomWebFormatter.h Tue May 26 11:06:13 2020 +0200 @@ -29,7 +29,6 @@ #include <json/value.h> #include <boost/noncopyable.hpp> -#include <boost/thread/mutex.hpp> namespace OrthancPlugins @@ -37,16 +36,9 @@ 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 @@ const uint32_t *levelIndex, uint16_t tagGroup, uint16_t tagElement, - OrthancPluginValueRepresentation vr); - - public: - class Locker : public boost::noncopyable - { - private: - DicomWebFormatter& that_; - boost::mutex::scoped_lock lock_; + OrthancPluginValueRepresentation vr, + void* payload); - public: - Locker(OrthancPluginDicomWebBinaryMode mode, - const std::string& bulkRoot); + DicomWebFormatter(OrthancPluginDicomWebBinaryMode mode, + const std::string& bulkRoot) : + mode_(mode), + bulkRoot_(bulkRoot) + { + } + + public: + static void Apply(std::string& target, + OrthancPluginContext* context, + const void* data, + size_t size, + bool xml, + 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); - }; + 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 {
--- a/Plugin/GdcmParsedDicomFile.cpp Tue May 26 11:05:10 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,438 +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()); - } -} - - -#include "./GdcmParsedDicomFile_TransferSyntaxes.impl.h"
--- a/Plugin/GdcmParsedDicomFile.h Tue May 26 11:05:10 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +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; - - Orthanc::DicomTransferSyntax GetTransferSyntax() const - { - return GetOrthancTransferSyntax(GetFile().GetHeader().GetDataSetTransferSyntax()); - } - - static gdcm::TransferSyntax GetGdcmTransferSyntax(Orthanc::DicomTransferSyntax syntax); - - static Orthanc::DicomTransferSyntax GetOrthancTransferSyntax(gdcm::TransferSyntax syntax); - }; -}
--- a/Plugin/GdcmParsedDicomFile_TransferSyntaxes.impl.h Tue May 26 11:05:10 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,121 +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/>. - **/ - -// This file is autogenerated by "../Resources/GenerateTransferSyntaxes.py" - -namespace OrthancPlugins -{ - gdcm::TransferSyntax GdcmParsedDicomFile::GetGdcmTransferSyntax(Orthanc::DicomTransferSyntax syntax) - { - switch (syntax) - { - case Orthanc::DicomTransferSyntax_LittleEndianImplicit: - return gdcm::TransferSyntax::ImplicitVRLittleEndian; - - case Orthanc::DicomTransferSyntax_LittleEndianExplicit: - return gdcm::TransferSyntax::ExplicitVRLittleEndian; - - case Orthanc::DicomTransferSyntax_JPEGProcess1: - return gdcm::TransferSyntax::JPEGBaselineProcess1; - - case Orthanc::DicomTransferSyntax_JPEGProcess2_4: - return gdcm::TransferSyntax::JPEGExtendedProcess2_4; - - case Orthanc::DicomTransferSyntax_JPEGProcess14: - return gdcm::TransferSyntax::JPEGLosslessProcess14; - - case Orthanc::DicomTransferSyntax_JPEGProcess14SV1: - return gdcm::TransferSyntax::JPEGLosslessProcess14_1; - - case Orthanc::DicomTransferSyntax_JPEGLSLossless: - return gdcm::TransferSyntax::JPEGLSLossless; - - case Orthanc::DicomTransferSyntax_JPEGLSLossy: - return gdcm::TransferSyntax::JPEGLSNearLossless; - - case Orthanc::DicomTransferSyntax_JPEG2000LosslessOnly: - return gdcm::TransferSyntax::JPEG2000Lossless; - - case Orthanc::DicomTransferSyntax_JPEG2000: - return gdcm::TransferSyntax::JPEG2000; - - case Orthanc::DicomTransferSyntax_JPEG2000MulticomponentLosslessOnly: - return gdcm::TransferSyntax::JPEG2000Part2Lossless; - - case Orthanc::DicomTransferSyntax_JPEG2000Multicomponent: - return gdcm::TransferSyntax::JPEG2000Part2; - - case Orthanc::DicomTransferSyntax_RLELossless: - return gdcm::TransferSyntax::RLELossless; - - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - } - - - Orthanc::DicomTransferSyntax GdcmParsedDicomFile::GetOrthancTransferSyntax(gdcm::TransferSyntax syntax) - { - switch (syntax) - { - case gdcm::TransferSyntax::ImplicitVRLittleEndian: - return Orthanc::DicomTransferSyntax_LittleEndianImplicit; - - case gdcm::TransferSyntax::ExplicitVRLittleEndian: - return Orthanc::DicomTransferSyntax_LittleEndianExplicit; - - case gdcm::TransferSyntax::JPEGBaselineProcess1: - return Orthanc::DicomTransferSyntax_JPEGProcess1; - - case gdcm::TransferSyntax::JPEGExtendedProcess2_4: - return Orthanc::DicomTransferSyntax_JPEGProcess2_4; - - case gdcm::TransferSyntax::JPEGLosslessProcess14: - return Orthanc::DicomTransferSyntax_JPEGProcess14; - - case gdcm::TransferSyntax::JPEGLosslessProcess14_1: - return Orthanc::DicomTransferSyntax_JPEGProcess14SV1; - - case gdcm::TransferSyntax::JPEGLSLossless: - return Orthanc::DicomTransferSyntax_JPEGLSLossless; - - case gdcm::TransferSyntax::JPEGLSNearLossless: - return Orthanc::DicomTransferSyntax_JPEGLSLossy; - - case gdcm::TransferSyntax::JPEG2000Lossless: - return Orthanc::DicomTransferSyntax_JPEG2000LosslessOnly; - - case gdcm::TransferSyntax::JPEG2000: - return Orthanc::DicomTransferSyntax_JPEG2000; - - case gdcm::TransferSyntax::JPEG2000Part2Lossless: - return Orthanc::DicomTransferSyntax_JPEG2000MulticomponentLosslessOnly; - - case gdcm::TransferSyntax::JPEG2000Part2: - return Orthanc::DicomTransferSyntax_JPEG2000Multicomponent; - - case gdcm::TransferSyntax::RLELossless: - return Orthanc::DicomTransferSyntax_RLELossless; - - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - } -}
--- a/Plugin/Plugin.cpp Tue May 26 11:05:10 2020 +0200 +++ b/Plugin/Plugin.cpp Tue May 26 11:06:13 2020 +0200 @@ -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 @@ // Read the configuration OrthancPlugins::Configuration::Initialize(); - // Initialize GDCM - OrthancPlugins::GdcmParsedDicomFile::Initialize(); - // Configure the DICOMweb callbacks if (OrthancPlugins::Configuration::GetBooleanValue("Enable", true)) {
--- a/Plugin/StowRs.cpp Tue May 26 11:05:10 2020 +0200 +++ b/Plugin/StowRs.cpp Tue May 26 11:06:13 2020 +0200 @@ -191,10 +191,8 @@ 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");
--- a/Plugin/WadoRs.cpp Tue May 26 11:05:10 2020 +0200 +++ b/Plugin/WadoRs.cpp Tue May 26 11:06:13 2020 +0200 @@ -692,9 +692,9 @@ 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);
--- a/Plugin/WadoRsRetrieveFrames.cpp Tue May 26 11:05:10 2020 +0200 +++ b/Plugin/WadoRsRetrieveFrames.cpp Tue May 26 11:06:13 2020 +0200 @@ -21,16 +21,11 @@ #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> @@ -61,8 +56,8 @@ -static Orthanc::DicomTransferSyntax ParseTransferSyntax(const OrthancPluginHttpRequest* request, - Orthanc::DicomTransferSyntax sourceTransferSyntax) +static bool ParseTransferSyntax(Orthanc::DicomTransferSyntax& syntax, + const OrthancPluginHttpRequest* request) { for (uint32_t i = 0; i < request->headersCount; i++) { @@ -77,7 +72,8 @@ if (tokens.size() == 0 || tokens[0] == "*/*") { - return Orthanc::DicomTransferSyntax_LittleEndianExplicit; + syntax = Orthanc::DicomTransferSyntax_LittleEndianExplicit; + return true; } if (tokens[0] != "multipart/related") @@ -113,14 +109,21 @@ if (type == "application/octet-stream") { - if (transferSyntax.empty()) + if (transferSyntax.empty() || + transferSyntax == "1.2.840.10008.1.2.1") { - return Orthanc::DicomTransferSyntax(Orthanc::DicomTransferSyntax_LittleEndianExplicit); + 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 { @@ -139,51 +142,62 @@ if (type == "image/jpeg" && (transferSyntax.empty() || // Default transferSyntax == "1.2.840.10008.1.2.4.70")) { - return Orthanc::DicomTransferSyntax_JPEGProcess14SV1; + syntax = Orthanc::DicomTransferSyntax_JPEGProcess14SV1; + return true; } else if (type == "image/jpeg" && transferSyntax == "1.2.840.10008.1.2.4.50") { - return Orthanc::DicomTransferSyntax_JPEGProcess1; + syntax = Orthanc::DicomTransferSyntax_JPEGProcess1; + return true; } else if (type == "image/jpeg" && transferSyntax == "1.2.840.10008.1.2.4.51") { - return Orthanc::DicomTransferSyntax_JPEGProcess2_4; + syntax = Orthanc::DicomTransferSyntax_JPEGProcess2_4; + return true; } else if (type == "image/jpeg" && transferSyntax == "1.2.840.10008.1.2.4.57") { - return Orthanc::DicomTransferSyntax_JPEGProcess14; + 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 Orthanc::DicomTransferSyntax_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 Orthanc::DicomTransferSyntax_JPEGLSLossless; + syntax = Orthanc::DicomTransferSyntax_JPEGLSLossless; + return true; } else if (type == "image/x-jls" && transferSyntax == "1.2.840.10008.1.2.4.81") { - return Orthanc::DicomTransferSyntax_JPEGLSLossy; + syntax = Orthanc::DicomTransferSyntax_JPEGLSLossy; + return true; } else if (type == "image/jp2" && (transferSyntax.empty() || // Default transferSyntax == "1.2.840.10008.1.2.4.90")) { - return Orthanc::DicomTransferSyntax_JPEG2000LosslessOnly; + syntax = Orthanc::DicomTransferSyntax_JPEG2000LosslessOnly; + return true; } else if (type == "image/jp2" && transferSyntax == "1.2.840.10008.1.2.4.91") { - return Orthanc::DicomTransferSyntax_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 Orthanc::DicomTransferSyntax_JPEG2000MulticomponentLosslessOnly; + syntax = Orthanc::DicomTransferSyntax_JPEG2000MulticomponentLosslessOnly; + return true; } else if (type == "image/jpx" && transferSyntax == "1.2.840.10008.1.2.4.93") { - return Orthanc::DicomTransferSyntax_JPEG2000Multicomponent; + syntax = Orthanc::DicomTransferSyntax_JPEG2000Multicomponent; + return true; } @@ -193,52 +207,63 @@ **/ if (type == "image/dicom+jpeg" && transferSyntax == "1.2.840.10008.1.2.4.50") { - return Orthanc::DicomTransferSyntax_JPEGProcess1; + syntax = Orthanc::DicomTransferSyntax_JPEGProcess1; + return true; } else if (type == "image/dicom+jpeg" && transferSyntax == "1.2.840.10008.1.2.4.51") { - return Orthanc::DicomTransferSyntax_JPEGProcess2_4; + syntax = Orthanc::DicomTransferSyntax_JPEGProcess2_4; + return true; } else if (type == "image/dicom+jpeg" && transferSyntax == "1.2.840.10008.1.2.4.57") { - return Orthanc::DicomTransferSyntax_JPEGProcess14; + syntax = Orthanc::DicomTransferSyntax_JPEGProcess14; + return true; } else if (type == "image/dicom+jpeg" && (transferSyntax.empty() || transferSyntax == "1.2.840.10008.1.2.4.70")) { - return Orthanc::DicomTransferSyntax_JPEGProcess14SV1; + syntax = Orthanc::DicomTransferSyntax_JPEGProcess14SV1; + return true; } else if (type == "image/dicom+rle" && (transferSyntax.empty() || transferSyntax == "1.2.840.10008.1.2.5")) { - return Orthanc::DicomTransferSyntax_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 Orthanc::DicomTransferSyntax_JPEGLSLossless; + syntax = Orthanc::DicomTransferSyntax_JPEGLSLossless; + return true; } else if (type == "image/dicom+jpeg-ls" && transferSyntax == "1.2.840.10008.1.2.4.81") { - return Orthanc::DicomTransferSyntax_JPEGLSLossy; + syntax = Orthanc::DicomTransferSyntax_JPEGLSLossy; + return true; } else if (type == "image/dicom+jp2" && (transferSyntax.empty() || transferSyntax == "1.2.840.10008.1.2.4.90")) { - return Orthanc::DicomTransferSyntax_JPEG2000LosslessOnly; + syntax = Orthanc::DicomTransferSyntax_JPEG2000LosslessOnly; + return true; } else if (type == "image/dicom+jp2" && transferSyntax == "1.2.840.10008.1.2.4.91") { - return Orthanc::DicomTransferSyntax_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 Orthanc::DicomTransferSyntax_JPEG2000MulticomponentLosslessOnly; + syntax = Orthanc::DicomTransferSyntax_JPEG2000MulticomponentLosslessOnly; + return true; } else if (type == "image/dicom+jpx" && transferSyntax == "1.2.840.10008.1.2.4.93") { - return Orthanc::DicomTransferSyntax_JPEG2000Multicomponent; + syntax = Orthanc::DicomTransferSyntax_JPEG2000Multicomponent; + return true; } throw Orthanc::OrthancException( @@ -250,7 +275,8 @@ } // By default, DICOMweb expectes Little Endian uncompressed pixel data - return Orthanc::DicomTransferSyntax_LittleEndianExplicit; + syntax = Orthanc::DicomTransferSyntax_LittleEndianExplicit; + return true; } @@ -286,7 +312,6 @@ } - 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 @@ -340,268 +365,55 @@ } - -static void ConvertYbrToRgb(uint8_t rgb[3], - const uint8_t ybr[3]) +static void AnswerFrames(OrthancPluginRestOutput* output, + const OrthancPluginHttpRequest* request, + 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) { - // 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) + if (OrthancPluginStartMultipartAnswer( + OrthancPlugins::GetGlobalContext(), + output, "related", GetMimeType(outputSyntax)) != OrthancPluginErrorCode_Success) { - 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, - const OrthancPluginHttpRequest* request, - const OrthancPlugins::GdcmParsedDicomFile& dicom, - const Orthanc::DicomTransferSyntax& syntax, - std::list<unsigned int>& frames) -{ - 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)) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat); - } - - 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; + throw Orthanc::OrthancException(Orthanc::ErrorCode_Plugin, + "Cannot start a multipart answer"); } - 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" && - // Only applicable to uncompressed transfer syntaxes - (syntax == Orthanc::DicomTransferSyntax_LittleEndianImplicit || - syntax == Orthanc::DicomTransferSyntax_LittleEndianExplicit || - syntax == Orthanc::DicomTransferSyntax_BigEndianExplicit)) - { - convertYbr = true; - } - } - - if (fragments == NULL) - { - // Single-fragment image + std::string content; + instance.GetRawFrame(content, *frame); + + const char* data = content.empty() ? NULL : content.c_str(); + size_t size = content.size(); + + OrthancPluginErrorCode error; - if (pixelData.GetByteValue() == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, - "Image was not properly decoded"); - } - - int width, height, bits; +#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 - 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) + if (error != OrthancPluginErrorCode_Success) { - 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; - - 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); - } + throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); } } - else - { - // Multi-fragment image, we assume that each fragment corresponds to one frame - - 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); - } - } - - for (std::list<unsigned int>::const_iterator - frame = frames.begin(); frame != frames.end(); ++frame) - { - 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); - } - } - } - - return true; } - void RetrieveFrames(OrthancPluginRestOutput* output, const char* url, const OrthancPluginHttpRequest* request) @@ -609,12 +421,10 @@ 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)) { { std::string s = "DICOMweb RetrieveFrames on " + orthancId + ", frames: "; @@ -627,81 +437,23 @@ OrthancPlugins::LogInfo(s); } - std::auto_ptr<OrthancPlugins::GdcmParsedDicomFile> source; - - Orthanc::DicomTransferSyntax sourceSyntax; + Orthanc::DicomTransferSyntax targetSyntax; - if (header.type() == Json::objectValue && - header.isMember("TransferSyntaxUID")) - { - std::string uid = header["TransferSyntaxUID"].asString(); - if (!Orthanc::LookupTransferSyntax(sourceSyntax, uid)) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange, - "Unknown transfer syntax: " + uid); - } - } - else + std::unique_ptr<OrthancPlugins::DicomInstance> instance; + if (ParseTransferSyntax(targetSyntax, request)) { - source.reset(new OrthancPlugins::GdcmParsedDicomFile(content)); - sourceSyntax = source->GetTransferSyntax(); - } - - Orthanc::DicomTransferSyntax targetSyntax = ParseTransferSyntax(request, sourceSyntax); + OrthancPlugins::LogInfo("DICOMweb RetrieveFrames: Transcoding instance " + orthancId + + " to transfer syntax " + Orthanc::GetTransferSyntaxUid(targetSyntax)); - if (sourceSyntax == targetSyntax) - { - // No need to change the transfer syntax - - if (source.get() == NULL) - { - source.reset(new OrthancPlugins::GdcmParsedDicomFile(content)); - } - - AnswerFrames(output, request, *source, targetSyntax, frames); + instance.reset(OrthancPlugins::DicomInstance::Transcode( + content.GetData(), content.GetSize(), GetTransferSyntaxUid(targetSyntax))); } else { - // Need to convert the transfer syntax (transcoding) - OrthancPlugins::LogInfo("DICOMweb RetrieveFrames: Transcoding instance " + orthancId + - " from transfer syntax " + Orthanc::GetTransferSyntaxUid(sourceSyntax) + - " to " + Orthanc::GetTransferSyntaxUid(targetSyntax)); - - gdcm::ImageChangeTransferSyntax change; - change.SetTransferSyntax(OrthancPlugins::GdcmParsedDicomFile::GetGdcmTransferSyntax(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); - - gdcm::ImageReader reader; - reader.SetStream(stream); - if (!reader.Read()) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, - "Cannot decode the image"); - } + instance.reset(new OrthancPlugins::DicomInstance(content.GetData(), content.GetSize())); + } - change.SetInput(reader.GetImage()); - if (!change.Change()) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, - "Cannot change the transfer syntax of the image"); - } - - 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); - } + AnswerFrames(output, request, *instance, studyInstanceUid, seriesInstanceUid, + sopInstanceUid, frames, targetSyntax); } }
--- a/Resources/CMake/GdcmConfiguration.cmake Tue May 26 11:05:10 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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()
--- a/Resources/GenerateTransferSyntaxes.mustache Tue May 26 11:05:10 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +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/>. - **/ - -// This file is autogenerated by "../Resources/GenerateTransferSyntaxes.py" - -namespace OrthancPlugins -{ - gdcm::TransferSyntax GdcmParsedDicomFile::GetGdcmTransferSyntax(Orthanc::DicomTransferSyntax syntax) - { - switch (syntax) - { - {{#Syntaxes}} - {{#GDCM}} - case Orthanc::DicomTransferSyntax_{{Value}}: - return {{GDCM}}; - - {{/GDCM}} - {{/Syntaxes}} - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - } - - - Orthanc::DicomTransferSyntax GdcmParsedDicomFile::GetOrthancTransferSyntax(gdcm::TransferSyntax syntax) - { - switch (syntax) - { - {{#Syntaxes}} - {{#GDCM}} - case {{GDCM}}: - return Orthanc::DicomTransferSyntax_{{Value}}; - - {{/GDCM}} - {{/Syntaxes}} - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - } -}
--- a/Resources/GenerateTransferSyntaxes.py Tue May 26 11:05:10 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -#!/usr/bin/python - -# 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 General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# In addition, as a special exception, the copyright holders of this -# program give permission to link the code of its release with the -# OpenSSL project's "OpenSSL" library (or with modified versions of it -# that use the same license as the "OpenSSL" library), and distribute -# the linked executables. You must obey the GNU General Public License -# in all respects for all of the code used other than "OpenSSL". If you -# modify file(s) with this exception, you may extend this exception to -# your version of the file(s), but you are not obligated to do so. If -# you do not wish to do so, delete this exception statement from your -# version. If you delete this exception statement from all source files -# in the program, then also delete it here. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - - -import json -import os -import pystache - -ORTHANC_ROOT = '/home/jodogne/Subversion/orthanc/' -BASE = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) - - -with open(os.path.join(ORTHANC_ROOT, 'Resources', 'DicomTransferSyntaxes.json'), 'r') as f: - SYNTAXES = json.loads(f.read()) - - -with open(os.path.join(BASE, 'Plugin', 'GdcmParsedDicomFile_TransferSyntaxes.impl.h'), 'w') as b: - with open(os.path.join(BASE, 'Resources', 'GenerateTransferSyntaxes.mustache'), 'r') as a: - b.write(pystache.render(a.read(), { - 'Syntaxes' : SYNTAXES - }))
--- a/Resources/Orthanc/DownloadOrthancFramework.cmake Tue May 26 11:05:10 2020 +0200 +++ b/Resources/Orthanc/DownloadOrthancFramework.cmake Tue May 26 11:06:13 2020 +0200 @@ -70,6 +70,12 @@ set(ORTHANC_FRAMEWORK_MINOR 999) set(ORTHANC_FRAMEWORK_REVISION 999) + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "transcoding") # TODO - REMOVE + set(ORTHANC_FRAMEWORK_BRANCH "transcoding") + set(ORTHANC_FRAMEWORK_MAJOR 999) + set(ORTHANC_FRAMEWORK_MINOR 999) + set(ORTHANC_FRAMEWORK_REVISION 999) + else() set(ORTHANC_FRAMEWORK_BRANCH "Orthanc-${ORTHANC_FRAMEWORK_VERSION}")