# HG changeset patch # User Sebastien Jodogne # Date 1589202796 -7200 # Node ID 7e33516965f89dfa3928e21bcc792fe96c6915a0 # Parent e14b5a7a0f75ba18944fdc56f464502893c3ddce merging sample GDCM decoder and Orthanc Web viewer diff -r e14b5a7a0f75 -r 7e33516965f8 Plugins/Samples/Common/OrthancPluginCppWrapper.cpp --- a/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp Mon May 11 12:12:23 2020 +0200 +++ b/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp Mon May 11 15:13:16 2020 +0200 @@ -1045,7 +1045,7 @@ } - const void* OrthancImage::GetBuffer() const + void* OrthancImage::GetBuffer() const { CheckImageAvailable(); return OrthancPluginGetImageBuffer(GetGlobalContext(), image_); @@ -1094,6 +1094,14 @@ } + OrthancPluginImage* OrthancImage::Release() + { + CheckImageAvailable(); + OrthancPluginImage* tmp = image_; + image_ = NULL; + return tmp; + } + #if HAS_ORTHANC_PLUGIN_FIND_MATCHER == 1 FindMatcher::FindMatcher(const OrthancPluginWorklistQuery* worklist) : diff -r e14b5a7a0f75 -r 7e33516965f8 Plugins/Samples/Common/OrthancPluginCppWrapper.h --- a/Plugins/Samples/Common/OrthancPluginCppWrapper.h Mon May 11 12:12:23 2020 +0200 +++ b/Plugins/Samples/Common/OrthancPluginCppWrapper.h Mon May 11 15:13:16 2020 +0200 @@ -412,7 +412,7 @@ unsigned int GetPitch() const; - const void* GetBuffer() const; + void* GetBuffer() const; const OrthancPluginImage* GetObject() const { @@ -428,6 +428,10 @@ void AnswerJpegImage(OrthancPluginRestOutput* output, uint8_t quality) const; + + void* GetWriteableBuffer(); + + OrthancPluginImage* Release(); }; diff -r e14b5a7a0f75 -r 7e33516965f8 Plugins/Samples/GdcmDecoder/CMakeLists.txt --- a/Plugins/Samples/GdcmDecoder/CMakeLists.txt Mon May 11 12:12:23 2020 +0200 +++ b/Plugins/Samples/GdcmDecoder/CMakeLists.txt Mon May 11 15:13:16 2020 +0200 @@ -1,32 +1,83 @@ +# 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 . + + cmake_minimum_required(VERSION 2.8) project(GdcmDecoder) -SET(GDCM_DECODER_VERSION "0.0" CACHE STRING "Version of the plugin") -SET(STATIC_BUILD OFF CACHE BOOL "Static build of the third-party libraries (necessary for Windows)") -SET(ALLOW_DOWNLOADS OFF CACHE BOOL "Allow CMake to download packages") -SET(USE_SYSTEM_BOOST ON CACHE BOOL "Use the system version of boost") +SET(PLUGIN_VERSION "0.0" CACHE STRING "Version of the plugin") + + +# Parameters of the build +set(STATIC_BUILD OFF CACHE BOOL "Static build of the third-party libraries (necessary for Windows)") +set(STANDALONE_BUILD ON CACHE BOOL "Standalone build (all the resources are embedded, necessary for releases)") +set(ALLOW_DOWNLOADS OFF CACHE BOOL "Allow CMake to download packages") -set(SAMPLES_ROOT ${CMAKE_SOURCE_DIR}/..) -include(${SAMPLES_ROOT}/Common/OrthancPlugins.cmake) -include(${ORTHANC_ROOT}/Resources/CMake/BoostConfiguration.cmake) +# 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") + +# Setup the Orthanc framework +set(ORTHANC_ROOT ${CMAKE_SOURCE_DIR}/../../..) + +set(ORTHANC_FRAMEWORK_PLUGIN ON) +include(${ORTHANC_ROOT}/Resources/CMake/OrthancFrameworkParameters.cmake) + +set(ENABLE_LOCALE OFF CACHE INTERNAL "") # Disable support for locales (notably in Boost) +set(ENABLE_MODULE_IMAGES OFF CACHE INTERNAL "") +set(ENABLE_MODULE_JOBS OFF CACHE INTERNAL "") -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) +include(${ORTHANC_ROOT}/Resources/CMake/OrthancFrameworkConfiguration.cmake) + +include(GdcmConfiguration.cmake) + -add_definitions(-DGDCM_DECODER_VERSION="${GDCM_DECODER_VERSION}") +# Check that the Orthanc SDK headers are available +if (STATIC_BUILD OR NOT USE_SYSTEM_ORTHANC_SDK) + #include_directories(${CMAKE_SOURCE_DIR}/Resources/Orthanc/Sdk-0.9.5) + include_directories(${CMAKE_SOURCE_DIR}/../../Include) # TODO => SYNC 0.9.5 +else () + CHECK_INCLUDE_FILE_CXX(orthanc/OrthancCPlugin.h HAVE_ORTHANC_H) + if (NOT HAVE_ORTHANC_H) + message(FATAL_ERROR "Please install the headers of the Orthanc plugins SDK") + endif() +endif() + + +include_directories(${ORTHANC_ROOT}) + +add_definitions( + -DPLUGIN_VERSION="${PLUGIN_VERSION}" + -DHAS_ORTHANC_EXCEPTION=1 + -DORTHANC_ENABLE_LOGGING_PLUGIN=1 + ) add_library(GdcmDecoder SHARED - ${BOOST_SOURCES} GdcmDecoderCache.cpp GdcmImageDecoder.cpp - OrthancImageWrapper.cpp Plugin.cpp + ${CMAKE_SOURCE_DIR}/../Common/OrthancPluginCppWrapper.cpp + ${ORTHANC_CORE_SOURCES} ) target_link_libraries(GdcmDecoder ${GDCM_LIBRARIES}) + +if (STATIC_BUILD OR NOT USE_SYSTEM_GDCM) + add_dependencies(GdcmDecoder GDCM) +endif() diff -r e14b5a7a0f75 -r 7e33516965f8 Plugins/Samples/GdcmDecoder/GdcmConfiguration.cmake --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Samples/GdcmDecoder/GdcmConfiguration.cmake Mon May 11 15:13:16 2020 +0200 @@ -0,0 +1,141 @@ +# 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 . + + +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(AdditionalCFlags "-fPIC") + set(AdditionalCxxFlags ${AdditionalCFlags}) + elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Windows" AND + CMAKE_COMPILER_IS_GNUCXX) + # Prevents error: "jump to label ‘err’ crosses initialization" of some variable + # within "Source/Common/gdcmCAPICryptographicMessageSyntax.cxx" if using MinGW + set(AdditionalCxxFlags "-fpermissive") + elseif (${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD") + # This definition is necessary to compile + # "Source/MediaStorageAndFileFormat/gdcmFileStreamer.cxx" + set(AdditionalCFlags "-Doff64_t=off_t") + set(AdditionalCxxFlags ${AdditionalCFlags}) + endif() + + set(Flags + "-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} ${AdditionalCFlags}" + "-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} ${AdditionalCxxFlags}" + -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) + 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} + #${Prefix}gdcmuuid${Suffix} + ) + + 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/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() diff -r e14b5a7a0f75 -r 7e33516965f8 Plugins/Samples/GdcmDecoder/GdcmDecoderCache.cpp --- a/Plugins/Samples/GdcmDecoder/GdcmDecoderCache.cpp Mon May 11 12:12:23 2020 +0200 +++ b/Plugins/Samples/GdcmDecoder/GdcmDecoderCache.cpp Mon May 11 15:13:16 2020 +0200 @@ -22,17 +22,15 @@ #include "GdcmDecoderCache.h" #include "../../../Core/Compatibility.h" -#include "OrthancImageWrapper.h" namespace OrthancPlugins { - std::string GdcmDecoderCache::ComputeMd5(OrthancPluginContext* context, - const void* dicom, + std::string GdcmDecoderCache::ComputeMd5(const void* dicom, size_t size) { std::string result; - char* md5 = OrthancPluginComputeMd5(context, dicom, size); + char* md5 = OrthancPluginComputeMd5(OrthancPlugins::GetGlobalContext(), dicom, size); if (md5 == NULL) { @@ -49,7 +47,7 @@ { } - OrthancPluginFreeString(context, md5); + OrthancPluginFreeString(OrthancPlugins::GetGlobalContext(), md5); if (!ok) { @@ -62,12 +60,11 @@ } - OrthancImageWrapper* GdcmDecoderCache::Decode(OrthancPluginContext* context, - const void* dicom, - const uint32_t size, - uint32_t frameIndex) + OrthancImage* GdcmDecoderCache::Decode(const void* dicom, + const uint32_t size, + uint32_t frameIndex) { - std::string md5 = ComputeMd5(context, dicom, size); + std::string md5 = ComputeMd5(dicom, size); // First check whether the previously decoded image is the same // as this one @@ -79,13 +76,13 @@ md5_ == md5) { // This is the same image: Reuse the previous decoding - return new OrthancImageWrapper(context, decoder_->Decode(context, frameIndex)); + return new OrthancImage(decoder_->Decode(frameIndex)); } } // This is not the same image std::unique_ptr decoder(new GdcmImageDecoder(dicom, size)); - std::unique_ptr image(new OrthancImageWrapper(context, decoder->Decode(context, frameIndex))); + std::unique_ptr image(new OrthancImage(decoder->Decode(frameIndex))); { // Cache the newly created decoder for further use diff -r e14b5a7a0f75 -r 7e33516965f8 Plugins/Samples/GdcmDecoder/GdcmDecoderCache.h --- a/Plugins/Samples/GdcmDecoder/GdcmDecoderCache.h Mon May 11 12:12:23 2020 +0200 +++ b/Plugins/Samples/GdcmDecoder/GdcmDecoderCache.h Mon May 11 15:13:16 2020 +0200 @@ -23,7 +23,7 @@ #include "../../../Core/Compatibility.h" #include "GdcmImageDecoder.h" -#include "OrthancImageWrapper.h" +#include "../Common/OrthancPluginCppWrapper.h" #include @@ -38,8 +38,7 @@ size_t size_; std::string md5_; - static std::string ComputeMd5(OrthancPluginContext* context, - const void* dicom, + static std::string ComputeMd5(const void* dicom, size_t size); public: @@ -47,9 +46,8 @@ { } - OrthancImageWrapper* Decode(OrthancPluginContext* context, - const void* dicom, - const uint32_t size, - uint32_t frameIndex); + OrthancImage* Decode(const void* dicom, + const uint32_t size, + uint32_t frameIndex); }; } diff -r e14b5a7a0f75 -r 7e33516965f8 Plugins/Samples/GdcmDecoder/GdcmImageDecoder.cpp --- a/Plugins/Samples/GdcmDecoder/GdcmImageDecoder.cpp Mon May 11 12:12:23 2020 +0200 +++ b/Plugins/Samples/GdcmDecoder/GdcmImageDecoder.cpp Mon May 11 15:13:16 2020 +0200 @@ -22,7 +22,6 @@ #include "GdcmImageDecoder.h" #include "../../../Core/Compatibility.h" -#include "OrthancImageWrapper.h" #include #include @@ -298,7 +297,7 @@ } - static void FixPhotometricInterpretation(OrthancImageWrapper& image, + static void FixPhotometricInterpretation(OrthancImage& image, gdcm::PhotometricInterpretation interpretation) { switch (interpretation) @@ -317,7 +316,7 @@ uint32_t pitch = image.GetPitch(); uint8_t* buffer = reinterpret_cast(image.GetBuffer()); - if (image.GetFormat() != OrthancPluginPixelFormat_RGB24 || + if (image.GetPixelFormat() != OrthancPluginPixelFormat_RGB24 || pitch < 3 * width) { throw std::runtime_error("Internal error"); @@ -346,8 +345,7 @@ } - OrthancPluginImage* GdcmImageDecoder::Decode(OrthancPluginContext* context, - unsigned int frameIndex) const + OrthancPluginImage* GdcmImageDecoder::Decode(unsigned int frameIndex) const { unsigned int frames = GetFramesCount(); unsigned int width = GetWidth(); @@ -361,7 +359,7 @@ } std::string& decoded = pimpl_->decoded_; - OrthancImageWrapper target(context, format, width, height); + OrthancImage target(format, width, height); if (width == 0 || height == 0) @@ -391,8 +389,9 @@ size_t targetPitch = target.GetPitch(); size_t sourcePitch = width * bpp; - const char* a = &decoded[sourcePitch * height * frameIndex]; - char* b = target.GetBuffer(); + const uint8_t* a = (reinterpret_cast(decoded.c_str()) + + sourcePitch * height * frameIndex); + uint8_t* b = reinterpret_cast(target.GetBuffer()); for (uint32_t y = 0; y < height; y++) { diff -r e14b5a7a0f75 -r 7e33516965f8 Plugins/Samples/GdcmDecoder/GdcmImageDecoder.h --- a/Plugins/Samples/GdcmDecoder/GdcmImageDecoder.h Mon May 11 12:12:23 2020 +0200 +++ b/Plugins/Samples/GdcmDecoder/GdcmImageDecoder.h Mon May 11 15:13:16 2020 +0200 @@ -21,23 +21,13 @@ #pragma once -#include +#include "../Common/OrthancPluginCppWrapper.h" + #include #include #include -// This is for compatibility with Orthanc SDK <= 1.3.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 && \ - ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER >= revision)))) -#endif - - namespace OrthancPlugins { class GdcmImageDecoder : public boost::noncopyable @@ -60,7 +50,6 @@ static size_t GetBytesPerPixel(OrthancPluginPixelFormat format); - OrthancPluginImage* Decode(OrthancPluginContext* context, - unsigned int frameIndex) const; + OrthancPluginImage* Decode(unsigned int frameIndex) const; }; } diff -r e14b5a7a0f75 -r 7e33516965f8 Plugins/Samples/GdcmDecoder/OrthancImageWrapper.cpp --- a/Plugins/Samples/GdcmDecoder/OrthancImageWrapper.cpp Mon May 11 12:12:23 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,100 +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 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 - * 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 . - **/ - - -#include "OrthancImageWrapper.h" - -#include - -namespace OrthancPlugins -{ - OrthancImageWrapper::OrthancImageWrapper(OrthancPluginContext* context, - OrthancPluginPixelFormat format, - uint32_t width, - uint32_t height) : - context_(context) - { - image_ = OrthancPluginCreateImage(context_, format, width, height); - if (image_ == NULL) - { - throw std::runtime_error("Cannot create an image"); - } - } - - - OrthancImageWrapper::OrthancImageWrapper(OrthancPluginContext* context, - OrthancPluginImage* image) : - context_(context), - image_(image) - { - if (image_ == NULL) - { - throw std::runtime_error("Invalid image returned by the core of Orthanc"); - } - } - - - - OrthancImageWrapper::~OrthancImageWrapper() - { - if (image_ != NULL) - { - OrthancPluginFreeImage(context_, image_); - } - } - - - OrthancPluginImage* OrthancImageWrapper::Release() - { - OrthancPluginImage* tmp = image_; - image_ = NULL; - return tmp; - } - - - uint32_t OrthancImageWrapper::GetWidth() - { - return OrthancPluginGetImageWidth(context_, image_); - } - - - uint32_t OrthancImageWrapper::GetHeight() - { - return OrthancPluginGetImageHeight(context_, image_); - } - - - uint32_t OrthancImageWrapper::GetPitch() - { - return OrthancPluginGetImagePitch(context_, image_); - } - - - OrthancPluginPixelFormat OrthancImageWrapper::GetFormat() - { - return OrthancPluginGetImagePixelFormat(context_, image_); - } - - - char* OrthancImageWrapper::GetBuffer() - { - return reinterpret_cast(OrthancPluginGetImageBuffer(context_, image_)); - } -} diff -r e14b5a7a0f75 -r 7e33516965f8 Plugins/Samples/GdcmDecoder/OrthancImageWrapper.h --- a/Plugins/Samples/GdcmDecoder/OrthancImageWrapper.h Mon May 11 12:12:23 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +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 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 - * 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 . - **/ - - -#pragma once - -#include - -#include "GdcmImageDecoder.h" - -namespace OrthancPlugins -{ - class OrthancImageWrapper - { - private: - OrthancPluginContext* context_; - OrthancPluginImage* image_; - - public: - OrthancImageWrapper(OrthancPluginContext* context, - OrthancPluginPixelFormat format, - uint32_t width, - uint32_t height); - - OrthancImageWrapper(OrthancPluginContext* context, - OrthancPluginImage* image); // Takes ownership - - ~OrthancImageWrapper(); - - OrthancPluginContext* GetContext() - { - return context_; - } - - OrthancPluginImage* Release(); - - uint32_t GetWidth(); - - uint32_t GetHeight(); - - uint32_t GetPitch(); - - OrthancPluginPixelFormat GetFormat(); - - char* GetBuffer(); - }; -} diff -r e14b5a7a0f75 -r 7e33516965f8 Plugins/Samples/GdcmDecoder/Plugin.cpp --- a/Plugins/Samples/GdcmDecoder/Plugin.cpp Mon May 11 12:12:23 2020 +0200 +++ b/Plugins/Samples/GdcmDecoder/Plugin.cpp Mon May 11 15:13:16 2020 +0200 @@ -20,13 +20,81 @@ #include "../../../Core/Compatibility.h" +#include "../../../Core/DicomFormat/DicomMap.h" +#include "../../../Core/Toolbox.h" #include "GdcmDecoderCache.h" -#include "OrthancImageWrapper.h" + +static OrthancPlugins::GdcmDecoderCache cache_; +static bool restrictTransferSyntaxes_ = false; +static std::set enabledTransferSyntaxes_; + + +static bool ExtractTransferSyntax(std::string& transferSyntax, + const void* dicom, + const uint32_t size) +{ + Orthanc::DicomMap header; + if (!Orthanc::DicomMap::ParseDicomMetaInformation(header, reinterpret_cast(dicom), size)) + { + return false; + } + + const Orthanc::DicomValue* tag = header.TestAndGetValue(0x0002, 0x0010); + if (tag == NULL || + tag->IsNull() || + tag->IsBinary()) + { + return false; + } + else + { + // Stripping spaces should not be required, as this is a UI value + // representation whose stripping is supported by the Orthanc + // core, but let's be careful... + transferSyntax = Orthanc::Toolbox::StripSpaces(tag->GetContent()); + return true; + } +} + -#include +static bool IsTransferSyntaxEnabled(const void* dicom, + const uint32_t size) +{ + std::string formattedSize; + + { + char tmp[16]; + sprintf(tmp, "%0.1fMB", static_cast(size) / (1024.0f * 1024.0f)); + formattedSize.assign(tmp); + } + + if (!restrictTransferSyntaxes_) + { + LOG(INFO) << "Decoding one DICOM instance of " << formattedSize << " using GDCM"; + return true; + } -static OrthancPluginContext* context_ = NULL; -static OrthancPlugins::GdcmDecoderCache cache_; + std::string transferSyntax; + if (!ExtractTransferSyntax(transferSyntax, dicom, size)) + { + LOG(INFO) << "Cannot extract the transfer syntax of this instance of " + << formattedSize << ", will use GDCM to decode it"; + return true; + } + else if (enabledTransferSyntaxes_.find(transferSyntax) != enabledTransferSyntaxes_.end()) + { + // Decoding for this transfer syntax is enabled + LOG(INFO) << "Using GDCM to decode this instance of " << formattedSize + << " with transfer syntax " << transferSyntax; + return true; + } + else + { + LOG(INFO) << "Won't use GDCM to decode this instance of " << formattedSize + << ", as its transfer syntax " << transferSyntax << " is disabled"; + return false; + } +} static OrthancPluginErrorCode DecodeImageCallback(OrthancPluginImage** target, @@ -36,62 +104,135 @@ { try { - std::unique_ptr image; + if (!IsTransferSyntaxEnabled(dicom, size)) + { + *target = NULL; + return OrthancPluginErrorCode_Success; + } + + std::unique_ptr image; #if 0 // Do not use the cache OrthancPlugins::GdcmImageDecoder decoder(dicom, size); - image.reset(new OrthancPlugins::OrthancImageWrapper(context_, decoder.Decode(context_, frameIndex))); + image.reset(new OrthancPlugins::OrthancImage(decoder.Decode(frameIndex))); #else - image.reset(cache_.Decode(context_, dicom, size, frameIndex)); + image.reset(cache_.Decode(dicom, size, frameIndex)); #endif *target = image->Release(); return OrthancPluginErrorCode_Success; } + catch (Orthanc::OrthancException& e) + { + *target = NULL; + + LOG(WARNING) << "Cannot decode image using GDCM: " << e.What(); + return OrthancPluginErrorCode_Plugin; + } catch (std::runtime_error& e) { *target = NULL; - std::string s = "Cannot decode image using GDCM: " + std::string(e.what()); - OrthancPluginLogInfo(context_, s.c_str()); + LOG(WARNING) << "Cannot decode image using GDCM: " << e.what(); + return OrthancPluginErrorCode_Plugin; + } + catch (...) + { + *target = NULL; + + LOG(WARNING) << "Native exception while decoding image using GDCM"; return OrthancPluginErrorCode_Plugin; } } +/** + * We force the redefinition of the "ORTHANC_PLUGINS_API" macro, that + * was left empty with gcc until Orthanc SDK 1.5.7 (no "default" + * visibility). This causes the version script, if run from "Holy + * Build Box", to make private the 4 global functions of the plugin. + **/ + +#undef ORTHANC_PLUGINS_API + +#ifdef WIN32 +# define ORTHANC_PLUGINS_API __declspec(dllexport) +#elif __GNUC__ >= 4 +# define ORTHANC_PLUGINS_API __attribute__ ((visibility ("default"))) +#else +# define ORTHANC_PLUGINS_API +#endif + + extern "C" { ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context) { - context_ = context; - OrthancPluginLogWarning(context_, "Initializing the advanced decoder of medical images using GDCM"); + static const char* const KEY_GDCM = "Gdcm"; + static const char* const KEY_ENABLE_GDCM = "EnableGdcm"; + static const char* const KEY_RESTRICT_TRANSFER_SYNTAXES = "RestrictTransferSyntaxes"; + + OrthancPlugins::SetGlobalContext(context); + LOG(INFO) << "Initializing the advanced decoder of medical images using GDCM"; /* Check the version of the Orthanc core */ - if (OrthancPluginCheckVersion(context_) == 0) + if (OrthancPluginCheckVersion(context) == 0) { char info[1024]; sprintf(info, "Your version of Orthanc (%s) must be above %d.%d.%d to run this plugin", - context_->orthancVersion, + context->orthancVersion, ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER, ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER, ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER); - OrthancPluginLogError(context_, info); + OrthancPluginLogError(context, info); return -1; } - OrthancPluginSetDescription(context_, "Advanced decoder of medical images using GDCM."); - OrthancPluginRegisterDecodeImageCallback(context_, DecodeImageCallback); + OrthancPluginSetDescription(context, "Advanced decoder of medical images using GDCM."); + + OrthancPlugins::OrthancConfiguration global; + + bool enabled = true; + + if (global.IsSection(KEY_GDCM)) + { + OrthancPlugins::OrthancConfiguration config; + global.GetSection(config, KEY_GDCM); + + enabled = config.GetBooleanValue(KEY_ENABLE_GDCM, true); + if (config.LookupSetOfStrings(enabledTransferSyntaxes_, KEY_RESTRICT_TRANSFER_SYNTAXES, false)) + { + restrictTransferSyntaxes_ = true; + + for (std::set::const_iterator it = enabledTransferSyntaxes_.begin(); + it != enabledTransferSyntaxes_.end(); ++it) + { + LOG(WARNING) << "Orthanc will use GDCM to decode transfer syntax: " << *it; + } + } + } + + if (enabled) + { + OrthancPluginRegisterDecodeImageCallback(context, DecodeImageCallback); + } + else + { + LOG(WARNING) << "The advanced decoder of medical images using GDCM is disabled"; + } + return 0; } ORTHANC_PLUGINS_API void OrthancPluginFinalize() { + LOG(INFO) << "Finalizing the advanced decoder of medical images using GDCM"; } @@ -103,6 +244,6 @@ ORTHANC_PLUGINS_API const char* OrthancPluginGetVersion() { - return GDCM_DECODER_VERSION; + return PLUGIN_VERSION; } }