[med-svn] [orthanc-wsi] 02/03: New upstream version 0.2+dfsg
Sebastien Jodogne
jodogne-guest at moszumanska.debian.org
Mon Nov 28 17:42:44 UTC 2016
This is an automated email from the git hooks/post-receive script.
jodogne-guest pushed a commit to branch master
in repository orthanc-wsi.
commit 3c6e241ea544677ae14a187e83474069df14ef44
Author: jodogne-guest <s.jodogne at gmail.com>
Date: Mon Nov 28 18:38:50 2016 +0100
New upstream version 0.2+dfsg
---
.hg_archival.txt | 6 +-
Applications/ApplicationToolbox.cpp | 10 +-
Applications/ApplicationToolbox.h | 2 +-
Applications/CMakeLists.txt | 57 +-
Applications/DicomToTiff.cpp | 136 +++--
Applications/Dicomizer.cpp | 44 +-
Framework/Algorithms/PyramidReader.cpp | 50 +-
Framework/Algorithms/PyramidReader.h | 11 +-
Framework/Algorithms/ReconstructPyramidCommand.cpp | 11 +-
Framework/Algorithms/ReconstructPyramidCommand.h | 2 +-
Framework/Algorithms/TranscodeTileCommand.cpp | 10 +-
Framework/Algorithms/TranscodeTileCommand.h | 2 +-
Framework/DicomToolbox.cpp | 95 +---
Framework/DicomToolbox.h | 17 -
Framework/DicomizerParameters.cpp | 6 +-
Framework/DicomizerParameters.h | 4 +-
Framework/Enumerations.cpp | 7 +-
Framework/Enumerations.h | 2 +-
Framework/ImageToolbox.cpp | 14 +-
Framework/ImageToolbox.h | 2 +-
Framework/ImagedVolumeParameters.cpp | 2 +-
Framework/Inputs/DecodedTiledPyramid.h | 6 +-
Framework/Inputs/DicomPyramid.cpp | 45 +-
Framework/Inputs/DicomPyramid.h | 19 +-
Framework/Inputs/DicomPyramidInstance.cpp | 251 +++++++--
Framework/Inputs/DicomPyramidInstance.h | 20 +-
Framework/Inputs/DicomPyramidLevel.cpp | 64 ++-
Framework/Inputs/DicomPyramidLevel.h | 47 +-
Framework/Inputs/HierarchicalTiff.cpp | 7 +-
Framework/Inputs/HierarchicalTiff.h | 9 +-
Framework/Inputs/ITiledPyramid.h | 6 +-
Framework/Inputs/OpenSlideLibrary.cpp | 4 +-
Framework/Inputs/OpenSlideLibrary.h | 4 +-
Framework/Inputs/OpenSlidePyramid.cpp | 6 +-
Framework/Inputs/PyramidWithRawTiles.cpp | 14 +-
Framework/Inputs/SingleLevelDecodedPyramid.cpp | 2 +-
Framework/Inputs/TiledJpegImage.h | 2 +-
Framework/Inputs/TiledPngImage.h | 2 +-
Framework/Inputs/TiledPyramidStatistics.cpp | 5 +-
Framework/Inputs/TiledPyramidStatistics.h | 8 +-
Framework/Jpeg2000Reader.cpp | 6 +-
Framework/Jpeg2000Reader.h | 2 +-
Framework/Jpeg2000Writer.cpp | 4 +-
Framework/Jpeg2000Writer.h | 2 +-
Framework/Messaging/CurlOrthancConnection.cpp | 59 ---
Framework/Messaging/CurlOrthancConnection.h | 53 --
Framework/Messaging/IOrthancConnection.cpp | 63 ---
Framework/Messaging/IOrthancConnection.h | 52 --
Framework/Messaging/OrthancConnectionBase.cpp | 41 --
Framework/Messaging/OrthancConnectionBase.h | 51 --
Framework/Messaging/PluginOrthancConnection.cpp | 133 -----
Framework/Messaging/PluginOrthancConnection.h | 50 --
Framework/Orthanc/Core/Uuid.cpp | 162 ------
Framework/Outputs/DicomPyramidWriter.cpp | 6 +-
Framework/Outputs/DicomPyramidWriter.h | 2 +-
Framework/Outputs/HierarchicalTiffWriter.cpp | 16 +-
Framework/Outputs/IPyramidWriter.h | 2 +-
Framework/Outputs/InMemoryTiledImage.cpp | 5 +-
Framework/Outputs/InMemoryTiledImage.h | 6 +-
Framework/Outputs/MultiframeDicomWriter.cpp | 4 +-
Framework/Outputs/MultiframeDicomWriter.h | 2 +-
Framework/Outputs/PyramidWriterBase.cpp | 4 +-
Framework/Outputs/TruncatedPyramidWriter.cpp | 2 +-
Framework/PrecompiledHeadersWSI.h | 5 +-
Framework/{Messaging => Targets}/FolderTarget.cpp | 6 +-
Framework/{Messaging => Targets}/FolderTarget.h | 0
Framework/{Messaging => Targets}/IFileTarget.h | 0
Framework/{Messaging => Targets}/OrthancTarget.cpp | 30 +-
Framework/{Messaging => Targets}/OrthancTarget.h | 10 +-
NEWS | 10 +
Resources/CMake/LibTiffConfiguration.cmake | 21 +-
Resources/CMake/Version.cmake | 2 +-
.../Graveyard}/CMakeLists.txt | 137 ++---
Resources/Graveyard/Hello.cpp | 85 +++
.../Orthanc/Core/Cache/LeastRecentlyUsedIndex.h | 346 ++++++++++++
.../Orthanc/Core/ChunkedBuffer.cpp | 0
.../Orthanc/Core/ChunkedBuffer.h | 0
.../Orthanc/Core/DicomFormat/DicomArray.cpp | 0
.../Orthanc/Core/DicomFormat/DicomArray.h | 0
.../Orthanc/Core/DicomFormat/DicomElement.h | 0
.../Orthanc/Core/DicomFormat/DicomMap.cpp | 0
.../Orthanc/Core/DicomFormat/DicomMap.h | 0
.../Orthanc/Core/DicomFormat/DicomTag.cpp | 0
.../Orthanc/Core/DicomFormat/DicomTag.h | 0
.../Orthanc/Core/DicomFormat/DicomValue.cpp | 2 +-
.../Orthanc/Core/DicomFormat/DicomValue.h | 7 +-
{Framework => Resources}/Orthanc/Core/Endianness.h | 0
.../Orthanc/Core/EnumerationDictionary.h | 0
.../Orthanc/Core/Enumerations.cpp | 5 +-
.../Orthanc/Core/Enumerations.h | 3 +-
.../Orthanc/Core/HttpClient.cpp | 29 +-
{Framework => Resources}/Orthanc/Core/HttpClient.h | 9 +
{Framework => Resources}/Orthanc/Core/ICommand.h | 0
.../Orthanc/Core/IDynamicObject.h | 0
.../Orthanc/Core/Images/IImageWriter.cpp | 13 +-
.../Orthanc/Core/Images/IImageWriter.h | 8 +
.../Orthanc/Core/Images/Image.cpp | 0
.../Orthanc/Core/Images/Image.h | 0
.../Orthanc/Core/Images/ImageAccessor.cpp | 0
.../Orthanc/Core/Images/ImageAccessor.h | 0
.../Orthanc/Core/Images/ImageBuffer.cpp | 0
.../Orthanc/Core/Images/ImageBuffer.h | 0
.../Orthanc/Core/Images/ImageProcessing.cpp | 0
.../Orthanc/Core/Images/ImageProcessing.h | 0
.../Orthanc/Core/Images/JpegErrorManager.cpp | 0
.../Orthanc/Core/Images/JpegErrorManager.h | 0
.../Orthanc/Core/Images/JpegReader.cpp | 10 +-
.../Orthanc/Core/Images/JpegReader.h | 6 +
.../Orthanc/Core/Images/JpegWriter.cpp | 10 +-
.../Orthanc/Core/Images/JpegWriter.h | 2 +
.../Orthanc/Core/Images/PngReader.cpp | 11 +-
.../Orthanc/Core/Images/PngReader.h | 6 +
.../Orthanc/Core/Images/PngWriter.cpp | 9 +-
.../Orthanc/Core/Images/PngWriter.h | 2 +
{Framework => Resources}/Orthanc/Core/Logging.cpp | 197 +++----
{Framework => Resources}/Orthanc/Core/Logging.h | 10 +
.../Orthanc/Core/MultiThreading/BagOfTasks.h | 0
.../Core/MultiThreading/BagOfTasksProcessor.cpp | 0
.../Core/MultiThreading/BagOfTasksProcessor.h | 0
.../Orthanc/Core/MultiThreading/Semaphore.cpp | 0
.../Orthanc/Core/MultiThreading/Semaphore.h | 0
.../Core/MultiThreading/SharedMessageQueue.cpp | 0
.../Core/MultiThreading/SharedMessageQueue.h | 0
.../Orthanc/Core/OrthancException.h | 0
.../Orthanc/Core/PrecompiledHeaders.cpp | 0
.../Orthanc/Core/PrecompiledHeaders.h | 3 +-
Resources/Orthanc/Core/SystemToolbox.cpp | 539 +++++++++++++++++++
.../Orthanc/Core/SystemToolbox.h | 98 ++--
.../Orthanc/Core/TemporaryFile.cpp | 82 +--
.../Orthanc/Core/TemporaryFile.h | 39 +-
{Framework => Resources}/Orthanc/Core/Toolbox.cpp | 589 +++------------------
{Framework => Resources}/Orthanc/Core/Toolbox.h | 113 ++--
.../Orthanc/Core/WebServiceParameters.cpp | 12 +-
.../Orthanc/Core/WebServiceParameters.h | 6 +
.../Orthanc/OrthancServer/FromDcmtkBridge.cpp | 271 +++++++---
.../Orthanc/OrthancServer/FromDcmtkBridge.h | 90 +++-
.../OrthancServer/PrecompiledHeadersServer.h | 0
.../Orthanc/OrthancServer/ServerEnumerations.cpp | 0
.../Orthanc/OrthancServer/ServerEnumerations.h | 0
.../Orthanc/OrthancServer/ToDcmtkBridge.cpp | 0
.../Orthanc/OrthancServer/ToDcmtkBridge.h | 0
.../Orthanc/Plugins/Engine/SharedLibrary.cpp | 2 +-
.../Orthanc/Plugins/Engine/SharedLibrary.h | 2 +-
.../Plugins/Samples/Common/DicomDatasetReader.cpp | 122 +++++
.../Plugins/Samples/Common/DicomDatasetReader.h | 30 +-
.../Orthanc/Plugins/Samples/Common/DicomPath.cpp | 77 ++-
.../Orthanc/Plugins/Samples/Common/DicomPath.h | 93 ++--
.../Orthanc/Plugins/Samples/Common/DicomTag.cpp | 110 ++++
.../Orthanc/Plugins/Samples/Common/DicomTag.h | 95 ++++
.../Plugins/Samples/Common/ExportedSymbols.list | 0
.../Plugins/Samples/Common/FullOrthancDataset.cpp | 196 +++++++
.../Plugins/Samples/Common/FullOrthancDataset.h | 35 +-
.../Orthanc/Plugins/Samples/Common/IDicomDataset.h | 24 +-
.../Plugins/Samples/Common/IOrthancConnection.cpp | 78 ++-
.../Plugins/Samples/Common/IOrthancConnection.h | 75 ++-
.../Samples/Common/OrthancHttpConnection.cpp | 107 ++++
.../Plugins/Samples/Common/OrthancHttpConnection.h | 53 +-
.../Samples/Common/OrthancPluginConnection.cpp | 74 ++-
.../Samples/Common/OrthancPluginConnection.h | 38 +-
.../Samples/Common/OrthancPluginCppWrapper.cpp | 68 ++-
.../Samples/Common/OrthancPluginCppWrapper.h | 35 +-
.../Samples/Common/SimplifiedOrthancDataset.cpp | 156 ++++++
.../Samples/Common/SimplifiedOrthancDataset.h | 35 +-
.../Plugins/Samples/Common/VersionScript.map | 0
{Framework => Resources}/Orthanc/README.txt | 0
.../Resources/CMake/AutoGeneratedCode.cmake | 0
.../Resources/CMake/BoostConfiguration.cmake | 5 +-
.../Orthanc/Resources/CMake/Compiler.cmake | 29 +-
.../Resources/CMake/DcmtkConfiguration.cmake | 26 +-
.../Orthanc/Resources/CMake/DownloadPackage.cmake | 24 +-
.../Resources/CMake/JsonCppConfiguration.cmake | 0
.../Resources/CMake/LibCurlConfiguration.cmake | 0
.../Resources/CMake/LibJpegConfiguration.cmake | 0
.../Resources/CMake/LibPngConfiguration.cmake | 0
.../Resources/CMake/OpenSslConfiguration.cmake | 0
.../CMake/VisualStudioPrecompiledHeaders.cmake | 0
.../Resources/CMake/ZlibConfiguration.cmake | 0
.../Orthanc/Resources/EmbedResources.py | 4 +
.../Orthanc/Resources/MinGW-W64-Toolchain32.cmake | 0
.../Orthanc/Resources/MinGW-W64-Toolchain64.cmake | 0
.../Orthanc/Resources/MinGWToolchain.cmake | 0
.../Resources/Patches/dcmtk-3.6.0-mingw64.patch | 0
.../Resources/Patches/dcmtk-3.6.0-speed.patch | 0
.../Resources/Patches/dcmtk-3.6.1-speed.patch | 0
.../Resources/ThirdParty/VisualStudio/stdint.h | 0
.../Orthanc/Resources/ThirdParty/base64/base64.cpp | 0
.../Orthanc/Resources/ThirdParty/base64/base64.h | 0
.../Orthanc/Resources/WindowsResources.py | 0
.../Orthanc/Resources/WindowsResources.rc | 0
.../Orthanc/Sdk-1.0.0/orthanc/OrthancCPlugin.h | 0
Resources/OrthancWSIClearCache.py | 77 +++
Resources/SyncOrthancFolder.py | 26 +-
TODO | 8 +-
ViewerPlugin/CMakeLists.txt | 16 +-
ViewerPlugin/DicomPyramidCache.cpp | 156 ++++++
ViewerPlugin/DicomPyramidCache.h | 70 +++
ViewerPlugin/Plugin.cpp | 145 ++---
197 files changed, 4022 insertions(+), 2640 deletions(-)
diff --git a/.hg_archival.txt b/.hg_archival.txt
index 9dab074..2add95f 100644
--- a/.hg_archival.txt
+++ b/.hg_archival.txt
@@ -1,5 +1,5 @@
repo: 4a7a53257c7df5a97aea39377b8c9a6e815c9763
-node: b1d6a0efe09b27f8d7095a792823c6da658b45b3
-branch: OrthancWSI-0.1
+node: cafc4728a8577cd9f07e4bbff7a638ba577ceb10
+branch: OrthancWSI-0.2
latesttag: null
-latesttagdistance: 35
+latesttagdistance: 76
diff --git a/Applications/ApplicationToolbox.cpp b/Applications/ApplicationToolbox.cpp
index 89fe8dd..49ebabb 100644
--- a/Applications/ApplicationToolbox.cpp
+++ b/Applications/ApplicationToolbox.cpp
@@ -21,10 +21,10 @@
#include "ApplicationToolbox.h"
#include "../Framework/Inputs/OpenSlideLibrary.h"
-#include "../Framework/Orthanc/Core/HttpClient.h"
-#include "../Framework/Orthanc/Core/Logging.h"
-#include "../Framework/Orthanc/Core/MultiThreading/BagOfTasksProcessor.h"
-#include "../Framework/Orthanc/OrthancServer/FromDcmtkBridge.h"
+#include "../Resources/Orthanc/Core/HttpClient.h"
+#include "../Resources/Orthanc/Core/Logging.h"
+#include "../Resources/Orthanc/Core/MultiThreading/BagOfTasksProcessor.h"
+#include "../Resources/Orthanc/OrthancServer/FromDcmtkBridge.h"
#include <boost/lexical_cast.hpp>
#include <boost/regex.hpp>
@@ -38,7 +38,7 @@ namespace OrthancWSI
Orthanc::Logging::Initialize();
Orthanc::HttpClient::InitializeOpenSsl();
Orthanc::HttpClient::GlobalInitialize();
- Orthanc::FromDcmtkBridge::InitializeDictionary();
+ Orthanc::FromDcmtkBridge::InitializeDictionary(false /* don't load private dictionary */);
}
diff --git a/Applications/ApplicationToolbox.h b/Applications/ApplicationToolbox.h
index 6650f1c..1bfe5ca 100644
--- a/Applications/ApplicationToolbox.h
+++ b/Applications/ApplicationToolbox.h
@@ -20,7 +20,7 @@
#pragma once
-#include "../Framework/Orthanc/Core/MultiThreading/BagOfTasks.h"
+#include "../Resources/Orthanc/Core/MultiThreading/BagOfTasks.h"
#include <string>
#include <stdint.h>
diff --git a/Applications/CMakeLists.txt b/Applications/CMakeLists.txt
index 622ba23..572a651 100644
--- a/Applications/CMakeLists.txt
+++ b/Applications/CMakeLists.txt
@@ -9,6 +9,7 @@ project(OrthancWSIApplications)
# Generic parameters
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(ENABLE_PROFILING OFF CACHE BOOL "Whether to enable the generation of profiling information with gprof")
# Optional components
SET(ENABLE_SSL OFF CACHE BOOL "Include support for SSL")
@@ -32,6 +33,7 @@ SET(USE_SYSTEM_LIBTIFF ON CACHE BOOL "Use the system version of libtiff")
SET(USE_SYSTEM_OPENJPEG ON CACHE BOOL "Use the system version of OpenJpeg")
SET(USE_SYSTEM_OPENSSL ON CACHE BOOL "Use the system version of OpenSSL")
SET(USE_SYSTEM_ZLIB ON CACHE BOOL "Use the system version of ZLib")
+SET(USE_SYSTEM_ORTHANC_SDK ON CACHE BOOL "Use the system version of the Orthanc plugin SDK")
SET(DCMTK_DICTIONARY_DIR "" CACHE PATH "Directory containing the DCMTK dictionaries \"dicom.dic\" and \"private.dic\" (only when using system version of DCMTK)")
@@ -41,12 +43,13 @@ SET(DCMTK_DICTIONARY_DIR "" CACHE PATH "Directory containing the DCMTK dictionar
#####################################################################
SET(ORTHANC_WSI_DIR ${CMAKE_CURRENT_LIST_DIR}/..)
-SET(ORTHANC_ROOT ${ORTHANC_WSI_DIR}/Framework/Orthanc)
+SET(ORTHANC_ROOT ${ORTHANC_WSI_DIR}/Resources/Orthanc)
SET(USE_OPENJPEG_JP2 ON)
SET(ENABLE_JPEG OFF) # Disable DCMTK's support for JPEG, that clashes with libtiff
SET(ENABLE_JPEG_LOSSLESS OFF) # Disable DCMTK's support for JPEG-LS
SET(ENABLE_DCMTK_NETWORK OFF) # Disable DCMTK's support for DICOM networking
SET(STANDALONE_BUILD ON) # Embed DCMTK's dictionaries for static builds
+SET(USE_DCMTK_361_PRIVATE_DIC OFF) # No need for private tags
include(CheckIncludeFiles)
include(CheckIncludeFileCXX)
@@ -80,23 +83,39 @@ add_definitions(
-DORTHANC_ENABLE_DCMTK=1
-DORTHANC_ENABLE_LOGGING=1
-DORTHANC_ENABLE_MD5=0
- -DORTHANC_JPEG_ENABLED=0 # Disable DCMTK's support for JPEG
- -DORTHANC_PKCS11_ENABLED=0
- -DORTHANC_PLUGINS_ENABLED=1 # To enable class Orthanc::SharedLibrary
- -DORTHANC_PUGIXML_ENABLED=0
+ -DORTHANC_ENABLE_JPEG=0 # Disable DCMTK's support for JPEG
+ -DORTHANC_ENABLE_PKCS11=0
+ -DORTHANC_ENABLE_PLUGINS=1 # To enable class Orthanc::SharedLibrary
+ -DORTHANC_ENABLE_PUGIXML=0
+ -DORTHANC_SANDBOXED=0
+ -DHAS_ORTHANC_EXCEPTION=1
)
#####################################################################
+## Find the Orthanc SDK
+#####################################################################
+
+if (STATIC_BUILD OR NOT USE_SYSTEM_ORTHANC_SDK)
+ include_directories(${ORTHANC_ROOT}/Sdk-1.0.0)
+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()
+
+
+#####################################################################
## Configure optional third-party components
#####################################################################
if (ENABLE_SSL)
set(ENABLE_PKCS11 OFF)
- add_definitions(-DORTHANC_SSL_ENABLED=1)
+ add_definitions(-DORTHANC_ENABLE_SSL=1)
include(${ORTHANC_ROOT}/Resources/CMake/OpenSslConfiguration.cmake)
else()
- add_definitions(-DORTHANC_SSL_ENABLED=0)
+ add_definitions(-DORTHANC_ENABLE_SSL=0)
endif()
@@ -106,7 +125,6 @@ endif()
#####################################################################
set(ORTHANC_WSI_SOURCES
- #${ORTHANC_WSI_DIR}/Framework/Messaging/PluginOrthancConnection.cpp
${ORTHANC_WSI_DIR}/Framework/Algorithms/PyramidReader.cpp
${ORTHANC_WSI_DIR}/Framework/Algorithms/ReconstructPyramidCommand.cpp
${ORTHANC_WSI_DIR}/Framework/Algorithms/TranscodeTileCommand.cpp
@@ -127,11 +145,8 @@ set(ORTHANC_WSI_SOURCES
${ORTHANC_WSI_DIR}/Framework/Inputs/TiledPyramidStatistics.cpp
${ORTHANC_WSI_DIR}/Framework/Jpeg2000Reader.cpp
${ORTHANC_WSI_DIR}/Framework/Jpeg2000Writer.cpp
- ${ORTHANC_WSI_DIR}/Framework/Messaging/CurlOrthancConnection.cpp
- ${ORTHANC_WSI_DIR}/Framework/Messaging/FolderTarget.cpp
- ${ORTHANC_WSI_DIR}/Framework/Messaging/IOrthancConnection.cpp
- ${ORTHANC_WSI_DIR}/Framework/Messaging/OrthancConnectionBase.cpp
- ${ORTHANC_WSI_DIR}/Framework/Messaging/OrthancTarget.cpp
+ ${ORTHANC_WSI_DIR}/Framework/Targets/FolderTarget.cpp
+ ${ORTHANC_WSI_DIR}/Framework/Targets/OrthancTarget.cpp
${ORTHANC_WSI_DIR}/Framework/Outputs/DicomPyramidWriter.cpp
${ORTHANC_WSI_DIR}/Framework/Outputs/HierarchicalTiffWriter.cpp
${ORTHANC_WSI_DIR}/Framework/Outputs/InMemoryTiledImage.cpp
@@ -161,13 +176,25 @@ set(ORTHANC_CORE_SOURCES
${ORTHANC_ROOT}/Core/Logging.cpp
${ORTHANC_ROOT}/Core/MultiThreading/BagOfTasksProcessor.cpp
${ORTHANC_ROOT}/Core/MultiThreading/SharedMessageQueue.cpp
+ ${ORTHANC_ROOT}/Core/SystemToolbox.cpp
+ ${ORTHANC_ROOT}/Core/TemporaryFile.cpp
${ORTHANC_ROOT}/Core/Toolbox.cpp
- ${ORTHANC_ROOT}/Core/Uuid.cpp
${ORTHANC_ROOT}/Core/WebServiceParameters.cpp
${ORTHANC_ROOT}/OrthancServer/FromDcmtkBridge.cpp
${ORTHANC_ROOT}/OrthancServer/ServerEnumerations.cpp
${ORTHANC_ROOT}/OrthancServer/ToDcmtkBridge.cpp
+
${ORTHANC_ROOT}/Plugins/Engine/SharedLibrary.cpp
+ ${ORTHANC_ROOT}/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
+ ${ORTHANC_ROOT}/Plugins/Samples/Common/DicomDatasetReader.cpp
+ ${ORTHANC_ROOT}/Plugins/Samples/Common/DicomPath.cpp
+ ${ORTHANC_ROOT}/Plugins/Samples/Common/DicomTag.cpp
+ ${ORTHANC_ROOT}/Plugins/Samples/Common/FullOrthancDataset.cpp
+ ${ORTHANC_ROOT}/Plugins/Samples/Common/IOrthancConnection.cpp
+ ${ORTHANC_ROOT}/Plugins/Samples/Common/OrthancHttpConnection.cpp
+ ${ORTHANC_ROOT}/Plugins/Samples/Common/OrthancPluginConnection.cpp
+ ${ORTHANC_ROOT}/Plugins/Samples/Common/SimplifiedOrthancDataset.cpp
+
${ORTHANC_ROOT}/Resources/ThirdParty/base64/base64.cpp
)
@@ -187,7 +214,7 @@ if (MSVC)
add_definitions(-DORTHANC_USE_PRECOMPILED_HEADERS=1)
ADD_VISUAL_STUDIO_PRECOMPILED_HEADERS(
- "PrecompiledHeaders.h" "${ORTHANC_WSI_DIR}/Framework/Orthanc/Core/PrecompiledHeaders.cpp" ORTHANC_CORE_SOURCES)
+ "PrecompiledHeaders.h" "${ORTHANC_WSI_DIR}/Resources/Orthanc/Core/PrecompiledHeaders.cpp" ORTHANC_CORE_SOURCES)
ADD_VISUAL_STUDIO_PRECOMPILED_HEADERS(
"PrecompiledHeadersWSI.h" "${ORTHANC_WSI_DIR}/Framework/PrecompiledHeadersWSI.cpp" ORTHANC_WSI_SOURCES)
diff --git a/Applications/DicomToTiff.cpp b/Applications/DicomToTiff.cpp
index 99d2c9c..cb43de1 100644
--- a/Applications/DicomToTiff.cpp
+++ b/Applications/DicomToTiff.cpp
@@ -21,11 +21,13 @@
#include "../Framework/DicomToolbox.h"
#include "../Framework/ImageToolbox.h"
#include "../Framework/Inputs/DicomPyramid.h"
-#include "../Framework/Messaging/CurlOrthancConnection.h"
-#include "../Framework/Orthanc/Core/Logging.h"
-#include "../Framework/Orthanc/Core/OrthancException.h"
+#include "../Framework/Inputs/TiledPyramidStatistics.h"
#include "../Framework/Outputs/HierarchicalTiffWriter.h"
+#include "../Resources/Orthanc/Core/Logging.h"
+#include "../Resources/Orthanc/Core/OrthancException.h"
+#include "../Resources/Orthanc/Plugins/Samples/Common/OrthancHttpConnection.h"
+
#include "ApplicationToolbox.h"
#include <boost/program_options.hpp>
@@ -114,7 +116,8 @@ static bool ParseParameters(int& exitStatus,
<< std::endl
<< "Orthanc, lightweight, RESTful DICOM server for healthcare and medical research."
<< std::endl << std::endl
- << "Convert a DICOM for digital pathology stored in some Orthanc server as a standard hierarchical TIFF."
+ << "Convert a DICOM image for digital pathology stored in some Orthanc server as a" << std::endl
+ << "standard hierarchical TIFF (whose tiles are all encoded using JPEG)."
<< std::endl;
std::cout << allWithoutHidden << "\n";
@@ -167,56 +170,8 @@ static Orthanc::ImageAccessor* CreateEmptyTile(const OrthancWSI::IPyramidWriter&
-static void RunTranscode(OrthancWSI::ITiledPyramid& source,
- const boost::program_options::variables_map& options)
-{
- OrthancWSI::HierarchicalTiffWriter target(options["output"].as<std::string>(),
- source.GetPixelFormat(),
- source.GetImageCompression(),
- source.GetTileWidth(),
- source.GetTileHeight());
-
- std::auto_ptr<Orthanc::ImageAccessor> empty(CreateEmptyTile(target, options));
-
- for (unsigned int level = 0; level < source.GetLevelCount(); level++)
- {
- LOG(WARNING) << "Creating level " << level << " of size "
- << source.GetLevelWidth(level) << "x" << source.GetLevelHeight(level);
- target.AddLevel(source.GetLevelWidth(level), source.GetLevelHeight(level));
- }
-
- for (unsigned int level = 0; level < source.GetLevelCount(); level++)
- {
- LOG(WARNING) << "Transcoding level " << level;
-
- unsigned int countX = OrthancWSI::CeilingDivision(source.GetLevelWidth(level), source.GetTileWidth());
- unsigned int countY = OrthancWSI::CeilingDivision(source.GetLevelHeight(level), source.GetTileHeight());
-
- for (unsigned int tileY = 0; tileY < countY; tileY++)
- {
- for (unsigned int tileX = 0; tileX < countX; tileX++)
- {
- LOG(INFO) << "Dealing with tile (" << tileX << "," << tileY << ") at level " << level;
- std::string tile;
-
- if (source.ReadRawTile(tile, level, tileX, tileY))
- {
- target.WriteRawTile(tile, source.GetImageCompression(), level, tileX, tileY);
- }
- else
- {
- target.EncodeTile(*empty, level, tileX, tileY);
- }
- }
- }
-
- target.Flush();
- }
-}
-
-
-static void RunReencode(OrthancWSI::ITiledPyramid& source,
- const boost::program_options::variables_map& options)
+static void Run(OrthancWSI::ITiledPyramid& source,
+ const boost::program_options::variables_map& options)
{
OrthancWSI::HierarchicalTiffWriter target(options["output"].as<std::string>(),
source.GetPixelFormat(),
@@ -224,6 +179,9 @@ static void RunReencode(OrthancWSI::ITiledPyramid& source,
source.GetTileWidth(),
source.GetTileHeight());
+ bool reencode = (options.count("reencode") &&
+ options["reencode"].as<bool>());
+
if (options.count("jpeg-quality"))
{
target.SetJpegQuality(options["jpeg-quality"].as<int>());
@@ -240,7 +198,7 @@ static void RunReencode(OrthancWSI::ITiledPyramid& source,
for (unsigned int level = 0; level < source.GetLevelCount(); level++)
{
- LOG(WARNING) << "Reencoding level " << level;
+ LOG(WARNING) << std::string(reencode ? "Reencoding" : "Transcoding") << " level " << level;
unsigned int countX = OrthancWSI::CeilingDivision(source.GetLevelWidth(level), source.GetTileWidth());
unsigned int countY = OrthancWSI::CeilingDivision(source.GetLevelHeight(level), source.GetTileHeight());
@@ -251,14 +209,58 @@ static void RunReencode(OrthancWSI::ITiledPyramid& source,
{
LOG(INFO) << "Dealing with tile (" << tileX << "," << tileY << ") at level " << level;
- std::auto_ptr<Orthanc::ImageAccessor> tile(source.DecodeTile(level, tileX, tileY));
- if (tile.get() == NULL)
+ bool missing = false;
+ bool success = true;
+
+ // Give a first try to get the raw tile
+ std::string tile;
+ OrthancWSI::ImageCompression compression;
+ if (source.ReadRawTile(tile, compression, level, tileX, tileY))
{
- target.EncodeTile(*empty, level, tileX, tileY);
+ if (reencode ||
+ compression == OrthancWSI::ImageCompression_Jpeg)
+ {
+ target.WriteRawTile(tile, compression, level, tileX, tileY);
+ }
+ else
+ {
+ success = false; // Re-encoding is mandatory
+ }
}
else
{
- target.EncodeTile(*tile, level, tileX, tileY);
+ // Give a second try to get the decoded tile
+ compression = OrthancWSI::ImageCompression_Unknown;
+
+ std::auto_ptr<Orthanc::ImageAccessor> tile(source.DecodeTile(level, tileX, tileY));
+ if (tile.get() == NULL)
+ {
+ // Unable to read the raw tile or to decode it: The tile is missing (sparse tiling)
+ missing = true;
+ }
+ else if (reencode)
+ {
+ target.EncodeTile(*empty, level, tileX, tileY);
+ }
+ else
+ {
+ success = false; // Re-encoding is mandatory
+ }
+ }
+
+ if (!success)
+ {
+ LOG(WARNING) << "Cannot transcode a DICOM image that is not encoded using JPEG (it is "
+ << OrthancWSI::EnumerationToString(compression)
+ << "), please use the --reencode=1 option";
+ throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+ }
+
+ if (missing)
+ {
+ LOG(WARNING) << "Sparse tiling: Using an empty image for missing tile ("
+ << tileX << "," << tileY << ") at level " << level;
+ target.EncodeTile(*empty, level, tileX, tileY);
}
}
}
@@ -297,18 +299,12 @@ int main(int argc, char* argv[])
params.SetPassword(options["password"].as<std::string>());
}
- OrthancWSI::CurlOrthancConnection orthanc(params);
- OrthancWSI::DicomPyramid source(orthanc, options["input"].as<std::string>());
+ OrthancPlugins::OrthancHttpConnection orthanc(params);
+ OrthancWSI::DicomPyramid source(orthanc, options["input"].as<std::string>(),
+ false /* don't use cached metadata */);
- if (options.count("reencode") &&
- options["reencode"].as<bool>())
- {
- RunReencode(source, options);
- }
- else
- {
- RunTranscode(source, options);
- }
+ OrthancWSI::TiledPyramidStatistics stats(source);
+ Run(stats, options);
}
}
catch (Orthanc::OrthancException& e)
diff --git a/Applications/Dicomizer.cpp b/Applications/Dicomizer.cpp
index c325fcc..d2de5a6 100644
--- a/Applications/Dicomizer.cpp
+++ b/Applications/Dicomizer.cpp
@@ -28,14 +28,15 @@
#include "../Framework/Inputs/TiledJpegImage.h"
#include "../Framework/Inputs/TiledPngImage.h"
#include "../Framework/Inputs/TiledPyramidStatistics.h"
-#include "../Framework/Orthanc/Core/HttpClient.h"
-#include "../Framework/Orthanc/Core/Logging.h"
-#include "../Framework/Orthanc/Core/MultiThreading/BagOfTasksProcessor.h"
-#include "../Framework/Orthanc/Core/Toolbox.h"
-#include "../Framework/Orthanc/OrthancServer/FromDcmtkBridge.h"
#include "../Framework/Outputs/DicomPyramidWriter.h"
#include "../Framework/Outputs/TruncatedPyramidWriter.h"
+#include "../Resources/Orthanc/Core/HttpClient.h"
+#include "../Resources/Orthanc/Core/Logging.h"
+#include "../Resources/Orthanc/Core/MultiThreading/BagOfTasksProcessor.h"
+#include "../Resources/Orthanc/Core/SystemToolbox.h"
+#include "../Resources/Orthanc/OrthancServer/FromDcmtkBridge.h"
+
#include "ApplicationToolbox.h"
#include <EmbeddedResources.h>
@@ -133,7 +134,6 @@ static void Recompress(OrthancWSI::IFileTarget& output,
OrthancWSI::TiledPyramidStatistics stats(source);
LOG(WARNING) << "Size of source tiles: " << stats.GetTileWidth() << "x" << stats.GetTileHeight();
- LOG(WARNING) << "Source image compression: " << OrthancWSI::EnumerationToString(stats.GetImageCompression());
LOG(WARNING) << "Pixel format: " << Orthanc::EnumerationToString(stats.GetPixelFormat());
LOG(WARNING) << "Smoothing is " << (parameters.IsSmoothEnabled() ? "enabled" : "disabled");
@@ -210,7 +210,7 @@ static DcmDataset* ParseDataset(const std::string& path)
else
{
std::string content;
- Orthanc::Toolbox::ReadFile(content, path);
+ Orthanc::SystemToolbox::ReadFile(content, path);
Json::Reader reader;
if (!reader.parse(content, json, false))
@@ -241,7 +241,7 @@ static DcmDataset* ParseDataset(const std::string& path)
OrthancWSI::DicomToolbox::SetStringTag(*dataset, DCM_ImageOrientationSlide, "0\\-1\\0\\-1\\0\\0");
std::string date, time;
- Orthanc::Toolbox::GetNowDicom(date, time);
+ Orthanc::SystemToolbox::GetNowDicom(date, time);
OrthancWSI::DicomToolbox::SetStringTag(*dataset, DCM_StudyDate, date);
OrthancWSI::DicomToolbox::SetStringTag(*dataset, DCM_StudyTime, time);
OrthancWSI::DicomToolbox::SetStringTag(*dataset, DCM_SeriesDate, date);
@@ -338,12 +338,13 @@ static void SetupDimension(DcmDataset& dataset,
static void EnrichDataset(DcmDataset& dataset,
const OrthancWSI::ITiledPyramid& source,
+ OrthancWSI::ImageCompression sourceCompression,
const OrthancWSI::DicomizerParameters& parameters,
const OrthancWSI::ImagedVolumeParameters& volume)
{
Orthanc::Encoding encoding = Orthanc::FromDcmtkBridge::DetectEncoding(dataset, Orthanc::Encoding_Latin1);
- if (source.GetImageCompression() == OrthancWSI::ImageCompression_Jpeg ||
+ if (sourceCompression == OrthancWSI::ImageCompression_Jpeg ||
parameters.GetTargetCompression() == OrthancWSI::ImageCompression_Jpeg)
{
// Takes as estimation a 1:10 compression ratio
@@ -410,7 +411,7 @@ static void EnrichDataset(DcmDataset& dataset,
}
else
{
- Orthanc::Toolbox::ReadFile(profile, parameters.GetIccProfilePath());
+ Orthanc::SystemToolbox::ReadFile(profile, parameters.GetIccProfilePath());
}
@@ -796,7 +797,8 @@ static bool ParseParameters(int& exitStatus,
}
-OrthancWSI::ITiledPyramid* OpenInputPyramid(const std::string& path,
+OrthancWSI::ITiledPyramid* OpenInputPyramid(OrthancWSI::ImageCompression& sourceCompression,
+ const std::string& path,
const OrthancWSI::DicomizerParameters& parameters)
{
LOG(WARNING) << "The input image is: " << path;
@@ -807,20 +809,28 @@ OrthancWSI::ITiledPyramid* OpenInputPyramid(const std::string& path,
switch (format)
{
case OrthancWSI::ImageCompression_Png:
+ {
+ sourceCompression = OrthancWSI::ImageCompression_Unknown;
return new OrthancWSI::TiledPngImage(path,
parameters.GetTargetTileWidth(512),
parameters.GetTargetTileHeight(512));
+ }
case OrthancWSI::ImageCompression_Jpeg:
+ {
+ sourceCompression = OrthancWSI::ImageCompression_Unknown;
return new OrthancWSI::TiledJpegImage(path,
parameters.GetTargetTileWidth(512),
parameters.GetTargetTileHeight(512));
+ }
case OrthancWSI::ImageCompression_Tiff:
{
try
{
- return new OrthancWSI::HierarchicalTiff(path);
+ std::auto_ptr<OrthancWSI::HierarchicalTiff> tiff(new OrthancWSI::HierarchicalTiff(path));
+ sourceCompression = tiff->GetImageCompression();
+ return tiff.release();
}
catch (Orthanc::OrthancException&)
{
@@ -835,6 +845,7 @@ OrthancWSI::ITiledPyramid* OpenInputPyramid(const std::string& path,
try
{
LOG(WARNING) << "Trying to open the input pyramid with OpenSlide";
+ sourceCompression = OrthancWSI::ImageCompression_Unknown;
return new OrthancWSI::OpenSlidePyramid(path,
parameters.GetTargetTileWidth(512),
parameters.GetTargetTileHeight(512));
@@ -860,15 +871,20 @@ int main(int argc, char* argv[])
if (ParseParameters(exitStatus, parameters, volume, argc, argv))
{
- std::auto_ptr<OrthancWSI::ITiledPyramid> source(OpenInputPyramid(parameters.GetInputFile(), parameters));
+ OrthancWSI::ImageCompression sourceCompression;
+ std::auto_ptr<OrthancWSI::ITiledPyramid> source;
+
+ source.reset(OpenInputPyramid(sourceCompression, parameters.GetInputFile(), parameters));
if (source.get() == NULL)
{
throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
}
+
+ LOG(WARNING) << "Compression of the individual source tiles: " << OrthancWSI::EnumerationToString(sourceCompression);
// Create the shared DICOM tags
std::auto_ptr<DcmDataset> dataset(ParseDataset(parameters.GetDatasetPath()));
- EnrichDataset(*dataset, *source, parameters, volume);
+ EnrichDataset(*dataset, *source, sourceCompression, parameters, volume);
std::auto_ptr<OrthancWSI::IFileTarget> output(parameters.CreateTarget());
Recompress(*output, *source, *dataset, parameters, volume);
diff --git a/Framework/Algorithms/PyramidReader.cpp b/Framework/Algorithms/PyramidReader.cpp
index 1bb30b1..0e15d11 100644
--- a/Framework/Algorithms/PyramidReader.cpp
+++ b/Framework/Algorithms/PyramidReader.cpp
@@ -22,8 +22,8 @@
#include "PyramidReader.h"
#include "../ImageToolbox.h"
-#include "../Orthanc/Core/Logging.h"
-#include "../Orthanc/Core/OrthancException.h"
+#include "../../Resources/Orthanc/Core/Logging.h"
+#include "../../Resources/Orthanc/Core/OrthancException.h"
#include <cassert>
@@ -32,11 +32,12 @@ namespace OrthancWSI
class PyramidReader::SourceTile : public boost::noncopyable
{
private:
- PyramidReader& that_;
- unsigned int tileX_;
- unsigned int tileY_;
- bool hasRawTile_;
- std::string rawTile_;
+ PyramidReader& that_;
+ unsigned int tileX_;
+ unsigned int tileY_;
+ bool hasRawTile_;
+ std::string rawTile_;
+ ImageCompression rawTileCompression_;
std::auto_ptr<Orthanc::ImageAccessor> decoded_;
@@ -96,7 +97,7 @@ namespace OrthancWSI
{
if (!that_.parameters_.IsForceReencode() &&
!IsRepaintNeeded() &&
- that_.source_.ReadRawTile(rawTile_, that_.level_, tileX, tileY))
+ that_.source_.ReadRawTile(rawTile_, rawTileCompression_, that_.level_, tileX, tileY))
{
hasRawTile_ = true;
}
@@ -113,9 +114,17 @@ namespace OrthancWSI
}
}
- bool HasRawTile() const
+ bool HasRawTile(ImageCompression& compression) const
{
- return hasRawTile_;
+ if (hasRawTile_)
+ {
+ compression = rawTileCompression_;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
}
const std::string& GetRawTile() const
@@ -139,7 +148,7 @@ namespace OrthancWSI
throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
}
- decoded_.reset(ImageToolbox::DecodeTile(rawTile_, that_.source_.GetImageCompression()));
+ decoded_.reset(ImageToolbox::DecodeTile(rawTile_, rawTileCompression_));
if (decoded_.get() == NULL)
{
throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
@@ -180,11 +189,12 @@ namespace OrthancWSI
}
- void PyramidReader::CheckTileSize(const std::string& tile) const
+ void PyramidReader::CheckTileSize(const std::string& tile,
+ ImageCompression compression) const
{
if (parameters_.IsSafetyCheck())
{
- std::auto_ptr<Orthanc::ImageAccessor> decoded(ImageToolbox::DecodeTile(tile, source_.GetImageCompression()));
+ std::auto_ptr<Orthanc::ImageAccessor> decoded(ImageToolbox::DecodeTile(tile, compression));
CheckTileSize(*decoded);
}
}
@@ -225,9 +235,9 @@ namespace OrthancWSI
levelHeight_(source.GetLevelHeight(level)),
sourceTileWidth_(source.GetTileWidth()),
sourceTileHeight_(source.GetTileHeight()),
- targetTileWidth_(targetTileWidth),
- targetTileHeight_(targetTileHeight),
- parameters_(parameters)
+ targetTileWidth_(targetTileWidth),
+ targetTileHeight_(targetTileHeight),
+ parameters_(parameters)
{
if (sourceTileWidth_ % targetTileWidth_ != 0 ||
sourceTileHeight_ % targetTileHeight_ != 0)
@@ -248,7 +258,8 @@ namespace OrthancWSI
}
- const std::string* PyramidReader::GetRawTile(unsigned int tileX,
+ const std::string* PyramidReader::GetRawTile(ImageCompression& compression,
+ unsigned int tileX,
unsigned int tileY)
{
if (sourceTileWidth_ != targetTileWidth_ ||
@@ -258,9 +269,10 @@ namespace OrthancWSI
}
SourceTile& source = AccessSourceTile(MapTargetToSourceLocation(tileX, tileY));
- if (source.HasRawTile())
+
+ if (source.HasRawTile(compression))
{
- CheckTileSize(source.GetRawTile());
+ CheckTileSize(source.GetRawTile(), compression);
return &source.GetRawTile();
}
else
diff --git a/Framework/Algorithms/PyramidReader.h b/Framework/Algorithms/PyramidReader.h
index d8ede82..05a5dad 100644
--- a/Framework/Algorithms/PyramidReader.h
+++ b/Framework/Algorithms/PyramidReader.h
@@ -56,7 +56,8 @@ namespace OrthancWSI
void CheckTileSize(const Orthanc::ImageAccessor& tile) const;
- void CheckTileSize(const std::string& tile) const;
+ void CheckTileSize(const std::string& tile,
+ ImageCompression compression) const;
SourceTile& AccessSourceTile(const Location& location);
@@ -77,17 +78,13 @@ namespace OrthancWSI
return parameters_;
}
- ImageCompression GetImageCompression() const
- {
- return source_.GetImageCompression();
- }
-
Orthanc::PixelFormat GetPixelFormat() const
{
return source_.GetPixelFormat();
}
- const std::string* GetRawTile(unsigned int tileX,
+ const std::string* GetRawTile(ImageCompression& compression,
+ unsigned int tileX,
unsigned int tileY);
Orthanc::ImageAccessor GetDecodedTile(unsigned int tileX,
diff --git a/Framework/Algorithms/ReconstructPyramidCommand.cpp b/Framework/Algorithms/ReconstructPyramidCommand.cpp
index fd4f368..5c85d4d 100644
--- a/Framework/Algorithms/ReconstructPyramidCommand.cpp
+++ b/Framework/Algorithms/ReconstructPyramidCommand.cpp
@@ -22,9 +22,9 @@
#include "ReconstructPyramidCommand.h"
#include "../ImageToolbox.h"
-#include "../Orthanc/Core/Logging.h"
-#include "../Orthanc/Core/OrthancException.h"
-#include "../Orthanc/Core/Images/Image.h"
+#include "../../Resources/Orthanc/Core/Logging.h"
+#include "../../Resources/Orthanc/Core/OrthancException.h"
+#include "../../Resources/Orthanc/Core/Images/Image.h"
#include <cassert>
@@ -51,12 +51,13 @@ namespace OrthancWSI
{
result.reset(new Orthanc::ImageAccessor(source_.GetDecodedTile(x, y)));
- const std::string* rawTile = source_.GetRawTile(x, y);
+ ImageCompression compression;
+ const std::string* rawTile = source_.GetRawTile(compression, x, y);
if (rawTile != NULL)
{
// Simple transcoding
- target_.WriteRawTile(*rawTile, source_.GetImageCompression(), level + shiftTargetLevel_, x, y);
+ target_.WriteRawTile(*rawTile, compression, level + shiftTargetLevel_, x, y);
}
else
{
diff --git a/Framework/Algorithms/ReconstructPyramidCommand.h b/Framework/Algorithms/ReconstructPyramidCommand.h
index d2f6c09..2f61c8b 100644
--- a/Framework/Algorithms/ReconstructPyramidCommand.h
+++ b/Framework/Algorithms/ReconstructPyramidCommand.h
@@ -22,7 +22,7 @@
#include "PyramidReader.h"
#include "../Outputs/IPyramidWriter.h"
-#include "../Orthanc/Core/MultiThreading/BagOfTasks.h"
+#include "../../Resources/Orthanc/Core/MultiThreading/BagOfTasks.h"
namespace OrthancWSI
diff --git a/Framework/Algorithms/TranscodeTileCommand.cpp b/Framework/Algorithms/TranscodeTileCommand.cpp
index 4409c0a..0c4f54d 100644
--- a/Framework/Algorithms/TranscodeTileCommand.cpp
+++ b/Framework/Algorithms/TranscodeTileCommand.cpp
@@ -21,8 +21,8 @@
#include "../PrecompiledHeadersWSI.h"
#include "TranscodeTileCommand.h"
-#include "../Orthanc/Core/OrthancException.h"
-#include "../Orthanc/Core/Logging.h"
+#include "../../Resources/Orthanc/Core/OrthancException.h"
+#include "../../Resources/Orthanc/Core/Logging.h"
#include <cassert>
@@ -61,12 +61,14 @@ namespace OrthancWSI
for (unsigned int y = y_; y < y_ + countTilesY_; y++)
{
LOG(INFO) << "Adding tile (" << x << "," << y << ") at level " << level_;
- const std::string* rawTile = source_.GetRawTile(x, y);
+
+ ImageCompression compression;
+ const std::string* rawTile = source_.GetRawTile(compression, x, y);
if (rawTile != NULL)
{
// Simple transcoding
- target_.WriteRawTile(*rawTile, source_.GetImageCompression(), level_, x, y);
+ target_.WriteRawTile(*rawTile, compression, level_, x, y);
}
else
{
diff --git a/Framework/Algorithms/TranscodeTileCommand.h b/Framework/Algorithms/TranscodeTileCommand.h
index 7136140..8e9b7b1 100644
--- a/Framework/Algorithms/TranscodeTileCommand.h
+++ b/Framework/Algorithms/TranscodeTileCommand.h
@@ -23,7 +23,7 @@
#include "PyramidReader.h"
#include "../Outputs/IPyramidWriter.h"
-#include "../Orthanc/Core/MultiThreading/BagOfTasks.h"
+#include "../../Resources/Orthanc/Core/MultiThreading/BagOfTasks.h"
namespace OrthancWSI
{
diff --git a/Framework/DicomToolbox.cpp b/Framework/DicomToolbox.cpp
index 1130a30..c35bc76 100644
--- a/Framework/DicomToolbox.cpp
+++ b/Framework/DicomToolbox.cpp
@@ -21,17 +21,15 @@
#include "PrecompiledHeadersWSI.h"
#include "DicomToolbox.h"
-#include "Orthanc/Core/Logging.h"
-#include "Orthanc/Core/OrthancException.h"
-#include "Orthanc/Core/Toolbox.h"
+#include "../Resources/Orthanc/Core/Logging.h"
+#include "../Resources/Orthanc/Core/OrthancException.h"
+#include "../Resources/Orthanc/Core/Toolbox.h"
#if ORTHANC_ENABLE_DCMTK == 1
# include <dcmtk/dcmdata/dcelem.h>
# include <dcmtk/dcmdata/dcsequen.h>
#endif
-#include <boost/lexical_cast.hpp>
-
namespace OrthancWSI
{
namespace DicomToolbox
@@ -160,92 +158,5 @@ namespace OrthancWSI
}
}
#endif
-
-
- bool GetStringTag(std::string& result,
- const Json::Value& simplifiedTags,
- const std::string& tagName,
- const std::string& defaultValue)
- {
- if (simplifiedTags.type() != Json::objectValue)
- {
- throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
- }
-
- if (!simplifiedTags.isMember(tagName))
- {
- result = defaultValue;
- return false;
- }
- else if (simplifiedTags[tagName].type() != Json::stringValue)
- {
- throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
- }
- else
- {
- result = simplifiedTags[tagName].asString();
- return true;
- }
- }
-
-
- std::string GetMandatoryStringTag(const Json::Value& simplifiedTags,
- const std::string& tagName)
- {
- std::string s;
- if (GetStringTag(s, simplifiedTags, tagName, ""))
- {
- return s;
- }
- else
- {
- throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentTag);
- }
- }
-
-
- const Json::Value& GetSequenceTag(const Json::Value& simplifiedTags,
- const std::string& tagName)
- {
- if (simplifiedTags.type() != Json::objectValue ||
- !simplifiedTags.isMember(tagName) ||
- simplifiedTags[tagName].type() != Json::arrayValue)
- {
- throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
- }
-
- return simplifiedTags[tagName];
- }
-
-
- int GetIntegerTag(const Json::Value& simplifiedTags,
- const std::string& tagName)
- {
- try
- {
- std::string s = Orthanc::Toolbox::StripSpaces(GetMandatoryStringTag(simplifiedTags, tagName));
- return boost::lexical_cast<int>(s);
- }
- catch (boost::bad_lexical_cast&)
- {
- throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
- }
- }
-
-
- unsigned int GetUnsignedIntegerTag(const Json::Value& simplifiedTags,
- const std::string& tagName)
- {
- int value = GetIntegerTag(simplifiedTags, tagName);
-
- if (value >= 0)
- {
- return static_cast<unsigned int>(value);
- }
- else
- {
- throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
- }
- }
}
}
diff --git a/Framework/DicomToolbox.h b/Framework/DicomToolbox.h
index f360226..874a8b3 100644
--- a/Framework/DicomToolbox.h
+++ b/Framework/DicomToolbox.h
@@ -62,22 +62,5 @@ namespace OrthancWSI
std::string GetStringTag(DcmItem& dataset,
const DcmTagKey& key);
#endif
-
- bool GetStringTag(std::string& result,
- const Json::Value& simplifiedTags,
- const std::string& tagName,
- const std::string& defaultValue);
-
- std::string GetMandatoryStringTag(const Json::Value& simplifiedTags,
- const std::string& tagName);
-
- const Json::Value& GetSequenceTag(const Json::Value& simplifiedTags,
- const std::string& tagName);
-
- int GetIntegerTag(const Json::Value& simplifiedTags,
- const std::string& tagName);
-
- unsigned int GetUnsignedIntegerTag(const Json::Value& simplifiedTags,
- const std::string& tagName);
}
}
diff --git a/Framework/DicomizerParameters.cpp b/Framework/DicomizerParameters.cpp
index c16c403..5af659a 100644
--- a/Framework/DicomizerParameters.cpp
+++ b/Framework/DicomizerParameters.cpp
@@ -21,10 +21,10 @@
#include "PrecompiledHeadersWSI.h"
#include "DicomizerParameters.h"
-#include "Messaging/FolderTarget.h"
-#include "Messaging/OrthancTarget.h"
+#include "Targets/FolderTarget.h"
+#include "Targets/OrthancTarget.h"
-#include "Orthanc/Core/OrthancException.h"
+#include "../Resources/Orthanc/Core/OrthancException.h"
#include <boost/thread.hpp>
#include <boost/lexical_cast.hpp>
diff --git a/Framework/DicomizerParameters.h b/Framework/DicomizerParameters.h
index ede1506..4b5e668 100644
--- a/Framework/DicomizerParameters.h
+++ b/Framework/DicomizerParameters.h
@@ -22,9 +22,9 @@
#include "Inputs/ITiledPyramid.h"
#include "Outputs/IPyramidWriter.h"
-#include "Messaging/IFileTarget.h"
+#include "Targets/IFileTarget.h"
#include "DicomToolbox.h"
-#include "Orthanc/Core/WebServiceParameters.h"
+#include "../Resources/Orthanc/Core/WebServiceParameters.h"
#include <stdint.h>
diff --git a/Framework/Enumerations.cpp b/Framework/Enumerations.cpp
index 52cda01..e1ff6b5 100644
--- a/Framework/Enumerations.cpp
+++ b/Framework/Enumerations.cpp
@@ -22,8 +22,9 @@
#include "Enumerations.h"
#include "Jpeg2000Reader.h"
-#include "Orthanc/Core/OrthancException.h"
-#include "Orthanc/Core/Toolbox.h"
+#include "../Resources/Orthanc/Core/OrthancException.h"
+#include "../Resources/Orthanc/Core/SystemToolbox.h"
+#include "../Resources/Orthanc/Core/Toolbox.h"
#include <string.h>
#include <boost/algorithm/string/predicate.hpp>
@@ -82,7 +83,7 @@ namespace OrthancWSI
ImageCompression DetectFormatFromFile(const std::string& path)
{
std::string header;
- Orthanc::Toolbox::ReadHeader(header, path, 256);
+ Orthanc::SystemToolbox::ReadHeader(header, path, 256);
ImageCompression tmp = DetectFormatFromMemory(header.c_str(), header.size());
if (tmp != ImageCompression_Unknown)
diff --git a/Framework/Enumerations.h b/Framework/Enumerations.h
index 0b63f81..a4f5715 100644
--- a/Framework/Enumerations.h
+++ b/Framework/Enumerations.h
@@ -20,7 +20,7 @@
#pragma once
-#include "Orthanc/Core/Enumerations.h"
+#include "../Resources/Orthanc/Core/Enumerations.h"
#include <stdint.h>
#include <string>
diff --git a/Framework/ImageToolbox.cpp b/Framework/ImageToolbox.cpp
index 112a41a..b72b3cb 100644
--- a/Framework/ImageToolbox.cpp
+++ b/Framework/ImageToolbox.cpp
@@ -24,13 +24,13 @@
#include "Jpeg2000Reader.h"
#include "Jpeg2000Writer.h"
-#include "Orthanc/Core/OrthancException.h"
-#include "Orthanc/Core/Images/ImageProcessing.h"
-#include "Orthanc/Core/Images/PngReader.h"
-#include "Orthanc/Core/Images/PngWriter.h"
-#include "Orthanc/Core/Images/JpegReader.h"
-#include "Orthanc/Core/Images/JpegWriter.h"
-#include "Orthanc/Core/Logging.h"
+#include "../Resources/Orthanc/Core/OrthancException.h"
+#include "../Resources/Orthanc/Core/Images/ImageProcessing.h"
+#include "../Resources/Orthanc/Core/Images/PngReader.h"
+#include "../Resources/Orthanc/Core/Images/PngWriter.h"
+#include "../Resources/Orthanc/Core/Images/JpegReader.h"
+#include "../Resources/Orthanc/Core/Images/JpegWriter.h"
+#include "../Resources/Orthanc/Core/Logging.h"
#include <string.h>
#include <memory>
diff --git a/Framework/ImageToolbox.h b/Framework/ImageToolbox.h
index f18328f..91b97a9 100644
--- a/Framework/ImageToolbox.h
+++ b/Framework/ImageToolbox.h
@@ -20,7 +20,7 @@
#pragma once
-#include "Orthanc/Core/Images/ImageAccessor.h"
+#include "../Resources/Orthanc/Core/Images/ImageAccessor.h"
#include "Enumerations.h"
#include "Inputs/ITiledPyramid.h"
diff --git a/Framework/ImagedVolumeParameters.cpp b/Framework/ImagedVolumeParameters.cpp
index 93b458d..1cff542 100644
--- a/Framework/ImagedVolumeParameters.cpp
+++ b/Framework/ImagedVolumeParameters.cpp
@@ -21,7 +21,7 @@
#include "PrecompiledHeadersWSI.h"
#include "ImagedVolumeParameters.h"
-#include "Orthanc/Core/OrthancException.h"
+#include "../Resources/Orthanc/Core/OrthancException.h"
namespace OrthancWSI
{
diff --git a/Framework/Inputs/DecodedTiledPyramid.h b/Framework/Inputs/DecodedTiledPyramid.h
index b4a5676..ed89878 100644
--- a/Framework/Inputs/DecodedTiledPyramid.h
+++ b/Framework/Inputs/DecodedTiledPyramid.h
@@ -59,12 +59,8 @@ namespace OrthancWSI
unsigned int tileX,
unsigned int tileY);
- virtual ImageCompression GetImageCompression() const
- {
- return ImageCompression_None;
- }
-
virtual bool ReadRawTile(std::string& tile,
+ ImageCompression& compression,
unsigned int level,
unsigned int tileX,
unsigned int tileY)
diff --git a/Framework/Inputs/DicomPyramid.cpp b/Framework/Inputs/DicomPyramid.cpp
index b3f04e0..c73e015 100644
--- a/Framework/Inputs/DicomPyramid.cpp
+++ b/Framework/Inputs/DicomPyramid.cpp
@@ -22,8 +22,8 @@
#include "DicomPyramid.h"
#include "../DicomToolbox.h"
-#include "../Orthanc/Core/Logging.h"
-#include "../Orthanc/Core/OrthancException.h"
+#include "../../Resources/Orthanc/Core/Logging.h"
+#include "../../Resources/Orthanc/Core/OrthancException.h"
#include <algorithm>
#include <cassert>
@@ -60,17 +60,20 @@ namespace OrthancWSI
}
- void DicomPyramid::RegisterInstances(const std::string& seriesId)
+ void DicomPyramid::RegisterInstances(const std::string& seriesId,
+ bool useCache)
{
Json::Value series;
- IOrthancConnection::RestApiGet(series, orthanc_, "/series/" + seriesId);
+ OrthancPlugins::IOrthancConnection::RestApiGet(series, orthanc_, "/series/" + seriesId);
- if (series.type() != Json::objectValue)
+ if (series.type() != Json::objectValue ||
+ !series.isMember("Instances") ||
+ series["Instances"].type() != Json::arrayValue)
{
throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
}
- const Json::Value& instances = DicomToolbox::GetSequenceTag(series, "Instances");
+ const Json::Value& instances = series["Instances"];
instances_.reserve(instances.size());
for (Json::Value::ArrayIndex i = 0; i < instances.size(); i++)
@@ -84,7 +87,7 @@ namespace OrthancWSI
try
{
- instances_.push_back(new DicomPyramidInstance(orthanc_, instance));
+ instances_.push_back(new DicomPyramidInstance(orthanc_, instance, useCache));
}
catch (Orthanc::OrthancException&)
{
@@ -108,8 +111,7 @@ namespace OrthancWSI
{
const DicomPyramidInstance& b = *instances_[i];
- if (a.GetImageCompression() != b.GetImageCompression() ||
- a.GetPixelFormat() != b.GetPixelFormat() ||
+ if (a.GetPixelFormat() != b.GetPixelFormat() ||
a.GetTileWidth() != b.GetTileWidth() ||
a.GetTileHeight() != b.GetTileHeight() ||
a.GetTotalWidth() < b.GetTotalWidth() ||
@@ -136,12 +138,13 @@ namespace OrthancWSI
}
- DicomPyramid::DicomPyramid(IOrthancConnection& orthanc,
- const std::string& seriesId) :
+ DicomPyramid::DicomPyramid(OrthancPlugins::IOrthancConnection& orthanc,
+ const std::string& seriesId,
+ bool useCache) :
orthanc_(orthanc),
seriesId_(seriesId)
{
- RegisterInstances(seriesId);
+ RegisterInstances(seriesId, useCache);
// Sort the instances of the pyramid by decreasing total widths
std::sort(instances_.begin(), instances_.end(), Comparator());
@@ -201,19 +204,22 @@ namespace OrthancWSI
bool DicomPyramid::ReadRawTile(std::string& tile,
+ ImageCompression& compression,
unsigned int level,
unsigned int tileX,
unsigned int tileY)
{
CheckLevel(level);
- ImageCompression compression;
Orthanc::PixelFormat format;
- if (levels_[level]->DownloadRawTile(compression, format, tile, orthanc_, tileX, tileY))
+ if (levels_[level]->DownloadRawTile(tile, format, compression, orthanc_, tileX, tileY))
{
- assert(compression == GetImageCompression() &&
- format == GetPixelFormat());
+ if (format != GetPixelFormat())
+ {
+ throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+ }
+
return true;
}
else
@@ -223,13 +229,6 @@ namespace OrthancWSI
}
- ImageCompression DicomPyramid::GetImageCompression() const
- {
- assert(!instances_.empty() && instances_[0] != NULL);
- return instances_[0]->GetImageCompression();
- }
-
-
Orthanc::PixelFormat DicomPyramid::GetPixelFormat() const
{
assert(!instances_.empty() && instances_[0] != NULL);
diff --git a/Framework/Inputs/DicomPyramid.h b/Framework/Inputs/DicomPyramid.h
index 0232a0c..0925e09 100644
--- a/Framework/Inputs/DicomPyramid.h
+++ b/Framework/Inputs/DicomPyramid.h
@@ -31,22 +31,24 @@ namespace OrthancWSI
private:
struct Comparator;
- IOrthancConnection& orthanc_;
- std::string seriesId_;
- std::vector<DicomPyramidInstance*> instances_;
- std::vector<DicomPyramidLevel*> levels_;
+ OrthancPlugins::IOrthancConnection& orthanc_;
+ std::string seriesId_;
+ std::vector<DicomPyramidInstance*> instances_;
+ std::vector<DicomPyramidLevel*> levels_;
void Clear();
- void RegisterInstances(const std::string& seriesId);
+ void RegisterInstances(const std::string& seriesId,
+ bool useCache);
void Check(const std::string& seriesId) const;
void CheckLevel(size_t level) const;
public:
- DicomPyramid(IOrthancConnection& orthanc,
- const std::string& seriesId);
+ DicomPyramid(OrthancPlugins::IOrthancConnection& orthanc,
+ const std::string& seriesId,
+ bool useCache);
virtual ~DicomPyramid()
{
@@ -72,12 +74,11 @@ namespace OrthancWSI
virtual unsigned int GetTileHeight() const;
virtual bool ReadRawTile(std::string& tile,
+ ImageCompression& compression,
unsigned int level,
unsigned int tileX,
unsigned int tileY);
- virtual ImageCompression GetImageCompression() const;
-
virtual Orthanc::PixelFormat GetPixelFormat() const;
};
}
diff --git a/Framework/Inputs/DicomPyramidInstance.cpp b/Framework/Inputs/DicomPyramidInstance.cpp
index 2ca7665..daf48cb 100644
--- a/Framework/Inputs/DicomPyramidInstance.cpp
+++ b/Framework/Inputs/DicomPyramidInstance.cpp
@@ -21,19 +21,30 @@
#include "../PrecompiledHeadersWSI.h"
#include "DicomPyramidInstance.h"
-#include "../Orthanc/Core/Logging.h"
-#include "../Orthanc/Core/OrthancException.h"
-#include "../Orthanc/Core/Toolbox.h"
+#include "../../Resources/Orthanc/Core/Logging.h"
+#include "../../Resources/Orthanc/Core/OrthancException.h"
+#include "../../Resources/Orthanc/Core/Toolbox.h"
+#include "../../Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.h"
+#include "../../Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.h"
#include "../DicomToolbox.h"
#include <cassert>
+#include <json/writer.h>
+
+#define SERIALIZED_METADATA "4200"
namespace OrthancWSI
{
- static ImageCompression DetectImageCompression(const Json::Value& header)
+ static ImageCompression DetectImageCompression(OrthancPlugins::IOrthancConnection& orthanc,
+ const std::string& instanceId)
{
+ using namespace OrthancPlugins;
+
+ DicomDatasetReader header(new FullOrthancDataset
+ (orthanc, "/instances/" + instanceId + "/header"));
+
std::string s = Orthanc::Toolbox::StripSpaces
- (DicomToolbox::GetMandatoryStringTag(header, "TransferSyntaxUID"));
+ (header.GetMandatoryStringValue(DICOM_TAG_TRANSFER_SYNTAX_UID));
if (s == "1.2.840.10008.1.2" ||
s == "1.2.840.10008.1.2.1")
@@ -57,10 +68,12 @@ namespace OrthancWSI
}
- static Orthanc::PixelFormat DetectPixelFormat(const Json::Value& dicom)
+ static Orthanc::PixelFormat DetectPixelFormat(OrthancPlugins::DicomDatasetReader& reader)
{
+ using namespace OrthancPlugins;
+
std::string photometric = Orthanc::Toolbox::StripSpaces
- (DicomToolbox::GetMandatoryStringTag(dicom, "PhotometricInterpretation"));
+ (reader.GetMandatoryStringValue(DICOM_TAG_PHOTOMETRIC_INTERPRETATION));
if (photometric == "PALETTE")
{
@@ -68,9 +81,9 @@ namespace OrthancWSI
throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
}
- unsigned int bitsStored = DicomToolbox::GetUnsignedIntegerTag(dicom, "BitsStored");
- unsigned int samplesPerPixel = DicomToolbox::GetUnsignedIntegerTag(dicom, "SamplesPerPixel");
- bool isSigned = (DicomToolbox::GetUnsignedIntegerTag(dicom, "PixelRepresentation") != 0);
+ unsigned int bitsStored = reader.GetUnsignedIntegerValue(DICOM_TAG_BITS_STORED);
+ unsigned int samplesPerPixel = reader.GetUnsignedIntegerValue(DICOM_TAG_SAMPLES_PER_PIXEL);
+ bool isSigned = (reader.GetUnsignedIntegerValue(DICOM_TAG_PIXEL_REPRESENTATION) != 0);
if (bitsStored == 8 &&
samplesPerPixel == 1 &&
@@ -91,49 +104,75 @@ namespace OrthancWSI
}
}
+
+ ImageCompression DicomPyramidInstance::GetImageCompression(OrthancPlugins::IOrthancConnection& orthanc)
+ {
+ /**
+ * Lazy detection of the image compression using the transfer
+ * syntax stored inside the DICOM header. Given the fact that
+ * reading the header is a time-consuming operation (it implies
+ * the decoding of the DICOM image by Orthanc, whereas the "/tags"
+ * endpoint only reads the "DICOM-as-JSON" attachment), the
+ * "/header" REST call is delayed until it is really required.
+ **/
+
+ if (!hasCompression_)
+ {
+ compression_ = DetectImageCompression(orthanc, instanceId_);
+ hasCompression_ = true;
+ }
+
+ return compression_;
+ }
+
- DicomPyramidInstance::DicomPyramidInstance(IOrthancConnection& orthanc,
- const std::string& instanceId) :
- instanceId_(instanceId)
+ void DicomPyramidInstance::Load(OrthancPlugins::IOrthancConnection& orthanc,
+ const std::string& instanceId)
{
- Json::Value dicom, header;
- IOrthancConnection::RestApiGet(dicom, orthanc, "/instances/" + instanceId + "/tags?simplify");
- IOrthancConnection::RestApiGet(header, orthanc, "/instances/" + instanceId + "/header?simplify");
+ using namespace OrthancPlugins;
- if (DicomToolbox::GetMandatoryStringTag(dicom, "SOPClassUID") != "1.2.840.10008.5.1.4.1.1.77.1.6" ||
- DicomToolbox::GetMandatoryStringTag(dicom, "Modality") != "SM")
+ DicomDatasetReader reader(new FullOrthancDataset(orthanc, "/instances/" + instanceId + "/tags"));
+
+ if (reader.GetMandatoryStringValue(DICOM_TAG_SOP_CLASS_UID) != "1.2.840.10008.5.1.4.1.1.77.1.6" ||
+ reader.GetMandatoryStringValue(DICOM_TAG_MODALITY) != "SM")
{
throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
}
- compression_ = DetectImageCompression(header);
- format_ = DetectPixelFormat(dicom);
- tileWidth_ = DicomToolbox::GetUnsignedIntegerTag(dicom, "Columns");
- tileHeight_ = DicomToolbox::GetUnsignedIntegerTag(dicom, "Rows");
- totalWidth_ = DicomToolbox::GetUnsignedIntegerTag(dicom, "TotalPixelMatrixColumns");
- totalHeight_ = DicomToolbox::GetUnsignedIntegerTag(dicom, "TotalPixelMatrixRows");
+ hasCompression_ = false;
+ format_ = DetectPixelFormat(reader);
+ tileWidth_ = reader.GetUnsignedIntegerValue(DICOM_TAG_COLUMNS);
+ tileHeight_ = reader.GetUnsignedIntegerValue(DICOM_TAG_ROWS);
+ totalWidth_ = reader.GetUnsignedIntegerValue(DICOM_TAG_TOTAL_PIXEL_MATRIX_COLUMNS);
+ totalHeight_ = reader.GetUnsignedIntegerValue(DICOM_TAG_TOTAL_PIXEL_MATRIX_ROWS);
- const Json::Value& frames = DicomToolbox::GetSequenceTag(dicom, "PerFrameFunctionalGroupsSequence");
+ size_t countFrames;
+ if (!reader.GetDataset().GetSequenceSize(countFrames, DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE))
+ {
+ throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+ }
- if (frames.size() != DicomToolbox::GetUnsignedIntegerTag(dicom, "NumberOfFrames"))
+ if (countFrames != reader.GetUnsignedIntegerValue(DICOM_TAG_NUMBER_OF_FRAMES))
{
LOG(ERROR) << "Mismatch between the number of frames in instance: " << instanceId;
throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
}
- frames_.resize(frames.size());
+ frames_.resize(countFrames);
- for (Json::Value::ArrayIndex i = 0; i < frames.size(); i++)
+ for (size_t i = 0; i < countFrames; i++)
{
- const Json::Value& frame = DicomToolbox::GetSequenceTag(frames[i], "PlanePositionSlideSequence");
- if (frame.size() != 1)
- {
- throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
- }
+ int xx = reader.GetIntegerValue(DicomPath(DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE, i,
+ DICOM_TAG_PLANE_POSITION_SLIDE_SEQUENCE, 0,
+ DICOM_TAG_COLUMN_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX));
+
+ int yy = reader.GetIntegerValue(DicomPath(DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE, i,
+ DICOM_TAG_PLANE_POSITION_SLIDE_SEQUENCE, 0,
+ DICOM_TAG_ROW_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX));
// "-1", because coordinates are shifted by 1 in DICOM
- int xx = DicomToolbox::GetIntegerTag(frame[0], "ColumnPositionInTotalImagePixelMatrix") - 1;
- int yy = DicomToolbox::GetIntegerTag(frame[0], "RowPositionInTotalImagePixelMatrix") - 1;
+ xx -= 1;
+ yy -= 1;
unsigned int x = static_cast<unsigned int>(xx);
unsigned int y = static_cast<unsigned int>(yy);
@@ -156,6 +195,41 @@ namespace OrthancWSI
}
+ DicomPyramidInstance::DicomPyramidInstance(OrthancPlugins::IOrthancConnection& orthanc,
+ const std::string& instanceId,
+ bool useCache) :
+ instanceId_(instanceId),
+ hasCompression_(false)
+ {
+ if (useCache)
+ {
+ try
+ {
+ // Try and deserialized the cached information about this instance
+ std::string serialized;
+ orthanc.RestApiGet(serialized, "/instances/" + instanceId + "/metadata/" + SERIALIZED_METADATA);
+ Deserialize(serialized);
+ return; // Success
+ }
+ catch (Orthanc::OrthancException&)
+ {
+ // No cached information yet
+ }
+ }
+
+ // Compute information about this instance from scratch
+ Load(orthanc, instanceId);
+
+ if (useCache)
+ {
+ // Serialize the computed information and cache it as a metadata
+ std::string serialized, tmp;
+ Serialize(serialized);
+ orthanc.RestApiPut(tmp, "/instances/" + instanceId + "/metadata/" + SERIALIZED_METADATA, serialized);
+ }
+ }
+
+
unsigned int DicomPyramidInstance::GetFrameLocationX(size_t frame) const
{
assert(frame < frames_.size());
@@ -168,4 +242,111 @@ namespace OrthancWSI
assert(frame < frames_.size());
return frames_[frame].second;
}
+
+
+ void DicomPyramidInstance::Serialize(std::string& result) const
+ {
+ Json::Value frames = Json::arrayValue;
+ for (size_t i = 0; i < frames_.size(); i++)
+ {
+ Json::Value frame = Json::arrayValue;
+ frame.append(frames_[i].first);
+ frame.append(frames_[i].second);
+
+ frames.append(frame);
+ }
+
+ Json::Value content;
+ content["Frames"] = frames;
+ content["TileHeight"] = tileHeight_;
+ content["TileWidth"] = tileWidth_;
+ content["TotalHeight"] = totalHeight_;
+ content["TotalWidth"] = totalWidth_;
+
+ switch (format_)
+ {
+ case Orthanc::PixelFormat_RGB24:
+ content["PixelFormat"] = 0;
+ break;
+
+ case Orthanc::PixelFormat_Grayscale8:
+ content["PixelFormat"] = 1;
+ break;
+
+ default:
+ throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
+ }
+
+ Json::FastWriter writer;
+ result = writer.write(content);
+ }
+
+
+ void DicomPyramidInstance::Deserialize(const std::string& s)
+ {
+ hasCompression_ = false;
+
+ Json::Value content;
+ OrthancPlugins::IOrthancConnection::ParseJson(content, s);
+
+ if (content.type() != Json::objectValue ||
+ !content.isMember("Frames") ||
+ !content.isMember("PixelFormat") ||
+ !content.isMember("TileHeight") ||
+ !content.isMember("TileWidth") ||
+ !content.isMember("TotalHeight") ||
+ !content.isMember("TotalWidth") ||
+ content["Frames"].type() != Json::arrayValue ||
+ content["PixelFormat"].type() != Json::intValue ||
+ content["TileHeight"].type() != Json::intValue ||
+ content["TileWidth"].type() != Json::intValue ||
+ content["TotalHeight"].type() != Json::intValue ||
+ content["TotalWidth"].type() != Json::intValue ||
+ content["TileHeight"].asInt() < 0 ||
+ content["TileWidth"].asInt() < 0 ||
+ content["TotalHeight"].asInt() < 0 ||
+ content["TotalWidth"].asInt() < 0)
+ {
+ throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+ }
+
+ switch (content["PixelFormat"].asInt())
+ {
+ case 0:
+ format_ = Orthanc::PixelFormat_RGB24;
+ break;
+
+ case 1:
+ format_ = Orthanc::PixelFormat_Grayscale8;
+ break;
+
+ default:
+ throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
+ }
+
+ hasCompression_ = false;
+ tileHeight_ = static_cast<unsigned int>(content["TileHeight"].asInt());
+ tileWidth_ = static_cast<unsigned int>(content["TileWidth"].asInt());
+ totalHeight_ = static_cast<unsigned int>(content["TotalHeight"].asInt());
+ totalWidth_ = static_cast<unsigned int>(content["TotalWidth"].asInt());
+
+ const Json::Value f = content["Frames"];
+ frames_.resize(f.size());
+
+ for (Json::Value::ArrayIndex i = 0; i < f.size(); i++)
+ {
+ if (f[i].type() != Json::arrayValue ||
+ f[i].size() != 2 ||
+ f[i][0].type() != Json::intValue ||
+ f[i][1].type() != Json::intValue ||
+ f[i][0].asInt() < 0 ||
+ f[i][1].asInt() < 0)
+ {
+ throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+ }
+
+ frames_[i].first = f[i][0].asInt();
+ frames_[i].second = f[i][1].asInt();
+ }
+ }
}
diff --git a/Framework/Inputs/DicomPyramidInstance.h b/Framework/Inputs/DicomPyramidInstance.h
index 8a5657a..8aced5a 100644
--- a/Framework/Inputs/DicomPyramidInstance.h
+++ b/Framework/Inputs/DicomPyramidInstance.h
@@ -21,7 +21,7 @@
#pragma once
#include "../Enumerations.h"
-#include "../Messaging/IOrthancConnection.h"
+#include "../../Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.h"
#include <boost/noncopyable.hpp>
#include <vector>
@@ -34,6 +34,7 @@ namespace OrthancWSI
typedef std::pair<unsigned int, unsigned int> FrameLocation;
std::string instanceId_;
+ bool hasCompression_;
ImageCompression compression_;
Orthanc::PixelFormat format_;
unsigned int tileWidth_;
@@ -42,19 +43,22 @@ namespace OrthancWSI
unsigned int totalHeight_;
std::vector<FrameLocation> frames_;
+ void Load(OrthancPlugins::IOrthancConnection& orthanc,
+ const std::string& instanceId);
+
+ void Deserialize(const std::string& content);
+
public:
- DicomPyramidInstance(IOrthancConnection& orthanc,
- const std::string& instanceId);
+ DicomPyramidInstance(OrthancPlugins::IOrthancConnection& orthanc,
+ const std::string& instanceId,
+ bool useCache);
const std::string& GetInstanceId() const
{
return instanceId_;
}
- ImageCompression GetImageCompression() const
- {
- return compression_;
- }
+ ImageCompression GetImageCompression(OrthancPlugins::IOrthancConnection& orthanc);
Orthanc::PixelFormat GetPixelFormat() const
{
@@ -89,5 +93,7 @@ namespace OrthancWSI
unsigned int GetFrameLocationX(size_t frame) const;
unsigned int GetFrameLocationY(size_t frame) const;
+
+ void Serialize(std::string& result) const;
};
}
diff --git a/Framework/Inputs/DicomPyramidLevel.cpp b/Framework/Inputs/DicomPyramidLevel.cpp
index 1626755..f76e7e8 100644
--- a/Framework/Inputs/DicomPyramidLevel.cpp
+++ b/Framework/Inputs/DicomPyramidLevel.cpp
@@ -21,28 +21,43 @@
#include "../PrecompiledHeadersWSI.h"
#include "DicomPyramidLevel.h"
-#include "../Orthanc/Core/Logging.h"
-#include "../Orthanc/Core/OrthancException.h"
+#include "../../Resources/Orthanc/Core/Logging.h"
+#include "../../Resources/Orthanc/Core/OrthancException.h"
#include <boost/lexical_cast.hpp>
namespace OrthancWSI
{
- void DicomPyramidLevel::RegisterFrame(const DicomPyramidInstance& instance,
+ DicomPyramidLevel::TileContent& DicomPyramidLevel::GetTileContent(unsigned int tileX,
+ unsigned int tileY)
+ {
+ if (tileX >= countTilesX_ ||
+ tileY >= countTilesY_)
+ {
+ LOG(ERROR) << "Tile location (" << tileX << "," << tileY << ") is outside the image";
+ throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+ }
+
+ return tiles_[tileY * countTilesX_ + tileX];
+ }
+
+ void DicomPyramidLevel::RegisterFrame(DicomPyramidInstance& instance,
unsigned int frame)
{
- TileLocation location(instance.GetFrameLocationX(frame),
- instance.GetFrameLocationY(frame));
+ unsigned int tileX = instance.GetFrameLocationX(frame);
+ unsigned int tileY = instance.GetFrameLocationY(frame);
+ TileContent& tile = GetTileContent(tileX, tileY);
- if (tiles_.find(location) != tiles_.end())
+ if (tile.instance_ != NULL)
{
- LOG(ERROR) << "Tile with location (" << location.first << ","
- << location.second << ") is indexed twice in level of size "
+ LOG(ERROR) << "Tile with location (" << tileX << ","
+ << tileY << ") is indexed twice in level of size "
<< totalWidth_ << "x" << totalHeight_;
throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
}
- tiles_[location] = std::make_pair(&instance, frame);
+ tile.instance_ = &instance;
+ tile.frame_ = frame;
}
@@ -50,20 +65,21 @@ namespace OrthancWSI
unsigned int tileX,
unsigned int tileY) const
{
- Tiles::const_iterator found = tiles_.find(std::make_pair(tileX, tileY));
- if (found == tiles_.end())
+ const TileContent& tmp = const_cast<DicomPyramidLevel&>(*this).GetTileContent(tileX, tileY);
+
+ if (tmp.instance_ == NULL)
{
return false;
}
else
{
- tile = found->second;
+ tile = tmp;
return true;
}
}
- DicomPyramidLevel::DicomPyramidLevel(const DicomPyramidInstance& instance) :
+ DicomPyramidLevel::DicomPyramidLevel(DicomPyramidInstance& instance) :
totalWidth_(instance.GetTotalWidth()),
totalHeight_(instance.GetTotalHeight()),
tileWidth_(instance.GetTileWidth()),
@@ -74,12 +90,16 @@ namespace OrthancWSI
{
throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
}
+
+ countTilesX_ = CeilingDivision(totalWidth_, tileWidth_);
+ countTilesY_ = CeilingDivision(totalHeight_, tileHeight_);
+ tiles_.resize(countTilesX_ * countTilesY_);
AddInstance(instance);
}
- void DicomPyramidLevel::AddInstance(const DicomPyramidInstance& instance)
+ void DicomPyramidLevel::AddInstance(DicomPyramidInstance& instance)
{
if (instance.GetTotalWidth() != totalWidth_ ||
instance.GetTotalHeight() != totalHeight_ ||
@@ -89,8 +109,6 @@ namespace OrthancWSI
throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageSize);
}
- instances_.push_back(&instance);
-
for (size_t frame = 0; frame < instance.GetFrameCount(); frame++)
{
RegisterFrame(instance, frame);
@@ -98,25 +116,25 @@ namespace OrthancWSI
}
- bool DicomPyramidLevel::DownloadRawTile(ImageCompression& compression /* out */,
+ bool DicomPyramidLevel::DownloadRawTile(std::string& raw /* out */,
Orthanc::PixelFormat& format /* out */,
- std::string& raw /* out */,
- IOrthancConnection& orthanc,
+ ImageCompression& compression /* out */,
+ OrthancPlugins::IOrthancConnection& orthanc,
unsigned int tileX,
unsigned int tileY) const
{
TileContent tile;
if (LookupTile(tile, tileX, tileY))
{
- assert(tile.first != NULL);
- const DicomPyramidInstance& instance = *tile.first;
+ assert(tile.instance_ != NULL);
+ DicomPyramidInstance& instance = *tile.instance_;
std::string uri = ("/instances/" + instance.GetInstanceId() +
- "/frames/" + boost::lexical_cast<std::string>(tile.second) + "/raw");
+ "/frames/" + boost::lexical_cast<std::string>(tile.frame_) + "/raw");
orthanc.RestApiGet(raw, uri);
- compression = instance.GetImageCompression();
+ compression = instance.GetImageCompression(orthanc);
format = instance.GetPixelFormat();
return true;
diff --git a/Framework/Inputs/DicomPyramidLevel.h b/Framework/Inputs/DicomPyramidLevel.h
index 62d79d3..a64796f 100644
--- a/Framework/Inputs/DicomPyramidLevel.h
+++ b/Framework/Inputs/DicomPyramidLevel.h
@@ -29,19 +29,30 @@ namespace OrthancWSI
class DicomPyramidLevel : public boost::noncopyable
{
private:
- typedef std::pair<unsigned int, unsigned int> TileLocation;
- typedef std::pair<const DicomPyramidInstance*, unsigned int> TileContent;
- typedef std::map<TileLocation, TileContent> Tiles;
- typedef std::list<const DicomPyramidInstance*> Instances;
-
- unsigned int totalWidth_;
- unsigned int totalHeight_;
- unsigned int tileWidth_;
- unsigned int tileHeight_;
- Instances instances_;
- Tiles tiles_;
-
- void RegisterFrame(const DicomPyramidInstance& instance,
+ struct TileContent
+ {
+ DicomPyramidInstance* instance_;
+ unsigned int frame_;
+
+ TileContent() :
+ instance_(NULL),
+ frame_(0)
+ {
+ }
+ };
+
+ unsigned int totalWidth_;
+ unsigned int totalHeight_;
+ unsigned int tileWidth_;
+ unsigned int tileHeight_;
+ unsigned int countTilesX_;
+ unsigned int countTilesY_;
+ std::vector<TileContent> tiles_;
+
+ TileContent& GetTileContent(unsigned int tileX,
+ unsigned int tileY);
+
+ void RegisterFrame(DicomPyramidInstance& instance,
unsigned int frame);
bool LookupTile(TileContent& tile,
@@ -49,9 +60,9 @@ namespace OrthancWSI
unsigned int tileY) const;
public:
- DicomPyramidLevel(const DicomPyramidInstance& instance);
+ DicomPyramidLevel(DicomPyramidInstance& instance);
- void AddInstance(const DicomPyramidInstance& instance);
+ void AddInstance(DicomPyramidInstance& instance);
unsigned int GetTotalWidth() const
{
@@ -73,10 +84,10 @@ namespace OrthancWSI
return tileHeight_;
}
- bool DownloadRawTile(ImageCompression& compression /* out */,
+ bool DownloadRawTile(std::string& raw /* out */,
Orthanc::PixelFormat& format /* out */,
- std::string& raw /* out */,
- IOrthancConnection& orthanc,
+ ImageCompression& compression /* out */,
+ OrthancPlugins::IOrthancConnection& orthanc,
unsigned int tileX,
unsigned int tileY) const;
};
diff --git a/Framework/Inputs/HierarchicalTiff.cpp b/Framework/Inputs/HierarchicalTiff.cpp
index edc4919..a8505ec 100644
--- a/Framework/Inputs/HierarchicalTiff.cpp
+++ b/Framework/Inputs/HierarchicalTiff.cpp
@@ -21,8 +21,8 @@
#include "../PrecompiledHeadersWSI.h"
#include "HierarchicalTiff.h"
-#include "../Orthanc/Core/Logging.h"
-#include "../Orthanc/Core/OrthancException.h"
+#include "../../Resources/Orthanc/Core/Logging.h"
+#include "../../Resources/Orthanc/Core/OrthancException.h"
#include <iostream>
#include <algorithm>
@@ -245,6 +245,7 @@ namespace OrthancWSI
bool HierarchicalTiff::ReadRawTile(std::string& tile,
+ ImageCompression& compression,
unsigned int level,
unsigned int tileX,
unsigned int tileY)
@@ -253,6 +254,8 @@ namespace OrthancWSI
CheckLevel(level);
+ compression = compression_;
+
// Make the TIFF context point to the level of interest
if (!TIFFSetDirectory(tiff_, levels_[level].directory_))
{
diff --git a/Framework/Inputs/HierarchicalTiff.h b/Framework/Inputs/HierarchicalTiff.h
index 6d3b6b8..3cf8ef0 100644
--- a/Framework/Inputs/HierarchicalTiff.h
+++ b/Framework/Inputs/HierarchicalTiff.h
@@ -94,18 +94,19 @@ namespace OrthancWSI
}
virtual bool ReadRawTile(std::string& tile,
+ ImageCompression& compression,
unsigned int level,
unsigned int tileX,
unsigned int tileY);
- virtual ImageCompression GetImageCompression() const
+ virtual Orthanc::PixelFormat GetPixelFormat() const
{
- return compression_;
+ return pixelFormat_;
}
- virtual Orthanc::PixelFormat GetPixelFormat() const
+ ImageCompression GetImageCompression()
{
- return pixelFormat_;
+ return compression_;
}
};
}
diff --git a/Framework/Inputs/ITiledPyramid.h b/Framework/Inputs/ITiledPyramid.h
index 7efa495..42b277c 100644
--- a/Framework/Inputs/ITiledPyramid.h
+++ b/Framework/Inputs/ITiledPyramid.h
@@ -22,7 +22,7 @@
#include "../Enumerations.h"
-#include "../Orthanc/Core/Images/ImageAccessor.h"
+#include "../../Resources/Orthanc/Core/Images/ImageAccessor.h"
#include <boost/noncopyable.hpp>
#include <string>
@@ -52,6 +52,7 @@ namespace OrthancWSI
virtual unsigned int GetTileHeight() const = 0;
virtual bool ReadRawTile(std::string& tile,
+ ImageCompression& compression,
unsigned int level,
unsigned int tileX,
unsigned int tileY) = 0;
@@ -60,9 +61,6 @@ namespace OrthancWSI
unsigned int tileX,
unsigned int tileY) = 0;
- // Only makes sense for images with raw access to tiles
- virtual ImageCompression GetImageCompression() const = 0;
-
virtual Orthanc::PixelFormat GetPixelFormat() const = 0;
};
}
diff --git a/Framework/Inputs/OpenSlideLibrary.cpp b/Framework/Inputs/OpenSlideLibrary.cpp
index b741f6c..babdfa9 100644
--- a/Framework/Inputs/OpenSlideLibrary.cpp
+++ b/Framework/Inputs/OpenSlideLibrary.cpp
@@ -21,8 +21,8 @@
#include "../PrecompiledHeadersWSI.h"
#include "OpenSlideLibrary.h"
-#include "../Orthanc/Core/Logging.h"
-#include "../Orthanc/Core/Images/Image.h"
+#include "../../Resources/Orthanc/Core/Logging.h"
+#include "../../Resources/Orthanc/Core/Images/Image.h"
namespace OrthancWSI
{
diff --git a/Framework/Inputs/OpenSlideLibrary.h b/Framework/Inputs/OpenSlideLibrary.h
index ac77998..f48eba9 100644
--- a/Framework/Inputs/OpenSlideLibrary.h
+++ b/Framework/Inputs/OpenSlideLibrary.h
@@ -20,8 +20,8 @@
#pragma once
-#include "../Orthanc/Plugins/Engine/SharedLibrary.h"
-#include "../Orthanc/Core/Images/ImageAccessor.h"
+#include "../../Resources/Orthanc/Plugins/Engine/SharedLibrary.h"
+#include "../../Resources/Orthanc/Core/Images/ImageAccessor.h"
#include <vector>
diff --git a/Framework/Inputs/OpenSlidePyramid.cpp b/Framework/Inputs/OpenSlidePyramid.cpp
index c816044..a9c95fa 100644
--- a/Framework/Inputs/OpenSlidePyramid.cpp
+++ b/Framework/Inputs/OpenSlidePyramid.cpp
@@ -21,9 +21,9 @@
#include "../PrecompiledHeadersWSI.h"
#include "OpenSlidePyramid.h"
-#include "../Orthanc/Core/Images/ImageProcessing.h"
-#include "../Orthanc/Core/OrthancException.h"
-#include "../Orthanc/Core/Logging.h"
+#include "../../Resources/Orthanc/Core/Images/ImageProcessing.h"
+#include "../../Resources/Orthanc/Core/OrthancException.h"
+#include "../../Resources/Orthanc/Core/Logging.h"
namespace OrthancWSI
{
diff --git a/Framework/Inputs/PyramidWithRawTiles.cpp b/Framework/Inputs/PyramidWithRawTiles.cpp
index 5342491..90a9104 100644
--- a/Framework/Inputs/PyramidWithRawTiles.cpp
+++ b/Framework/Inputs/PyramidWithRawTiles.cpp
@@ -21,9 +21,9 @@
#include "../PrecompiledHeadersWSI.h"
#include "PyramidWithRawTiles.h"
-#include "../Orthanc/Core/Images/PngReader.h"
-#include "../Orthanc/Core/Images/JpegReader.h"
-#include "../Orthanc/Core/OrthancException.h"
+#include "../../Resources/Orthanc/Core/Images/PngReader.h"
+#include "../../Resources/Orthanc/Core/Images/JpegReader.h"
+#include "../../Resources/Orthanc/Core/OrthancException.h"
#include "../Jpeg2000Reader.h"
namespace OrthancWSI
@@ -33,14 +33,16 @@ namespace OrthancWSI
unsigned int tileY)
{
std::string tile;
- if (!ReadRawTile(tile, level, tileX, tileY))
+ ImageCompression compression;
+
+ if (!ReadRawTile(tile, compression, level, tileX, tileY))
{
- throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+ return NULL;
}
std::auto_ptr<Orthanc::ImageAccessor> result;
- switch (GetImageCompression())
+ switch (compression)
{
case ImageCompression_None:
result.reset(new Orthanc::ImageAccessor);
diff --git a/Framework/Inputs/SingleLevelDecodedPyramid.cpp b/Framework/Inputs/SingleLevelDecodedPyramid.cpp
index 8bb55eb..6532198 100644
--- a/Framework/Inputs/SingleLevelDecodedPyramid.cpp
+++ b/Framework/Inputs/SingleLevelDecodedPyramid.cpp
@@ -22,7 +22,7 @@
#include "SingleLevelDecodedPyramid.h"
#include "../ImageToolbox.h"
-#include "../Orthanc/Core/OrthancException.h"
+#include "../../Resources/Orthanc/Core/OrthancException.h"
namespace OrthancWSI
{
diff --git a/Framework/Inputs/TiledJpegImage.h b/Framework/Inputs/TiledJpegImage.h
index 4414d8d..c3585ad 100644
--- a/Framework/Inputs/TiledJpegImage.h
+++ b/Framework/Inputs/TiledJpegImage.h
@@ -22,7 +22,7 @@
#include "SingleLevelDecodedPyramid.h"
-#include "../Orthanc/Core/Images/JpegReader.h"
+#include "../../Resources/Orthanc/Core/Images/JpegReader.h"
namespace OrthancWSI
{
diff --git a/Framework/Inputs/TiledPngImage.h b/Framework/Inputs/TiledPngImage.h
index c8d1551..3d90678 100644
--- a/Framework/Inputs/TiledPngImage.h
+++ b/Framework/Inputs/TiledPngImage.h
@@ -22,7 +22,7 @@
#include "SingleLevelDecodedPyramid.h"
-#include "../Orthanc/Core/Images/PngReader.h"
+#include "../../Resources/Orthanc/Core/Images/PngReader.h"
namespace OrthancWSI
{
diff --git a/Framework/Inputs/TiledPyramidStatistics.cpp b/Framework/Inputs/TiledPyramidStatistics.cpp
index 405506f..da2fa29 100644
--- a/Framework/Inputs/TiledPyramidStatistics.cpp
+++ b/Framework/Inputs/TiledPyramidStatistics.cpp
@@ -21,7 +21,7 @@
#include "../PrecompiledHeadersWSI.h"
#include "TiledPyramidStatistics.h"
-#include "../Orthanc/Core/Logging.h"
+#include "../../Resources/Orthanc/Core/Logging.h"
namespace OrthancWSI
@@ -43,11 +43,12 @@ namespace OrthancWSI
bool TiledPyramidStatistics::ReadRawTile(std::string& tile,
+ ImageCompression& compression,
unsigned int level,
unsigned int tileX,
unsigned int tileY)
{
- if (source_.ReadRawTile(tile, level, tileX, tileY))
+ if (source_.ReadRawTile(tile, compression, level, tileX, tileY))
{
boost::mutex::scoped_lock lock(mutex_);
countRawAccesses_++;
diff --git a/Framework/Inputs/TiledPyramidStatistics.h b/Framework/Inputs/TiledPyramidStatistics.h
index 7b5917d..bdecde6 100644
--- a/Framework/Inputs/TiledPyramidStatistics.h
+++ b/Framework/Inputs/TiledPyramidStatistics.h
@@ -30,7 +30,7 @@ namespace OrthancWSI
{
private:
boost::mutex mutex_;
- ITiledPyramid& source_;
+ ITiledPyramid& source_; // This is a facade design pattern
unsigned int countRawAccesses_;
unsigned int countDecodedTiles_;
@@ -64,17 +64,13 @@ namespace OrthancWSI
return source_.GetTileHeight();
}
- virtual ImageCompression GetImageCompression() const
- {
- return source_.GetImageCompression();
- }
-
virtual Orthanc::PixelFormat GetPixelFormat() const
{
return source_.GetPixelFormat();
}
virtual bool ReadRawTile(std::string& tile,
+ ImageCompression& compression,
unsigned int level,
unsigned int tileX,
unsigned int tileY);
diff --git a/Framework/Jpeg2000Reader.cpp b/Framework/Jpeg2000Reader.cpp
index 41637e2..38579bd 100644
--- a/Framework/Jpeg2000Reader.cpp
+++ b/Framework/Jpeg2000Reader.cpp
@@ -21,8 +21,8 @@
#include "PrecompiledHeadersWSI.h"
#include "Jpeg2000Reader.h"
-#include "Orthanc/Core/OrthancException.h"
-#include "Orthanc/Core/Toolbox.h"
+#include "../Resources/Orthanc/Core/OrthancException.h"
+#include "../Resources/Orthanc/Core/SystemToolbox.h"
#include "ImageToolbox.h"
#include <cassert>
@@ -460,7 +460,7 @@ namespace OrthancWSI
// TODO Use opj_stream_create_file_stream() ?
std::string content;
- Orthanc::Toolbox::ReadFile(content, filename);
+ Orthanc::SystemToolbox::ReadFile(content, filename);
}
diff --git a/Framework/Jpeg2000Reader.h b/Framework/Jpeg2000Reader.h
index dd59358..beba04f 100644
--- a/Framework/Jpeg2000Reader.h
+++ b/Framework/Jpeg2000Reader.h
@@ -20,7 +20,7 @@
#pragma once
-#include "Orthanc/Core/Images/Image.h"
+#include "../Resources/Orthanc/Core/Images/Image.h"
#include <memory>
namespace OrthancWSI
diff --git a/Framework/Jpeg2000Writer.cpp b/Framework/Jpeg2000Writer.cpp
index 2b0a977..0757efc 100644
--- a/Framework/Jpeg2000Writer.cpp
+++ b/Framework/Jpeg2000Writer.cpp
@@ -21,8 +21,8 @@
#include "PrecompiledHeadersWSI.h"
#include "Jpeg2000Writer.h"
-#include "Orthanc/Core/ChunkedBuffer.h"
-#include "Orthanc/Core/OrthancException.h"
+#include "../Resources/Orthanc/Core/ChunkedBuffer.h"
+#include "../Resources/Orthanc/Core/OrthancException.h"
#include <openjpeg.h>
#include <string.h>
diff --git a/Framework/Jpeg2000Writer.h b/Framework/Jpeg2000Writer.h
index 268a9b3..315f66c 100644
--- a/Framework/Jpeg2000Writer.h
+++ b/Framework/Jpeg2000Writer.h
@@ -20,7 +20,7 @@
#pragma once
-#include "Orthanc/Core/Images/IImageWriter.h"
+#include "../Resources/Orthanc/Core/Images/IImageWriter.h"
namespace OrthancWSI
{
diff --git a/Framework/Messaging/CurlOrthancConnection.cpp b/Framework/Messaging/CurlOrthancConnection.cpp
deleted file mode 100644
index 55c669f..0000000
--- a/Framework/Messaging/CurlOrthancConnection.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, 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 "../PrecompiledHeadersWSI.h"
-#include "CurlOrthancConnection.h"
-
-#include "../Orthanc/Core/OrthancException.h"
-
-namespace OrthancWSI
-{
- void CurlOrthancConnection::ApplyGet(std::string& result,
- const std::string& uri)
- {
- Orthanc::HttpClient client(parameters_, uri);
-
- // Don't follow 3xx HTTP (avoid redirections to "unsupported.png" in Orthanc)
- client.SetRedirectionFollowed(false);
-
- if (!client.Apply(result))
- {
- throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource);
- }
- }
-
- void CurlOrthancConnection::ApplyPost(std::string& result,
- const std::string& uri,
- const std::string& body)
- {
- Orthanc::HttpClient client(parameters_, uri);
-
- client.SetMethod(Orthanc::HttpMethod_Post);
- client.SetBody(body);
-
- // Don't follow 3xx HTTP (avoid redirections to "unsupported.png" in Orthanc)
- client.SetRedirectionFollowed(false);
-
- if (!client.Apply(result))
- {
- throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource);
- }
- }
-}
diff --git a/Framework/Messaging/CurlOrthancConnection.h b/Framework/Messaging/CurlOrthancConnection.h
deleted file mode 100644
index e9333a0..0000000
--- a/Framework/Messaging/CurlOrthancConnection.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, 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 "OrthancConnectionBase.h"
-
-#include "../Orthanc/Core/HttpClient.h"
-
-namespace OrthancWSI
-{
- class CurlOrthancConnection : public OrthancConnectionBase
- {
- private:
- Orthanc::WebServiceParameters parameters_;
-
- protected:
- virtual void ApplyGet(std::string& result,
- const std::string& uri);
-
- virtual void ApplyPost(std::string& result,
- const std::string& uri,
- const std::string& body);
-
- public:
- CurlOrthancConnection(const Orthanc::WebServiceParameters& parameters) :
- parameters_(parameters)
- {
- }
-
- const Orthanc::WebServiceParameters& GetParameters() const
- {
- return parameters_;
- }
- };
-}
diff --git a/Framework/Messaging/IOrthancConnection.cpp b/Framework/Messaging/IOrthancConnection.cpp
deleted file mode 100644
index d414cfa..0000000
--- a/Framework/Messaging/IOrthancConnection.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, 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 "../PrecompiledHeadersWSI.h"
-#include "IOrthancConnection.h"
-
-#include "../Orthanc/Core/Logging.h"
-#include "../Orthanc/Core/OrthancException.h"
-
-#include <json/reader.h>
-
-
-namespace OrthancWSI
-{
- void IOrthancConnection::RestApiGet(Json::Value& result,
- IOrthancConnection& orthanc,
- const std::string& uri)
- {
- std::string content;
- orthanc.RestApiGet(content, uri);
-
- Json::Reader reader;
- if (!reader.parse(content, result))
- {
- LOG(ERROR) << "Cannot parse a JSON file";
- throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
- }
- }
-
-
- void IOrthancConnection::RestApiPost(Json::Value& result,
- IOrthancConnection& orthanc,
- const std::string& uri,
- const std::string& body)
- {
- std::string content;
- orthanc.RestApiPost(content, uri, body);
-
- Json::Reader reader;
- if (!reader.parse(content, result))
- {
- LOG(ERROR) << "Cannot parse a JSON file";
- throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
- }
- }
-}
diff --git a/Framework/Messaging/IOrthancConnection.h b/Framework/Messaging/IOrthancConnection.h
deleted file mode 100644
index 8b9fc84..0000000
--- a/Framework/Messaging/IOrthancConnection.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, 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 <boost/noncopyable.hpp>
-#include <json/value.h>
-
-namespace OrthancWSI
-{
- // Derived classes must be thread-safe
- class IOrthancConnection : public boost::noncopyable
- {
- public:
- virtual ~IOrthancConnection()
- {
- }
-
- virtual void RestApiGet(std::string& result,
- const std::string& uri) = 0;
-
- virtual void RestApiPost(std::string& result,
- const std::string& uri,
- const std::string& body) = 0;
-
- static void RestApiGet(Json::Value& result,
- IOrthancConnection& orthanc,
- const std::string& uri);
-
- static void RestApiPost(Json::Value& result,
- IOrthancConnection& orthanc,
- const std::string& uri,
- const std::string& body);
- };
-}
diff --git a/Framework/Messaging/OrthancConnectionBase.cpp b/Framework/Messaging/OrthancConnectionBase.cpp
deleted file mode 100644
index 35fdb20..0000000
--- a/Framework/Messaging/OrthancConnectionBase.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, 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 "../PrecompiledHeadersWSI.h"
-#include "OrthancConnectionBase.h"
-
-namespace OrthancWSI
-{
- void OrthancConnectionBase::RestApiGet(std::string& result,
- const std::string& uri)
- {
- boost::mutex::scoped_lock lock_;
- ApplyGet(result, uri);
- }
-
-
- void OrthancConnectionBase::RestApiPost(std::string& result,
- const std::string& uri,
- const std::string& body)
- {
- boost::mutex::scoped_lock lock_;
- ApplyPost(result, uri, body);
- }
-}
diff --git a/Framework/Messaging/OrthancConnectionBase.h b/Framework/Messaging/OrthancConnectionBase.h
deleted file mode 100644
index 0a71373..0000000
--- a/Framework/Messaging/OrthancConnectionBase.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, 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 "IOrthancConnection.h"
-
-#include <boost/thread/mutex.hpp>
-
-namespace OrthancWSI
-{
- class OrthancConnectionBase : public IOrthancConnection
- {
- private:
- boost::mutex mutex_;
-
- protected:
- // Will be invoked in mutual exclusion
- virtual void ApplyGet(std::string& result,
- const std::string& uri) = 0;
-
- virtual void ApplyPost(std::string& result,
- const std::string& uri,
- const std::string& body) = 0;
-
- public:
- virtual void RestApiGet(std::string& result,
- const std::string& uri);
-
- virtual void RestApiPost(std::string& result,
- const std::string& uri,
- const std::string& body);
- };
-}
diff --git a/Framework/Messaging/PluginOrthancConnection.cpp b/Framework/Messaging/PluginOrthancConnection.cpp
deleted file mode 100644
index 262cfab..0000000
--- a/Framework/Messaging/PluginOrthancConnection.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, 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 "../PrecompiledHeadersWSI.h"
-#include "PluginOrthancConnection.h"
-
-#include "../Orthanc/Core/OrthancException.h"
-
-namespace OrthancWSI
-{
- class PluginOrthancConnection::MemoryBuffer : public boost::noncopyable
- {
- private:
- OrthancPluginContext* context_;
- OrthancPluginMemoryBuffer buffer_;
-
- void Clear()
- {
- if (buffer_.data != NULL)
- {
- OrthancPluginFreeMemoryBuffer(context_, &buffer_);
- buffer_.data = NULL;
- buffer_.size = 0;
- }
- }
-
-
- public:
- MemoryBuffer(OrthancPluginContext* context) :
- context_(context)
- {
- buffer_.data = NULL;
- buffer_.size = 0;
- }
-
- ~MemoryBuffer()
- {
- Clear();
- }
-
- void RestApiGet(const std::string& uri)
- {
- Clear();
-
- OrthancPluginErrorCode error = OrthancPluginRestApiGet(context_, &buffer_, uri.c_str());
-
- if (error == OrthancPluginErrorCode_Success)
- {
- // OK, success
- }
- else if (error == OrthancPluginErrorCode_UnknownResource ||
- error == OrthancPluginErrorCode_InexistentItem)
- {
- throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource);
- }
- else
- {
- throw Orthanc::OrthancException(Orthanc::ErrorCode_Plugin);
- }
- }
-
- void RestApiPost(const std::string& uri,
- const std::string& body)
- {
- Clear();
-
- OrthancPluginErrorCode error = OrthancPluginRestApiPost(context_, &buffer_, uri.c_str(), body.c_str(), body.size());
-
- if (error == OrthancPluginErrorCode_Success)
- {
- // OK, success
- }
- else if (error == OrthancPluginErrorCode_UnknownResource ||
- error == OrthancPluginErrorCode_InexistentItem)
- {
- throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource);
- }
- else
- {
- throw Orthanc::OrthancException(Orthanc::ErrorCode_Plugin);
- }
- }
-
- void ToString(std::string& target) const
- {
- if (buffer_.size == 0)
- {
- target.clear();
- }
- else
- {
- target.assign(reinterpret_cast<const char*>(buffer_.data), buffer_.size);
- }
- }
- };
-
-
-
- void PluginOrthancConnection::ApplyGet(std::string& result,
- const std::string& uri)
- {
- MemoryBuffer buffer(context_);
- buffer.RestApiGet(uri);
- buffer.ToString(result);
- }
-
-
- void PluginOrthancConnection::ApplyPost(std::string& result,
- const std::string& uri,
- const std::string& body)
- {
- MemoryBuffer buffer(context_);
- buffer.RestApiPost(uri, body);
- buffer.ToString(result);
- }
-}
diff --git a/Framework/Messaging/PluginOrthancConnection.h b/Framework/Messaging/PluginOrthancConnection.h
deleted file mode 100644
index d2bdf43..0000000
--- a/Framework/Messaging/PluginOrthancConnection.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, 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 "OrthancConnectionBase.h"
-
-#include <orthanc/OrthancCPlugin.h>
-
-namespace OrthancWSI
-{
- class PluginOrthancConnection : public OrthancConnectionBase
- {
- private:
- class MemoryBuffer;
-
- OrthancPluginContext* context_;
-
- protected:
- virtual void ApplyGet(std::string& result,
- const std::string& uri);
-
- virtual void ApplyPost(std::string& result,
- const std::string& uri,
- const std::string& body);
-
- public:
- PluginOrthancConnection(OrthancPluginContext* context) :
- context_(context)
- {
- }
- };
-}
diff --git a/Framework/Orthanc/Core/Uuid.cpp b/Framework/Orthanc/Core/Uuid.cpp
deleted file mode 100644
index 8681095..0000000
--- a/Framework/Orthanc/Core/Uuid.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, 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/>.
- **/
-
-
-#include "PrecompiledHeaders.h"
-#include "Uuid.h"
-
-// http://stackoverflow.com/a/1626302
-
-extern "C"
-{
-#ifdef WIN32
-#include <rpc.h>
-#else
-#include <uuid/uuid.h>
-#endif
-}
-
-#include <boost/filesystem.hpp>
-
-namespace Orthanc
-{
- namespace Toolbox
- {
- std::string GenerateUuid()
- {
-#ifdef WIN32
- UUID uuid;
- UuidCreate ( &uuid );
-
- unsigned char * str;
- UuidToStringA ( &uuid, &str );
-
- std::string s( ( char* ) str );
-
- RpcStringFreeA ( &str );
-#else
- uuid_t uuid;
- uuid_generate_random ( uuid );
- char s[37];
- uuid_unparse ( uuid, s );
-#endif
- return s;
- }
-
-
- bool IsUuid(const std::string& str)
- {
- if (str.size() != 36)
- {
- return false;
- }
-
- for (size_t i = 0; i < str.length(); i++)
- {
- if (i == 8 || i == 13 || i == 18 || i == 23)
- {
- if (str[i] != '-')
- return false;
- }
- else
- {
- if (!isalnum(str[i]))
- return false;
- }
- }
-
- return true;
- }
-
-
- bool StartsWithUuid(const std::string& str)
- {
- if (str.size() < 36)
- {
- return false;
- }
-
- if (str.size() == 36)
- {
- return IsUuid(str);
- }
-
- assert(str.size() > 36);
- if (!isspace(str[36]))
- {
- return false;
- }
-
- return IsUuid(str.substr(0, 36));
- }
-
-
- static std::string CreateTemporaryPath(const char* extension)
- {
-#if BOOST_HAS_FILESYSTEM_V3 == 1
- boost::filesystem::path tmpDir = boost::filesystem::temp_directory_path();
-#elif defined(__linux__)
- boost::filesystem::path tmpDir("/tmp");
-#else
-#error Support your platform here
-#endif
-
- // We use UUID to create unique path to temporary files
- std::string filename = "Orthanc-" + Orthanc::Toolbox::GenerateUuid();
-
- if (extension != NULL)
- {
- filename.append(extension);
- }
-
- tmpDir /= filename;
- return tmpDir.string();
- }
-
-
- TemporaryFile::TemporaryFile() :
- path_(CreateTemporaryPath(NULL))
- {
- }
-
-
- TemporaryFile::TemporaryFile(const char* extension) :
- path_(CreateTemporaryPath(extension))
- {
- }
-
-
- TemporaryFile::~TemporaryFile()
- {
- boost::filesystem::remove(path_);
- }
- }
-}
diff --git a/Framework/Outputs/DicomPyramidWriter.cpp b/Framework/Outputs/DicomPyramidWriter.cpp
index 7d887fb..53db9b5 100644
--- a/Framework/Outputs/DicomPyramidWriter.cpp
+++ b/Framework/Outputs/DicomPyramidWriter.cpp
@@ -23,9 +23,9 @@
#include "../DicomToolbox.h"
-#include "../Orthanc/Core/Logging.h"
-#include "../Orthanc/Core/OrthancException.h"
-#include "../Orthanc/OrthancServer/FromDcmtkBridge.h"
+#include "../../Resources/Orthanc/Core/Logging.h"
+#include "../../Resources/Orthanc/Core/OrthancException.h"
+#include "../../Resources/Orthanc/OrthancServer/FromDcmtkBridge.h"
#include <dcmtk/dcmdata/dcdeftag.h>
#include <boost/lexical_cast.hpp>
diff --git a/Framework/Outputs/DicomPyramidWriter.h b/Framework/Outputs/DicomPyramidWriter.h
index 48f3abc..f9fb8ee 100644
--- a/Framework/Outputs/DicomPyramidWriter.h
+++ b/Framework/Outputs/DicomPyramidWriter.h
@@ -22,7 +22,7 @@
#include "PyramidWriterBase.h"
#include "MultiframeDicomWriter.h"
-#include "../Messaging/IFileTarget.h"
+#include "../Targets/IFileTarget.h"
#include "../ImagedVolumeParameters.h"
namespace OrthancWSI
diff --git a/Framework/Outputs/HierarchicalTiffWriter.cpp b/Framework/Outputs/HierarchicalTiffWriter.cpp
index adb7918..5e2e5eb 100644
--- a/Framework/Outputs/HierarchicalTiffWriter.cpp
+++ b/Framework/Outputs/HierarchicalTiffWriter.cpp
@@ -21,20 +21,20 @@
#include "../PrecompiledHeadersWSI.h"
#include "HierarchicalTiffWriter.h"
-#include "../Orthanc/Core/Logging.h"
-#include "../Orthanc/Core/OrthancException.h"
-#include "../Orthanc/Core/Uuid.h"
+#include "../../Resources/Orthanc/Core/Logging.h"
+#include "../../Resources/Orthanc/Core/OrthancException.h"
+#include "../../Resources/Orthanc/Core/TemporaryFile.h"
namespace OrthancWSI
{
class HierarchicalTiffWriter::PendingTile
{
private:
- HierarchicalTiffWriter& that_;
- unsigned int level_;
- unsigned int tileX_;
- unsigned int tileY_;
- Orthanc::Toolbox::TemporaryFile file_;
+ HierarchicalTiffWriter& that_;
+ unsigned int level_;
+ unsigned int tileX_;
+ unsigned int tileY_;
+ Orthanc::TemporaryFile file_;
public:
PendingTile(HierarchicalTiffWriter& that,
diff --git a/Framework/Outputs/IPyramidWriter.h b/Framework/Outputs/IPyramidWriter.h
index 0e4229e..04dac0c 100644
--- a/Framework/Outputs/IPyramidWriter.h
+++ b/Framework/Outputs/IPyramidWriter.h
@@ -21,7 +21,7 @@
#pragma once
#include "../Enumerations.h"
-#include "../Orthanc/Core/Images/ImageAccessor.h"
+#include "../../Resources/Orthanc/Core/Images/ImageAccessor.h"
#include <boost/noncopyable.hpp>
diff --git a/Framework/Outputs/InMemoryTiledImage.cpp b/Framework/Outputs/InMemoryTiledImage.cpp
index 1990e09..283328a 100644
--- a/Framework/Outputs/InMemoryTiledImage.cpp
+++ b/Framework/Outputs/InMemoryTiledImage.cpp
@@ -22,8 +22,8 @@
#include "InMemoryTiledImage.h"
#include "../ImageToolbox.h"
-#include "../Orthanc/Core/Logging.h"
-#include "../Orthanc/Core/OrthancException.h"
+#include "../../Resources/Orthanc/Core/Logging.h"
+#include "../../Resources/Orthanc/Core/OrthancException.h"
namespace OrthancWSI
{
@@ -88,6 +88,7 @@ namespace OrthancWSI
bool InMemoryTiledImage::ReadRawTile(std::string& tile,
+ ImageCompression& compression,
unsigned int level,
unsigned int tileX,
unsigned int tileY)
diff --git a/Framework/Outputs/InMemoryTiledImage.h b/Framework/Outputs/InMemoryTiledImage.h
index da471ae..2352060 100644
--- a/Framework/Outputs/InMemoryTiledImage.h
+++ b/Framework/Outputs/InMemoryTiledImage.h
@@ -77,6 +77,7 @@ namespace OrthancWSI
}
virtual bool ReadRawTile(std::string& tile,
+ ImageCompression& compression,
unsigned int level,
unsigned int tileX,
unsigned int tileY);
@@ -85,11 +86,6 @@ namespace OrthancWSI
unsigned int tileX,
unsigned int tileY);
- virtual ImageCompression GetImageCompression() const
- {
- return ImageCompression_None;
- }
-
virtual Orthanc::PixelFormat GetPixelFormat() const
{
return format_;
diff --git a/Framework/Outputs/MultiframeDicomWriter.cpp b/Framework/Outputs/MultiframeDicomWriter.cpp
index c3dfb89..d727d40 100644
--- a/Framework/Outputs/MultiframeDicomWriter.cpp
+++ b/Framework/Outputs/MultiframeDicomWriter.cpp
@@ -21,8 +21,8 @@
#include "../PrecompiledHeadersWSI.h"
#include "MultiframeDicomWriter.h"
-#include "../Orthanc/Core/OrthancException.h"
-#include "../Orthanc/Core/Logging.h"
+#include "../../Resources/Orthanc/Core/OrthancException.h"
+#include "../../Resources/Orthanc/Core/Logging.h"
#include "../DicomToolbox.h"
#include <dcmtk/dcmdata/dcuid.h>
diff --git a/Framework/Outputs/MultiframeDicomWriter.h b/Framework/Outputs/MultiframeDicomWriter.h
index 5aafc3e..b185e94 100644
--- a/Framework/Outputs/MultiframeDicomWriter.h
+++ b/Framework/Outputs/MultiframeDicomWriter.h
@@ -21,7 +21,7 @@
#pragma once
#include "../Enumerations.h"
-#include "../Orthanc/Core/ChunkedBuffer.h"
+#include "../../Resources/Orthanc/Core/ChunkedBuffer.h"
#include <boost/noncopyable.hpp>
#include <memory>
diff --git a/Framework/Outputs/PyramidWriterBase.cpp b/Framework/Outputs/PyramidWriterBase.cpp
index b7b91bc..09394dd 100644
--- a/Framework/Outputs/PyramidWriterBase.cpp
+++ b/Framework/Outputs/PyramidWriterBase.cpp
@@ -22,8 +22,8 @@
#include "PyramidWriterBase.h"
#include "../ImageToolbox.h"
-#include "../Orthanc/Core/OrthancException.h"
-#include "../Orthanc/Core/Logging.h"
+#include "../../Resources/Orthanc/Core/OrthancException.h"
+#include "../../Resources/Orthanc/Core/Logging.h"
namespace OrthancWSI
{
diff --git a/Framework/Outputs/TruncatedPyramidWriter.cpp b/Framework/Outputs/TruncatedPyramidWriter.cpp
index ec6f9ab..802c2dc 100644
--- a/Framework/Outputs/TruncatedPyramidWriter.cpp
+++ b/Framework/Outputs/TruncatedPyramidWriter.cpp
@@ -21,7 +21,7 @@
#include "../PrecompiledHeadersWSI.h"
#include "TruncatedPyramidWriter.h"
-#include "../Orthanc/Core/OrthancException.h"
+#include "../../Resources/Orthanc/Core/OrthancException.h"
namespace OrthancWSI
{
diff --git a/Framework/PrecompiledHeadersWSI.h b/Framework/PrecompiledHeadersWSI.h
index 4232c01..55d8766 100644
--- a/Framework/PrecompiledHeadersWSI.h
+++ b/Framework/PrecompiledHeadersWSI.h
@@ -22,13 +22,12 @@
#if ORTHANC_USE_PRECOMPILED_HEADERS == 1
-#include "Orthanc/Core/PrecompiledHeaders.h"
+#include "../Resources/Orthanc/Core/PrecompiledHeaders.h"
#include "DicomToolbox.h"
#include "ImageToolbox.h"
#include "Inputs/ITiledPyramid.h"
-#include "Messaging/IFileTarget.h"
-#include "Messaging/IOrthancConnection.h"
+#include "Targets/IFileTarget.h"
#include "Outputs/IPyramidWriter.h"
#endif
diff --git a/Framework/Messaging/FolderTarget.cpp b/Framework/Targets/FolderTarget.cpp
similarity index 88%
rename from Framework/Messaging/FolderTarget.cpp
rename to Framework/Targets/FolderTarget.cpp
index a293a9c..6451e4b 100644
--- a/Framework/Messaging/FolderTarget.cpp
+++ b/Framework/Targets/FolderTarget.cpp
@@ -21,8 +21,8 @@
#include "../PrecompiledHeadersWSI.h"
#include "FolderTarget.h"
-#include "../Orthanc/Core/Toolbox.h"
-#include "../Orthanc/Core/Logging.h"
+#include "../../Resources/Orthanc/Core/SystemToolbox.h"
+#include "../../Resources/Orthanc/Core/Logging.h"
#include <stdio.h>
@@ -40,6 +40,6 @@ namespace OrthancWSI
}
LOG(INFO) << "Writing file " << path;
- Orthanc::Toolbox::WriteFile(file, path);
+ Orthanc::SystemToolbox::WriteFile(file, path);
}
}
diff --git a/Framework/Messaging/FolderTarget.h b/Framework/Targets/FolderTarget.h
similarity index 100%
rename from Framework/Messaging/FolderTarget.h
rename to Framework/Targets/FolderTarget.h
diff --git a/Framework/Messaging/IFileTarget.h b/Framework/Targets/IFileTarget.h
similarity index 100%
rename from Framework/Messaging/IFileTarget.h
rename to Framework/Targets/IFileTarget.h
diff --git a/Framework/Messaging/OrthancTarget.cpp b/Framework/Targets/OrthancTarget.cpp
similarity index 57%
rename from Framework/Messaging/OrthancTarget.cpp
rename to Framework/Targets/OrthancTarget.cpp
index 68e4295..987af94 100644
--- a/Framework/Messaging/OrthancTarget.cpp
+++ b/Framework/Targets/OrthancTarget.cpp
@@ -21,15 +21,15 @@
#include "../PrecompiledHeadersWSI.h"
#include "OrthancTarget.h"
-#include "CurlOrthancConnection.h"
#include "../DicomToolbox.h"
-#include "../Orthanc/Core/OrthancException.h"
-#include "../Orthanc/Core/Logging.h"
+#include "../../Resources/Orthanc/Core/OrthancException.h"
+#include "../../Resources/Orthanc/Core/Logging.h"
+#include "../../Resources/Orthanc/Plugins/Samples/Common/OrthancHttpConnection.h"
namespace OrthancWSI
{
OrthancTarget::OrthancTarget(const Orthanc::WebServiceParameters& parameters) :
- orthanc_(new CurlOrthancConnection(parameters)),
+ orthanc_(new OrthancPlugins::OrthancHttpConnection(parameters)),
first_(true)
{
}
@@ -38,16 +38,30 @@ namespace OrthancWSI
void OrthancTarget::Write(const std::string& file)
{
Json::Value result;
- IOrthancConnection::RestApiPost(result, *orthanc_, "/instances", file);
+ OrthancPlugins::IOrthancConnection::RestApiPost(result, *orthanc_, "/instances", file);
- std::string instanceId = DicomToolbox::GetMandatoryStringTag(result, "ID");
+ if (result.type() != Json::objectValue ||
+ !result.isMember("ID") ||
+ result["ID"].type() != Json::stringValue)
+ {
+ throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
+ }
+
+ std::string instanceId = result["ID"].asString();
if (first_)
{
Json::Value instance;
- IOrthancConnection::RestApiGet(instance, *orthanc_, "/instances/" + instanceId);
+ OrthancPlugins::IOrthancConnection::RestApiGet(instance, *orthanc_, "/instances/" + instanceId);
+
+ if (instance.type() != Json::objectValue ||
+ !instance.isMember("ParentSeries") ||
+ instance["ParentSeries"].type() != Json::stringValue)
+ {
+ throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
+ }
- std::string seriesId = DicomToolbox::GetMandatoryStringTag(instance, "ParentSeries");
+ std::string seriesId = instance["ParentSeries"].asString();
LOG(WARNING) << "ID of the whole-slide image series in Orthanc: " << seriesId;
first_ = false;
diff --git a/Framework/Messaging/OrthancTarget.h b/Framework/Targets/OrthancTarget.h
similarity index 79%
rename from Framework/Messaging/OrthancTarget.h
rename to Framework/Targets/OrthancTarget.h
index cc81671..15d333d 100644
--- a/Framework/Messaging/OrthancTarget.h
+++ b/Framework/Targets/OrthancTarget.h
@@ -21,8 +21,8 @@
#pragma once
#include "IFileTarget.h"
-#include "IOrthancConnection.h"
-#include "../Orthanc/Core/WebServiceParameters.h"
+#include "../../Resources/Orthanc/Core/WebServiceParameters.h"
+#include "../../Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.h"
#include <memory>
@@ -31,13 +31,13 @@ namespace OrthancWSI
class OrthancTarget : public IFileTarget
{
private:
- std::auto_ptr<IOrthancConnection> orthanc_;
- bool first_;
+ std::auto_ptr<OrthancPlugins::IOrthancConnection> orthanc_;
+ bool first_;
public:
OrthancTarget(const Orthanc::WebServiceParameters& parameters);
- OrthancTarget(IOrthancConnection* orthanc) : // Takes ownership
+ OrthancTarget(OrthancPlugins::IOrthancConnection* orthanc) : // Takes ownership
orthanc_(orthanc),
first_(true)
{
diff --git a/NEWS b/NEWS
index 0e56822..97f7cbf 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,16 @@ Pending changes in the mainline
===============================
+Version 0.2 (2016/11/28)
+========================
+
+* Huge speed-up in the whole-slide imaging Web viewer plugin:
+ - Reduction of the number of calls to the Orthanc REST API
+ - Cache pre-computed information for each instance as metadata
+ - Larger cache with LRU recycling to improve viewer performance
+* "OrthancWSIClearCache.py" companion script to clear the WSI cache
+* Various refactorings
+
Version 0.1 (2016/10/28)
========================
diff --git a/Resources/CMake/LibTiffConfiguration.cmake b/Resources/CMake/LibTiffConfiguration.cmake
index d35580e..77ca942 100644
--- a/Resources/CMake/LibTiffConfiguration.cmake
+++ b/Resources/CMake/LibTiffConfiguration.cmake
@@ -19,7 +19,7 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_LIBTIFF)
# include <windows.h>
# define ssize_t SSIZE_T
# endif
-# if !defined(snprintf)
+# if !defined(snprintf) && (_MSC_VER < 1900)
# define snprintf _snprintf
# endif
#endif
@@ -51,12 +51,23 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_LIBTIFF)
-DHAVE_SNPRINTF=1
-DJPEG_SUPPORT=1
-DLZW_SUPPORT=1
-
- -DTIFF_INT64_FORMAT="%lld"
- -DTIFF_UINT64_FORMAT="%llu"
- -DTIFF_SSIZE_FORMAT="%d"
)
+ if (MSVC)
+ # The "%" must be escaped if using Visual Studio
+ add_definitions(
+ -DTIFF_INT64_FORMAT="%%lld"
+ -DTIFF_UINT64_FORMAT="%%llu"
+ -DTIFF_SSIZE_FORMAT="%%d"
+ )
+ else()
+ add_definitions(
+ -DTIFF_INT64_FORMAT="%lld"
+ -DTIFF_UINT64_FORMAT="%llu"
+ -DTIFF_SSIZE_FORMAT="%d"
+ )
+ endif()
+
set(LIBTIFF_SOURCES
#${LIBTIFF_SOURCES_DIR}/libtiff/mkg3states.c
${LIBTIFF_SOURCES_DIR}/libtiff/tif_aux.c
diff --git a/Resources/CMake/Version.cmake b/Resources/CMake/Version.cmake
index 9291846..f491a13 100644
--- a/Resources/CMake/Version.cmake
+++ b/Resources/CMake/Version.cmake
@@ -1,4 +1,4 @@
-set(ORTHANC_WSI_VERSION "0.1")
+set(ORTHANC_WSI_VERSION "0.2")
add_definitions(
-DORTHANC_WSI_VERSION="${ORTHANC_WSI_VERSION}"
diff --git a/Applications/CMakeLists.txt b/Resources/Graveyard/CMakeLists.txt
similarity index 70%
copy from Applications/CMakeLists.txt
copy to Resources/Graveyard/CMakeLists.txt
index 622ba23..19f572c 100644
--- a/Applications/CMakeLists.txt
+++ b/Resources/Graveyard/CMakeLists.txt
@@ -9,6 +9,7 @@ project(OrthancWSIApplications)
# Generic parameters
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(ENABLE_PROFILING OFF CACHE BOOL "Whether to enable the generation of profiling information with gprof")
# Optional components
SET(ENABLE_SSL OFF CACHE BOOL "Include support for SSL")
@@ -40,13 +41,14 @@ SET(DCMTK_DICTIONARY_DIR "" CACHE PATH "Directory containing the DCMTK dictionar
## Configure mandatory third-party components
#####################################################################
-SET(ORTHANC_WSI_DIR ${CMAKE_CURRENT_LIST_DIR}/..)
-SET(ORTHANC_ROOT ${ORTHANC_WSI_DIR}/Framework/Orthanc)
+SET(ORTHANC_WSI_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
+SET(ORTHANC_ROOT ${ORTHANC_WSI_DIR}/Resources/Orthanc)
SET(USE_OPENJPEG_JP2 ON)
SET(ENABLE_JPEG OFF) # Disable DCMTK's support for JPEG, that clashes with libtiff
SET(ENABLE_JPEG_LOSSLESS OFF) # Disable DCMTK's support for JPEG-LS
SET(ENABLE_DCMTK_NETWORK OFF) # Disable DCMTK's support for DICOM networking
SET(STANDALONE_BUILD ON) # Embed DCMTK's dictionaries for static builds
+SET(USE_DCMTK_361_PRIVATE_DIC OFF) # No need for private tags
include(CheckIncludeFiles)
include(CheckIncludeFileCXX)
@@ -80,10 +82,11 @@ add_definitions(
-DORTHANC_ENABLE_DCMTK=1
-DORTHANC_ENABLE_LOGGING=1
-DORTHANC_ENABLE_MD5=0
- -DORTHANC_JPEG_ENABLED=0 # Disable DCMTK's support for JPEG
- -DORTHANC_PKCS11_ENABLED=0
- -DORTHANC_PLUGINS_ENABLED=1 # To enable class Orthanc::SharedLibrary
- -DORTHANC_PUGIXML_ENABLED=0
+ -DORTHANC_ENABLE_JPEG=0 # Disable DCMTK's support for JPEG
+ -DORTHANC_ENABLE_PKCS11=0
+ -DORTHANC_ENABLE_PLUGINS=1 # To enable class Orthanc::SharedLibrary
+ -DORTHANC_ENABLE_PUGIXML=0
+ -DORTHANC_SANDBOXED=0
)
@@ -93,10 +96,10 @@ add_definitions(
if (ENABLE_SSL)
set(ENABLE_PKCS11 OFF)
- add_definitions(-DORTHANC_SSL_ENABLED=1)
+ add_definitions(-DORTHANC_ENABLE_SSL=1)
include(${ORTHANC_ROOT}/Resources/CMake/OpenSslConfiguration.cmake)
else()
- add_definitions(-DORTHANC_SSL_ENABLED=0)
+ add_definitions(-DORTHANC_ENABLE_SSL=0)
endif()
@@ -106,7 +109,6 @@ endif()
#####################################################################
set(ORTHANC_WSI_SOURCES
- #${ORTHANC_WSI_DIR}/Framework/Messaging/PluginOrthancConnection.cpp
${ORTHANC_WSI_DIR}/Framework/Algorithms/PyramidReader.cpp
${ORTHANC_WSI_DIR}/Framework/Algorithms/ReconstructPyramidCommand.cpp
${ORTHANC_WSI_DIR}/Framework/Algorithms/TranscodeTileCommand.cpp
@@ -127,11 +129,8 @@ set(ORTHANC_WSI_SOURCES
${ORTHANC_WSI_DIR}/Framework/Inputs/TiledPyramidStatistics.cpp
${ORTHANC_WSI_DIR}/Framework/Jpeg2000Reader.cpp
${ORTHANC_WSI_DIR}/Framework/Jpeg2000Writer.cpp
- ${ORTHANC_WSI_DIR}/Framework/Messaging/CurlOrthancConnection.cpp
- ${ORTHANC_WSI_DIR}/Framework/Messaging/FolderTarget.cpp
- ${ORTHANC_WSI_DIR}/Framework/Messaging/IOrthancConnection.cpp
- ${ORTHANC_WSI_DIR}/Framework/Messaging/OrthancConnectionBase.cpp
- ${ORTHANC_WSI_DIR}/Framework/Messaging/OrthancTarget.cpp
+ ${ORTHANC_WSI_DIR}/Framework/Targets/FolderTarget.cpp
+ ${ORTHANC_WSI_DIR}/Framework/Targets/OrthancTarget.cpp
${ORTHANC_WSI_DIR}/Framework/Outputs/DicomPyramidWriter.cpp
${ORTHANC_WSI_DIR}/Framework/Outputs/HierarchicalTiffWriter.cpp
${ORTHANC_WSI_DIR}/Framework/Outputs/InMemoryTiledImage.cpp
@@ -161,8 +160,9 @@ set(ORTHANC_CORE_SOURCES
${ORTHANC_ROOT}/Core/Logging.cpp
${ORTHANC_ROOT}/Core/MultiThreading/BagOfTasksProcessor.cpp
${ORTHANC_ROOT}/Core/MultiThreading/SharedMessageQueue.cpp
+ ${ORTHANC_ROOT}/Core/SystemToolbox.cpp
+ ${ORTHANC_ROOT}/Core/TemporaryFile.cpp
${ORTHANC_ROOT}/Core/Toolbox.cpp
- ${ORTHANC_ROOT}/Core/Uuid.cpp
${ORTHANC_ROOT}/Core/WebServiceParameters.cpp
${ORTHANC_ROOT}/OrthancServer/FromDcmtkBridge.cpp
${ORTHANC_ROOT}/OrthancServer/ServerEnumerations.cpp
@@ -197,10 +197,10 @@ endif()
#####################################################################
-## Create the static library containing the framework
+## Build a hello world
#####################################################################
-add_library(OrthancWSIFramework STATIC
+add_executable(Hello
${ORTHANC_CORE_SOURCES}
${ORTHANC_WSI_SOURCES}
${AUTOGENERATED_SOURCES}
@@ -218,96 +218,23 @@ add_library(OrthancWSIFramework STATIC
# Optional components
${OPENSSL_SOURCES}
- )
-
-
-#####################################################################
-## Build the WSI DICOM-izer
-#####################################################################
-
-# Create the Windows resources, if need be
-if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
- execute_process(
- COMMAND
- ${PYTHON_EXECUTABLE} ${ORTHANC_ROOT}/Resources/WindowsResources.py
- ${ORTHANC_WSI_VERSION} OrthancWSIDicomizer OrthancWSIDicomizer.exe "Companion tool to Orthanc for whole-slide imaging"
- ERROR_VARIABLE Failure
- OUTPUT_FILE ${AUTOGENERATED_DIR}/OrthancWSIDicomizer.rc
- )
-
- if (Failure)
- message(FATAL_ERROR "Error while computing the version information: ${Failure}")
- endif()
-
- set(DICOMIZER_RESOURCES ${AUTOGENERATED_DIR}/OrthancWSIDicomizer.rc)
-endif()
-
-add_executable(OrthancWSIDicomizer
- Dicomizer.cpp
- ApplicationToolbox.cpp
+ ${ORTHANC_ROOT}/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
+ ${ORTHANC_ROOT}/Plugins/Samples/Common/DicomDatasetReader.cpp
+ ${ORTHANC_ROOT}/Plugins/Samples/Common/DicomPath.cpp
+ ${ORTHANC_ROOT}/Plugins/Samples/Common/DicomTag.cpp
+ ${ORTHANC_ROOT}/Plugins/Samples/Common/FullOrthancDataset.cpp
+ ${ORTHANC_ROOT}/Plugins/Samples/Common/IOrthancConnection.cpp
+ ${ORTHANC_ROOT}/Plugins/Samples/Common/OrthancHttpConnection.cpp
+ ${ORTHANC_ROOT}/Plugins/Samples/Common/OrthancPluginConnection.cpp
+ ${ORTHANC_ROOT}/Plugins/Samples/Common/SimplifiedOrthancDataset.cpp
+
+ Hello.cpp
+ ${ORTHANC_WSI_DIR}/Applications/ApplicationToolbox.cpp
+
${DICOMIZER_RESOURCES}
)
-target_link_libraries(OrthancWSIDicomizer OrthancWSIFramework ${DCMTK_LIBRARIES})
-
-install(
- TARGETS OrthancWSIDicomizer
- RUNTIME DESTINATION bin
- )
-
-
-#####################################################################
-## Build the DICOM-to-TIFF conversion tool
-#####################################################################
-
-# Create the Windows resources, if need be
-if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
- execute_process(
- COMMAND
- ${PYTHON_EXECUTABLE} ${ORTHANC_ROOT}/Resources/WindowsResources.py
- ${ORTHANC_WSI_VERSION} OrthancWSIDicomToTiff OrthancWSIDicomToTiff.exe "Companion tool to Orthanc for whole-slide imaging"
- ERROR_VARIABLE Failure
- OUTPUT_FILE ${AUTOGENERATED_DIR}/OrthancWSIDicomToTiff.rc
- )
-
- if (Failure)
- message(FATAL_ERROR "Error while computing the version information: ${Failure}")
- endif()
-
- set(DICOM_TO_TIFF_RESOURCES ${AUTOGENERATED_DIR}/OrthancWSIDicomToTiff.rc)
-endif()
-
-
-add_executable(OrthancWSIDicomToTiff
- DicomToTiff.cpp
- ApplicationToolbox.cpp
- ${DICOM_TO_TIFF_RESOURCES}
- )
-
-target_link_libraries(OrthancWSIDicomToTiff OrthancWSIFramework ${DCMTK_LIBRARIES})
-
-install(
- TARGETS OrthancWSIDicomToTiff
- RUNTIME DESTINATION bin
- )
-
+add_definitions(-DHAS_ORTHANC_EXCEPTION=1)
-#####################################################################
-## Generate the documentation if Doxygen is present
-#####################################################################
-
-find_package(Doxygen)
-if (DOXYGEN_FOUND)
- configure_file(
- ${ORTHANC_WSI_DIR}/Resources/OrthancWSI.doxygen
- ${CMAKE_CURRENT_BINARY_DIR}/OrthancWSI.doxygen
- @ONLY)
-
- add_custom_target(doc
- ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/OrthancWSI.doxygen
- COMMENT "Generating documentation with Doxygen" VERBATIM
- )
-else()
- message("Doxygen not found. The documentation will not be built.")
-endif()
+target_link_libraries(Hello ${DCMTK_LIBRARIES})
diff --git a/Resources/Graveyard/Hello.cpp b/Resources/Graveyard/Hello.cpp
new file mode 100644
index 0000000..4064608
--- /dev/null
+++ b/Resources/Graveyard/Hello.cpp
@@ -0,0 +1,85 @@
+
+#include <stdint.h>
+#include <boost/noncopyable.hpp>
+#include <string>
+#include <vector>
+#include <json/reader.h>
+#include <json/value.h>
+#include <boost/thread/mutex.hpp>
+
+#include "../../Framework/Inputs/DicomPyramid.h"
+#include "../../Applications/ApplicationToolbox.h"
+#include "../../Resources/Orthanc/Plugins/Samples/Common/OrthancHttpConnection.h"
+#include "../../Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.h"
+#include "../../Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.h"
+#include "../../Resources/Orthanc/Plugins/Samples/Common/SimplifiedOrthancDataset.h"
+
+#include <stdio.h>
+
+namespace OrthancPlugins
+{
+ void Run()
+ {
+ OrthancHttpConnection orthanc;
+
+#if 0
+ //DicomDatasetReader reader(new SimplifiedOrthancDataset(orthanc, "/instances/2791b060-6ff103b3-8078bed0-5abbd75a-a5c675f7/tags?simplify"));
+ DicomDatasetReader reader(new FullOrthancDataset(orthanc, "/instances/2791b060-6ff103b3-8078bed0-5abbd75a-a5c675f7/tags"));
+
+ std::cout << reader.GetIntegerValue(DICOM_TAG_TOTAL_PIXEL_MATRIX_COLUMNS) << "x"
+ << reader.GetIntegerValue(DICOM_TAG_TOTAL_PIXEL_MATRIX_ROWS) << std::endl;
+
+ std::string s;
+ printf("%d ", reader.GetDataset().GetStringValue(s, DICOM_TAG_SOP_CLASS_UID));
+ printf("[%s]\n", s.c_str());
+
+ size_t c;
+
+ {
+ DicomPath p(DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE);
+ printf("%d ", reader.GetDataset().GetSequenceSize(c, p));
+ printf("%d\n", c);
+ }
+
+ for (size_t i = 0; i < c; i++)
+ {
+ /*DicomPath p(DICOM_TAG_COLUMN_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX);
+ p.AddToPrefix(DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE, i);
+ p.AddToPrefix(DICOM_TAG_PLANE_POSITION_SLIDE_SEQUENCE, 0);
+
+ std::string x, y;
+ printf("%d %d ", i, reader.GetDataset().GetStringValue(x, p));
+ p.SetFinalTag(DICOM_TAG_ROW_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX);
+ printf("%d ", reader.GetDataset().GetStringValue(y, p));
+ printf("[%s,%s]\n", x.c_str(), y.c_str());*/
+
+ std::cout << i << ": ["
+ << reader.GetMandatoryStringValue(
+ DicomPath(DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE, i,
+ DICOM_TAG_PLANE_POSITION_SLIDE_SEQUENCE, 0,
+ DICOM_TAG_COLUMN_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX)) << ","
+ << reader.GetMandatoryStringValue(
+ DicomPath(DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE, i,
+ DICOM_TAG_PLANE_POSITION_SLIDE_SEQUENCE, 0,
+ DICOM_TAG_ROW_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX))
+ << "]" << std::endl;
+ }
+
+#else
+ OrthancWSI::DicomPyramid pyramid(orthanc, "09d0cca4-a8f0cd78-5480c690-ed14eb3b-a6614d14", true);
+ //OrthancWSI::DicomPyramid pyramid(orthanc, "4fdff9b9-8b81bc8f-04a3f903-4d44bd57-cc3bf42c");
+#endif
+ }
+
+}
+
+
+
+
+int main()
+{
+ OrthancWSI::ApplicationToolbox::GlobalInitialize();
+ OrthancPlugins::Run();
+ OrthancWSI::ApplicationToolbox::GlobalFinalize();
+ return 0;
+}
diff --git a/Resources/Orthanc/Core/Cache/LeastRecentlyUsedIndex.h b/Resources/Orthanc/Core/Cache/LeastRecentlyUsedIndex.h
new file mode 100644
index 0000000..a5bf7b2
--- /dev/null
+++ b/Resources/Orthanc/Core/Cache/LeastRecentlyUsedIndex.h
@@ -0,0 +1,346 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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/>.
+ **/
+
+
+#pragma once
+
+#include <list>
+#include <map>
+#include <boost/noncopyable.hpp>
+#include <cassert>
+
+#include "../OrthancException.h"
+#include "../Toolbox.h"
+
+namespace Orthanc
+{
+ /**
+ * This class implements the index of a cache with least recently
+ * used (LRU) recycling policy. All the items of the cache index
+ * can be associated with a payload.
+ * Reference: http://stackoverflow.com/a/2504317
+ **/
+ template <typename T, typename Payload = NullType>
+ class LeastRecentlyUsedIndex : public boost::noncopyable
+ {
+ private:
+ typedef std::list< std::pair<T, Payload> > Queue;
+ typedef std::map<T, typename Queue::iterator> Index;
+
+ Index index_;
+ Queue queue_;
+
+ /**
+ * Internal method for debug builds to check whether the internal
+ * data structures are not corrupted.
+ **/
+ void CheckInvariants() const;
+
+ public:
+ /**
+ * Add a new element to the cache index, and make it the most
+ * recent element.
+ * \param id The ID of the element.
+ * \param payload The payload of the element.
+ **/
+ void Add(T id, Payload payload = Payload());
+
+ void AddOrMakeMostRecent(T id, Payload payload = Payload());
+
+ /**
+ * When accessing an element of the cache, this method tags the
+ * element as the most recently used.
+ * \param id The most recently accessed item.
+ **/
+ void MakeMostRecent(T id);
+
+ void MakeMostRecent(T id, Payload updatedPayload);
+
+ /**
+ * Remove an element from the cache index.
+ * \param id The item to remove.
+ **/
+ Payload Invalidate(T id);
+
+ /**
+ * Get the oldest element in the cache and remove it.
+ * \return The oldest item.
+ **/
+ T RemoveOldest();
+
+ /**
+ * Get the oldest element in the cache, remove it and return the
+ * associated payload.
+ * \param payload Where to store the associated payload.
+ * \return The oldest item.
+ **/
+ T RemoveOldest(Payload& payload);
+
+ /**
+ * Check whether an element is contained in the cache.
+ * \param id The item.
+ * \return \c true iff the item is indexed by the cache.
+ **/
+ bool Contains(T id) const
+ {
+ return index_.find(id) != index_.end();
+ }
+
+ bool Contains(T id, Payload& payload) const
+ {
+ typename Index::const_iterator it = index_.find(id);
+ if (it == index_.end())
+ {
+ return false;
+ }
+ else
+ {
+ payload = it->second->second;
+ return true;
+ }
+ }
+
+ /**
+ * Return the number of elements in the cache.
+ * \return The number of elements.
+ **/
+ size_t GetSize() const
+ {
+ assert(index_.size() == queue_.size());
+ return queue_.size();
+ }
+
+ /**
+ * Check whether the cache index is empty.
+ * \return \c true iff the cache is empty.
+ **/
+ bool IsEmpty() const
+ {
+ return index_.empty();
+ }
+
+ const T& GetOldest() const;
+
+ const Payload& GetOldestPayload() const;
+ };
+
+
+
+
+ /******************************************************************
+ ** Implementation of the template
+ ******************************************************************/
+
+ template <typename T, typename Payload>
+ void LeastRecentlyUsedIndex<T, Payload>::CheckInvariants() const
+ {
+#ifndef NDEBUG
+ assert(index_.size() == queue_.size());
+
+ for (typename Index::const_iterator
+ it = index_.begin(); it != index_.end(); it++)
+ {
+ assert(it->second != queue_.end());
+ assert(it->second->first == it->first);
+ }
+#endif
+ }
+
+
+ template <typename T, typename Payload>
+ void LeastRecentlyUsedIndex<T, Payload>::Add(T id, Payload payload)
+ {
+ if (Contains(id))
+ {
+ throw OrthancException(ErrorCode_BadSequenceOfCalls);
+ }
+
+ queue_.push_front(std::make_pair(id, payload));
+ index_[id] = queue_.begin();
+
+ CheckInvariants();
+ }
+
+
+ template <typename T, typename Payload>
+ void LeastRecentlyUsedIndex<T, Payload>::MakeMostRecent(T id)
+ {
+ if (!Contains(id))
+ {
+ throw OrthancException(ErrorCode_InexistentItem);
+ }
+
+ typename Index::iterator it = index_.find(id);
+ assert(it != index_.end());
+
+ std::pair<T, Payload> item = *(it->second);
+
+ queue_.erase(it->second);
+ queue_.push_front(item);
+ index_[id] = queue_.begin();
+
+ CheckInvariants();
+ }
+
+
+ template <typename T, typename Payload>
+ void LeastRecentlyUsedIndex<T, Payload>::AddOrMakeMostRecent(T id, Payload payload)
+ {
+ typename Index::iterator it = index_.find(id);
+
+ if (it != index_.end())
+ {
+ // Already existing. Make it most recent.
+ std::pair<T, Payload> item = *(it->second);
+ item.second = payload;
+ queue_.erase(it->second);
+ queue_.push_front(item);
+ }
+ else
+ {
+ // New item
+ queue_.push_front(std::make_pair(id, payload));
+ }
+
+ index_[id] = queue_.begin();
+
+ CheckInvariants();
+ }
+
+
+ template <typename T, typename Payload>
+ void LeastRecentlyUsedIndex<T, Payload>::MakeMostRecent(T id, Payload updatedPayload)
+ {
+ if (!Contains(id))
+ {
+ throw OrthancException(ErrorCode_InexistentItem);
+ }
+
+ typename Index::iterator it = index_.find(id);
+ assert(it != index_.end());
+
+ std::pair<T, Payload> item = *(it->second);
+ item.second = updatedPayload;
+
+ queue_.erase(it->second);
+ queue_.push_front(item);
+ index_[id] = queue_.begin();
+
+ CheckInvariants();
+ }
+
+
+ template <typename T, typename Payload>
+ Payload LeastRecentlyUsedIndex<T, Payload>::Invalidate(T id)
+ {
+ if (!Contains(id))
+ {
+ throw OrthancException(ErrorCode_InexistentItem);
+ }
+
+ typename Index::iterator it = index_.find(id);
+ assert(it != index_.end());
+
+ Payload payload = it->second->second;
+ queue_.erase(it->second);
+ index_.erase(it);
+
+ CheckInvariants();
+ return payload;
+ }
+
+
+ template <typename T, typename Payload>
+ T LeastRecentlyUsedIndex<T, Payload>::RemoveOldest(Payload& payload)
+ {
+ if (IsEmpty())
+ {
+ throw OrthancException(ErrorCode_BadSequenceOfCalls);
+ }
+
+ std::pair<T, Payload> item = queue_.back();
+ T oldest = item.first;
+ payload = item.second;
+
+ queue_.pop_back();
+ assert(index_.find(oldest) != index_.end());
+ index_.erase(oldest);
+
+ CheckInvariants();
+
+ return oldest;
+ }
+
+
+ template <typename T, typename Payload>
+ T LeastRecentlyUsedIndex<T, Payload>::RemoveOldest()
+ {
+ if (IsEmpty())
+ {
+ throw OrthancException(ErrorCode_BadSequenceOfCalls);
+ }
+
+ std::pair<T, Payload> item = queue_.back();
+ T oldest = item.first;
+
+ queue_.pop_back();
+ assert(index_.find(oldest) != index_.end());
+ index_.erase(oldest);
+
+ CheckInvariants();
+
+ return oldest;
+ }
+
+
+ template <typename T, typename Payload>
+ const T& LeastRecentlyUsedIndex<T, Payload>::GetOldest() const
+ {
+ if (IsEmpty())
+ {
+ throw OrthancException(ErrorCode_BadSequenceOfCalls);
+ }
+
+ return queue_.back().first;
+ }
+
+
+ template <typename T, typename Payload>
+ const Payload& LeastRecentlyUsedIndex<T, Payload>::GetOldestPayload() const
+ {
+ if (IsEmpty())
+ {
+ throw OrthancException(ErrorCode_BadSequenceOfCalls);
+ }
+
+ return queue_.back().second;
+ }
+}
diff --git a/Framework/Orthanc/Core/ChunkedBuffer.cpp b/Resources/Orthanc/Core/ChunkedBuffer.cpp
similarity index 100%
copy from Framework/Orthanc/Core/ChunkedBuffer.cpp
copy to Resources/Orthanc/Core/ChunkedBuffer.cpp
diff --git a/Framework/Orthanc/Core/ChunkedBuffer.h b/Resources/Orthanc/Core/ChunkedBuffer.h
similarity index 100%
copy from Framework/Orthanc/Core/ChunkedBuffer.h
copy to Resources/Orthanc/Core/ChunkedBuffer.h
diff --git a/Framework/Orthanc/Core/DicomFormat/DicomArray.cpp b/Resources/Orthanc/Core/DicomFormat/DicomArray.cpp
similarity index 100%
rename from Framework/Orthanc/Core/DicomFormat/DicomArray.cpp
rename to Resources/Orthanc/Core/DicomFormat/DicomArray.cpp
diff --git a/Framework/Orthanc/Core/DicomFormat/DicomArray.h b/Resources/Orthanc/Core/DicomFormat/DicomArray.h
similarity index 100%
copy from Framework/Orthanc/Core/DicomFormat/DicomArray.h
copy to Resources/Orthanc/Core/DicomFormat/DicomArray.h
diff --git a/Framework/Orthanc/Core/DicomFormat/DicomElement.h b/Resources/Orthanc/Core/DicomFormat/DicomElement.h
similarity index 100%
rename from Framework/Orthanc/Core/DicomFormat/DicomElement.h
rename to Resources/Orthanc/Core/DicomFormat/DicomElement.h
diff --git a/Framework/Orthanc/Core/DicomFormat/DicomMap.cpp b/Resources/Orthanc/Core/DicomFormat/DicomMap.cpp
similarity index 100%
rename from Framework/Orthanc/Core/DicomFormat/DicomMap.cpp
rename to Resources/Orthanc/Core/DicomFormat/DicomMap.cpp
diff --git a/Framework/Orthanc/Core/DicomFormat/DicomMap.h b/Resources/Orthanc/Core/DicomFormat/DicomMap.h
similarity index 100%
rename from Framework/Orthanc/Core/DicomFormat/DicomMap.h
rename to Resources/Orthanc/Core/DicomFormat/DicomMap.h
diff --git a/Framework/Orthanc/Core/DicomFormat/DicomTag.cpp b/Resources/Orthanc/Core/DicomFormat/DicomTag.cpp
similarity index 100%
rename from Framework/Orthanc/Core/DicomFormat/DicomTag.cpp
rename to Resources/Orthanc/Core/DicomFormat/DicomTag.cpp
diff --git a/Framework/Orthanc/Core/DicomFormat/DicomTag.h b/Resources/Orthanc/Core/DicomFormat/DicomTag.h
similarity index 100%
rename from Framework/Orthanc/Core/DicomFormat/DicomTag.h
rename to Resources/Orthanc/Core/DicomFormat/DicomTag.h
diff --git a/Framework/Orthanc/Core/DicomFormat/DicomValue.cpp b/Resources/Orthanc/Core/DicomFormat/DicomValue.cpp
similarity index 97%
copy from Framework/Orthanc/Core/DicomFormat/DicomValue.cpp
copy to Resources/Orthanc/Core/DicomFormat/DicomValue.cpp
index 32a17b5..2a4c2f2 100644
--- a/Framework/Orthanc/Core/DicomFormat/DicomValue.cpp
+++ b/Resources/Orthanc/Core/DicomFormat/DicomValue.cpp
@@ -81,7 +81,7 @@ namespace Orthanc
}
-#if !defined(ORTHANC_ENABLE_BASE64) || ORTHANC_ENABLE_BASE64 == 1
+#if ORTHANC_ENABLE_BASE64 == 1
void DicomValue::FormatDataUriScheme(std::string& target,
const std::string& mime) const
{
diff --git a/Framework/Orthanc/Core/DicomFormat/DicomValue.h b/Resources/Orthanc/Core/DicomFormat/DicomValue.h
similarity index 95%
copy from Framework/Orthanc/Core/DicomFormat/DicomValue.h
copy to Resources/Orthanc/Core/DicomFormat/DicomValue.h
index ad0ec54..c4844b7 100644
--- a/Framework/Orthanc/Core/DicomFormat/DicomValue.h
+++ b/Resources/Orthanc/Core/DicomFormat/DicomValue.h
@@ -35,6 +35,11 @@
#include <string>
#include <boost/noncopyable.hpp>
+#if !defined(ORTHANC_ENABLE_BASE64)
+# error The macro ORTHANC_ENABLE_BASE64 must be defined
+#endif
+
+
namespace Orthanc
{
class DicomValue : public boost::noncopyable
@@ -78,7 +83,7 @@ namespace Orthanc
DicomValue* Clone() const;
-#if !defined(ORTHANC_ENABLE_BASE64) || ORTHANC_ENABLE_BASE64 == 1
+#if ORTHANC_ENABLE_BASE64 == 1
void FormatDataUriScheme(std::string& target,
const std::string& mime) const;
diff --git a/Framework/Orthanc/Core/Endianness.h b/Resources/Orthanc/Core/Endianness.h
similarity index 100%
rename from Framework/Orthanc/Core/Endianness.h
rename to Resources/Orthanc/Core/Endianness.h
diff --git a/Framework/Orthanc/Core/EnumerationDictionary.h b/Resources/Orthanc/Core/EnumerationDictionary.h
similarity index 100%
rename from Framework/Orthanc/Core/EnumerationDictionary.h
rename to Resources/Orthanc/Core/EnumerationDictionary.h
diff --git a/Framework/Orthanc/Core/Enumerations.cpp b/Resources/Orthanc/Core/Enumerations.cpp
similarity index 99%
rename from Framework/Orthanc/Core/Enumerations.cpp
rename to Resources/Orthanc/Core/Enumerations.cpp
index 8ed74c2..5a72585 100644
--- a/Framework/Orthanc/Core/Enumerations.cpp
+++ b/Resources/Orthanc/Core/Enumerations.cpp
@@ -64,7 +64,7 @@ namespace Orthanc
return "Parameter out of range";
case ErrorCode_NotEnoughMemory:
- return "Not enough memory";
+ return "The server hosting Orthanc is running out of memory";
case ErrorCode_BadParameterType:
return "Bad type for a parameter";
@@ -156,6 +156,9 @@ namespace Orthanc
case ErrorCode_NotAcceptable:
return "Cannot send a response which is acceptable according to the Accept HTTP header";
+ case ErrorCode_NullPointer:
+ return "Cannot handle a NULL pointer";
+
case ErrorCode_SQLiteNotOpened:
return "SQLite: The database is not opened";
diff --git a/Framework/Orthanc/Core/Enumerations.h b/Resources/Orthanc/Core/Enumerations.h
similarity index 99%
rename from Framework/Orthanc/Core/Enumerations.h
rename to Resources/Orthanc/Core/Enumerations.h
index 50f64c7..9b18661 100644
--- a/Framework/Orthanc/Core/Enumerations.h
+++ b/Resources/Orthanc/Core/Enumerations.h
@@ -52,7 +52,7 @@ namespace Orthanc
ErrorCode_Plugin = 1 /*!< Error encountered within the plugin engine */,
ErrorCode_NotImplemented = 2 /*!< Not implemented yet */,
ErrorCode_ParameterOutOfRange = 3 /*!< Parameter out of range */,
- ErrorCode_NotEnoughMemory = 4 /*!< Not enough memory */,
+ ErrorCode_NotEnoughMemory = 4 /*!< The server hosting Orthanc is running out of memory */,
ErrorCode_BadParameterType = 5 /*!< Bad type for a parameter */,
ErrorCode_BadSequenceOfCalls = 6 /*!< Bad sequence of calls */,
ErrorCode_InexistentItem = 7 /*!< Accessing an inexistent item */,
@@ -83,6 +83,7 @@ namespace Orthanc
ErrorCode_StorageAreaPlugin = 32 /*!< Error in the plugin implementing a custom storage area */,
ErrorCode_EmptyRequest = 33 /*!< The request is empty */,
ErrorCode_NotAcceptable = 34 /*!< Cannot send a response which is acceptable according to the Accept HTTP header */,
+ ErrorCode_NullPointer = 35 /*!< Cannot handle a NULL pointer */,
ErrorCode_SQLiteNotOpened = 1000 /*!< SQLite: The database is not opened */,
ErrorCode_SQLiteAlreadyOpened = 1001 /*!< SQLite: Connection is already open */,
ErrorCode_SQLiteCannotOpen = 1002 /*!< SQLite: Unable to open the database */,
diff --git a/Framework/Orthanc/Core/HttpClient.cpp b/Resources/Orthanc/Core/HttpClient.cpp
similarity index 97%
rename from Framework/Orthanc/Core/HttpClient.cpp
rename to Resources/Orthanc/Core/HttpClient.cpp
index f028d30..0999b84 100644
--- a/Framework/Orthanc/Core/HttpClient.cpp
+++ b/Resources/Orthanc/Core/HttpClient.cpp
@@ -37,6 +37,7 @@
#include "OrthancException.h"
#include "Logging.h"
#include "ChunkedBuffer.h"
+#include "SystemToolbox.h"
#include <string.h>
#include <curl/curl.h>
@@ -44,7 +45,7 @@
#include <boost/thread/mutex.hpp>
-#if ORTHANC_SSL_ENABLED == 1
+#if ORTHANC_ENABLE_SSL == 1
// For OpenSSL initialization and finalization
# include <openssl/conf.h>
# include <openssl/engine.h>
@@ -54,7 +55,7 @@
#endif
-#if ORTHANC_PKCS11_ENABLED == 1
+#if ORTHANC_ENABLE_PKCS11 == 1
# include "Pkcs11.h"
#endif
@@ -161,7 +162,7 @@ namespace Orthanc
return timeout_;
}
-#if ORTHANC_PKCS11_ENABLED == 1
+#if ORTHANC_ENABLE_PKCS11 == 1
bool IsPkcs11Initialized()
{
boost::mutex::scoped_lock lock(mutex_);
@@ -435,7 +436,7 @@ namespace Orthanc
CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HEADERDATA, &headerParameters));
}
-#if ORTHANC_SSL_ENABLED == 1
+#if ORTHANC_ENABLE_SSL == 1
// Setup HTTPS-related options
if (verifyPeers_)
@@ -461,7 +462,7 @@ namespace Orthanc
if (pkcs11Enabled_)
{
-#if ORTHANC_PKCS11_ENABLED == 1
+#if ORTHANC_ENABLE_PKCS11 == 1
if (GlobalParameters::GetInstance().IsPkcs11Initialized())
{
CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLENGINE, Pkcs11::GetEngineIdentifier()));
@@ -480,7 +481,7 @@ namespace Orthanc
}
else if (!clientCertificateFile_.empty())
{
-#if ORTHANC_SSL_ENABLED == 1
+#if ORTHANC_ENABLE_SSL == 1
CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLCERTTYPE, "PEM"));
CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLCERT, clientCertificateFile_.c_str()));
@@ -671,7 +672,7 @@ namespace Orthanc
void HttpClient::ConfigureSsl(bool httpsVerifyPeers,
const std::string& httpsVerifyCertificates)
{
-#if ORTHANC_SSL_ENABLED == 1
+#if ORTHANC_ENABLE_SSL == 1
if (httpsVerifyPeers)
{
if (httpsVerifyCertificates.empty())
@@ -696,7 +697,7 @@ namespace Orthanc
void HttpClient::GlobalInitialize()
{
-#if ORTHANC_SSL_ENABLED == 1
+#if ORTHANC_ENABLE_SSL == 1
CheckCode(curl_global_init(CURL_GLOBAL_ALL));
#else
CheckCode(curl_global_init(CURL_GLOBAL_ALL & ~CURL_GLOBAL_SSL));
@@ -708,7 +709,7 @@ namespace Orthanc
{
curl_global_cleanup();
-#if ORTHANC_PKCS11_ENABLED == 1
+#if ORTHANC_ENABLE_PKCS11 == 1
Pkcs11::Finalize();
#endif
}
@@ -773,14 +774,14 @@ namespace Orthanc
throw OrthancException(ErrorCode_ParameterOutOfRange);
}
- if (!Toolbox::IsRegularFile(certificateFile))
+ if (!SystemToolbox::IsRegularFile(certificateFile))
{
LOG(ERROR) << "Cannot open certificate file: " << certificateFile;
throw OrthancException(ErrorCode_InexistentFile);
}
if (!certificateKeyFile.empty() &&
- !Toolbox::IsRegularFile(certificateKeyFile))
+ !SystemToolbox::IsRegularFile(certificateKeyFile))
{
LOG(ERROR) << "Cannot open key file: " << certificateKeyFile;
throw OrthancException(ErrorCode_InexistentFile);
@@ -796,7 +797,7 @@ namespace Orthanc
const std::string& pin,
bool verbose)
{
-#if ORTHANC_PKCS11_ENABLED == 1
+#if ORTHANC_ENABLE_PKCS11 == 1
LOG(INFO) << "Initializing PKCS#11 using " << module
<< (pin.empty() ? " (no PIN provided)" : " (PIN is provided)");
GlobalParameters::GetInstance().InitializePkcs11(module, pin, verbose);
@@ -809,7 +810,7 @@ namespace Orthanc
void HttpClient::InitializeOpenSsl()
{
-#if ORTHANC_SSL_ENABLED == 1
+#if ORTHANC_ENABLE_SSL == 1
// https://wiki.openssl.org/index.php/Library_Initialization
SSL_library_init();
SSL_load_error_strings();
@@ -821,7 +822,7 @@ namespace Orthanc
void HttpClient::FinalizeOpenSsl()
{
- #if ORTHANC_SSL_ENABLED == 1
+ #if ORTHANC_ENABLE_SSL == 1
// Finalize OpenSSL
// https://wiki.openssl.org/index.php/Library_Initialization#Cleanup
FIPS_mode_set(0);
diff --git a/Framework/Orthanc/Core/HttpClient.h b/Resources/Orthanc/Core/HttpClient.h
similarity index 97%
rename from Framework/Orthanc/Core/HttpClient.h
rename to Resources/Orthanc/Core/HttpClient.h
index c699dc9..1b80f33 100644
--- a/Framework/Orthanc/Core/HttpClient.h
+++ b/Resources/Orthanc/Core/HttpClient.h
@@ -39,6 +39,15 @@
#include <boost/shared_ptr.hpp>
#include <json/json.h>
+#if !defined(ORTHANC_ENABLE_SSL)
+# error The macro ORTHANC_ENABLE_SSL must be defined
+#endif
+
+#if !defined(ORTHANC_ENABLE_PKCS11)
+# error The macro ORTHANC_ENABLE_PKCS11 must be defined
+#endif
+
+
namespace Orthanc
{
class HttpClient
diff --git a/Framework/Orthanc/Core/ICommand.h b/Resources/Orthanc/Core/ICommand.h
similarity index 100%
rename from Framework/Orthanc/Core/ICommand.h
rename to Resources/Orthanc/Core/ICommand.h
diff --git a/Framework/Orthanc/Core/IDynamicObject.h b/Resources/Orthanc/Core/IDynamicObject.h
similarity index 100%
rename from Framework/Orthanc/Core/IDynamicObject.h
rename to Resources/Orthanc/Core/IDynamicObject.h
diff --git a/Framework/Orthanc/Core/Images/IImageWriter.cpp b/Resources/Orthanc/Core/Images/IImageWriter.cpp
similarity index 89%
rename from Framework/Orthanc/Core/Images/IImageWriter.cpp
rename to Resources/Orthanc/Core/Images/IImageWriter.cpp
index 096adb3..b215080 100644
--- a/Framework/Orthanc/Core/Images/IImageWriter.cpp
+++ b/Resources/Orthanc/Core/Images/IImageWriter.cpp
@@ -32,11 +32,13 @@
#include "IImageWriter.h"
-#include "../OrthancException.h"
-#include "../Toolbox.h"
+#if ORTHANC_SANDBOXED == 0
+# include "../SystemToolbox.h"
+#endif
namespace Orthanc
{
+#if ORTHANC_SANDBOXED == 0
void IImageWriter::WriteToFileInternal(const std::string& path,
unsigned int width,
unsigned int height,
@@ -44,12 +46,9 @@ namespace Orthanc
PixelFormat format,
const void* buffer)
{
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
std::string compressed;
WriteToMemoryInternal(compressed, width, height, pitch, format, buffer);
- Toolbox::WriteFile(compressed, path);
-#else
- throw OrthancException(ErrorCode_CannotWriteFile); // Unavailable in sandboxed environments
-#endif
+ SystemToolbox::WriteFile(compressed, path);
}
+#endif
}
diff --git a/Framework/Orthanc/Core/Images/IImageWriter.h b/Resources/Orthanc/Core/Images/IImageWriter.h
similarity index 95%
rename from Framework/Orthanc/Core/Images/IImageWriter.h
rename to Resources/Orthanc/Core/Images/IImageWriter.h
index f2d1c97..ca27010 100644
--- a/Framework/Orthanc/Core/Images/IImageWriter.h
+++ b/Resources/Orthanc/Core/Images/IImageWriter.h
@@ -36,6 +36,10 @@
#include <boost/noncopyable.hpp>
+#if !defined(ORTHANC_SANDBOXED)
+# error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
namespace Orthanc
{
class IImageWriter : public boost::noncopyable
@@ -48,12 +52,14 @@ namespace Orthanc
PixelFormat format,
const void* buffer) = 0;
+#if ORTHANC_SANDBOXED == 0
virtual void WriteToFileInternal(const std::string& path,
unsigned int width,
unsigned int height,
unsigned int pitch,
PixelFormat format,
const void* buffer);
+#endif
public:
virtual ~IImageWriter()
@@ -67,11 +73,13 @@ namespace Orthanc
accessor.GetPitch(), accessor.GetFormat(), accessor.GetConstBuffer());
}
+#if ORTHANC_SANDBOXED == 0
virtual void WriteToFile(const std::string& path,
const ImageAccessor& accessor)
{
WriteToFileInternal(path, accessor.GetWidth(), accessor.GetHeight(),
accessor.GetPitch(), accessor.GetFormat(), accessor.GetConstBuffer());
}
+#endif
};
}
diff --git a/Framework/Orthanc/Core/Images/Image.cpp b/Resources/Orthanc/Core/Images/Image.cpp
similarity index 100%
rename from Framework/Orthanc/Core/Images/Image.cpp
rename to Resources/Orthanc/Core/Images/Image.cpp
diff --git a/Framework/Orthanc/Core/Images/Image.h b/Resources/Orthanc/Core/Images/Image.h
similarity index 100%
rename from Framework/Orthanc/Core/Images/Image.h
rename to Resources/Orthanc/Core/Images/Image.h
diff --git a/Framework/Orthanc/Core/Images/ImageAccessor.cpp b/Resources/Orthanc/Core/Images/ImageAccessor.cpp
similarity index 100%
rename from Framework/Orthanc/Core/Images/ImageAccessor.cpp
rename to Resources/Orthanc/Core/Images/ImageAccessor.cpp
diff --git a/Framework/Orthanc/Core/Images/ImageAccessor.h b/Resources/Orthanc/Core/Images/ImageAccessor.h
similarity index 100%
rename from Framework/Orthanc/Core/Images/ImageAccessor.h
rename to Resources/Orthanc/Core/Images/ImageAccessor.h
diff --git a/Framework/Orthanc/Core/Images/ImageBuffer.cpp b/Resources/Orthanc/Core/Images/ImageBuffer.cpp
similarity index 100%
rename from Framework/Orthanc/Core/Images/ImageBuffer.cpp
rename to Resources/Orthanc/Core/Images/ImageBuffer.cpp
diff --git a/Framework/Orthanc/Core/Images/ImageBuffer.h b/Resources/Orthanc/Core/Images/ImageBuffer.h
similarity index 100%
copy from Framework/Orthanc/Core/Images/ImageBuffer.h
copy to Resources/Orthanc/Core/Images/ImageBuffer.h
diff --git a/Framework/Orthanc/Core/Images/ImageProcessing.cpp b/Resources/Orthanc/Core/Images/ImageProcessing.cpp
similarity index 100%
rename from Framework/Orthanc/Core/Images/ImageProcessing.cpp
rename to Resources/Orthanc/Core/Images/ImageProcessing.cpp
diff --git a/Framework/Orthanc/Core/Images/ImageProcessing.h b/Resources/Orthanc/Core/Images/ImageProcessing.h
similarity index 100%
rename from Framework/Orthanc/Core/Images/ImageProcessing.h
rename to Resources/Orthanc/Core/Images/ImageProcessing.h
diff --git a/Framework/Orthanc/Core/Images/JpegErrorManager.cpp b/Resources/Orthanc/Core/Images/JpegErrorManager.cpp
similarity index 100%
rename from Framework/Orthanc/Core/Images/JpegErrorManager.cpp
rename to Resources/Orthanc/Core/Images/JpegErrorManager.cpp
diff --git a/Framework/Orthanc/Core/Images/JpegErrorManager.h b/Resources/Orthanc/Core/Images/JpegErrorManager.h
similarity index 100%
rename from Framework/Orthanc/Core/Images/JpegErrorManager.h
rename to Resources/Orthanc/Core/Images/JpegErrorManager.h
diff --git a/Framework/Orthanc/Core/Images/JpegReader.cpp b/Resources/Orthanc/Core/Images/JpegReader.cpp
similarity index 96%
rename from Framework/Orthanc/Core/Images/JpegReader.cpp
rename to Resources/Orthanc/Core/Images/JpegReader.cpp
index c8e725e..9d6ea08 100644
--- a/Framework/Orthanc/Core/Images/JpegReader.cpp
+++ b/Resources/Orthanc/Core/Images/JpegReader.cpp
@@ -36,7 +36,11 @@
#include "JpegErrorManager.h"
#include "../OrthancException.h"
#include "../Logging.h"
-#include "../Toolbox.h"
+
+#if ORTHANC_SANDBOXED == 0
+# include "../SystemToolbox.h"
+#endif
+
namespace Orthanc
{
@@ -94,9 +98,10 @@ namespace Orthanc
}
+#if ORTHANC_SANDBOXED == 0
void JpegReader::ReadFromFile(const std::string& filename)
{
- FILE* fp = Toolbox::OpenFile(filename, FileMode_ReadBinary);
+ FILE* fp = SystemToolbox::OpenFile(filename, FileMode_ReadBinary);
if (!fp)
{
throw OrthancException(ErrorCode_InexistentFile);
@@ -135,6 +140,7 @@ namespace Orthanc
jpeg_destroy_decompress(&cinfo);
fclose(fp);
}
+#endif
void JpegReader::ReadFromMemory(const void* buffer,
diff --git a/Framework/Orthanc/Core/Images/JpegReader.h b/Resources/Orthanc/Core/Images/JpegReader.h
similarity index 94%
copy from Framework/Orthanc/Core/Images/JpegReader.h
copy to Resources/Orthanc/Core/Images/JpegReader.h
index 5cb5551..978058c 100644
--- a/Framework/Orthanc/Core/Images/JpegReader.h
+++ b/Resources/Orthanc/Core/Images/JpegReader.h
@@ -37,6 +37,10 @@
#include <string>
#include <boost/noncopyable.hpp>
+#if !defined(ORTHANC_SANDBOXED)
+# error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
namespace Orthanc
{
class JpegReader :
@@ -47,7 +51,9 @@ namespace Orthanc
std::string content_;
public:
+#if ORTHANC_SANDBOXED == 0
void ReadFromFile(const std::string& filename);
+#endif
void ReadFromMemory(const void* buffer,
size_t size);
diff --git a/Framework/Orthanc/Core/Images/JpegWriter.cpp b/Resources/Orthanc/Core/Images/JpegWriter.cpp
similarity index 97%
rename from Framework/Orthanc/Core/Images/JpegWriter.cpp
rename to Resources/Orthanc/Core/Images/JpegWriter.cpp
index abe98fa..9f5ae8d 100644
--- a/Framework/Orthanc/Core/Images/JpegWriter.cpp
+++ b/Resources/Orthanc/Core/Images/JpegWriter.cpp
@@ -35,10 +35,12 @@
#include "../OrthancException.h"
#include "../Logging.h"
-#include "../Toolbox.h"
-
#include "JpegErrorManager.h"
+#if ORTHANC_SANDBOXED == 0
+# include "../SystemToolbox.h"
+#endif
+
#include <stdlib.h>
#include <vector>
@@ -112,6 +114,7 @@ namespace Orthanc
}
+#if ORTHANC_SANDBOXED == 0
void JpegWriter::WriteToFileInternal(const std::string& filename,
unsigned int width,
unsigned int height,
@@ -119,7 +122,7 @@ namespace Orthanc
PixelFormat format,
const void* buffer)
{
- FILE* fp = Toolbox::OpenFile(filename, FileMode_WriteBinary);
+ FILE* fp = SystemToolbox::OpenFile(filename, FileMode_WriteBinary);
if (fp == NULL)
{
throw OrthancException(ErrorCode_CannotWriteFile);
@@ -155,6 +158,7 @@ namespace Orthanc
fclose(fp);
}
+#endif
void JpegWriter::WriteToMemoryInternal(std::string& jpeg,
diff --git a/Framework/Orthanc/Core/Images/JpegWriter.h b/Resources/Orthanc/Core/Images/JpegWriter.h
similarity index 98%
rename from Framework/Orthanc/Core/Images/JpegWriter.h
rename to Resources/Orthanc/Core/Images/JpegWriter.h
index 5d18af3..ffb6098 100644
--- a/Framework/Orthanc/Core/Images/JpegWriter.h
+++ b/Resources/Orthanc/Core/Images/JpegWriter.h
@@ -46,12 +46,14 @@ namespace Orthanc
PixelFormat format,
const void* buffer);
+#if ORTHANC_SANDBOXED == 0
virtual void WriteToMemoryInternal(std::string& jpeg,
unsigned int width,
unsigned int height,
unsigned int pitch,
PixelFormat format,
const void* buffer);
+#endif
private:
uint8_t quality_;
diff --git a/Framework/Orthanc/Core/Images/PngReader.cpp b/Resources/Orthanc/Core/Images/PngReader.cpp
similarity index 97%
rename from Framework/Orthanc/Core/Images/PngReader.cpp
rename to Resources/Orthanc/Core/Images/PngReader.cpp
index b93aee0..8315ca7 100644
--- a/Framework/Orthanc/Core/Images/PngReader.cpp
+++ b/Resources/Orthanc/Core/Images/PngReader.cpp
@@ -36,11 +36,16 @@
#include "../OrthancException.h"
#include "../Toolbox.h"
+#if ORTHANC_SANDBOXED == 0
+# include "../SystemToolbox.h"
+#endif
+
#include <png.h>
#include <string.h> // For memcpy()
namespace Orthanc
{
+#if ORTHANC_SANDBOXED == 0
namespace
{
struct FileRabi
@@ -49,7 +54,7 @@ namespace Orthanc
FileRabi(const char* filename)
{
- fp_ = Toolbox::OpenFile(filename, FileMode_ReadBinary);
+ fp_ = SystemToolbox::OpenFile(filename, FileMode_ReadBinary);
if (!fp_)
{
throw OrthancException(ErrorCode_InexistentFile);
@@ -65,6 +70,7 @@ namespace Orthanc
}
};
}
+#endif
struct PngReader::PngRabi
@@ -206,6 +212,8 @@ namespace Orthanc
AssignWritable(format, width, height, pitch, &data_[0]);
}
+
+#if ORTHANC_SANDBOXED == 0
void PngReader::ReadFromFile(const std::string& filename)
{
FileRabi f(filename.c_str());
@@ -230,6 +238,7 @@ namespace Orthanc
Read(rabi);
}
+#endif
namespace
diff --git a/Framework/Orthanc/Core/Images/PngReader.h b/Resources/Orthanc/Core/Images/PngReader.h
similarity index 94%
rename from Framework/Orthanc/Core/Images/PngReader.h
rename to Resources/Orthanc/Core/Images/PngReader.h
index b6ad811..fd18d26 100644
--- a/Framework/Orthanc/Core/Images/PngReader.h
+++ b/Resources/Orthanc/Core/Images/PngReader.h
@@ -41,6 +41,10 @@
#include <boost/shared_ptr.hpp>
#include <boost/noncopyable.hpp>
+#if !defined(ORTHANC_SANDBOXED)
+# error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
namespace Orthanc
{
class PngReader :
@@ -59,7 +63,9 @@ namespace Orthanc
public:
PngReader();
+#if ORTHANC_SANDBOXED == 0
void ReadFromFile(const std::string& filename);
+#endif
void ReadFromMemory(const void* buffer,
size_t size);
diff --git a/Framework/Orthanc/Core/Images/PngWriter.cpp b/Resources/Orthanc/Core/Images/PngWriter.cpp
similarity index 97%
rename from Framework/Orthanc/Core/Images/PngWriter.cpp
rename to Resources/Orthanc/Core/Images/PngWriter.cpp
index 8a2d66a..5603bcf 100644
--- a/Framework/Orthanc/Core/Images/PngWriter.cpp
+++ b/Resources/Orthanc/Core/Images/PngWriter.cpp
@@ -40,6 +40,10 @@
#include "../ChunkedBuffer.h"
#include "../Toolbox.h"
+#if ORTHANC_SANDBOXED == 0
+# include "../SystemToolbox.h"
+#endif
+
// http://www.libpng.org/pub/png/libpng-1.2.5-manual.html#section-4
// http://zarb.org/~gc/html/libpng.html
@@ -202,6 +206,7 @@ namespace Orthanc
}
+#if ORTHANC_SANDBOXED == 0
void PngWriter::WriteToFileInternal(const std::string& filename,
unsigned int width,
unsigned int height,
@@ -211,7 +216,7 @@ namespace Orthanc
{
Prepare(width, height, pitch, format, buffer);
- FILE* fp = Toolbox::OpenFile(filename, FileMode_WriteBinary);
+ FILE* fp = SystemToolbox::OpenFile(filename, FileMode_WriteBinary);
if (!fp)
{
throw OrthancException(ErrorCode_CannotWriteFile);
@@ -229,7 +234,7 @@ namespace Orthanc
fclose(fp);
}
-
+#endif
static void MemoryCallback(png_structp png_ptr,
diff --git a/Framework/Orthanc/Core/Images/PngWriter.h b/Resources/Orthanc/Core/Images/PngWriter.h
similarity index 98%
rename from Framework/Orthanc/Core/Images/PngWriter.h
rename to Resources/Orthanc/Core/Images/PngWriter.h
index 591112f..7d8b87f 100644
--- a/Framework/Orthanc/Core/Images/PngWriter.h
+++ b/Resources/Orthanc/Core/Images/PngWriter.h
@@ -48,12 +48,14 @@ namespace Orthanc
PixelFormat format,
const void* buffer);
+#if ORTHANC_SANDBOXED == 0
virtual void WriteToMemoryInternal(std::string& png,
unsigned int width,
unsigned int height,
unsigned int pitch,
PixelFormat format,
const void* buffer);
+#endif
private:
struct PImpl;
diff --git a/Framework/Orthanc/Core/Logging.cpp b/Resources/Orthanc/Core/Logging.cpp
similarity index 70%
rename from Framework/Orthanc/Core/Logging.cpp
rename to Resources/Orthanc/Core/Logging.cpp
index 7bce92b..cffdb5b 100644
--- a/Framework/Orthanc/Core/Logging.cpp
+++ b/Resources/Orthanc/Core/Logging.cpp
@@ -83,6 +83,7 @@ namespace Orthanc
#include "OrthancException.h"
#include "Enumerations.h"
#include "Toolbox.h"
+#include "SystemToolbox.h"
#include <fstream>
#include <boost/filesystem.hpp>
@@ -150,7 +151,7 @@ namespace Orthanc
boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
boost::filesystem::path root(directory);
- boost::filesystem::path exe(Toolbox::GetPathToExecutable());
+ boost::filesystem::path exe(SystemToolbox::GetPathToExecutable());
if (!boost::filesystem::exists(root) ||
!boost::filesystem::is_directory(root))
@@ -166,7 +167,7 @@ namespace Orthanc
now.time_of_day().hours(),
now.time_of_day().minutes(),
now.time_of_day().seconds(),
- Toolbox::GetProcessId());
+ SystemToolbox::GetProcessId());
std::string programName = exe.filename().replace_extension("").string();
@@ -318,113 +319,123 @@ namespace Orthanc
return;
}
- LogLevel l = StringToLogLevel(level);
-
- if ((l == LogLevel_Info && !loggingContext_->infoEnabled_) ||
- (l == LogLevel_Trace && !loggingContext_->traceEnabled_))
+ try
{
- // This logging level is disabled, directly exit and unlock
- // the mutex to speed-up things. The stream is set to "/dev/null"
+ LogLevel l = StringToLogLevel(level);
+
+ if ((l == LogLevel_Info && !loggingContext_->infoEnabled_) ||
+ (l == LogLevel_Trace && !loggingContext_->traceEnabled_))
+ {
+ // This logging level is disabled, directly exit and unlock
+ // the mutex to speed-up things. The stream is set to "/dev/null"
+ lock_.unlock();
+ return;
+ }
+
+ // Compute the header of the line, temporary release the lock as
+ // this is a time-consuming operation
lock_.unlock();
- return;
- }
+ std::string header;
- // Compute the header of the line, temporary release the lock as
- // this is a time-consuming operation
- lock_.unlock();
- std::string header;
+ {
+ boost::filesystem::path path(file);
+ boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time();
+ boost::posix_time::time_duration duration = now.time_of_day();
+
+ /**
+ From Google Log documentation:
+
+ "Log lines have this form:
+
+ Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg...
+
+ where the fields are defined as follows:
+
+ L A single character, representing the log level (eg 'I' for INFO)
+ mm The month (zero padded; ie May is '05')
+ dd The day (zero padded)
+ hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds
+ threadid The space-padded thread ID as returned by GetTID() (this matches the PID on Linux)
+ file The file name
+ line The line number
+ msg The user-supplied message"
+
+ In this implementation, "threadid" is not printed.
+ **/
+
+ char date[32];
+ sprintf(date, "%c%02d%02d %02d:%02d:%02d.%06d ",
+ level[0],
+ now.date().month().as_number(),
+ now.date().day().as_number(),
+ duration.hours(),
+ duration.minutes(),
+ duration.seconds(),
+ static_cast<int>(duration.fractional_seconds()));
+
+ header = std::string(date) + path.filename().string() + ":" + boost::lexical_cast<std::string>(line) + "] ";
+ }
- {
- boost::filesystem::path path(file);
- boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time();
- boost::posix_time::time_duration duration = now.time_of_day();
-
- /**
- From Google Log documentation:
-
- "Log lines have this form:
-
- Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg...
-
- where the fields are defined as follows:
-
- L A single character, representing the log level (eg 'I' for INFO)
- mm The month (zero padded; ie May is '05')
- dd The day (zero padded)
- hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds
- threadid The space-padded thread ID as returned by GetTID() (this matches the PID on Linux)
- file The file name
- line The line number
- msg The user-supplied message"
-
- In this implementation, "threadid" is not printed.
- **/
-
- char date[32];
- sprintf(date, "%c%02d%02d %02d:%02d:%02d.%06d ",
- level[0],
- now.date().month().as_number(),
- now.date().day().as_number(),
- duration.hours(),
- duration.minutes(),
- duration.seconds(),
- static_cast<int>(duration.fractional_seconds()));
-
- header = std::string(date) + path.filename().string() + ":" + boost::lexical_cast<std::string>(line) + "] ";
- }
+ // The header is computed, we now re-lock the mutex to access
+ // the stream objects. Pay attention that "loggingContext_",
+ // "infoEnabled_" or "traceEnabled_" might have changed while
+ // the mutex was unlocked.
+ lock_.lock();
- // The header is computed, we now re-lock the mutex to access
- // the stream objects. Pay attention that "loggingContext_",
- // "infoEnabled_" or "traceEnabled_" might have changed while
- // the mutex was unlocked.
- lock_.lock();
+ if (loggingContext_.get() == NULL)
+ {
+ fprintf(stderr, "ERROR: Trying to log a message after the finalization of the logging engine\n");
+ return;
+ }
- if (loggingContext_.get() == NULL)
- {
- fprintf(stderr, "ERROR: Trying to log a message after the finalization of the logging engine\n");
- return;
- }
+ switch (l)
+ {
+ case LogLevel_Error:
+ stream_ = loggingContext_->error_;
+ break;
- switch (l)
- {
- case LogLevel_Error:
- stream_ = loggingContext_->error_;
- break;
+ case LogLevel_Warning:
+ stream_ = loggingContext_->warning_;
+ break;
- case LogLevel_Warning:
- stream_ = loggingContext_->warning_;
- break;
+ case LogLevel_Info:
+ if (loggingContext_->infoEnabled_)
+ {
+ stream_ = loggingContext_->info_;
+ }
- case LogLevel_Info:
- if (loggingContext_->infoEnabled_)
- {
- stream_ = loggingContext_->info_;
- }
+ break;
- break;
+ case LogLevel_Trace:
+ if (loggingContext_->traceEnabled_)
+ {
+ stream_ = loggingContext_->info_;
+ }
- case LogLevel_Trace:
- if (loggingContext_->traceEnabled_)
- {
- stream_ = loggingContext_->info_;
- }
+ break;
- break;
+ default:
+ throw OrthancException(ErrorCode_InternalError);
+ }
- default:
- throw OrthancException(ErrorCode_InternalError);
- }
+ if (stream_ == &null_)
+ {
+ // The logging is disabled for this level. The stream is the
+ // "null_" member of this object, so we can release the global
+ // mutex.
+ lock_.unlock();
+ }
- if (stream_ == &null_)
- {
- // The logging is disabled for this level. The stream is the
- // "null_" member of this object, so we can release the global
- // mutex.
- lock_.unlock();
+ (*stream_) << header;
+ }
+ catch (...)
+ {
+ // Something is going really wrong, probably running out of
+ // memory. Fallback to a degraded mode.
+ stream_ = loggingContext_->error_;
+ (*stream_) << "E???? ??:??:??.?????? ] ";
}
-
- (*stream_) << header;
}
diff --git a/Framework/Orthanc/Core/Logging.h b/Resources/Orthanc/Core/Logging.h
similarity index 92%
rename from Framework/Orthanc/Core/Logging.h
rename to Resources/Orthanc/Core/Logging.h
index dd791d1..abec83f 100644
--- a/Framework/Orthanc/Core/Logging.h
+++ b/Resources/Orthanc/Core/Logging.h
@@ -34,6 +34,10 @@
#include <iostream>
+#if !defined(ORTHANC_ENABLE_LOGGING)
+# error The macro ORTHANC_ENABLE_LOGGING must be defined
+#endif
+
namespace Orthanc
{
namespace Logging
@@ -110,6 +114,12 @@ namespace Orthanc
{
return (*stream_) << message;
}
+
+ // This overload fixes build problems with Visual Studio 2015
+ std::ostream& operator<< (const char* message)
+ {
+ return (*stream_) << message;
+ }
};
}
}
diff --git a/Framework/Orthanc/Core/MultiThreading/BagOfTasks.h b/Resources/Orthanc/Core/MultiThreading/BagOfTasks.h
similarity index 100%
rename from Framework/Orthanc/Core/MultiThreading/BagOfTasks.h
rename to Resources/Orthanc/Core/MultiThreading/BagOfTasks.h
diff --git a/Framework/Orthanc/Core/MultiThreading/BagOfTasksProcessor.cpp b/Resources/Orthanc/Core/MultiThreading/BagOfTasksProcessor.cpp
similarity index 100%
rename from Framework/Orthanc/Core/MultiThreading/BagOfTasksProcessor.cpp
rename to Resources/Orthanc/Core/MultiThreading/BagOfTasksProcessor.cpp
diff --git a/Framework/Orthanc/Core/MultiThreading/BagOfTasksProcessor.h b/Resources/Orthanc/Core/MultiThreading/BagOfTasksProcessor.h
similarity index 100%
rename from Framework/Orthanc/Core/MultiThreading/BagOfTasksProcessor.h
rename to Resources/Orthanc/Core/MultiThreading/BagOfTasksProcessor.h
diff --git a/Framework/Orthanc/Core/MultiThreading/Semaphore.cpp b/Resources/Orthanc/Core/MultiThreading/Semaphore.cpp
similarity index 100%
rename from Framework/Orthanc/Core/MultiThreading/Semaphore.cpp
rename to Resources/Orthanc/Core/MultiThreading/Semaphore.cpp
diff --git a/Framework/Orthanc/Core/MultiThreading/Semaphore.h b/Resources/Orthanc/Core/MultiThreading/Semaphore.h
similarity index 100%
rename from Framework/Orthanc/Core/MultiThreading/Semaphore.h
rename to Resources/Orthanc/Core/MultiThreading/Semaphore.h
diff --git a/Framework/Orthanc/Core/MultiThreading/SharedMessageQueue.cpp b/Resources/Orthanc/Core/MultiThreading/SharedMessageQueue.cpp
similarity index 100%
rename from Framework/Orthanc/Core/MultiThreading/SharedMessageQueue.cpp
rename to Resources/Orthanc/Core/MultiThreading/SharedMessageQueue.cpp
diff --git a/Framework/Orthanc/Core/MultiThreading/SharedMessageQueue.h b/Resources/Orthanc/Core/MultiThreading/SharedMessageQueue.h
similarity index 100%
rename from Framework/Orthanc/Core/MultiThreading/SharedMessageQueue.h
rename to Resources/Orthanc/Core/MultiThreading/SharedMessageQueue.h
diff --git a/Framework/Orthanc/Core/OrthancException.h b/Resources/Orthanc/Core/OrthancException.h
similarity index 100%
copy from Framework/Orthanc/Core/OrthancException.h
copy to Resources/Orthanc/Core/OrthancException.h
diff --git a/Framework/Orthanc/Core/PrecompiledHeaders.cpp b/Resources/Orthanc/Core/PrecompiledHeaders.cpp
similarity index 100%
rename from Framework/Orthanc/Core/PrecompiledHeaders.cpp
rename to Resources/Orthanc/Core/PrecompiledHeaders.cpp
diff --git a/Framework/Orthanc/Core/PrecompiledHeaders.h b/Resources/Orthanc/Core/PrecompiledHeaders.h
similarity index 97%
rename from Framework/Orthanc/Core/PrecompiledHeaders.h
rename to Resources/Orthanc/Core/PrecompiledHeaders.h
index e22f012..1422e30 100644
--- a/Framework/Orthanc/Core/PrecompiledHeaders.h
+++ b/Resources/Orthanc/Core/PrecompiledHeaders.h
@@ -48,7 +48,7 @@
#include <json/value.h>
-#if ORTHANC_PUGIXML_ENABLED == 1
+#if ORTHANC_ENABLE_PUGIXML == 1
#include <pugixml.hpp>
#endif
@@ -56,6 +56,5 @@
#include "Logging.h"
#include "OrthancException.h"
#include "Toolbox.h"
-#include "Uuid.h"
#endif
diff --git a/Resources/Orthanc/Core/SystemToolbox.cpp b/Resources/Orthanc/Core/SystemToolbox.cpp
new file mode 100644
index 0000000..e22a006
--- /dev/null
+++ b/Resources/Orthanc/Core/SystemToolbox.cpp
@@ -0,0 +1,539 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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/>.
+ **/
+
+
+#include "PrecompiledHeaders.h"
+#include "SystemToolbox.h"
+
+
+#if BOOST_HAS_DATE_TIME == 1
+# include <boost/date_time/posix_time/posix_time.hpp>
+#endif
+
+
+#if defined(_WIN32)
+# include <windows.h>
+# include <process.h> // For "_spawnvp()" and "_getpid()"
+#else
+# include <unistd.h> // For "execvp()"
+# include <sys/wait.h> // For "waitpid()"
+#endif
+
+
+#if defined(__APPLE__) && defined(__MACH__)
+# include <mach-o/dyld.h> /* _NSGetExecutablePath */
+# include <limits.h> /* PATH_MAX */
+#endif
+
+
+#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
+# include <limits.h> /* PATH_MAX */
+# include <signal.h>
+# include <unistd.h>
+#endif
+
+
+// Inclusions for UUID
+// http://stackoverflow.com/a/1626302
+
+extern "C"
+{
+#ifdef WIN32
+# include <rpc.h>
+#else
+# include <uuid/uuid.h>
+#endif
+}
+
+
+#include "Logging.h"
+#include "OrthancException.h"
+#include "Toolbox.h"
+
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+
+
+namespace Orthanc
+{
+ static bool finish_;
+ static ServerBarrierEvent barrierEvent_;
+
+#if defined(_WIN32)
+ static BOOL WINAPI ConsoleControlHandler(DWORD dwCtrlType)
+ {
+ // http://msdn.microsoft.com/en-us/library/ms683242(v=vs.85).aspx
+ finish_ = true;
+ return true;
+ }
+#else
+ static void SignalHandler(int signal)
+ {
+ if (signal == SIGHUP)
+ {
+ barrierEvent_ = ServerBarrierEvent_Reload;
+ }
+
+ finish_ = true;
+ }
+#endif
+
+
+ static ServerBarrierEvent ServerBarrierInternal(const bool* stopFlag)
+ {
+#if defined(_WIN32)
+ SetConsoleCtrlHandler(ConsoleControlHandler, true);
+#else
+ signal(SIGINT, SignalHandler);
+ signal(SIGQUIT, SignalHandler);
+ signal(SIGTERM, SignalHandler);
+ signal(SIGHUP, SignalHandler);
+#endif
+
+ // Active loop that awakens every 100ms
+ finish_ = false;
+ barrierEvent_ = ServerBarrierEvent_Stop;
+ while (!(*stopFlag || finish_))
+ {
+ Toolbox::USleep(100 * 1000);
+ }
+
+#if defined(_WIN32)
+ SetConsoleCtrlHandler(ConsoleControlHandler, false);
+#else
+ signal(SIGINT, NULL);
+ signal(SIGQUIT, NULL);
+ signal(SIGTERM, NULL);
+ signal(SIGHUP, NULL);
+#endif
+
+ return barrierEvent_;
+ }
+
+
+ ServerBarrierEvent SystemToolbox::ServerBarrier(const bool& stopFlag)
+ {
+ return ServerBarrierInternal(&stopFlag);
+ }
+
+
+ ServerBarrierEvent SystemToolbox::ServerBarrier()
+ {
+ const bool stopFlag = false;
+ return ServerBarrierInternal(&stopFlag);
+ }
+
+
+ static std::streamsize GetStreamSize(std::istream& f)
+ {
+ // http://www.cplusplus.com/reference/iostream/istream/tellg/
+ f.seekg(0, std::ios::end);
+ std::streamsize size = f.tellg();
+ f.seekg(0, std::ios::beg);
+
+ return size;
+ }
+
+
+ void SystemToolbox::ReadFile(std::string& content,
+ const std::string& path)
+ {
+ if (!IsRegularFile(path))
+ {
+ LOG(ERROR) << std::string("The path does not point to a regular file: ") << path;
+ throw OrthancException(ErrorCode_RegularFileExpected);
+ }
+
+ boost::filesystem::ifstream f;
+ f.open(path, std::ifstream::in | std::ifstream::binary);
+ if (!f.good())
+ {
+ throw OrthancException(ErrorCode_InexistentFile);
+ }
+
+ std::streamsize size = GetStreamSize(f);
+ content.resize(size);
+ if (size != 0)
+ {
+ f.read(reinterpret_cast<char*>(&content[0]), size);
+ }
+
+ f.close();
+ }
+
+
+ bool SystemToolbox::ReadHeader(std::string& header,
+ const std::string& path,
+ size_t headerSize)
+ {
+ if (!IsRegularFile(path))
+ {
+ LOG(ERROR) << std::string("The path does not point to a regular file: ") << path;
+ throw OrthancException(ErrorCode_RegularFileExpected);
+ }
+
+ boost::filesystem::ifstream f;
+ f.open(path, std::ifstream::in | std::ifstream::binary);
+ if (!f.good())
+ {
+ throw OrthancException(ErrorCode_InexistentFile);
+ }
+
+ bool full = true;
+
+ {
+ std::streamsize size = GetStreamSize(f);
+ if (size <= 0)
+ {
+ headerSize = 0;
+ full = false;
+ }
+ else if (static_cast<size_t>(size) < headerSize)
+ {
+ headerSize = size; // Truncate to the size of the file
+ full = false;
+ }
+ }
+
+ header.resize(headerSize);
+ if (headerSize != 0)
+ {
+ f.read(reinterpret_cast<char*>(&header[0]), headerSize);
+ }
+
+ f.close();
+
+ return full;
+ }
+
+
+ void SystemToolbox::WriteFile(const void* content,
+ size_t size,
+ const std::string& path)
+ {
+ boost::filesystem::ofstream f;
+ f.open(path, std::ofstream::out | std::ofstream::binary);
+ if (!f.good())
+ {
+ throw OrthancException(ErrorCode_CannotWriteFile);
+ }
+
+ if (size != 0)
+ {
+ f.write(reinterpret_cast<const char*>(content), size);
+
+ if (!f.good())
+ {
+ f.close();
+ throw OrthancException(ErrorCode_FileStorageCannotWrite);
+ }
+ }
+
+ f.close();
+ }
+
+
+ void SystemToolbox::WriteFile(const std::string& content,
+ const std::string& path)
+ {
+ WriteFile(content.size() > 0 ? content.c_str() : NULL,
+ content.size(), path);
+ }
+
+
+ void SystemToolbox::RemoveFile(const std::string& path)
+ {
+ if (boost::filesystem::exists(path))
+ {
+ if (IsRegularFile(path))
+ {
+ boost::filesystem::remove(path);
+ }
+ else
+ {
+ throw OrthancException(ErrorCode_RegularFileExpected);
+ }
+ }
+ }
+
+
+ uint64_t SystemToolbox::GetFileSize(const std::string& path)
+ {
+ try
+ {
+ return static_cast<uint64_t>(boost::filesystem::file_size(path));
+ }
+ catch (boost::filesystem::filesystem_error&)
+ {
+ throw OrthancException(ErrorCode_InexistentFile);
+ }
+ }
+
+
+ void SystemToolbox::MakeDirectory(const std::string& path)
+ {
+ if (boost::filesystem::exists(path))
+ {
+ if (!boost::filesystem::is_directory(path))
+ {
+ throw OrthancException(ErrorCode_DirectoryOverFile);
+ }
+ }
+ else
+ {
+ if (!boost::filesystem::create_directories(path))
+ {
+ throw OrthancException(ErrorCode_MakeDirectory);
+ }
+ }
+ }
+
+
+ bool SystemToolbox::IsExistingFile(const std::string& path)
+ {
+ return boost::filesystem::exists(path);
+ }
+
+
+#if defined(_WIN32)
+ static std::string GetPathToExecutableInternal()
+ {
+ // Yes, this is ugly, but there is no simple way to get the
+ // required buffer size, so we use a big constant
+ std::vector<char> buffer(32768);
+ /*int bytes =*/ GetModuleFileNameA(NULL, &buffer[0], static_cast<DWORD>(buffer.size() - 1));
+ return std::string(&buffer[0]);
+ }
+
+#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
+ static std::string GetPathToExecutableInternal()
+ {
+ std::vector<char> buffer(PATH_MAX + 1);
+ ssize_t bytes = readlink("/proc/self/exe", &buffer[0], buffer.size() - 1);
+ if (bytes == 0)
+ {
+ throw OrthancException(ErrorCode_PathToExecutable);
+ }
+
+ return std::string(&buffer[0]);
+ }
+
+#elif defined(__APPLE__) && defined(__MACH__)
+ static std::string GetPathToExecutableInternal()
+ {
+ char pathbuf[PATH_MAX + 1];
+ unsigned int bufsize = static_cast<int>(sizeof(pathbuf));
+
+ _NSGetExecutablePath( pathbuf, &bufsize);
+
+ return std::string(pathbuf);
+ }
+
+#else
+#error Support your platform here
+#endif
+
+
+ std::string SystemToolbox::GetPathToExecutable()
+ {
+ boost::filesystem::path p(GetPathToExecutableInternal());
+ return boost::filesystem::absolute(p).string();
+ }
+
+
+ std::string SystemToolbox::GetDirectoryOfExecutable()
+ {
+ boost::filesystem::path p(GetPathToExecutableInternal());
+ return boost::filesystem::absolute(p.parent_path()).string();
+ }
+
+
+ void SystemToolbox::ExecuteSystemCommand(const std::string& command,
+ const std::vector<std::string>& arguments)
+ {
+ // Convert the arguments as a C array
+ std::vector<char*> args(arguments.size() + 2);
+
+ args.front() = const_cast<char*>(command.c_str());
+
+ for (size_t i = 0; i < arguments.size(); i++)
+ {
+ args[i + 1] = const_cast<char*>(arguments[i].c_str());
+ }
+
+ args.back() = NULL;
+
+ int status;
+
+#if defined(_WIN32)
+ // http://msdn.microsoft.com/en-us/library/275khfab.aspx
+ status = static_cast<int>(_spawnvp(_P_OVERLAY, command.c_str(), &args[0]));
+
+#else
+ int pid = fork();
+
+ if (pid == -1)
+ {
+ // Error in fork()
+#if ORTHANC_ENABLE_LOGGING == 1
+ LOG(ERROR) << "Cannot fork a child process";
+#endif
+
+ throw OrthancException(ErrorCode_SystemCommand);
+ }
+ else if (pid == 0)
+ {
+ // Execute the system command in the child process
+ execvp(command.c_str(), &args[0]);
+
+ // We should never get here
+ _exit(1);
+ }
+ else
+ {
+ // Wait for the system command to exit
+ waitpid(pid, &status, 0);
+ }
+#endif
+
+ if (status != 0)
+ {
+#if ORTHANC_ENABLE_LOGGING == 1
+ LOG(ERROR) << "System command failed with status code " << status;
+#endif
+
+ throw OrthancException(ErrorCode_SystemCommand);
+ }
+ }
+
+
+ int SystemToolbox::GetProcessId()
+ {
+#if defined(_WIN32)
+ return static_cast<int>(_getpid());
+#else
+ return static_cast<int>(getpid());
+#endif
+ }
+
+
+ bool SystemToolbox::IsRegularFile(const std::string& path)
+ {
+ namespace fs = boost::filesystem;
+
+ try
+ {
+ if (fs::exists(path))
+ {
+ fs::file_status status = fs::status(path);
+ return (status.type() == boost::filesystem::regular_file ||
+ status.type() == boost::filesystem::reparse_file); // Fix BitBucket issue #11
+ }
+ }
+ catch (fs::filesystem_error&)
+ {
+ }
+
+ return false;
+ }
+
+
+ FILE* SystemToolbox::OpenFile(const std::string& path,
+ FileMode mode)
+ {
+#if defined(_WIN32)
+ // TODO Deal with special characters by converting to the current locale
+#endif
+
+ const char* m;
+ switch (mode)
+ {
+ case FileMode_ReadBinary:
+ m = "rb";
+ break;
+
+ case FileMode_WriteBinary:
+ m = "wb";
+ break;
+
+ default:
+ throw OrthancException(ErrorCode_ParameterOutOfRange);
+ }
+
+ return fopen(path.c_str(), m);
+ }
+
+
+ std::string SystemToolbox::GenerateUuid()
+ {
+#ifdef WIN32
+ UUID uuid;
+ UuidCreate ( &uuid );
+
+ unsigned char * str;
+ UuidToStringA ( &uuid, &str );
+
+ std::string s( ( char* ) str );
+
+ RpcStringFreeA ( &str );
+#else
+ uuid_t uuid;
+ uuid_generate_random ( uuid );
+ char s[37];
+ uuid_unparse ( uuid, s );
+#endif
+ return s;
+ }
+
+
+#if BOOST_HAS_DATE_TIME == 1
+ std::string SystemToolbox::GetNowIsoString()
+ {
+ boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
+ return boost::posix_time::to_iso_string(now);
+ }
+
+ void SystemToolbox::GetNowDicom(std::string& date,
+ std::string& time)
+ {
+ boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
+ tm tm = boost::posix_time::to_tm(now);
+
+ char s[32];
+ sprintf(s, "%04d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+ date.assign(s);
+
+ // TODO milliseconds
+ sprintf(s, "%02d%02d%02d.%06d", tm.tm_hour, tm.tm_min, tm.tm_sec, 0);
+ time.assign(s);
+ }
+#endif
+}
diff --git a/Framework/Orthanc/Core/OrthancException.h b/Resources/Orthanc/Core/SystemToolbox.h
similarity index 52%
rename from Framework/Orthanc/Core/OrthancException.h
rename to Resources/Orthanc/Core/SystemToolbox.h
index 5afa41f..e62b529 100644
--- a/Framework/Orthanc/Core/OrthancException.h
+++ b/Resources/Orthanc/Core/SystemToolbox.h
@@ -32,45 +32,71 @@
#pragma once
-#include <stdint.h>
-#include <string>
+#if !defined(ORTHANC_SANDBOXED)
+# error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
+#if ORTHANC_SANDBOXED == 1
+# error The namespace SystemToolbox cannot be used in sandboxed environments
+#endif
+
#include "Enumerations.h"
+#include <vector>
+#include <string>
+#include <stdint.h>
+
namespace Orthanc
{
- class OrthancException
+ namespace SystemToolbox
{
- protected:
- ErrorCode errorCode_;
- HttpStatus httpStatus_;
-
- public:
- OrthancException(ErrorCode errorCode) :
- errorCode_(errorCode),
- httpStatus_(ConvertErrorCodeToHttpStatus(errorCode))
- {
- }
-
- OrthancException(ErrorCode errorCode,
- HttpStatus httpStatus) :
- errorCode_(errorCode),
- httpStatus_(httpStatus)
- {
- }
-
- ErrorCode GetErrorCode() const
- {
- return errorCode_;
- }
-
- HttpStatus GetHttpStatus() const
- {
- return httpStatus_;
- }
-
- const char* What() const
- {
- return EnumerationToString(errorCode_);
- }
- };
+ ServerBarrierEvent ServerBarrier(const bool& stopFlag);
+
+ ServerBarrierEvent ServerBarrier();
+
+ void ReadFile(std::string& content,
+ const std::string& path);
+
+ bool ReadHeader(std::string& header,
+ const std::string& path,
+ size_t headerSize);
+
+ void WriteFile(const void* content,
+ size_t size,
+ const std::string& path);
+
+ void WriteFile(const std::string& content,
+ const std::string& path);
+
+ void RemoveFile(const std::string& path);
+
+ uint64_t GetFileSize(const std::string& path);
+
+ void MakeDirectory(const std::string& path);
+
+ bool IsExistingFile(const std::string& path);
+
+ std::string GetPathToExecutable();
+
+ std::string GetDirectoryOfExecutable();
+
+ void ExecuteSystemCommand(const std::string& command,
+ const std::vector<std::string>& arguments);
+
+ int GetProcessId();
+
+ bool IsRegularFile(const std::string& path);
+
+ FILE* OpenFile(const std::string& path,
+ FileMode mode);
+
+ std::string GenerateUuid();
+
+#if BOOST_HAS_DATE_TIME == 1
+ std::string GetNowIsoString();
+
+ void GetNowDicom(std::string& date,
+ std::string& time);
+#endif
+ }
}
diff --git a/Framework/Orthanc/Core/Uuid.h b/Resources/Orthanc/Core/TemporaryFile.cpp
similarity index 58%
rename from Framework/Orthanc/Core/Uuid.h
rename to Resources/Orthanc/Core/TemporaryFile.cpp
index 88819a3..955489b 100644
--- a/Framework/Orthanc/Core/Uuid.h
+++ b/Resources/Orthanc/Core/TemporaryFile.cpp
@@ -30,57 +30,65 @@
**/
-#pragma once
-
-#include <string>
-
-/**
- * GUID vs. UUID
- * The simple answer is: no difference, they are the same thing. Treat
- * them as a 16 byte (128 bits) value that is used as a unique
- * value. In Microsoft-speak they are called GUIDs, but call them
- * UUIDs when not using Microsoft-speak.
- * http://stackoverflow.com/questions/246930/is-there-any-difference-between-a-guid-and-a-uuid
- **/
+#include "PrecompiledHeaders.h"
+#include "TemporaryFile.h"
+#include "SystemToolbox.h"
#include "Toolbox.h"
+#include <boost/filesystem.hpp>
+
namespace Orthanc
{
- namespace Toolbox
+ static std::string CreateTemporaryPath(const char* extension)
{
- std::string GenerateUuid();
-
- bool IsUuid(const std::string& str);
+#if BOOST_HAS_FILESYSTEM_V3 == 1
+ boost::filesystem::path tmpDir = boost::filesystem::temp_directory_path();
+#elif defined(__linux__)
+ boost::filesystem::path tmpDir("/tmp");
+#else
+#error Support your platform here
+#endif
- bool StartsWithUuid(const std::string& str);
+ // We use UUID to create unique path to temporary files
+ std::string filename = "Orthanc-" + Orthanc::SystemToolbox::GenerateUuid();
- class TemporaryFile
+ if (extension != NULL)
{
- private:
- std::string path_;
+ filename.append(extension);
+ }
- public:
- TemporaryFile();
+ tmpDir /= filename;
+ return tmpDir.string();
+ }
- TemporaryFile(const char* extension);
- ~TemporaryFile();
+ TemporaryFile::TemporaryFile() :
+ path_(CreateTemporaryPath(NULL))
+ {
+ }
- const std::string& GetPath() const
- {
- return path_;
- }
- void Write(const std::string& content)
- {
- Toolbox::WriteFile(content, path_);
- }
+ TemporaryFile::TemporaryFile(const char* extension) :
+ path_(CreateTemporaryPath(extension))
+ {
+ }
- void Read(std::string& content) const
- {
- Toolbox::ReadFile(content, path_);
- }
- };
+
+ TemporaryFile::~TemporaryFile()
+ {
+ boost::filesystem::remove(path_);
+ }
+
+
+ void TemporaryFile::Write(const std::string& content)
+ {
+ SystemToolbox::WriteFile(content, path_);
+ }
+
+
+ void TemporaryFile::Read(std::string& content) const
+ {
+ SystemToolbox::ReadFile(content, path_);
}
}
diff --git a/Framework/Orthanc/Core/ChunkedBuffer.h b/Resources/Orthanc/Core/TemporaryFile.h
similarity index 77%
rename from Framework/Orthanc/Core/ChunkedBuffer.h
rename to Resources/Orthanc/Core/TemporaryFile.h
index 552c1ec..1dd4f73 100644
--- a/Framework/Orthanc/Core/ChunkedBuffer.h
+++ b/Resources/Orthanc/Core/TemporaryFile.h
@@ -32,40 +32,37 @@
#pragma once
-#include <list>
+#if !defined(ORTHANC_SANDBOXED)
+# error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
+#if ORTHANC_SANDBOXED == 1
+# error The class TemporaryFile cannot be used in sandboxed environments
+#endif
+
#include <string>
namespace Orthanc
{
- class ChunkedBuffer
+ class TemporaryFile
{
private:
- typedef std::list<std::string*> Chunks;
- size_t numBytes_;
- Chunks chunks_;
-
- void Clear();
+ std::string path_;
public:
- ChunkedBuffer() : numBytes_(0)
- {
- }
+ TemporaryFile();
- ~ChunkedBuffer()
- {
- Clear();
- }
+ TemporaryFile(const char* extension);
- size_t GetNumBytes() const
+ ~TemporaryFile();
+
+ const std::string& GetPath() const
{
- return numBytes_;
+ return path_;
}
- void AddChunk(const void* chunkData,
- size_t chunkSize);
-
- void AddChunk(const std::string& chunk);
+ void Write(const std::string& content);
- void Flatten(std::string& result);
+ void Read(std::string& content) const;
};
}
diff --git a/Framework/Orthanc/Core/Toolbox.cpp b/Resources/Orthanc/Core/Toolbox.cpp
similarity index 69%
rename from Framework/Orthanc/Core/Toolbox.cpp
rename to Resources/Orthanc/Core/Toolbox.cpp
index ac1ad51..cb9bcb2 100644
--- a/Framework/Orthanc/Core/Toolbox.cpp
+++ b/Resources/Orthanc/Core/Toolbox.cpp
@@ -36,57 +36,31 @@
#include "OrthancException.h"
#include "Logging.h"
+#include <boost/algorithm/string/replace.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/locale.hpp>
+#include <boost/uuid/sha1.hpp>
+
#include <string>
#include <stdint.h>
#include <string.h>
-#include <boost/filesystem.hpp>
-#include <boost/filesystem/fstream.hpp>
-#include <boost/uuid/sha1.hpp>
-#include <boost/lexical_cast.hpp>
#include <algorithm>
#include <ctype.h>
-#if BOOST_HAS_DATE_TIME == 1
-#include <boost/date_time/posix_time/posix_time.hpp>
-#endif
-
#if BOOST_HAS_REGEX == 1
-#include <boost/regex.hpp>
-#endif
-
-#if defined(_WIN32)
-#include <windows.h>
-#include <process.h> // For "_spawnvp()" and "_getpid()"
-#else
-#include <unistd.h> // For "execvp()"
-#include <sys/wait.h> // For "waitpid()"
-#endif
-
-#if defined(__APPLE__) && defined(__MACH__)
-#include <mach-o/dyld.h> /* _NSGetExecutablePath */
-#include <limits.h> /* PATH_MAX */
-#endif
-
-#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
-#include <limits.h> /* PATH_MAX */
-#include <signal.h>
-#include <unistd.h>
+# include <boost/regex.hpp>
#endif
#if BOOST_HAS_LOCALE != 1
-#error Since version 0.7.6, Orthanc entirely relies on boost::locale
+# error Since version 0.7.6, Orthanc entirely relies on boost::locale
#endif
-#include <boost/locale.hpp>
-
-
-#if !defined(ORTHANC_ENABLE_MD5) || ORTHANC_ENABLE_MD5 == 1
-#include "../Resources/ThirdParty/md5/md5.h"
+#if ORTHANC_ENABLE_MD5 == 1
+# include "../Resources/ThirdParty/md5/md5.h"
#endif
-
-#if !defined(ORTHANC_ENABLE_BASE64) || ORTHANC_ENABLE_BASE64 == 1
-#include "../Resources/ThirdParty/base64/base64.h"
+#if ORTHANC_ENABLE_BASE64 == 1
+# include "../Resources/ThirdParty/base64/base64.h"
#endif
@@ -103,9 +77,14 @@ extern "C"
#endif
-#if ORTHANC_PUGIXML_ENABLED == 1
-#include "ChunkedBuffer.h"
-#include <pugixml.hpp>
+#if defined(_WIN32)
+# include <windows.h> // For ::Sleep
+#endif
+
+
+#if ORTHANC_ENABLE_PUGIXML == 1
+# include "ChunkedBuffer.h"
+# include <pugixml.hpp>
#endif
@@ -123,75 +102,6 @@ namespace Orthanc
}
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
- static bool finish_;
- static ServerBarrierEvent barrierEvent_;
-
-#if defined(_WIN32)
- static BOOL WINAPI ConsoleControlHandler(DWORD dwCtrlType)
- {
- // http://msdn.microsoft.com/en-us/library/ms683242(v=vs.85).aspx
- finish_ = true;
- return true;
- }
-#else
- static void SignalHandler(int signal)
- {
- if (signal == SIGHUP)
- {
- barrierEvent_ = ServerBarrierEvent_Reload;
- }
-
- finish_ = true;
- }
-#endif
-
-
- static ServerBarrierEvent ServerBarrierInternal(const bool* stopFlag)
- {
-#if defined(_WIN32)
- SetConsoleCtrlHandler(ConsoleControlHandler, true);
-#else
- signal(SIGINT, SignalHandler);
- signal(SIGQUIT, SignalHandler);
- signal(SIGTERM, SignalHandler);
- signal(SIGHUP, SignalHandler);
-#endif
-
- // Active loop that awakens every 100ms
- finish_ = false;
- barrierEvent_ = ServerBarrierEvent_Stop;
- while (!(*stopFlag || finish_))
- {
- Toolbox::USleep(100 * 1000);
- }
-
-#if defined(_WIN32)
- SetConsoleCtrlHandler(ConsoleControlHandler, false);
-#else
- signal(SIGINT, NULL);
- signal(SIGQUIT, NULL);
- signal(SIGTERM, NULL);
- signal(SIGHUP, NULL);
-#endif
-
- return barrierEvent_;
- }
-
-
- ServerBarrierEvent Toolbox::ServerBarrier(const bool& stopFlag)
- {
- return ServerBarrierInternal(&stopFlag);
- }
-
- ServerBarrierEvent Toolbox::ServerBarrier()
- {
- const bool stopFlag = false;
- return ServerBarrierInternal(&stopFlag);
- }
-#endif /* ORTHANC_SANDBOXED */
-
-
void Toolbox::ToUpperCase(std::string& s)
{
std::transform(s.begin(), s.end(), s.begin(), toupper);
@@ -219,149 +129,6 @@ namespace Orthanc
}
- static std::streamsize GetStreamSize(std::istream& f)
- {
- // http://www.cplusplus.com/reference/iostream/istream/tellg/
- f.seekg(0, std::ios::end);
- std::streamsize size = f.tellg();
- f.seekg(0, std::ios::beg);
-
- return size;
- }
-
-
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
- void Toolbox::ReadFile(std::string& content,
- const std::string& path)
- {
- if (!IsRegularFile(path))
- {
- LOG(ERROR) << std::string("The path does not point to a regular file: ") << path;
- throw OrthancException(ErrorCode_RegularFileExpected);
- }
-
- boost::filesystem::ifstream f;
- f.open(path, std::ifstream::in | std::ifstream::binary);
- if (!f.good())
- {
- throw OrthancException(ErrorCode_InexistentFile);
- }
-
- std::streamsize size = GetStreamSize(f);
- content.resize(size);
- if (size != 0)
- {
- f.read(reinterpret_cast<char*>(&content[0]), size);
- }
-
- f.close();
- }
-#endif
-
-
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
- bool Toolbox::ReadHeader(std::string& header,
- const std::string& path,
- size_t headerSize)
- {
- if (!IsRegularFile(path))
- {
- LOG(ERROR) << std::string("The path does not point to a regular file: ") << path;
- throw OrthancException(ErrorCode_RegularFileExpected);
- }
-
- boost::filesystem::ifstream f;
- f.open(path, std::ifstream::in | std::ifstream::binary);
- if (!f.good())
- {
- throw OrthancException(ErrorCode_InexistentFile);
- }
-
- bool full = true;
-
- {
- std::streamsize size = GetStreamSize(f);
- if (size <= 0)
- {
- headerSize = 0;
- full = false;
- }
- else if (static_cast<size_t>(size) < headerSize)
- {
- headerSize = size; // Truncate to the size of the file
- full = false;
- }
- }
-
- header.resize(headerSize);
- if (headerSize != 0)
- {
- f.read(reinterpret_cast<char*>(&header[0]), headerSize);
- }
-
- f.close();
-
- return full;
- }
-#endif
-
-
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
- void Toolbox::WriteFile(const void* content,
- size_t size,
- const std::string& path)
- {
- boost::filesystem::ofstream f;
- f.open(path, std::ofstream::out | std::ofstream::binary);
- if (!f.good())
- {
- throw OrthancException(ErrorCode_CannotWriteFile);
- }
-
- if (size != 0)
- {
- f.write(reinterpret_cast<const char*>(content), size);
-
- if (!f.good())
- {
- f.close();
- throw OrthancException(ErrorCode_FileStorageCannotWrite);
- }
- }
-
- f.close();
- }
-#endif
-
-
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
- void Toolbox::WriteFile(const std::string& content,
- const std::string& path)
- {
- WriteFile(content.size() > 0 ? content.c_str() : NULL,
- content.size(), path);
- }
-#endif
-
-
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
- void Toolbox::RemoveFile(const std::string& path)
- {
- if (boost::filesystem::exists(path))
- {
- if (IsRegularFile(path))
- {
- boost::filesystem::remove(path);
- }
- else
- {
- throw OrthancException(ErrorCode_RegularFileExpected);
- }
- }
- }
-#endif
-
-
void Toolbox::SplitUriComponents(UriComponents& components,
const std::string& uri)
{
@@ -529,23 +296,7 @@ namespace Orthanc
}
-
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
- uint64_t Toolbox::GetFileSize(const std::string& path)
- {
- try
- {
- return static_cast<uint64_t>(boost::filesystem::file_size(path));
- }
- catch (boost::filesystem::filesystem_error&)
- {
- throw OrthancException(ErrorCode_InexistentFile);
- }
- }
-#endif
-
-
-#if !defined(ORTHANC_ENABLE_MD5) || ORTHANC_ENABLE_MD5 == 1
+#if ORTHANC_ENABLE_MD5 == 1
static char GetHexadecimalCharacter(uint8_t value)
{
assert(value < 16);
@@ -602,7 +353,7 @@ namespace Orthanc
#endif
-#if !defined(ORTHANC_ENABLE_BASE64) || ORTHANC_ENABLE_BASE64 == 1
+#if ORTHANC_ENABLE_BASE64 == 1
void Toolbox::EncodeBase64(std::string& result,
const std::string& data)
{
@@ -661,65 +412,6 @@ namespace Orthanc
#endif
-
-#if defined(_WIN32)
- static std::string GetPathToExecutableInternal()
- {
- // Yes, this is ugly, but there is no simple way to get the
- // required buffer size, so we use a big constant
- std::vector<char> buffer(32768);
- /*int bytes =*/ GetModuleFileNameA(NULL, &buffer[0], static_cast<DWORD>(buffer.size() - 1));
- return std::string(&buffer[0]);
- }
-
-#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
- static std::string GetPathToExecutableInternal()
- {
- std::vector<char> buffer(PATH_MAX + 1);
- ssize_t bytes = readlink("/proc/self/exe", &buffer[0], buffer.size() - 1);
- if (bytes == 0)
- {
- throw OrthancException(ErrorCode_PathToExecutable);
- }
-
- return std::string(&buffer[0]);
- }
-
-#elif defined(__APPLE__) && defined(__MACH__)
- static std::string GetPathToExecutableInternal()
- {
- char pathbuf[PATH_MAX + 1];
- unsigned int bufsize = static_cast<int>(sizeof(pathbuf));
-
- _NSGetExecutablePath( pathbuf, &bufsize);
-
- return std::string(pathbuf);
- }
-
-#elif defined(ORTHANC_SANDBOXED) && ORTHANC_SANDBOXED == 1
- // Sandboxed Orthanc, no access to the executable
-
-#else
-#error Support your platform here
-#endif
-
-
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
- std::string Toolbox::GetPathToExecutable()
- {
- boost::filesystem::path p(GetPathToExecutableInternal());
- return boost::filesystem::absolute(p).string();
- }
-
-
- std::string Toolbox::GetDirectoryOfExecutable()
- {
- boost::filesystem::path p(GetPathToExecutableInternal());
- return boost::filesystem::absolute(p.parent_path()).string();
- }
-#endif
-
-
static const char* GetBoostLocaleEncoding(const Encoding sourceEncoding)
{
switch (sourceEncoding)
@@ -844,6 +536,23 @@ namespace Orthanc
}
+ bool Toolbox::IsAsciiString(const void* data,
+ size_t size)
+ {
+ const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
+
+ for (size_t i = 0; i < size; i++, p++)
+ {
+ if (*p > 127 || (*p != 0 && iscntrl(*p)))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
std::string Toolbox::ConvertToAscii(const std::string& source)
{
std::string result;
@@ -980,30 +689,6 @@ namespace Orthanc
}
-#if BOOST_HAS_DATE_TIME == 1
- std::string Toolbox::GetNowIsoString()
- {
- boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
- return boost::posix_time::to_iso_string(now);
- }
-
- void Toolbox::GetNowDicom(std::string& date,
- std::string& time)
- {
- boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
- tm tm = boost::posix_time::to_tm(now);
-
- char s[32];
- sprintf(s, "%04d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
- date.assign(s);
-
- // TODO milliseconds
- sprintf(s, "%02d%02d%02d.%06d", tm.tm_hour, tm.tm_min, tm.tm_sec, 0);
- time.assign(s);
- }
-#endif
-
-
std::string Toolbox::StripSpaces(const std::string& source)
{
size_t first = 0;
@@ -1161,36 +846,7 @@ namespace Orthanc
}
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
- void Toolbox::MakeDirectory(const std::string& path)
- {
- if (boost::filesystem::exists(path))
- {
- if (!boost::filesystem::is_directory(path))
- {
- throw OrthancException(ErrorCode_DirectoryOverFile);
- }
- }
- else
- {
- if (!boost::filesystem::create_directories(path))
- {
- throw OrthancException(ErrorCode_MakeDirectory);
- }
- }
- }
-#endif
-
-
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
- bool Toolbox::IsExistingFile(const std::string& path)
- {
- return boost::filesystem::exists(path);
- }
-#endif
-
-
-#if ORTHANC_PUGIXML_ENABLED == 1
+#if ORTHANC_ENABLE_PUGIXML == 1
class ChunkedBufferWriter : public pugi::xml_writer
{
private:
@@ -1312,66 +968,6 @@ namespace Orthanc
#endif
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
- void Toolbox::ExecuteSystemCommand(const std::string& command,
- const std::vector<std::string>& arguments)
- {
- // Convert the arguments as a C array
- std::vector<char*> args(arguments.size() + 2);
-
- args.front() = const_cast<char*>(command.c_str());
-
- for (size_t i = 0; i < arguments.size(); i++)
- {
- args[i + 1] = const_cast<char*>(arguments[i].c_str());
- }
-
- args.back() = NULL;
-
- int status;
-
-#if defined(_WIN32)
- // http://msdn.microsoft.com/en-us/library/275khfab.aspx
- status = static_cast<int>(_spawnvp(_P_OVERLAY, command.c_str(), &args[0]));
-
-#else
- int pid = fork();
-
- if (pid == -1)
- {
- // Error in fork()
-#if ORTHANC_ENABLE_LOGGING == 1
- LOG(ERROR) << "Cannot fork a child process";
-#endif
-
- throw OrthancException(ErrorCode_SystemCommand);
- }
- else if (pid == 0)
- {
- // Execute the system command in the child process
- execvp(command.c_str(), &args[0]);
-
- // We should never get here
- _exit(1);
- }
- else
- {
- // Wait for the system command to exit
- waitpid(pid, &status, 0);
- }
-#endif
-
- if (status != 0)
- {
-#if ORTHANC_ENABLE_LOGGING == 1
- LOG(ERROR) << "System command failed with status code " << status;
-#endif
-
- throw OrthancException(ErrorCode_SystemCommand);
- }
- }
-#endif
-
bool Toolbox::IsInteger(const std::string& str)
{
@@ -1479,66 +1075,6 @@ namespace Orthanc
return str.compare(0, prefix.size(), prefix) == 0;
}
}
-
-
- int Toolbox::GetProcessId()
- {
-#if defined(_WIN32)
- return static_cast<int>(_getpid());
-#else
- return static_cast<int>(getpid());
-#endif
- }
-
-
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
- bool Toolbox::IsRegularFile(const std::string& path)
- {
- namespace fs = boost::filesystem;
-
- try
- {
- if (fs::exists(path))
- {
- fs::file_status status = fs::status(path);
- return (status.type() == boost::filesystem::regular_file ||
- status.type() == boost::filesystem::reparse_file); // Fix BitBucket issue #11
- }
- }
- catch (fs::filesystem_error&)
- {
- }
-
- return false;
- }
-#endif
-
-
- FILE* Toolbox::OpenFile(const std::string& path,
- FileMode mode)
- {
-#if defined(_WIN32)
- // TODO Deal with special characters by converting to the current locale
-#endif
-
- const char* m;
- switch (mode)
- {
- case FileMode_ReadBinary:
- m = "rb";
- break;
-
- case FileMode_WriteBinary:
- m = "wb";
- break;
-
- default:
- throw OrthancException(ErrorCode_ParameterOutOfRange);
- }
-
- return fopen(path.c_str(), m);
- }
-
static bool IsUnreservedCharacter(char c)
@@ -1679,4 +1215,51 @@ namespace Orthanc
return static_cast<unsigned int>(v);
}
}
+
+
+ bool Toolbox::IsUuid(const std::string& str)
+ {
+ if (str.size() != 36)
+ {
+ return false;
+ }
+
+ for (size_t i = 0; i < str.length(); i++)
+ {
+ if (i == 8 || i == 13 || i == 18 || i == 23)
+ {
+ if (str[i] != '-')
+ return false;
+ }
+ else
+ {
+ if (!isalnum(str[i]))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ bool Toolbox::StartsWithUuid(const std::string& str)
+ {
+ if (str.size() < 36)
+ {
+ return false;
+ }
+
+ if (str.size() == 36)
+ {
+ return IsUuid(str);
+ }
+
+ assert(str.size() > 36);
+ if (!isspace(str[36]))
+ {
+ return false;
+ }
+
+ return IsUuid(str.substr(0, 36));
+ }
}
diff --git a/Framework/Orthanc/Core/Toolbox.h b/Resources/Orthanc/Core/Toolbox.h
similarity index 72%
rename from Framework/Orthanc/Core/Toolbox.h
rename to Resources/Orthanc/Core/Toolbox.h
index 98195bc..d32777a 100644
--- a/Framework/Orthanc/Core/Toolbox.h
+++ b/Resources/Orthanc/Core/Toolbox.h
@@ -39,6 +39,35 @@
#include <string>
#include <json/json.h>
+
+#if !defined(ORTHANC_ENABLE_BASE64)
+# error The macro ORTHANC_ENABLE_BASE64 must be defined
+#endif
+
+#if !defined(ORTHANC_ENABLE_MD5)
+# error The macro ORTHANC_ENABLE_MD5 must be defined
+#endif
+
+#if !defined(ORTHANC_ENABLE_PUGIXML)
+# error The macro ORTHANC_ENABLE_PUGIXML must be defined
+#endif
+
+#if !defined(BOOST_HAS_REGEX)
+# error The macro BOOST_HAS_REGEX must be defined
+#endif
+
+
+/**
+ * NOTE: GUID vs. UUID
+ * The simple answer is: no difference, they are the same thing. Treat
+ * them as a 16 byte (128 bits) value that is used as a unique
+ * value. In Microsoft-speak they are called GUIDs, but call them
+ * UUIDs when not using Microsoft-speak.
+ * http://stackoverflow.com/questions/246930/is-there-any-difference-between-a-guid-and-a-uuid
+ **/
+
+
+
namespace Orthanc
{
typedef std::vector<std::string> UriComponents;
@@ -51,12 +80,6 @@ namespace Orthanc
{
void USleep(uint64_t microSeconds);
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
- ServerBarrierEvent ServerBarrier(const bool& stopFlag);
-
- ServerBarrierEvent ServerBarrier();
-#endif
-
void ToUpperCase(std::string& s); // Inplace version
void ToLowerCase(std::string& s); // Inplace version
@@ -67,32 +90,6 @@ namespace Orthanc
void ToLowerCase(std::string& result,
const std::string& source);
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
- void ReadFile(std::string& content,
- const std::string& path);
-#endif
-
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
- bool ReadHeader(std::string& header,
- const std::string& path,
- size_t headerSize);
-#endif
-
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
- void WriteFile(const std::string& content,
- const std::string& path);
-#endif
-
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
- void WriteFile(const void* content,
- size_t size,
- const std::string& path);
-#endif
-
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
- void RemoveFile(const std::string& path);
-#endif
-
void SplitUriComponents(UriComponents& components,
const std::string& uri);
@@ -108,11 +105,7 @@ namespace Orthanc
std::string FlattenUri(const UriComponents& components,
size_t fromLevel = 0);
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
- uint64_t GetFileSize(const std::string& path);
-#endif
-
-#if !defined(ORTHANC_ENABLE_MD5) || ORTHANC_ENABLE_MD5 == 1
+#if ORTHANC_ENABLE_MD5 == 1
void ComputeMD5(std::string& result,
const std::string& data);
@@ -133,7 +126,7 @@ namespace Orthanc
bool IsSHA1(const std::string& s);
-#if !defined(ORTHANC_ENABLE_BASE64) || ORTHANC_ENABLE_BASE64 == 1
+#if ORTHANC_ENABLE_BASE64 == 1
void DecodeBase64(std::string& result,
const std::string& data);
@@ -151,29 +144,19 @@ namespace Orthanc
const std::string& content);
#endif
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
- std::string GetPathToExecutable();
-
- std::string GetDirectoryOfExecutable();
-#endif
-
std::string ConvertToUtf8(const std::string& source,
Encoding sourceEncoding);
std::string ConvertFromUtf8(const std::string& source,
Encoding targetEncoding);
+ bool IsAsciiString(const void* data,
+ size_t size);
+
std::string ConvertToAscii(const std::string& source);
std::string StripSpaces(const std::string& source);
-#if BOOST_HAS_DATE_TIME == 1
- std::string GetNowIsoString();
-
- void GetNowDicom(std::string& date,
- std::string& time);
-#endif
-
// In-place percent-decoding for URL
void UrlDecode(std::string& s);
@@ -187,26 +170,13 @@ namespace Orthanc
const std::string& source,
char separator);
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
- void MakeDirectory(const std::string& path);
-#endif
-
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
- bool IsExistingFile(const std::string& path);
-#endif
-
-#if ORTHANC_PUGIXML_ENABLED == 1
+#if ORTHANC_ENABLE_PUGIXML == 1
void JsonToXml(std::string& target,
const Json::Value& source,
const std::string& rootElement = "root",
const std::string& arrayElement = "item");
#endif
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
- void ExecuteSystemCommand(const std::string& command,
- const std::vector<std::string>& arguments);
-#endif
-
bool IsInteger(const std::string& str);
void CopyJsonWithoutComments(Json::Value& target,
@@ -215,15 +185,6 @@ namespace Orthanc
bool StartsWith(const std::string& str,
const std::string& prefix);
- int GetProcessId();
-
-#if !defined(ORTHANC_SANDBOXED) || ORTHANC_SANDBOXED != 1
- bool IsRegularFile(const std::string& path);
-#endif
-
- FILE* OpenFile(const std::string& path,
- FileMode mode);
-
void UriEncode(std::string& target,
const std::string& source);
@@ -242,5 +203,9 @@ namespace Orthanc
unsigned int GetJsonUnsignedIntegerField(const ::Json::Value& json,
const std::string& key,
unsigned int defaultValue);
+
+ bool IsUuid(const std::string& str);
+
+ bool StartsWithUuid(const std::string& str);
}
}
diff --git a/Framework/Orthanc/Core/WebServiceParameters.cpp b/Resources/Orthanc/Core/WebServiceParameters.cpp
similarity index 96%
rename from Framework/Orthanc/Core/WebServiceParameters.cpp
rename to Resources/Orthanc/Core/WebServiceParameters.cpp
index 52e0ea6..cef2e26 100644
--- a/Framework/Orthanc/Core/WebServiceParameters.cpp
+++ b/Resources/Orthanc/Core/WebServiceParameters.cpp
@@ -37,6 +37,10 @@
#include "../Core/Toolbox.h"
#include "../Core/OrthancException.h"
+#if ORTHANC_SANDBOXED == 0
+# include "../Core/SystemToolbox.h"
+#endif
+
#include <cassert>
namespace Orthanc
@@ -57,6 +61,7 @@ namespace Orthanc
}
+#if ORTHANC_SANDBOXED == 0
void WebServiceParameters::SetClientCertificate(const std::string& certificateFile,
const std::string& certificateKeyFile,
const std::string& certificateKeyPassword)
@@ -66,14 +71,14 @@ namespace Orthanc
throw OrthancException(ErrorCode_ParameterOutOfRange);
}
- if (!Toolbox::IsRegularFile(certificateFile))
+ if (!SystemToolbox::IsRegularFile(certificateFile))
{
LOG(ERROR) << "Cannot open certificate file: " << certificateFile;
throw OrthancException(ErrorCode_InexistentFile);
}
if (!certificateKeyFile.empty() &&
- !Toolbox::IsRegularFile(certificateKeyFile))
+ !SystemToolbox::IsRegularFile(certificateKeyFile))
{
LOG(ERROR) << "Cannot open key file: " << certificateKeyFile;
throw OrthancException(ErrorCode_InexistentFile);
@@ -84,6 +89,7 @@ namespace Orthanc
certificateKeyFile_ = certificateKeyFile;
certificateKeyPassword_ = certificateKeyPassword;
}
+#endif
static void AddTrailingSlash(std::string& url)
@@ -171,12 +177,14 @@ namespace Orthanc
SetUsername(GetStringMember(peer, "Username", ""));
SetPassword(GetStringMember(peer, "Password", ""));
+#if ORTHANC_SANDBOXED == 0
if (peer.isMember("CertificateFile"))
{
SetClientCertificate(GetStringMember(peer, "CertificateFile", ""),
GetStringMember(peer, "CertificateKeyFile", ""),
GetStringMember(peer, "CertificateKeyPassword", ""));
}
+#endif
if (peer.isMember("Pkcs11"))
{
diff --git a/Framework/Orthanc/Core/WebServiceParameters.h b/Resources/Orthanc/Core/WebServiceParameters.h
similarity index 96%
rename from Framework/Orthanc/Core/WebServiceParameters.h
rename to Resources/Orthanc/Core/WebServiceParameters.h
index 40d6cf9..b6b373f 100644
--- a/Framework/Orthanc/Core/WebServiceParameters.h
+++ b/Resources/Orthanc/Core/WebServiceParameters.h
@@ -32,6 +32,10 @@
#pragma once
+#if !defined(ORTHANC_SANDBOXED)
+# error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
#include <string>
#include <json/json.h>
@@ -88,9 +92,11 @@ namespace Orthanc
void ClearClientCertificate();
+#if ORTHANC_SANDBOXED == 0
void SetClientCertificate(const std::string& certificateFile,
const std::string& certificateKeyFile,
const std::string& certificateKeyPassword);
+#endif
const std::string& GetCertificateFile() const
{
diff --git a/Framework/Orthanc/OrthancServer/FromDcmtkBridge.cpp b/Resources/Orthanc/OrthancServer/FromDcmtkBridge.cpp
similarity index 85%
rename from Framework/Orthanc/OrthancServer/FromDcmtkBridge.cpp
rename to Resources/Orthanc/OrthancServer/FromDcmtkBridge.cpp
index fde86e2..243dcc0 100644
--- a/Framework/Orthanc/OrthancServer/FromDcmtkBridge.cpp
+++ b/Resources/Orthanc/OrthancServer/FromDcmtkBridge.cpp
@@ -39,8 +39,9 @@
#include "FromDcmtkBridge.h"
#include "ToDcmtkBridge.h"
#include "../Core/Logging.h"
+#include "../Core/SystemToolbox.h"
#include "../Core/Toolbox.h"
-#include "../Core/Uuid.h"
+#include "../Core/TemporaryFile.h"
#include "../Core/OrthancException.h"
#include <list>
@@ -118,7 +119,7 @@ namespace Orthanc
std::string content;
EmbeddedResources::GetFileResource(content, resource);
- Toolbox::TemporaryFile tmp;
+ TemporaryFile tmp;
tmp.Write(content);
if (!dictionary.loadDictionary(tmp.GetPath().c_str()))
@@ -144,7 +145,6 @@ namespace Orthanc
throw OrthancException(ErrorCode_InternalError);
}
}
-
#endif
@@ -178,7 +178,7 @@ namespace Orthanc
}
- void FromDcmtkBridge::InitializeDictionary()
+ void FromDcmtkBridge::InitializeDictionary(bool loadPrivateDictionary)
{
{
DictionaryLocker locker;
@@ -195,7 +195,16 @@ namespace Orthanc
//LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_DICONDE);
LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_DICOM);
- LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_PRIVATE);
+
+ if (loadPrivateDictionary)
+ {
+ LOG(INFO) << "Loading the embedded dictionary of private tags";
+ LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_PRIVATE);
+ }
+ else
+ {
+ LOG(INFO) << "The dictionary of private tags has not been loaded";
+ }
#elif defined(__linux__) || defined(__FreeBSD_kernel__)
std::string path = DCMTK_DICTIONARY_DIR;
@@ -207,7 +216,15 @@ namespace Orthanc
}
LoadExternalDictionary(*locker, path, "dicom.dic");
- LoadExternalDictionary(*locker, path, "private.dic");
+
+ if (loadPrivateDictionary)
+ {
+ LoadExternalDictionary(*locker, path, "private.dic");
+ }
+ else
+ {
+ LOG(INFO) << "The dictionary of private tags has not been loaded";
+ }
#else
#error Support your platform here
@@ -237,7 +254,8 @@ namespace Orthanc
ValueRepresentation vr,
const std::string& name,
unsigned int minMultiplicity,
- unsigned int maxMultiplicity)
+ unsigned int maxMultiplicity,
+ const std::string& privateCreator)
{
if (minMultiplicity < 1)
{
@@ -261,20 +279,68 @@ namespace Orthanc
<< name << " (multiplicity: " << minMultiplicity << "-"
<< (arbitrary ? "n" : boost::lexical_cast<std::string>(maxMultiplicity)) << ")";
- std::auto_ptr<DcmDictEntry> entry(new DcmDictEntry(tag.GetGroup(),
- tag.GetElement(),
- evr, name.c_str(),
- static_cast<int>(minMultiplicity),
- static_cast<int>(maxMultiplicity),
- NULL /* version */,
- OFTrue /* doCopyString */,
- NULL /* private creator */));
+ std::auto_ptr<DcmDictEntry> entry;
+ if (privateCreator.empty())
+ {
+ if (tag.GetGroup() % 2 == 1)
+ {
+ char buf[128];
+ sprintf(buf, "Warning: You are registering a private tag (%04x,%04x), "
+ "but no private creator was associated with it",
+ tag.GetGroup(), tag.GetElement());
+ LOG(WARNING) << buf;
+ }
+
+ entry.reset(new DcmDictEntry(tag.GetGroup(),
+ tag.GetElement(),
+ evr, name.c_str(),
+ static_cast<int>(minMultiplicity),
+ static_cast<int>(maxMultiplicity),
+ NULL /* version */,
+ OFTrue /* doCopyString */,
+ NULL /* private creator */));
+ }
+ else
+ {
+ // "Private Data Elements have an odd Group Number that is not
+ // (0001,eeee), (0003,eeee), (0005,eeee), (0007,eeee), or
+ // (FFFF,eeee)."
+ if (tag.GetGroup() % 2 == 0 /* even */ ||
+ tag.GetGroup() == 0x0001 ||
+ tag.GetGroup() == 0x0003 ||
+ tag.GetGroup() == 0x0005 ||
+ tag.GetGroup() == 0x0007 ||
+ tag.GetGroup() == 0xffff)
+ {
+ char buf[128];
+ sprintf(buf, "Trying to register private tag (%04x,%04x), but it must have an odd group >= 0x0009",
+ tag.GetGroup(), tag.GetElement());
+ LOG(ERROR) << buf;
+ throw OrthancException(ErrorCode_ParameterOutOfRange);
+ }
+
+ entry.reset(new DcmDictEntry(tag.GetGroup(),
+ tag.GetElement(),
+ evr, name.c_str(),
+ static_cast<int>(minMultiplicity),
+ static_cast<int>(maxMultiplicity),
+ "private" /* version */,
+ OFTrue /* doCopyString */,
+ privateCreator.c_str()));
+ }
entry->setGroupRangeRestriction(DcmDictRange_Unspecified);
entry->setElementRangeRestriction(DcmDictRange_Unspecified);
{
DictionaryLocker locker;
+
+ if (locker->findEntry(name.c_str()))
+ {
+ LOG(ERROR) << "Cannot register two tags with the same symbolic name \"" << name << "\"";
+ throw OrthancException(ErrorCode_AlreadyExistingTag);
+ }
+
locker->addEntry(entry.release());
}
}
@@ -314,10 +380,10 @@ namespace Orthanc
}
- void FromDcmtkBridge::Convert(DicomMap& target,
- DcmItem& dataset,
- unsigned int maxStringLength,
- Encoding defaultEncoding)
+ void FromDcmtkBridge::ExtractDicomSummary(DicomMap& target,
+ DcmItem& dataset,
+ unsigned int maxStringLength,
+ Encoding defaultEncoding)
{
Encoding encoding = DetectEncoding(dataset, defaultEncoding);
@@ -374,7 +440,7 @@ namespace Orthanc
if (maxStringLength != 0 &&
utf8.size() > maxStringLength)
{
- return new DicomValue; // Create a NULL value
+ return new DicomValue; // Too long, create a NULL value
}
else
{
@@ -383,6 +449,47 @@ namespace Orthanc
}
}
+
+ if (element.getVR() == EVR_UN)
+ {
+ // Unknown value representation: Lookup in the dictionary. This
+ // is notably the case for private tags registered with the
+ // "Dictionary" configuration option.
+ DictionaryLocker locker;
+
+ const DcmDictEntry* entry = locker->findEntry(element.getTag().getXTag(),
+ element.getTag().getPrivateCreator());
+ if (entry != NULL &&
+ entry->getVR().isaString())
+ {
+ Uint8* data = NULL;
+
+ // At (*), we do not try and convert to UTF-8, as nothing says
+ // the encoding of the private tag is the same as that of the
+ // remaining of the DICOM dataset. Only go for ASCII strings.
+
+ if (element.getUint8Array(data) == EC_Normal &&
+ Toolbox::IsAsciiString(data, element.getLength())) // (*)
+ {
+ if (data == NULL)
+ {
+ return new DicomValue("", false); // Empty string
+ }
+ else if (maxStringLength != 0 &&
+ element.getLength() > maxStringLength)
+ {
+ return new DicomValue; // Too long, create a NULL value
+ }
+ else
+ {
+ std::string s(reinterpret_cast<const char*>(data), element.getLength());
+ return new DicomValue(s, false);
+ }
+ }
+ }
+ }
+
+
try
{
// http://support.dcmtk.org/docs/dcvr_8h-source.html
@@ -429,7 +536,7 @@ namespace Orthanc
}
/**
- * Numberic types
+ * Numeric types
**/
case EVR_SL: // signed long
@@ -571,7 +678,7 @@ namespace Orthanc
}
// This code gives access to the name of the private tags
- const std::string tagName = FromDcmtkBridge::GetName(tag);
+ std::string tagName = FromDcmtkBridge::GetTagName(element);
switch (format)
{
@@ -692,20 +799,12 @@ namespace Orthanc
}
- static void DatasetToJson(Json::Value& parent,
- DcmItem& item,
- DicomToJsonFormat format,
- DicomToJsonFlags flags,
- unsigned int maxStringLength,
- Encoding encoding);
-
-
- void FromDcmtkBridge::ToJson(Json::Value& parent,
- DcmElement& element,
- DicomToJsonFormat format,
- DicomToJsonFlags flags,
- unsigned int maxStringLength,
- Encoding encoding)
+ void FromDcmtkBridge::ElementToJson(Json::Value& parent,
+ DcmElement& element,
+ DicomToJsonFormat format,
+ DicomToJsonFlags flags,
+ unsigned int maxStringLength,
+ Encoding encoding)
{
if (parent.type() == Json::nullValue)
{
@@ -717,7 +816,8 @@ namespace Orthanc
if (element.isLeaf())
{
- std::auto_ptr<DicomValue> v(FromDcmtkBridge::ConvertLeafElement(element, flags, maxStringLength, encoding));
+ // The "0" below lets "LeafValueToJson()" take care of "TooLong" values
+ std::auto_ptr<DicomValue> v(FromDcmtkBridge::ConvertLeafElement(element, flags, 0, encoding));
LeafValueToJson(target, *v, format, flags, maxStringLength);
}
else
@@ -740,12 +840,12 @@ namespace Orthanc
}
- static void DatasetToJson(Json::Value& parent,
- DcmItem& item,
- DicomToJsonFormat format,
- DicomToJsonFlags flags,
- unsigned int maxStringLength,
- Encoding encoding)
+ void FromDcmtkBridge::DatasetToJson(Json::Value& parent,
+ DcmItem& item,
+ DicomToJsonFormat format,
+ DicomToJsonFlags flags,
+ unsigned int maxStringLength,
+ Encoding encoding)
{
assert(parent.type() == Json::objectValue);
@@ -790,47 +890,53 @@ namespace Orthanc
}
}
- FromDcmtkBridge::ToJson(parent, *element, format, flags, maxStringLength, encoding);
+ FromDcmtkBridge::ElementToJson(parent, *element, format, flags, maxStringLength, encoding);
}
}
- void FromDcmtkBridge::ToJson(Json::Value& target,
- DcmDataset& dataset,
- DicomToJsonFormat format,
- DicomToJsonFlags flags,
- unsigned int maxStringLength,
- Encoding defaultEncoding)
+ void FromDcmtkBridge::ExtractDicomAsJson(Json::Value& target,
+ DcmDataset& dataset,
+ DicomToJsonFormat format,
+ DicomToJsonFlags flags,
+ unsigned int maxStringLength,
+ Encoding defaultEncoding)
{
+ Encoding encoding = DetectEncoding(dataset, defaultEncoding);
+
target = Json::objectValue;
- DatasetToJson(target, dataset, format, flags, maxStringLength, DetectEncoding(dataset, defaultEncoding));
+ DatasetToJson(target, dataset, format, flags, maxStringLength, encoding);
}
- void FromDcmtkBridge::ToJson(Json::Value& target,
- DcmMetaInfo& dataset,
- DicomToJsonFormat format,
- DicomToJsonFlags flags,
- unsigned int maxStringLength)
+ void FromDcmtkBridge::ExtractHeaderAsJson(Json::Value& target,
+ DcmMetaInfo& dataset,
+ DicomToJsonFormat format,
+ DicomToJsonFlags flags,
+ unsigned int maxStringLength)
{
target = Json::objectValue;
DatasetToJson(target, dataset, format, flags, maxStringLength, Encoding_Ascii);
}
- std::string FromDcmtkBridge::GetName(const DicomTag& t)
+
+ static std::string GetTagNameInternal(DcmTag& tag)
{
- // Some patches for important tags because of different DICOM
- // dictionaries between DCMTK versions
- std::string n = t.GetMainTagsName();
- if (n.size() != 0)
{
- return n;
+ // Some patches for important tags because of different DICOM
+ // dictionaries between DCMTK versions
+ DicomTag tmp(tag.getGroup(), tag.getElement());
+ std::string n = tmp.GetMainTagsName();
+ if (n.size() != 0)
+ {
+ return n;
+ }
+ // End of patches
}
- // End of patches
#if 0
- DcmTagKey tag(t.GetGroup(), t.GetElement());
+ // This version explicitly calls the dictionary
const DcmDataDictionary& dict = dcmDataDict.rdlock();
const DcmDictEntry* entry = dict.findEntry(tag, NULL);
@@ -843,7 +949,6 @@ namespace Orthanc
dcmDataDict.unlock();
return s;
#else
- DcmTag tag(t.GetGroup(), t.GetElement());
const char* name = tag.getTagName();
if (name == NULL)
{
@@ -857,6 +962,31 @@ namespace Orthanc
}
+ std::string FromDcmtkBridge::GetTagName(const DicomTag& t,
+ const std::string& privateCreator)
+ {
+ DcmTag tag(t.GetGroup(), t.GetElement());
+
+ if (!privateCreator.empty())
+ {
+ tag.setPrivateCreator(privateCreator.c_str());
+ }
+
+ return GetTagNameInternal(tag);
+ }
+
+
+ std::string FromDcmtkBridge::GetTagName(const DcmElement& element)
+ {
+ // Copy the tag to ensure const-correctness of DcmElement. Note
+ // that the private creator information is also copied.
+ DcmTag tag(element.getTag());
+
+ return GetTagNameInternal(tag);
+ }
+
+
+
DicomTag FromDcmtkBridge::ParseTag(const char* name)
{
if (strlen(name) == 9 &&
@@ -941,23 +1071,26 @@ namespace Orthanc
for (DicomMap::Map::const_iterator
it = values.map_.begin(); it != values.map_.end(); ++it)
{
+ // TODO Inject PrivateCreator if some is available in the DicomMap?
+ const std::string tagName = GetTagName(it->first, "");
+
if (simplify)
{
if (it->second->IsNull())
{
- result[GetName(it->first)] = Json::nullValue;
+ result[tagName] = Json::nullValue;
}
else
{
// TODO IsBinary
- result[GetName(it->first)] = it->second->GetContent();
+ result[tagName] = it->second->GetContent();
}
}
else
{
Json::Value value = Json::objectValue;
- value["Name"] = GetName(it->first);
+ value["Name"] = tagName;
if (it->second->IsNull())
{
@@ -987,7 +1120,7 @@ namespace Orthanc
// The "PatientID" field is of type LO (Long String), 64
// Bytes Maximum. An UUID is of length 36, thus it can be used
// as a random PatientID.
- return Toolbox::GenerateUuid();
+ return SystemToolbox::GenerateUuid();
case ResourceType_Instance:
return dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT);
diff --git a/Framework/Orthanc/OrthancServer/FromDcmtkBridge.h b/Resources/Orthanc/OrthancServer/FromDcmtkBridge.h
similarity index 68%
rename from Framework/Orthanc/OrthancServer/FromDcmtkBridge.h
rename to Resources/Orthanc/OrthancServer/FromDcmtkBridge.h
index eff3b81..398f061 100644
--- a/Framework/Orthanc/OrthancServer/FromDcmtkBridge.h
+++ b/Resources/Orthanc/OrthancServer/FromDcmtkBridge.h
@@ -34,6 +34,7 @@
#include "ServerEnumerations.h"
+#include "../Core/DicomFormat/DicomElement.h"
#include "../Core/DicomFormat/DicomMap.h"
#include <dcmtk/dcmdata/dcdatset.h>
@@ -42,27 +43,64 @@
#include <dcmtk/dcmdata/dcfilefo.h>
#include <json/json.h>
+#if ORTHANC_BUILD_UNIT_TESTS == 1
+# include <gtest/gtest_prod.h>
+#endif
+
+
namespace Orthanc
{
- class FromDcmtkBridge
+ class FromDcmtkBridge : public boost::noncopyable
{
+#if ORTHANC_BUILD_UNIT_TESTS == 1
+ FRIEND_TEST(FromDcmtkBridge, FromJson);
+#endif
+
+ friend class ParsedDicomFile;
+ friend class Configuration;
+
+ private:
+ FromDcmtkBridge(); // Pure static class
+
+ static void ExtractDicomSummary(DicomMap& target,
+ DcmItem& dataset,
+ unsigned int maxStringLength,
+ Encoding defaultEncoding);
+
+ static void DatasetToJson(Json::Value& parent,
+ DcmItem& item,
+ DicomToJsonFormat format,
+ DicomToJsonFlags flags,
+ unsigned int maxStringLength,
+ Encoding encoding);
+
+ static void ElementToJson(Json::Value& parent,
+ DcmElement& element,
+ DicomToJsonFormat format,
+ DicomToJsonFlags flags,
+ unsigned int maxStringLength,
+ Encoding dicomEncoding);
+
+ static void ExtractDicomAsJson(Json::Value& target,
+ DcmDataset& dataset,
+ DicomToJsonFormat format,
+ DicomToJsonFlags flags,
+ unsigned int maxStringLength,
+ Encoding defaultEncoding);
+
public:
- static void InitializeDictionary();
+ static void InitializeDictionary(bool loadPrivateDictionary);
static void RegisterDictionaryTag(const DicomTag& tag,
ValueRepresentation vr,
const std::string& name,
unsigned int minMultiplicity,
- unsigned int maxMultiplicity);
+ unsigned int maxMultiplicity,
+ const std::string& privateCreator);
static Encoding DetectEncoding(DcmItem& dataset,
Encoding defaultEncoding);
- static void Convert(DicomMap& target,
- DcmItem& dataset,
- unsigned int maxStringLength,
- Encoding defaultEncoding);
-
static DicomTag Convert(const DcmTag& tag);
static DicomTag GetTag(const DcmElement& element);
@@ -74,27 +112,21 @@ namespace Orthanc
unsigned int maxStringLength,
Encoding encoding);
- static void ToJson(Json::Value& parent,
- DcmElement& element,
- DicomToJsonFormat format,
- DicomToJsonFlags flags,
- unsigned int maxStringLength,
- Encoding dicomEncoding);
-
- static void ToJson(Json::Value& target,
- DcmDataset& dataset,
- DicomToJsonFormat format,
- DicomToJsonFlags flags,
- unsigned int maxStringLength,
- Encoding defaultEncoding);
-
- static void ToJson(Json::Value& target,
- DcmMetaInfo& header,
- DicomToJsonFormat format,
- DicomToJsonFlags flags,
- unsigned int maxStringLength);
-
- static std::string GetName(const DicomTag& tag);
+ static void ExtractHeaderAsJson(Json::Value& target,
+ DcmMetaInfo& header,
+ DicomToJsonFormat format,
+ DicomToJsonFlags flags,
+ unsigned int maxStringLength);
+
+ static std::string GetTagName(const DicomTag& tag,
+ const std::string& privateCreator);
+
+ static std::string GetTagName(const DcmElement& element);
+
+ static std::string GetTagName(const DicomElement& element)
+ {
+ return GetTagName(element.GetTag(), "");
+ }
static DicomTag ParseTag(const char* name);
diff --git a/Framework/Orthanc/OrthancServer/PrecompiledHeadersServer.h b/Resources/Orthanc/OrthancServer/PrecompiledHeadersServer.h
similarity index 100%
rename from Framework/Orthanc/OrthancServer/PrecompiledHeadersServer.h
rename to Resources/Orthanc/OrthancServer/PrecompiledHeadersServer.h
diff --git a/Framework/Orthanc/OrthancServer/ServerEnumerations.cpp b/Resources/Orthanc/OrthancServer/ServerEnumerations.cpp
similarity index 100%
rename from Framework/Orthanc/OrthancServer/ServerEnumerations.cpp
rename to Resources/Orthanc/OrthancServer/ServerEnumerations.cpp
diff --git a/Framework/Orthanc/OrthancServer/ServerEnumerations.h b/Resources/Orthanc/OrthancServer/ServerEnumerations.h
similarity index 100%
rename from Framework/Orthanc/OrthancServer/ServerEnumerations.h
rename to Resources/Orthanc/OrthancServer/ServerEnumerations.h
diff --git a/Framework/Orthanc/OrthancServer/ToDcmtkBridge.cpp b/Resources/Orthanc/OrthancServer/ToDcmtkBridge.cpp
similarity index 100%
rename from Framework/Orthanc/OrthancServer/ToDcmtkBridge.cpp
rename to Resources/Orthanc/OrthancServer/ToDcmtkBridge.cpp
diff --git a/Framework/Orthanc/OrthancServer/ToDcmtkBridge.h b/Resources/Orthanc/OrthancServer/ToDcmtkBridge.h
similarity index 100%
rename from Framework/Orthanc/OrthancServer/ToDcmtkBridge.h
rename to Resources/Orthanc/OrthancServer/ToDcmtkBridge.h
diff --git a/Framework/Orthanc/Plugins/Engine/SharedLibrary.cpp b/Resources/Orthanc/Plugins/Engine/SharedLibrary.cpp
similarity index 99%
rename from Framework/Orthanc/Plugins/Engine/SharedLibrary.cpp
rename to Resources/Orthanc/Plugins/Engine/SharedLibrary.cpp
index 7fefc49..1adc878 100644
--- a/Framework/Orthanc/Plugins/Engine/SharedLibrary.cpp
+++ b/Resources/Orthanc/Plugins/Engine/SharedLibrary.cpp
@@ -33,7 +33,7 @@
#include "../../OrthancServer/PrecompiledHeadersServer.h"
#include "SharedLibrary.h"
-#if ORTHANC_PLUGINS_ENABLED != 1
+#if ORTHANC_ENABLE_PLUGINS != 1
#error The plugin support is disabled
#endif
diff --git a/Framework/Orthanc/Plugins/Engine/SharedLibrary.h b/Resources/Orthanc/Plugins/Engine/SharedLibrary.h
similarity index 98%
copy from Framework/Orthanc/Plugins/Engine/SharedLibrary.h
copy to Resources/Orthanc/Plugins/Engine/SharedLibrary.h
index 5a7913a..2bf9a69 100644
--- a/Framework/Orthanc/Plugins/Engine/SharedLibrary.h
+++ b/Resources/Orthanc/Plugins/Engine/SharedLibrary.h
@@ -32,7 +32,7 @@
#pragma once
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
#include "../../Core/OrthancException.h"
diff --git a/Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.cpp b/Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.cpp
new file mode 100644
index 0000000..b354bb1
--- /dev/null
+++ b/Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.cpp
@@ -0,0 +1,122 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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/>.
+ **/
+
+
+#include "DicomDatasetReader.h"
+
+#include "OrthancPluginCppWrapper.h"
+
+#include <boost/lexical_cast.hpp>
+
+namespace OrthancPlugins
+{
+ // This function is copied-pasted from "../../../Core/Toolbox.cpp",
+ // in order to avoid the dependency of plugins against the Orthanc core
+ static std::string StripSpaces(const std::string& source)
+ {
+ size_t first = 0;
+
+ while (first < source.length() &&
+ isspace(source[first]))
+ {
+ first++;
+ }
+
+ if (first == source.length())
+ {
+ // String containing only spaces
+ return "";
+ }
+
+ size_t last = source.length();
+ while (last > first &&
+ isspace(source[last - 1]))
+ {
+ last--;
+ }
+
+ assert(first <= last);
+ return source.substr(first, last - first);
+ }
+
+
+ DicomDatasetReader::DicomDatasetReader(IDicomDataset* dataset) : // takes ownership
+ dataset_(dataset)
+ {
+ if (dataset == NULL)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
+ }
+ }
+
+
+ std::string DicomDatasetReader::GetMandatoryStringValue(const DicomPath& path) const
+ {
+ std::string s;
+ if (dataset_->GetStringValue(s, path))
+ {
+ return s;
+ }
+ else
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InexistentTag);
+ }
+ }
+
+
+ int DicomDatasetReader::GetIntegerValue(const DicomPath& path)
+ {
+ try
+ {
+ std::string s = StripSpaces(GetMandatoryStringValue(path));
+ return boost::lexical_cast<int>(s);
+ }
+ catch (boost::bad_lexical_cast&)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+ }
+
+
+ unsigned int DicomDatasetReader::GetUnsignedIntegerValue(const DicomPath& path)
+ {
+ int value = GetIntegerValue(path);
+
+ if (value >= 0)
+ {
+ return static_cast<unsigned int>(value);
+ }
+ else
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
+ }
+ }
+}
diff --git a/Framework/Orthanc/Core/DicomFormat/DicomArray.h b/Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.h
similarity index 77%
copy from Framework/Orthanc/Core/DicomFormat/DicomArray.h
copy to Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.h
index a223685..0074071 100644
--- a/Framework/Orthanc/Core/DicomFormat/DicomArray.h
+++ b/Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.h
@@ -32,35 +32,29 @@
#pragma once
-#include "DicomElement.h"
-#include "DicomMap.h"
+#include "IDicomDataset.h"
-#include <vector>
+#include <memory>
-namespace Orthanc
+namespace OrthancPlugins
{
- class DicomArray : public boost::noncopyable
+ class DicomDatasetReader : public boost::noncopyable
{
private:
- typedef std::vector<DicomElement*> Elements;
-
- Elements elements_;
+ std::auto_ptr<IDicomDataset> dataset_;
public:
- DicomArray(const DicomMap& map);
-
- ~DicomArray();
+ DicomDatasetReader(IDicomDataset* dataset); // takes ownership
- size_t GetSize() const
+ IDicomDataset& GetDataset() const
{
- return elements_.size();
+ return *dataset_;
}
- const DicomElement& GetElement(size_t i) const
- {
- return *elements_[i];
- }
+ std::string GetMandatoryStringValue(const DicomPath& path) const;
+
+ int GetIntegerValue(const DicomPath& path);
- void Print(FILE* fp) const;
+ unsigned int GetUnsignedIntegerValue(const DicomPath& path);
};
}
diff --git a/Framework/Orthanc/Core/DicomFormat/DicomValue.cpp b/Resources/Orthanc/Plugins/Samples/Common/DicomPath.cpp
similarity index 57%
copy from Framework/Orthanc/Core/DicomFormat/DicomValue.cpp
copy to Resources/Orthanc/Plugins/Samples/Common/DicomPath.cpp
index 32a17b5..3437e60 100644
--- a/Framework/Orthanc/Core/DicomFormat/DicomValue.cpp
+++ b/Resources/Orthanc/Plugins/Samples/Common/DicomPath.cpp
@@ -30,64 +30,57 @@
**/
-#include "../PrecompiledHeaders.h"
-#include "DicomValue.h"
+#include "DicomPath.h"
-#include "../OrthancException.h"
-#include "../Toolbox.h"
+#include "OrthancPluginCppWrapper.h"
-namespace Orthanc
+namespace OrthancPlugins
{
- DicomValue::DicomValue(const DicomValue& other) :
- type_(other.type_),
- content_(other.content_)
+ const DicomPath::Prefix& DicomPath::GetPrefixItem(size_t depth) const
{
- }
-
-
- DicomValue::DicomValue(const std::string& content,
- bool isBinary) :
- type_(isBinary ? Type_Binary : Type_String),
- content_(content)
- {
- }
-
-
- DicomValue::DicomValue(const char* data,
- size_t size,
- bool isBinary) :
- type_(isBinary ? Type_Binary : Type_String)
- {
- content_.assign(data, size);
- }
-
-
- const std::string& DicomValue::GetContent() const
- {
- if (type_ == Type_Null)
+ if (depth >= prefix_.size())
{
- throw OrthancException(ErrorCode_BadParameterType);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
}
else
{
- return content_;
+ return prefix_[depth];
}
}
- DicomValue* DicomValue::Clone() const
+ DicomPath::DicomPath(const DicomTag& sequence,
+ size_t index,
+ const DicomTag& tag) :
+ finalTag_(tag)
{
- return new DicomValue(*this);
+ AddToPrefix(sequence, index);
}
-
-#if !defined(ORTHANC_ENABLE_BASE64) || ORTHANC_ENABLE_BASE64 == 1
- void DicomValue::FormatDataUriScheme(std::string& target,
- const std::string& mime) const
+
+ DicomPath::DicomPath(const DicomTag& sequence1,
+ size_t index1,
+ const DicomTag& sequence2,
+ size_t index2,
+ const DicomTag& tag) :
+ finalTag_(tag)
{
- Toolbox::EncodeBase64(target, GetContent());
- target.insert(0, "data:" + mime + ";base64,");
+ AddToPrefix(sequence1, index1);
+ AddToPrefix(sequence2, index2);
}
-#endif
+
+ DicomPath::DicomPath(const DicomTag& sequence1,
+ size_t index1,
+ const DicomTag& sequence2,
+ size_t index2,
+ const DicomTag& sequence3,
+ size_t index3,
+ const DicomTag& tag) :
+ finalTag_(tag)
+ {
+ AddToPrefix(sequence1, index1);
+ AddToPrefix(sequence2, index2);
+ AddToPrefix(sequence3, index3);
+ }
}
diff --git a/Framework/Orthanc/Core/Images/ImageBuffer.h b/Resources/Orthanc/Plugins/Samples/Common/DicomPath.h
similarity index 56%
rename from Framework/Orthanc/Core/Images/ImageBuffer.h
rename to Resources/Orthanc/Plugins/Samples/Common/DicomPath.h
index 21b1b15..f14f051 100644
--- a/Framework/Orthanc/Core/Images/ImageBuffer.h
+++ b/Resources/Orthanc/Plugins/Samples/Common/DicomPath.h
@@ -32,83 +32,76 @@
#pragma once
-#include "ImageAccessor.h"
+#include "DicomTag.h"
#include <vector>
-#include <stdint.h>
-#include <boost/noncopyable.hpp>
+#include <stddef.h>
-namespace Orthanc
+namespace OrthancPlugins
{
- class ImageBuffer : public boost::noncopyable
+ class DicomPath
{
private:
- bool changed_;
+ typedef std::pair<DicomTag, size_t> Prefix;
- bool forceMinimalPitch_; // Currently unused
- PixelFormat format_;
- unsigned int width_;
- unsigned int height_;
- unsigned int pitch_;
- void *buffer_;
+ std::vector<Prefix> prefix_;
+ DicomTag finalTag_;
- void Initialize();
-
- void Allocate();
-
- void Deallocate();
+ const Prefix& GetPrefixItem(size_t depth) const;
public:
- ImageBuffer(PixelFormat format,
- unsigned int width,
- unsigned int height,
- bool forceMinimalPitch);
-
- ImageBuffer()
+ DicomPath(const DicomTag& finalTag) :
+ finalTag_(finalTag)
{
- Initialize();
}
- ~ImageBuffer()
+ DicomPath(const DicomTag& sequence,
+ size_t index,
+ const DicomTag& tag);
+
+ DicomPath(const DicomTag& sequence1,
+ size_t index1,
+ const DicomTag& sequence2,
+ size_t index2,
+ const DicomTag& tag);
+
+ DicomPath(const DicomTag& sequence1,
+ size_t index1,
+ const DicomTag& sequence2,
+ size_t index2,
+ const DicomTag& sequence3,
+ size_t index3,
+ const DicomTag& tag);
+
+ void AddToPrefix(const DicomTag& tag,
+ size_t position)
{
- Deallocate();
+ prefix_.push_back(std::make_pair(tag, position));
}
- PixelFormat GetFormat() const
+ size_t GetPrefixLength() const
{
- return format_;
+ return prefix_.size();
}
-
- void SetFormat(PixelFormat format);
-
- unsigned int GetWidth() const
+
+ DicomTag GetPrefixTag(size_t depth) const
{
- return width_;
+ return GetPrefixItem(depth).first;
}
- void SetWidth(unsigned int width);
-
- unsigned int GetHeight() const
+ size_t GetPrefixIndex(size_t depth) const
{
- return height_;
+ return GetPrefixItem(depth).second;
}
-
- void SetHeight(unsigned int height);
-
- unsigned int GetBytesPerPixel() const
+
+ const DicomTag& GetFinalTag() const
{
- return ::Orthanc::GetBytesPerPixel(format_);
+ return finalTag_;
}
- ImageAccessor GetAccessor();
-
- ImageAccessor GetConstAccessor();
-
- bool IsMinimalPitchForced() const
+ void SetFinalTag(const DicomTag& tag)
{
- return forceMinimalPitch_;
+ finalTag_ = tag;
}
-
- void AcquireOwnership(ImageBuffer& other);
};
}
diff --git a/Resources/Orthanc/Plugins/Samples/Common/DicomTag.cpp b/Resources/Orthanc/Plugins/Samples/Common/DicomTag.cpp
new file mode 100644
index 0000000..040d885
--- /dev/null
+++ b/Resources/Orthanc/Plugins/Samples/Common/DicomTag.cpp
@@ -0,0 +1,110 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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/>.
+ **/
+
+
+#include "DicomTag.h"
+
+#include "OrthancPluginCppWrapper.h"
+
+namespace OrthancPlugins
+{
+ const char* DicomTag::GetName() const
+ {
+ if (*this == DICOM_TAG_BITS_STORED)
+ {
+ return "BitsStored";
+ }
+ else if (*this == DICOM_TAG_COLUMN_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX)
+ {
+ return "ColumnPositionInTotalImagePixelMatrix";
+ }
+ else if (*this == DICOM_TAG_COLUMNS)
+ {
+ return "Columns";
+ }
+ else if (*this == DICOM_TAG_MODALITY)
+ {
+ return "Modality";
+ }
+ else if (*this == DICOM_TAG_NUMBER_OF_FRAMES)
+ {
+ return "NumberOfFrames";
+ }
+ else if (*this == DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE)
+ {
+ return "PerFrameFunctionalGroupsSequence";
+ }
+ else if (*this == DICOM_TAG_PHOTOMETRIC_INTERPRETATION)
+ {
+ return "PhotometricInterpretation";
+ }
+ else if (*this == DICOM_TAG_PIXEL_REPRESENTATION)
+ {
+ return "PixelRepresentation";
+ }
+ else if (*this == DICOM_TAG_PLANE_POSITION_SLIDE_SEQUENCE)
+ {
+ return "PlanePositionSlideSequence";
+ }
+ else if (*this == DICOM_TAG_ROW_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX)
+ {
+ return "RowPositionInTotalImagePixelMatrix";
+ }
+ else if (*this == DICOM_TAG_ROWS)
+ {
+ return "Rows";
+ }
+ else if (*this == DICOM_TAG_SOP_CLASS_UID)
+ {
+ return "SOPClassUID";
+ }
+ else if (*this == DICOM_TAG_SAMPLES_PER_PIXEL)
+ {
+ return "SamplesPerPixel";
+ }
+ else if (*this == DICOM_TAG_TOTAL_PIXEL_MATRIX_COLUMNS)
+ {
+ return "TotalPixelMatrixColumns";
+ }
+ else if (*this == DICOM_TAG_TOTAL_PIXEL_MATRIX_ROWS)
+ {
+ return "TotalPixelMatrixRows";
+ }
+ else if (*this == DICOM_TAG_TRANSFER_SYNTAX_UID)
+ {
+ return "TransferSyntaxUID";
+ }
+ else
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_NotImplemented);
+ }
+ }
+}
diff --git a/Resources/Orthanc/Plugins/Samples/Common/DicomTag.h b/Resources/Orthanc/Plugins/Samples/Common/DicomTag.h
new file mode 100644
index 0000000..660d078
--- /dev/null
+++ b/Resources/Orthanc/Plugins/Samples/Common/DicomTag.h
@@ -0,0 +1,95 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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/>.
+ **/
+
+
+#pragma once
+
+#include <stdint.h>
+
+namespace OrthancPlugins
+{
+ class DicomTag
+ {
+ private:
+ uint16_t group_;
+ uint16_t element_;
+
+ DicomTag(); // Forbidden
+
+ public:
+ DicomTag(uint16_t group,
+ uint16_t element) :
+ group_(group),
+ element_(element)
+ {
+ }
+
+ uint16_t GetGroup() const
+ {
+ return group_;
+ }
+
+ uint16_t GetElement() const
+ {
+ return element_;
+ }
+
+ const char* GetName() const;
+
+ bool operator== (const DicomTag& other) const
+ {
+ return group_ == other.group_ && element_ == other.element_;
+ }
+
+ bool operator!= (const DicomTag& other) const
+ {
+ return !(*this == other);
+ }
+ };
+
+
+ static const DicomTag DICOM_TAG_BITS_STORED(0x0028, 0x0101);
+ static const DicomTag DICOM_TAG_COLUMN_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX(0x0048, 0x021e);
+ static const DicomTag DICOM_TAG_COLUMNS(0x0028, 0x0011);
+ static const DicomTag DICOM_TAG_MODALITY(0x0008, 0x0060);
+ static const DicomTag DICOM_TAG_NUMBER_OF_FRAMES(0x0028, 0x0008);
+ static const DicomTag DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE(0x5200, 0x9230);
+ static const DicomTag DICOM_TAG_PHOTOMETRIC_INTERPRETATION(0x0028, 0x0004);
+ static const DicomTag DICOM_TAG_PIXEL_REPRESENTATION(0x0028, 0x0103);
+ static const DicomTag DICOM_TAG_PLANE_POSITION_SLIDE_SEQUENCE(0x0048, 0x021a);
+ static const DicomTag DICOM_TAG_ROW_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX(0x0048, 0x021f);
+ static const DicomTag DICOM_TAG_ROWS(0x0028, 0x0010);
+ static const DicomTag DICOM_TAG_SOP_CLASS_UID(0x0008, 0x0016);
+ static const DicomTag DICOM_TAG_SAMPLES_PER_PIXEL(0x0028, 0x0002);
+ static const DicomTag DICOM_TAG_TOTAL_PIXEL_MATRIX_COLUMNS(0x0048, 0x0006);
+ static const DicomTag DICOM_TAG_TOTAL_PIXEL_MATRIX_ROWS(0x0048, 0x0007);
+ static const DicomTag DICOM_TAG_TRANSFER_SYNTAX_UID(0x0002, 0x0010);
+}
diff --git a/Framework/Orthanc/Plugins/Samples/Common/ExportedSymbols.list b/Resources/Orthanc/Plugins/Samples/Common/ExportedSymbols.list
similarity index 100%
rename from Framework/Orthanc/Plugins/Samples/Common/ExportedSymbols.list
rename to Resources/Orthanc/Plugins/Samples/Common/ExportedSymbols.list
diff --git a/Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.cpp b/Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.cpp
new file mode 100644
index 0000000..638654b
--- /dev/null
+++ b/Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.cpp
@@ -0,0 +1,196 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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/>.
+ **/
+
+
+#include "FullOrthancDataset.h"
+
+#include "OrthancPluginCppWrapper.h"
+
+namespace OrthancPlugins
+{
+ static const Json::Value* AccessTag(const Json::Value& dataset,
+ const DicomTag& tag)
+ {
+ if (dataset.type() != Json::objectValue)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+
+ char name[16];
+ sprintf(name, "%04x,%04x", tag.GetGroup(), tag.GetElement());
+
+ if (!dataset.isMember(name))
+ {
+ return NULL;
+ }
+
+ const Json::Value& value = dataset[name];
+ if (value.type() != Json::objectValue ||
+ !value.isMember("Name") ||
+ !value.isMember("Type") ||
+ !value.isMember("Value") ||
+ value["Name"].type() != Json::stringValue ||
+ value["Type"].type() != Json::stringValue)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+
+ return &value;
+ }
+
+
+ static const Json::Value& GetSequenceContent(const Json::Value& sequence)
+ {
+ assert(sequence.type() == Json::objectValue);
+ assert(sequence.isMember("Type"));
+ assert(sequence.isMember("Value"));
+
+ const Json::Value& value = sequence["Value"];
+
+ if (sequence["Type"].asString() != "Sequence" ||
+ value.type() != Json::arrayValue)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+ else
+ {
+ return value;
+ }
+ }
+
+
+ static bool GetStringInternal(std::string& result,
+ const Json::Value& tag)
+ {
+ assert(tag.type() == Json::objectValue);
+ assert(tag.isMember("Type"));
+ assert(tag.isMember("Value"));
+
+ const Json::Value& value = tag["Value"];
+
+ if (tag["Type"].asString() != "String" ||
+ value.type() != Json::stringValue)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+ else
+ {
+ result = value.asString();
+ return true;
+ }
+ }
+
+
+ const Json::Value* FullOrthancDataset::LookupPath(const DicomPath& path) const
+ {
+ const Json::Value* content = &root_;
+
+ for (unsigned int depth = 0; depth < path.GetPrefixLength(); depth++)
+ {
+ const Json::Value* sequence = AccessTag(*content, path.GetPrefixTag(depth));
+ if (sequence == NULL)
+ {
+ return NULL;
+ }
+
+ const Json::Value& nextContent = GetSequenceContent(*sequence);
+
+ size_t index = path.GetPrefixIndex(depth);
+ if (index >= nextContent.size())
+ {
+ return NULL;
+ }
+ else
+ {
+ content = &nextContent[static_cast<Json::Value::ArrayIndex>(index)];
+ }
+ }
+
+ return AccessTag(*content, path.GetFinalTag());
+ }
+
+
+ void FullOrthancDataset::CheckRoot() const
+ {
+ if (root_.type() != Json::objectValue)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+ }
+
+
+ FullOrthancDataset::FullOrthancDataset(IOrthancConnection& orthanc,
+ const std::string& uri)
+ {
+ IOrthancConnection::RestApiGet(root_, orthanc, uri);
+ CheckRoot();
+ }
+
+
+ FullOrthancDataset::FullOrthancDataset(const std::string& content)
+ {
+ IOrthancConnection::ParseJson(root_, content);
+ CheckRoot();
+ }
+
+
+ bool FullOrthancDataset::GetStringValue(std::string& result,
+ const DicomPath& path) const
+ {
+ const Json::Value* value = LookupPath(path);
+
+ if (value == NULL)
+ {
+ return false;
+ }
+ else
+ {
+ return GetStringInternal(result, *value);
+ }
+ }
+
+
+ bool FullOrthancDataset::GetSequenceSize(size_t& size,
+ const DicomPath& path) const
+ {
+ const Json::Value* sequence = LookupPath(path);
+
+ if (sequence == NULL)
+ {
+ return false;
+ }
+ else
+ {
+ size = GetSequenceContent(*sequence).size();
+ return true;
+ }
+ }
+}
diff --git a/Framework/Orthanc/Core/DicomFormat/DicomArray.h b/Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.h
similarity index 71%
copy from Framework/Orthanc/Core/DicomFormat/DicomArray.h
copy to Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.h
index a223685..18ab444 100644
--- a/Framework/Orthanc/Core/DicomFormat/DicomArray.h
+++ b/Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.h
@@ -32,35 +32,32 @@
#pragma once
-#include "DicomElement.h"
-#include "DicomMap.h"
+#include "IOrthancConnection.h"
+#include "IDicomDataset.h"
-#include <vector>
+#include <json/value.h>
-namespace Orthanc
+namespace OrthancPlugins
{
- class DicomArray : public boost::noncopyable
+ class FullOrthancDataset : public IDicomDataset
{
private:
- typedef std::vector<DicomElement*> Elements;
+ Json::Value root_;
- Elements elements_;
+ const Json::Value* LookupPath(const DicomPath& path) const;
- public:
- DicomArray(const DicomMap& map);
+ void CheckRoot() const;
- ~DicomArray();
+ public:
+ FullOrthancDataset(IOrthancConnection& orthanc,
+ const std::string& uri);
- size_t GetSize() const
- {
- return elements_.size();
- }
+ FullOrthancDataset(const std::string& content);
- const DicomElement& GetElement(size_t i) const
- {
- return *elements_[i];
- }
+ virtual bool GetStringValue(std::string& result,
+ const DicomPath& path) const;
- void Print(FILE* fp) const;
+ virtual bool GetSequenceSize(size_t& size,
+ const DicomPath& path) const;
};
}
diff --git a/Framework/Orthanc/Core/Images/JpegReader.h b/Resources/Orthanc/Plugins/Samples/Common/IDicomDataset.h
similarity index 81%
rename from Framework/Orthanc/Core/Images/JpegReader.h
rename to Resources/Orthanc/Plugins/Samples/Common/IDicomDataset.h
index 5cb5551..7fc549e 100644
--- a/Framework/Orthanc/Core/Images/JpegReader.h
+++ b/Resources/Orthanc/Plugins/Samples/Common/IDicomDataset.h
@@ -32,26 +32,24 @@
#pragma once
-#include "ImageAccessor.h"
+#include "DicomPath.h"
-#include <string>
#include <boost/noncopyable.hpp>
+#include <string>
-namespace Orthanc
+namespace OrthancPlugins
{
- class JpegReader :
- public ImageAccessor,
- public boost::noncopyable
+ class IDicomDataset : public boost::noncopyable
{
- private:
- std::string content_;
-
public:
- void ReadFromFile(const std::string& filename);
+ virtual ~IDicomDataset()
+ {
+ }
- void ReadFromMemory(const void* buffer,
- size_t size);
+ virtual bool GetStringValue(std::string& result,
+ const DicomPath& path) const = 0;
- void ReadFromMemory(const std::string& buffer);
+ virtual bool GetSequenceSize(size_t& size,
+ const DicomPath& path) const = 0;
};
}
diff --git a/Framework/Orthanc/Core/DicomFormat/DicomValue.cpp b/Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.cpp
similarity index 54%
rename from Framework/Orthanc/Core/DicomFormat/DicomValue.cpp
rename to Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.cpp
index 32a17b5..5a66912 100644
--- a/Framework/Orthanc/Core/DicomFormat/DicomValue.cpp
+++ b/Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.cpp
@@ -30,64 +30,54 @@
**/
-#include "../PrecompiledHeaders.h"
-#include "DicomValue.h"
+#include "IOrthancConnection.h"
-#include "../OrthancException.h"
-#include "../Toolbox.h"
-
-namespace Orthanc
-{
- DicomValue::DicomValue(const DicomValue& other) :
- type_(other.type_),
- content_(other.content_)
- {
- }
+#include "OrthancPluginCppWrapper.h"
+#include <json/reader.h>
- DicomValue::DicomValue(const std::string& content,
- bool isBinary) :
- type_(isBinary ? Type_Binary : Type_String),
- content_(content)
- {
- }
-
-
- DicomValue::DicomValue(const char* data,
- size_t size,
- bool isBinary) :
- type_(isBinary ? Type_Binary : Type_String)
+namespace OrthancPlugins
+{
+ void IOrthancConnection::ParseJson(Json::Value& result,
+ const std::string& content)
{
- content_.assign(data, size);
- }
+ Json::Reader reader;
-
- const std::string& DicomValue::GetContent() const
- {
- if (type_ == Type_Null)
- {
- throw OrthancException(ErrorCode_BadParameterType);
- }
- else
+ if (!reader.parse(content, result))
{
- return content_;
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
}
}
- DicomValue* DicomValue::Clone() const
+ void IOrthancConnection::RestApiGet(Json::Value& result,
+ IOrthancConnection& orthanc,
+ const std::string& uri)
{
- return new DicomValue(*this);
+ std::string content;
+ orthanc.RestApiGet(content, uri);
+ ParseJson(result, content);
}
-
-#if !defined(ORTHANC_ENABLE_BASE64) || ORTHANC_ENABLE_BASE64 == 1
- void DicomValue::FormatDataUriScheme(std::string& target,
- const std::string& mime) const
+
+ void IOrthancConnection::RestApiPost(Json::Value& result,
+ IOrthancConnection& orthanc,
+ const std::string& uri,
+ const std::string& body)
{
- Toolbox::EncodeBase64(target, GetContent());
- target.insert(0, "data:" + mime + ";base64,");
+ std::string content;
+ orthanc.RestApiPost(content, uri, body);
+ ParseJson(result, content);
}
-#endif
+
+ void IOrthancConnection::RestApiPut(Json::Value& result,
+ IOrthancConnection& orthanc,
+ const std::string& uri,
+ const std::string& body)
+ {
+ std::string content;
+ orthanc.RestApiPut(content, uri, body);
+ ParseJson(result, content);
+ }
}
diff --git a/Framework/Orthanc/Core/DicomFormat/DicomValue.h b/Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.h
similarity index 56%
rename from Framework/Orthanc/Core/DicomFormat/DicomValue.h
rename to Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.h
index ad0ec54..f64dd5a 100644
--- a/Framework/Orthanc/Core/DicomFormat/DicomValue.h
+++ b/Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.h
@@ -32,60 +32,49 @@
#pragma once
-#include <string>
+#include "DicomPath.h"
+
#include <boost/noncopyable.hpp>
+#include <string>
+#include <json/value.h>
-namespace Orthanc
+namespace OrthancPlugins
{
- class DicomValue : public boost::noncopyable
+ class IOrthancConnection : public boost::noncopyable
{
- private:
- enum Type
+ public:
+ virtual ~IOrthancConnection()
{
- Type_Null,
- Type_String,
- Type_Binary
- };
+ }
- Type type_;
- std::string content_;
+ virtual void RestApiGet(std::string& result,
+ const std::string& uri) = 0;
- DicomValue(const DicomValue& other);
+ virtual void RestApiPost(std::string& result,
+ const std::string& uri,
+ const std::string& body) = 0;
- public:
- DicomValue() : type_(Type_Null)
- {
- }
-
- DicomValue(const std::string& content,
- bool isBinary);
-
- DicomValue(const char* data,
- size_t size,
- bool isBinary);
-
- const std::string& GetContent() const;
+ virtual void RestApiPut(std::string& result,
+ const std::string& uri,
+ const std::string& body) = 0;
- bool IsNull() const
- {
- return type_ == Type_Null;
- }
+ virtual void RestApiDelete(const std::string& uri) = 0;
- bool IsBinary() const
- {
- return type_ == Type_Binary;
- }
-
- DicomValue* Clone() const;
+ static void ParseJson(Json::Value& result,
+ const std::string& content);
-#if !defined(ORTHANC_ENABLE_BASE64) || ORTHANC_ENABLE_BASE64 == 1
- void FormatDataUriScheme(std::string& target,
- const std::string& mime) const;
+ static void RestApiGet(Json::Value& result,
+ IOrthancConnection& orthanc,
+ const std::string& uri);
- void FormatDataUriScheme(std::string& target) const
- {
- FormatDataUriScheme(target, "application/octet-stream");
- }
-#endif
+ static void RestApiPost(Json::Value& result,
+ IOrthancConnection& orthanc,
+ const std::string& uri,
+ const std::string& body);
+
+ static void RestApiPut(Json::Value& result,
+ IOrthancConnection& orthanc,
+ const std::string& uri,
+ const std::string& body);
};
}
diff --git a/Resources/Orthanc/Plugins/Samples/Common/OrthancHttpConnection.cpp b/Resources/Orthanc/Plugins/Samples/Common/OrthancHttpConnection.cpp
new file mode 100644
index 0000000..a1f9846
--- /dev/null
+++ b/Resources/Orthanc/Plugins/Samples/Common/OrthancHttpConnection.cpp
@@ -0,0 +1,107 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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/>.
+ **/
+
+
+#include "OrthancHttpConnection.h"
+
+namespace OrthancPlugins
+{
+ void OrthancHttpConnection::Setup()
+ {
+ url_ = client_.GetUrl();
+
+ // Don't follow 3xx HTTP (avoid redirections to "unsupported.png" in Orthanc)
+ client_.SetRedirectionFollowed(false);
+ }
+
+
+ OrthancHttpConnection::OrthancHttpConnection() :
+ client_(Orthanc::WebServiceParameters(), "")
+ {
+ Setup();
+ }
+
+
+ OrthancHttpConnection::OrthancHttpConnection(const Orthanc::WebServiceParameters& parameters) :
+ client_(parameters, "")
+ {
+ Setup();
+ }
+
+
+ void OrthancHttpConnection::RestApiGet(std::string& result,
+ const std::string& uri)
+ {
+ boost::mutex::scoped_lock lock(mutex_);
+
+ client_.SetMethod(Orthanc::HttpMethod_Get);
+ client_.SetUrl(url_ + uri);
+ client_.ApplyAndThrowException(result);
+ }
+
+
+ void OrthancHttpConnection::RestApiPost(std::string& result,
+ const std::string& uri,
+ const std::string& body)
+ {
+ boost::mutex::scoped_lock lock(mutex_);
+
+ client_.SetMethod(Orthanc::HttpMethod_Post);
+ client_.SetUrl(url_ + uri);
+ client_.SetBody(body);
+ client_.ApplyAndThrowException(result);
+ }
+
+
+ void OrthancHttpConnection::RestApiPut(std::string& result,
+ const std::string& uri,
+ const std::string& body)
+ {
+ boost::mutex::scoped_lock lock(mutex_);
+
+ client_.SetMethod(Orthanc::HttpMethod_Put);
+ client_.SetUrl(url_ + uri);
+ client_.SetBody(body);
+ client_.ApplyAndThrowException(result);
+ }
+
+
+ void OrthancHttpConnection::RestApiDelete(const std::string& uri)
+ {
+ boost::mutex::scoped_lock lock(mutex_);
+
+ std::string result;
+
+ client_.SetMethod(Orthanc::HttpMethod_Delete);
+ client_.SetUrl(url_ + uri);
+ client_.ApplyAndThrowException(result);
+ }
+}
diff --git a/Framework/Orthanc/Plugins/Engine/SharedLibrary.h b/Resources/Orthanc/Plugins/Samples/Common/OrthancHttpConnection.h
similarity index 61%
rename from Framework/Orthanc/Plugins/Engine/SharedLibrary.h
rename to Resources/Orthanc/Plugins/Samples/Common/OrthancHttpConnection.h
index 5a7913a..c1e69bd 100644
--- a/Framework/Orthanc/Plugins/Engine/SharedLibrary.h
+++ b/Resources/Orthanc/Plugins/Samples/Common/OrthancHttpConnection.h
@@ -32,47 +32,44 @@
#pragma once
-#if ORTHANC_PLUGINS_ENABLED == 1
+#include "IOrthancConnection.h"
-#include "../../Core/OrthancException.h"
+#if HAS_ORTHANC_EXCEPTION != 1
+# error The macro HAS_ORTHANC_EXCEPTION must be set to 1 if using this header
+#endif
-#include <boost/noncopyable.hpp>
+#include "../../../Core/HttpClient.h"
-#if defined(_WIN32)
-#include <windows.h>
-#endif
+#include <boost/thread/mutex.hpp>
-namespace Orthanc
+namespace OrthancPlugins
{
- class SharedLibrary : public boost::noncopyable
+ // This class is thread-safe
+ class OrthancHttpConnection : public IOrthancConnection
{
- public:
-#if defined(_WIN32)
- typedef FARPROC FunctionPointer;
-#else
- typedef void* FunctionPointer;
-#endif
-
private:
- std::string path_;
- void *handle_;
+ boost::mutex mutex_;
+ Orthanc::HttpClient client_;
+ std::string url_;
- FunctionPointer GetFunctionInternal(const std::string& name);
+ void Setup();
public:
- SharedLibrary(const std::string& path);
+ OrthancHttpConnection();
+
+ OrthancHttpConnection(const Orthanc::WebServiceParameters& parameters);
- ~SharedLibrary();
+ virtual void RestApiGet(std::string& result,
+ const std::string& uri);
- const std::string& GetPath() const
- {
- return path_;
- }
+ virtual void RestApiPost(std::string& result,
+ const std::string& uri,
+ const std::string& body);
- bool HasFunction(const std::string& name);
+ virtual void RestApiPut(std::string& result,
+ const std::string& uri,
+ const std::string& body);
- FunctionPointer GetFunction(const std::string& name);
+ virtual void RestApiDelete(const std::string& uri);
};
}
-
-#endif
diff --git a/Framework/Orthanc/Core/ChunkedBuffer.cpp b/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginConnection.cpp
similarity index 51%
rename from Framework/Orthanc/Core/ChunkedBuffer.cpp
rename to Resources/Orthanc/Plugins/Samples/Common/OrthancPluginConnection.cpp
index 5d2c2c8..fb82353 100644
--- a/Framework/Orthanc/Core/ChunkedBuffer.cpp
+++ b/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginConnection.cpp
@@ -30,73 +30,69 @@
**/
-#include "PrecompiledHeaders.h"
-#include "ChunkedBuffer.h"
+#include "OrthancPluginConnection.h"
-#include <cassert>
-#include <string.h>
+#include "OrthancPluginCppWrapper.h"
-
-namespace Orthanc
+namespace OrthancPlugins
{
- void ChunkedBuffer::Clear()
+ void OrthancPluginConnection::RestApiGet(std::string& result,
+ const std::string& uri)
{
- numBytes_ = 0;
+ OrthancPlugins::MemoryBuffer buffer(context_);
- for (Chunks::iterator it = chunks_.begin();
- it != chunks_.end(); ++it)
+ if (buffer.RestApiGet(uri, false))
+ {
+ buffer.ToString(result);
+ }
+ else
{
- delete *it;
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_UnknownResource);
}
}
- void ChunkedBuffer::AddChunk(const void* chunkData,
- size_t chunkSize)
+ void OrthancPluginConnection::RestApiPost(std::string& result,
+ const std::string& uri,
+ const std::string& body)
{
- if (chunkSize == 0)
+ OrthancPlugins::MemoryBuffer buffer(context_);
+
+ if (buffer.RestApiPost(uri, body.c_str(), body.size(), false))
{
- return;
+ buffer.ToString(result);
}
else
{
- assert(chunkData != NULL);
- chunks_.push_back(new std::string(reinterpret_cast<const char*>(chunkData), chunkSize));
- numBytes_ += chunkSize;
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_UnknownResource);
}
}
- void ChunkedBuffer::AddChunk(const std::string& chunk)
+ void OrthancPluginConnection::RestApiPut(std::string& result,
+ const std::string& uri,
+ const std::string& body)
{
- if (chunk.size() > 0)
+ OrthancPlugins::MemoryBuffer buffer(context_);
+
+ if (buffer.RestApiPut(uri, body.c_str(), body.size(), false))
{
- AddChunk(&chunk[0], chunk.size());
+ buffer.ToString(result);
+ }
+ else
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_UnknownResource);
}
}
- void ChunkedBuffer::Flatten(std::string& result)
+ void OrthancPluginConnection::RestApiDelete(const std::string& uri)
{
- result.resize(numBytes_);
+ OrthancPlugins::MemoryBuffer buffer(context_);
- size_t pos = 0;
- for (Chunks::iterator it = chunks_.begin();
- it != chunks_.end(); ++it)
+ if (!::OrthancPlugins::RestApiDelete(context_, uri, false))
{
- assert(*it != NULL);
-
- size_t s = (*it)->size();
- if (s != 0)
- {
- memcpy(&result[pos], (*it)->c_str(), s);
- pos += s;
- }
-
- delete *it;
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_UnknownResource);
}
-
- chunks_.clear();
- numBytes_ = 0;
}
}
diff --git a/Framework/Orthanc/Core/DicomFormat/DicomArray.h b/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginConnection.h
similarity index 68%
copy from Framework/Orthanc/Core/DicomFormat/DicomArray.h
copy to Resources/Orthanc/Plugins/Samples/Common/OrthancPluginConnection.h
index a223685..f4b06ff 100644
--- a/Framework/Orthanc/Core/DicomFormat/DicomArray.h
+++ b/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginConnection.h
@@ -32,35 +32,35 @@
#pragma once
-#include "DicomElement.h"
-#include "DicomMap.h"
+#include "IOrthancConnection.h"
-#include <vector>
+#include <orthanc/OrthancCPlugin.h>
-namespace Orthanc
+namespace OrthancPlugins
{
- class DicomArray : public boost::noncopyable
+ // This class is thread-safe
+ class OrthancPluginConnection : public IOrthancConnection
{
private:
- typedef std::vector<DicomElement*> Elements;
-
- Elements elements_;
+ OrthancPluginContext* context_;
public:
- DicomArray(const DicomMap& map);
-
- ~DicomArray();
-
- size_t GetSize() const
+ OrthancPluginConnection(OrthancPluginContext* context) :
+ context_(context)
{
- return elements_.size();
}
- const DicomElement& GetElement(size_t i) const
- {
- return *elements_[i];
- }
+ virtual void RestApiGet(std::string& result,
+ const std::string& uri);
+
+ virtual void RestApiPost(std::string& result,
+ const std::string& uri,
+ const std::string& body);
+
+ virtual void RestApiPut(std::string& result,
+ const std::string& uri,
+ const std::string& body);
- void Print(FILE* fp) const;
+ virtual void RestApiDelete(const std::string& uri);
};
}
diff --git a/Framework/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp b/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
similarity index 90%
rename from Framework/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
rename to Resources/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
index 50412d7..4b5650e 100644
--- a/Framework/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
+++ b/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
@@ -38,9 +38,10 @@
namespace OrthancPlugins
{
- const char* PluginException::GetErrorDescription(OrthancPluginContext* context) const
+ const char* GetErrorDescription(OrthancPluginContext* context,
+ OrthancPluginErrorCode code)
{
- const char* description = OrthancPluginGetErrorDescription(context, code_);
+ const char* description = OrthancPluginGetErrorDescription(context, code);
if (description)
{
return description;
@@ -52,13 +53,15 @@ namespace OrthancPlugins
}
+#if HAS_ORTHANC_EXCEPTION == 0
void PluginException::Check(OrthancPluginErrorCode code)
{
if (code != OrthancPluginErrorCode_Success)
{
- throw PluginException(code);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(code);
}
}
+#endif
void MemoryBuffer::Check(OrthancPluginErrorCode code)
@@ -68,7 +71,7 @@ namespace OrthancPlugins
// Prevent using garbage information
buffer_.data = NULL;
buffer_.size = 0;
- throw PluginException(code);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(code);
}
}
@@ -122,7 +125,7 @@ namespace OrthancPlugins
if (buffer_.data == NULL ||
buffer_.size == 0)
{
- throw PluginException(OrthancPluginErrorCode_InternalError);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InternalError);
}
const char* tmp = reinterpret_cast<const char*>(buffer_.data);
@@ -131,7 +134,7 @@ namespace OrthancPlugins
if (!reader.parse(tmp, tmp + buffer_.size, target))
{
OrthancPluginLogError(context_, "Cannot convert some memory buffer to JSON");
- throw PluginException(OrthancPluginErrorCode_BadFileFormat);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
}
}
@@ -163,7 +166,7 @@ namespace OrthancPlugins
}
else
{
- throw PluginException(error);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(error);
}
}
@@ -197,7 +200,7 @@ namespace OrthancPlugins
}
else
{
- throw PluginException(error);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(error);
}
}
@@ -231,7 +234,7 @@ namespace OrthancPlugins
}
else
{
- throw PluginException(error);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(error);
}
}
@@ -309,14 +312,14 @@ namespace OrthancPlugins
if (str_ == NULL)
{
OrthancPluginLogError(context_, "Cannot convert an empty memory buffer to JSON");
- throw PluginException(OrthancPluginErrorCode_InternalError);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InternalError);
}
Json::Reader reader;
if (!reader.parse(str_, target))
{
OrthancPluginLogError(context_, "Cannot convert some memory buffer to JSON");
- throw PluginException(OrthancPluginErrorCode_BadFileFormat);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
}
}
@@ -329,7 +332,7 @@ namespace OrthancPlugins
if (str.GetContent() == NULL)
{
OrthancPluginLogError(context, "Cannot access the Orthanc configuration");
- throw PluginException(OrthancPluginErrorCode_InternalError);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InternalError);
}
str.ToJson(configuration_);
@@ -337,7 +340,7 @@ namespace OrthancPlugins
if (configuration_.type() != Json::objectValue)
{
OrthancPluginLogError(context, "Unable to read the Orthanc configuration");
- throw PluginException(OrthancPluginErrorCode_InternalError);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InternalError);
}
}
@@ -346,7 +349,7 @@ namespace OrthancPlugins
{
if (context_ == NULL)
{
- throw PluginException(OrthancPluginErrorCode_Plugin);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_Plugin);
}
else
{
@@ -368,6 +371,15 @@ namespace OrthancPlugins
}
+ bool OrthancConfiguration::IsSection(const std::string& key) const
+ {
+ assert(configuration_.type() == Json::objectValue);
+
+ return (configuration_.isMember(key) &&
+ configuration_[key].type() == Json::objectValue);
+ }
+
+
void OrthancConfiguration::GetSection(OrthancConfiguration& target,
const std::string& key) const
{
@@ -390,7 +402,7 @@ namespace OrthancPlugins
OrthancPluginLogError(context_, s.c_str());
}
- throw PluginException(OrthancPluginErrorCode_BadFileFormat);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
}
target.configuration_ = configuration_[key];
@@ -416,7 +428,7 @@ namespace OrthancPlugins
OrthancPluginLogError(context_, s.c_str());
}
- throw PluginException(OrthancPluginErrorCode_BadFileFormat);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
}
target = configuration_[key].asString();
@@ -451,7 +463,7 @@ namespace OrthancPlugins
OrthancPluginLogError(context_, s.c_str());
}
- throw PluginException(OrthancPluginErrorCode_BadFileFormat);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
}
}
@@ -473,7 +485,7 @@ namespace OrthancPlugins
OrthancPluginLogError(context_, s.c_str());
}
- throw PluginException(OrthancPluginErrorCode_BadFileFormat);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
}
else
{
@@ -501,7 +513,7 @@ namespace OrthancPlugins
OrthancPluginLogError(context_, s.c_str());
}
- throw PluginException(OrthancPluginErrorCode_BadFileFormat);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
}
target = configuration_[key].asBool();
@@ -540,7 +552,7 @@ namespace OrthancPlugins
OrthancPluginLogError(context_, s.c_str());
}
- throw PluginException(OrthancPluginErrorCode_BadFileFormat);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
}
}
@@ -635,7 +647,7 @@ namespace OrthancPlugins
if (image_ == NULL)
{
OrthancPluginLogError(context_, "Trying to access a NULL image");
- throw PluginException(OrthancPluginErrorCode_ParameterOutOfRange);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
}
}
@@ -646,7 +658,7 @@ namespace OrthancPlugins
{
if (context == NULL)
{
- throw PluginException(OrthancPluginErrorCode_ParameterOutOfRange);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
}
}
@@ -658,7 +670,7 @@ namespace OrthancPlugins
{
if (context == NULL)
{
- throw PluginException(OrthancPluginErrorCode_ParameterOutOfRange);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
}
}
@@ -671,7 +683,7 @@ namespace OrthancPlugins
{
if (context == NULL)
{
- throw PluginException(OrthancPluginErrorCode_ParameterOutOfRange);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
}
else
{
@@ -688,7 +700,7 @@ namespace OrthancPlugins
if (image_ == NULL)
{
OrthancPluginLogError(context_, "Cannot uncompress a PNG image");
- throw PluginException(OrthancPluginErrorCode_ParameterOutOfRange);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
}
}
@@ -701,7 +713,7 @@ namespace OrthancPlugins
if (image_ == NULL)
{
OrthancPluginLogError(context_, "Cannot uncompress a JPEG image");
- throw PluginException(OrthancPluginErrorCode_ParameterOutOfRange);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
}
}
@@ -715,7 +727,7 @@ namespace OrthancPlugins
if (image_ == NULL)
{
OrthancPluginLogError(context_, "Cannot uncompress a DICOM image");
- throw PluginException(OrthancPluginErrorCode_ParameterOutOfRange);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
}
}
@@ -903,7 +915,7 @@ namespace OrthancPlugins
}
else
{
- throw PluginException(error);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(error);
}
}
diff --git a/Framework/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.h b/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.h
similarity index 94%
rename from Framework/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.h
rename to Resources/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.h
index 6a6ab91..8f0bb7a 100644
--- a/Framework/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.h
+++ b/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.h
@@ -37,18 +37,30 @@
#include <boost/lexical_cast.hpp>
#include <json/value.h>
+#if !defined(HAS_ORTHANC_EXCEPTION)
+# error The macro HAS_ORTHANC_EXCEPTION must be defined
+#endif
+
+
#if HAS_ORTHANC_EXCEPTION == 1
# include "../../../Core/OrthancException.h"
+# define ORTHANC_PLUGINS_THROW_EXCEPTION(code) throw ::Orthanc::OrthancException(static_cast<Orthanc::ErrorCode>(code))
+#else
+# define ORTHANC_PLUGINS_THROW_EXCEPTION(code) throw ::OrthancPlugins::PluginException(code)
#endif
+
namespace OrthancPlugins
{
typedef void (*RestCallback) (OrthancPluginRestOutput* output,
const char* url,
const OrthancPluginHttpRequest* request);
+ const char* GetErrorDescription(OrthancPluginContext* context,
+ OrthancPluginErrorCode code);
+#if HAS_ORTHANC_EXCEPTION == 0
class PluginException
{
private:
@@ -64,10 +76,14 @@ namespace OrthancPlugins
return code_;
}
- const char* GetErrorDescription(OrthancPluginContext* context) const;
+ const char* What(OrthancPluginContext* context) const
+ {
+ return ::OrthancPlugins::GetErrorDescription(context, code_);
+ }
static void Check(OrthancPluginErrorCode code);
};
+#endif
class MemoryBuffer : public boost::noncopyable
@@ -191,7 +207,7 @@ namespace OrthancPlugins
{
private:
OrthancPluginContext* context_;
- Json::Value configuration_;
+ Json::Value configuration_; // Necessarily a Json::objectValue
std::string path_;
std::string GetPath(const std::string& key) const;
@@ -210,6 +226,8 @@ namespace OrthancPlugins
return configuration_;
}
+ bool IsSection(const std::string& key) const;
+
void GetSection(OrthancConfiguration& target,
const std::string& key) const;
@@ -357,10 +375,6 @@ namespace OrthancPlugins
const std::string& uri,
bool applyPlugins);
- bool RestApiDelete(OrthancPluginContext* context,
- const std::string& uri,
- bool applyPlugins);
-
inline void LogError(OrthancPluginContext* context,
const std::string& message)
{
@@ -406,15 +420,16 @@ namespace OrthancPlugins
Callback(output, url, request);
return OrthancPluginErrorCode_Success;
}
- catch (OrthancPlugins::PluginException& e)
- {
- return e.GetErrorCode();
- }
#if HAS_ORTHANC_EXCEPTION == 1
catch (Orthanc::OrthancException& e)
{
return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());
}
+#else
+ catch (OrthancPlugins::PluginException& e)
+ {
+ return e.GetErrorCode();
+ }
#endif
catch (boost::bad_lexical_cast&)
{
diff --git a/Resources/Orthanc/Plugins/Samples/Common/SimplifiedOrthancDataset.cpp b/Resources/Orthanc/Plugins/Samples/Common/SimplifiedOrthancDataset.cpp
new file mode 100644
index 0000000..1fa2bea
--- /dev/null
+++ b/Resources/Orthanc/Plugins/Samples/Common/SimplifiedOrthancDataset.cpp
@@ -0,0 +1,156 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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/>.
+ **/
+
+
+#include "SimplifiedOrthancDataset.h"
+
+#include "OrthancPluginCppWrapper.h"
+
+namespace OrthancPlugins
+{
+ const Json::Value* SimplifiedOrthancDataset::LookupPath(const DicomPath& path) const
+ {
+ const Json::Value* content = &root_;
+
+ for (unsigned int depth = 0; depth < path.GetPrefixLength(); depth++)
+ {
+ const char* name = path.GetPrefixTag(depth).GetName();
+ if (content->type() != Json::objectValue)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+
+ if (!content->isMember(name))
+ {
+ return NULL;
+ }
+
+ const Json::Value& sequence = (*content) [name];
+ if (sequence.type() != Json::arrayValue)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+
+ size_t index = path.GetPrefixIndex(depth);
+ if (index >= sequence.size())
+ {
+ return NULL;
+ }
+ else
+ {
+ content = &sequence[static_cast<Json::Value::ArrayIndex>(index)];
+ }
+ }
+
+ const char* name = path.GetFinalTag().GetName();
+
+ if (content->type() != Json::objectValue)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+ if (!content->isMember(name))
+ {
+ return NULL;
+ }
+ else
+ {
+ return &((*content) [name]);
+ }
+ }
+
+
+ void SimplifiedOrthancDataset::CheckRoot() const
+ {
+ if (root_.type() != Json::objectValue)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+ }
+
+
+ SimplifiedOrthancDataset::SimplifiedOrthancDataset(IOrthancConnection& orthanc,
+ const std::string& uri)
+ {
+ IOrthancConnection::RestApiGet(root_, orthanc, uri);
+ CheckRoot();
+ }
+
+
+ SimplifiedOrthancDataset::SimplifiedOrthancDataset(const std::string& content)
+ {
+ IOrthancConnection::ParseJson(root_, content);
+ CheckRoot();
+ }
+
+
+ bool SimplifiedOrthancDataset::GetStringValue(std::string& result,
+ const DicomPath& path) const
+ {
+ const Json::Value* value = LookupPath(path);
+
+ if (value == NULL)
+ {
+ return false;
+ }
+ else if (value->type() != Json::stringValue)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+ else
+ {
+ result = value->asString();
+ return true;
+ }
+ }
+
+
+ bool SimplifiedOrthancDataset::GetSequenceSize(size_t& size,
+ const DicomPath& path) const
+ {
+ const Json::Value* sequence = LookupPath(path);
+
+ if (sequence == NULL)
+ {
+ // Inexistent path
+ return false;
+ }
+ else if (sequence->type() != Json::arrayValue)
+ {
+ // Not a sequence
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+ else
+ {
+ size = sequence->size();
+ return true;
+ }
+ }
+}
diff --git a/Framework/Orthanc/Core/DicomFormat/DicomArray.h b/Resources/Orthanc/Plugins/Samples/Common/SimplifiedOrthancDataset.h
similarity index 71%
rename from Framework/Orthanc/Core/DicomFormat/DicomArray.h
rename to Resources/Orthanc/Plugins/Samples/Common/SimplifiedOrthancDataset.h
index a223685..a71e1e0 100644
--- a/Framework/Orthanc/Core/DicomFormat/DicomArray.h
+++ b/Resources/Orthanc/Plugins/Samples/Common/SimplifiedOrthancDataset.h
@@ -32,35 +32,30 @@
#pragma once
-#include "DicomElement.h"
-#include "DicomMap.h"
+#include "IOrthancConnection.h"
+#include "IDicomDataset.h"
-#include <vector>
-
-namespace Orthanc
+namespace OrthancPlugins
{
- class DicomArray : public boost::noncopyable
+ class SimplifiedOrthancDataset : public IDicomDataset
{
private:
- typedef std::vector<DicomElement*> Elements;
+ Json::Value root_;
- Elements elements_;
+ const Json::Value* LookupPath(const DicomPath& path) const;
- public:
- DicomArray(const DicomMap& map);
+ void CheckRoot() const;
- ~DicomArray();
+ public:
+ SimplifiedOrthancDataset(IOrthancConnection& orthanc,
+ const std::string& uri);
- size_t GetSize() const
- {
- return elements_.size();
- }
+ SimplifiedOrthancDataset(const std::string& content);
- const DicomElement& GetElement(size_t i) const
- {
- return *elements_[i];
- }
+ virtual bool GetStringValue(std::string& result,
+ const DicomPath& path) const;
- void Print(FILE* fp) const;
+ virtual bool GetSequenceSize(size_t& size,
+ const DicomPath& path) const;
};
}
diff --git a/Framework/Orthanc/Plugins/Samples/Common/VersionScript.map b/Resources/Orthanc/Plugins/Samples/Common/VersionScript.map
similarity index 100%
rename from Framework/Orthanc/Plugins/Samples/Common/VersionScript.map
rename to Resources/Orthanc/Plugins/Samples/Common/VersionScript.map
diff --git a/Framework/Orthanc/README.txt b/Resources/Orthanc/README.txt
similarity index 100%
rename from Framework/Orthanc/README.txt
rename to Resources/Orthanc/README.txt
diff --git a/Framework/Orthanc/Resources/CMake/AutoGeneratedCode.cmake b/Resources/Orthanc/Resources/CMake/AutoGeneratedCode.cmake
similarity index 100%
rename from Framework/Orthanc/Resources/CMake/AutoGeneratedCode.cmake
rename to Resources/Orthanc/Resources/CMake/AutoGeneratedCode.cmake
diff --git a/Framework/Orthanc/Resources/CMake/BoostConfiguration.cmake b/Resources/Orthanc/Resources/CMake/BoostConfiguration.cmake
similarity index 99%
rename from Framework/Orthanc/Resources/CMake/BoostConfiguration.cmake
rename to Resources/Orthanc/Resources/CMake/BoostConfiguration.cmake
index efe0e70..3596427 100644
--- a/Framework/Orthanc/Resources/CMake/BoostConfiguration.cmake
+++ b/Resources/Orthanc/Resources/CMake/BoostConfiguration.cmake
@@ -125,10 +125,11 @@ if (BOOST_STATIC)
add_definitions(
-DBOOST_HAS_FILESYSTEM_V3=0
-D__INTEGRITY=1
- -DORTHANC_SANDBOXED=1
)
else()
- add_definitions(-DBOOST_HAS_FILESYSTEM_V3=1)
+ add_definitions(
+ -DBOOST_HAS_FILESYSTEM_V3=1
+ )
list(APPEND BOOST_SOURCES
${BOOST_FILESYSTEM_SOURCES_DIR}/codecvt_error_category.cpp
${BOOST_FILESYSTEM_SOURCES_DIR}/operations.cpp
diff --git a/Framework/Orthanc/Resources/CMake/Compiler.cmake b/Resources/Orthanc/Resources/CMake/Compiler.cmake
similarity index 84%
rename from Framework/Orthanc/Resources/CMake/Compiler.cmake
rename to Resources/Orthanc/Resources/CMake/Compiler.cmake
index 52f4fab..fa7577d 100644
--- a/Framework/Orthanc/Resources/CMake/Compiler.cmake
+++ b/Resources/Orthanc/Resources/CMake/Compiler.cmake
@@ -41,7 +41,17 @@ elseif (MSVC)
-D_CRT_SECURE_NO_WARNINGS=1
-D_CRT_SECURE_NO_DEPRECATE=1
)
- include_directories(${ORTHANC_ROOT}/Resources/ThirdParty/VisualStudio)
+
+ if (MSVC_VERSION LESS 1600)
+ # Starting with Visual Studio >= 2010 (i.e. macro _MSC_VER >=
+ # 1600), Microsoft ships a standard-compliant <stdint.h>
+ # header. For earlier versions of Visual Studio, give access to a
+ # compatibility header.
+ # http://stackoverflow.com/a/70630/881731
+ # https://en.wikibooks.org/wiki/C_Programming/C_Reference/stdint.h#External_links
+ include_directories(${ORTHANC_ROOT}/Resources/ThirdParty/VisualStudio)
+ endif()
+
link_libraries(netapi32)
endif()
@@ -154,6 +164,23 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
endif()
+if (DEFINED ENABLE_PROFILING AND ENABLE_PROFILING)
+ if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
+ message(WARNING "Enabling profiling on a non-debug build will not produce full information")
+ endif()
+
+ if (CMAKE_COMPILER_IS_GNUCXX)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pg")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg")
+ set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -pg")
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -pg")
+ else()
+ message(FATAL_ERROR "Don't know how to enable profiling on your configuration")
+ endif()
+endif()
+
+
if (STATIC_BUILD)
add_definitions(-DORTHANC_STATIC=1)
else()
diff --git a/Framework/Orthanc/Resources/CMake/DcmtkConfiguration.cmake b/Resources/Orthanc/Resources/CMake/DcmtkConfiguration.cmake
similarity index 92%
rename from Framework/Orthanc/Resources/CMake/DcmtkConfiguration.cmake
rename to Resources/Orthanc/Resources/CMake/DcmtkConfiguration.cmake
index 6d48ccb..96d07cb 100644
--- a/Framework/Orthanc/Resources/CMake/DcmtkConfiguration.cmake
+++ b/Resources/Orthanc/Resources/CMake/DcmtkConfiguration.cmake
@@ -35,6 +35,24 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_DCMTK)
DownloadPackage(${DCMTK_MD5} ${DCMTK_URL} "${DCMTK_SOURCES_DIR}")
+
+ if (FirstRun AND
+ NOT USE_DCMTK_361)
+ if (USE_DCMTK_361_PRIVATE_DIC)
+ # If using DCMTK 3.6.0, backport the "private.dic" file from DCMTK
+ # 3.6.1 snapshot. This adds support for more private tags, and
+ # fixes some import problems with Philips MRI Achieva.
+ message("Using the dictionary of private tags from DCMTK 3.6.1")
+ configure_file(
+ ${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.1-private.dic
+ ${DCMTK_SOURCES_DIR}/dcmdata/data/private.dic
+ COPYONLY)
+ else()
+ message("Using the dictionary of private tags from DCMTK 3.6.0")
+ endif()
+ endif()
+
+
IF (CMAKE_CROSSCOMPILING)
SET(C_CHAR_UNSIGNED 1 CACHE INTERNAL "Whether char is unsigned.")
ENDIF()
@@ -181,9 +199,15 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_DCMTK)
list(REMOVE_ITEM DCMTK_SOURCES
${DCMTK_SOURCES_DIR}/dcmdata/libsrc/mkdictbi.cc
${DCMTK_SOURCES_DIR}/dcmdata/libsrc/mkdeftag.cc
- ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/dcdictbi.cc
)
+ if (NOT USE_DCMTK_361)
+ # Removing this file is required with DCMTK 3.6.0
+ list(REMOVE_ITEM DCMTK_SOURCES
+ ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/dcdictbi.cc
+ )
+ endif()
+
#set_source_files_properties(${DCMTK_SOURCES}
# PROPERTIES COMPILE_DEFINITIONS
# "PACKAGE_VERSION=\"${DCMTK_PACKAGE_VERSION}\";PACKAGE_VERSION_NUMBER=\"${DCMTK_VERSION_NUMBER}\"")
diff --git a/Framework/Orthanc/Resources/CMake/DownloadPackage.cmake b/Resources/Orthanc/Resources/CMake/DownloadPackage.cmake
similarity index 88%
rename from Framework/Orthanc/Resources/CMake/DownloadPackage.cmake
rename to Resources/Orthanc/Resources/CMake/DownloadPackage.cmake
index b529cef..2a73cda 100644
--- a/Framework/Orthanc/Resources/CMake/DownloadPackage.cmake
+++ b/Resources/Orthanc/Resources/CMake/DownloadPackage.cmake
@@ -15,16 +15,18 @@ endmacro()
## Setup the patch command-line tool
##
-if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")
- set(PATCH_EXECUTABLE ${CMAKE_CURRENT_LIST_DIR}/../ThirdParty/patch/patch.exe)
- if (NOT EXISTS ${PATCH_EXECUTABLE})
- message(FATAL_ERROR "Unable to find the patch.exe tool that is shipped with Orthanc")
- endif()
+if (NOT ORTHANC_DISABLE_PATCH)
+ if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")
+ set(PATCH_EXECUTABLE ${CMAKE_CURRENT_LIST_DIR}/../ThirdParty/patch/patch.exe)
+ if (NOT EXISTS ${PATCH_EXECUTABLE})
+ message(FATAL_ERROR "Unable to find the patch.exe tool that is shipped with Orthanc")
+ endif()
-else ()
- find_program(PATCH_EXECUTABLE patch)
- if (${PATCH_EXECUTABLE} MATCHES "PATCH_EXECUTABLE-NOTFOUND")
- message(FATAL_ERROR "Please install the 'patch' standard command-line tool")
+ else ()
+ find_program(PATCH_EXECUTABLE patch)
+ if (${PATCH_EXECUTABLE} MATCHES "PATCH_EXECUTABLE-NOTFOUND")
+ message(FATAL_ERROR "Please install the 'patch' standard command-line tool")
+ endif()
endif()
endif()
@@ -74,7 +76,9 @@ macro(DownloadPackage MD5 Url TargetDirectory)
message(FATAL_ERROR "CMake is not allowed to download from Internet. Please set the ALLOW_DOWNLOADS option to ON")
endif()
- file(DOWNLOAD "${Url}" "${TMP_PATH}" SHOW_PROGRESS EXPECTED_MD5 "${MD5}")
+ file(DOWNLOAD "${Url}" "${TMP_PATH}"
+ SHOW_PROGRESS EXPECTED_MD5 "${MD5}"
+ TIMEOUT 60 INACTIVITY_TIMEOUT 60)
else()
message("Using local copy of ${Url}")
endif()
diff --git a/Framework/Orthanc/Resources/CMake/JsonCppConfiguration.cmake b/Resources/Orthanc/Resources/CMake/JsonCppConfiguration.cmake
similarity index 100%
rename from Framework/Orthanc/Resources/CMake/JsonCppConfiguration.cmake
rename to Resources/Orthanc/Resources/CMake/JsonCppConfiguration.cmake
diff --git a/Framework/Orthanc/Resources/CMake/LibCurlConfiguration.cmake b/Resources/Orthanc/Resources/CMake/LibCurlConfiguration.cmake
similarity index 100%
rename from Framework/Orthanc/Resources/CMake/LibCurlConfiguration.cmake
rename to Resources/Orthanc/Resources/CMake/LibCurlConfiguration.cmake
diff --git a/Framework/Orthanc/Resources/CMake/LibJpegConfiguration.cmake b/Resources/Orthanc/Resources/CMake/LibJpegConfiguration.cmake
similarity index 100%
rename from Framework/Orthanc/Resources/CMake/LibJpegConfiguration.cmake
rename to Resources/Orthanc/Resources/CMake/LibJpegConfiguration.cmake
diff --git a/Framework/Orthanc/Resources/CMake/LibPngConfiguration.cmake b/Resources/Orthanc/Resources/CMake/LibPngConfiguration.cmake
similarity index 100%
rename from Framework/Orthanc/Resources/CMake/LibPngConfiguration.cmake
rename to Resources/Orthanc/Resources/CMake/LibPngConfiguration.cmake
diff --git a/Framework/Orthanc/Resources/CMake/OpenSslConfiguration.cmake b/Resources/Orthanc/Resources/CMake/OpenSslConfiguration.cmake
similarity index 100%
rename from Framework/Orthanc/Resources/CMake/OpenSslConfiguration.cmake
rename to Resources/Orthanc/Resources/CMake/OpenSslConfiguration.cmake
diff --git a/Framework/Orthanc/Resources/CMake/VisualStudioPrecompiledHeaders.cmake b/Resources/Orthanc/Resources/CMake/VisualStudioPrecompiledHeaders.cmake
similarity index 100%
rename from Framework/Orthanc/Resources/CMake/VisualStudioPrecompiledHeaders.cmake
rename to Resources/Orthanc/Resources/CMake/VisualStudioPrecompiledHeaders.cmake
diff --git a/Framework/Orthanc/Resources/CMake/ZlibConfiguration.cmake b/Resources/Orthanc/Resources/CMake/ZlibConfiguration.cmake
similarity index 100%
rename from Framework/Orthanc/Resources/CMake/ZlibConfiguration.cmake
rename to Resources/Orthanc/Resources/CMake/ZlibConfiguration.cmake
diff --git a/Framework/Orthanc/Resources/EmbedResources.py b/Resources/Orthanc/Resources/EmbedResources.py
similarity index 98%
rename from Framework/Orthanc/Resources/EmbedResources.py
rename to Resources/Orthanc/Resources/EmbedResources.py
index d914d15..ad5cf61 100755
--- a/Framework/Orthanc/Resources/EmbedResources.py
+++ b/Resources/Orthanc/Resources/EmbedResources.py
@@ -159,6 +159,10 @@ header.write("""
#include <string>
#include <list>
+#if defined(_MSC_VER)
+# pragma warning(disable: 4065) // "Switch statement contains 'default' but no 'case' labels"
+#endif
+
namespace %s
{
namespace EmbeddedResources
diff --git a/Framework/Orthanc/Resources/MinGW-W64-Toolchain32.cmake b/Resources/Orthanc/Resources/MinGW-W64-Toolchain32.cmake
similarity index 100%
rename from Framework/Orthanc/Resources/MinGW-W64-Toolchain32.cmake
rename to Resources/Orthanc/Resources/MinGW-W64-Toolchain32.cmake
diff --git a/Framework/Orthanc/Resources/MinGW-W64-Toolchain64.cmake b/Resources/Orthanc/Resources/MinGW-W64-Toolchain64.cmake
similarity index 100%
rename from Framework/Orthanc/Resources/MinGW-W64-Toolchain64.cmake
rename to Resources/Orthanc/Resources/MinGW-W64-Toolchain64.cmake
diff --git a/Framework/Orthanc/Resources/MinGWToolchain.cmake b/Resources/Orthanc/Resources/MinGWToolchain.cmake
similarity index 100%
rename from Framework/Orthanc/Resources/MinGWToolchain.cmake
rename to Resources/Orthanc/Resources/MinGWToolchain.cmake
diff --git a/Framework/Orthanc/Resources/Patches/dcmtk-3.6.0-mingw64.patch b/Resources/Orthanc/Resources/Patches/dcmtk-3.6.0-mingw64.patch
similarity index 100%
rename from Framework/Orthanc/Resources/Patches/dcmtk-3.6.0-mingw64.patch
rename to Resources/Orthanc/Resources/Patches/dcmtk-3.6.0-mingw64.patch
diff --git a/Framework/Orthanc/Resources/Patches/dcmtk-3.6.0-speed.patch b/Resources/Orthanc/Resources/Patches/dcmtk-3.6.0-speed.patch
similarity index 100%
rename from Framework/Orthanc/Resources/Patches/dcmtk-3.6.0-speed.patch
rename to Resources/Orthanc/Resources/Patches/dcmtk-3.6.0-speed.patch
diff --git a/Framework/Orthanc/Resources/Patches/dcmtk-3.6.1-speed.patch b/Resources/Orthanc/Resources/Patches/dcmtk-3.6.1-speed.patch
similarity index 100%
rename from Framework/Orthanc/Resources/Patches/dcmtk-3.6.1-speed.patch
rename to Resources/Orthanc/Resources/Patches/dcmtk-3.6.1-speed.patch
diff --git a/Framework/Orthanc/Resources/ThirdParty/VisualStudio/stdint.h b/Resources/Orthanc/Resources/ThirdParty/VisualStudio/stdint.h
similarity index 100%
rename from Framework/Orthanc/Resources/ThirdParty/VisualStudio/stdint.h
rename to Resources/Orthanc/Resources/ThirdParty/VisualStudio/stdint.h
diff --git a/Framework/Orthanc/Resources/ThirdParty/base64/base64.cpp b/Resources/Orthanc/Resources/ThirdParty/base64/base64.cpp
similarity index 100%
rename from Framework/Orthanc/Resources/ThirdParty/base64/base64.cpp
rename to Resources/Orthanc/Resources/ThirdParty/base64/base64.cpp
diff --git a/Framework/Orthanc/Resources/ThirdParty/base64/base64.h b/Resources/Orthanc/Resources/ThirdParty/base64/base64.h
similarity index 100%
rename from Framework/Orthanc/Resources/ThirdParty/base64/base64.h
rename to Resources/Orthanc/Resources/ThirdParty/base64/base64.h
diff --git a/Framework/Orthanc/Resources/WindowsResources.py b/Resources/Orthanc/Resources/WindowsResources.py
similarity index 100%
rename from Framework/Orthanc/Resources/WindowsResources.py
rename to Resources/Orthanc/Resources/WindowsResources.py
diff --git a/Framework/Orthanc/Resources/WindowsResources.rc b/Resources/Orthanc/Resources/WindowsResources.rc
similarity index 100%
rename from Framework/Orthanc/Resources/WindowsResources.rc
rename to Resources/Orthanc/Resources/WindowsResources.rc
diff --git a/Framework/Orthanc/Sdk-1.0.0/orthanc/OrthancCPlugin.h b/Resources/Orthanc/Sdk-1.0.0/orthanc/OrthancCPlugin.h
similarity index 100%
rename from Framework/Orthanc/Sdk-1.0.0/orthanc/OrthancCPlugin.h
rename to Resources/Orthanc/Sdk-1.0.0/orthanc/OrthancCPlugin.h
diff --git a/Resources/OrthancWSIClearCache.py b/Resources/OrthancWSIClearCache.py
new file mode 100755
index 0000000..b7e3591
--- /dev/null
+++ b/Resources/OrthancWSIClearCache.py
@@ -0,0 +1,77 @@
+#!/usr/bin/python
+
+# Orthanc - A Lightweight, RESTful DICOM Store
+# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+# Department, University Hospital of Liege, 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/>.
+
+
+import base64
+import httplib2
+import json
+import os
+import sys
+
+if len(sys.argv) != 3 and len(sys.argv) != 5:
+ print("""
+Script to reinitialize the cache of the whole-slide imaging plugin for
+Orthanc. Please make sure that Orthanc is running before starting this
+script.
+
+Usage: %s [hostname] [HTTP port]
+Usage: %s [hostname] [HTTP port] [username] [password]
+For instance: %s 127.0.0.1 8042
+""" % (sys.argv[0], sys.argv[0], sys.argv[0]))
+ exit(-1)
+
+
+METADATA=4200
+
+
+def RunHttpRequest(uri, method, body = None):
+ http = httplib2.Http()
+ headers = { }
+
+ if len(sys.argv) == 5:
+ username = sys.argv[4]
+ password = sys.argv[5]
+
+ # h.add_credentials(username, password)
+
+ # This is a custom reimplementation of the
+ # "Http.add_credentials()" method for Basic HTTP Access
+ # Authentication (for some weird reason, this method does not
+ # always work)
+ # http://en.wikipedia.org/wiki/Basic_access_authentication
+ headers['authorization'] = 'Basic ' + base64.b64encode(username + ':' + password)
+
+ url = 'http://%s:%d/%s' % (sys.argv[1], int(sys.argv[2]), uri)
+ resp, content = http.request(url, method,
+ body = body,
+ headers = headers)
+
+ if resp.status != 200:
+ raise Exception('Cannot %s on URL %s, HTTP status %d '
+ '(Is Orthanc running? Is there a password?)' %
+ (method, url, resp.status))
+ else:
+ return content.decode('utf8')
+
+
+for instance in json.loads(RunHttpRequest('/instances', 'GET')):
+ print('Clearing cache for instance %s' % instance)
+ RunHttpRequest('/instances/%s/metadata/%s' % (instance, METADATA), 'DELETE')
+
+print('The WSI cache was successfully cleared')
diff --git a/Resources/SyncOrthancFolder.py b/Resources/SyncOrthancFolder.py
index eb1bc9e..528206e 100755
--- a/Resources/SyncOrthancFolder.py
+++ b/Resources/SyncOrthancFolder.py
@@ -10,11 +10,12 @@ import os
import stat
import urllib2
-TARGET = os.path.join(os.path.dirname(__file__), '..', 'Framework', 'Orthanc')
+TARGET = os.path.join(os.path.dirname(__file__), '..', 'Resources', 'Orthanc')
PLUGIN_SDK_VERSION = '1.0.0'
REPOSITORY = 'http://bitbucket.org/sjodogne/orthanc/raw'
FILES = [
+ 'Core/Cache/LeastRecentlyUsedIndex.h',
'Core/ChunkedBuffer.cpp',
'Core/ChunkedBuffer.h',
'Core/DicomFormat/DicomArray.cpp',
@@ -66,10 +67,12 @@ FILES = [
'Core/OrthancException.h',
'Core/PrecompiledHeaders.cpp',
'Core/PrecompiledHeaders.h',
+ 'Core/SystemToolbox.cpp',
+ 'Core/SystemToolbox.h',
+ 'Core/TemporaryFile.cpp',
+ 'Core/TemporaryFile.h',
'Core/Toolbox.cpp',
'Core/Toolbox.h',
- 'Core/Uuid.cpp',
- 'Core/Uuid.h',
'Core/WebServiceParameters.cpp',
'Core/WebServiceParameters.h',
'OrthancServer/FromDcmtkBridge.cpp',
@@ -85,6 +88,23 @@ FILES = [
'Plugins/Samples/Common/OrthancPluginCppWrapper.cpp',
'Plugins/Samples/Common/OrthancPluginCppWrapper.h',
'Plugins/Samples/Common/VersionScript.map',
+ 'Plugins/Samples/Common/DicomDatasetReader.cpp',
+ 'Plugins/Samples/Common/DicomDatasetReader.h',
+ 'Plugins/Samples/Common/DicomPath.cpp',
+ 'Plugins/Samples/Common/DicomPath.h',
+ 'Plugins/Samples/Common/DicomTag.cpp',
+ 'Plugins/Samples/Common/DicomTag.h',
+ 'Plugins/Samples/Common/FullOrthancDataset.cpp',
+ 'Plugins/Samples/Common/FullOrthancDataset.h',
+ 'Plugins/Samples/Common/IDicomDataset.h',
+ 'Plugins/Samples/Common/IOrthancConnection.cpp',
+ 'Plugins/Samples/Common/IOrthancConnection.h',
+ 'Plugins/Samples/Common/OrthancHttpConnection.cpp',
+ 'Plugins/Samples/Common/OrthancHttpConnection.h',
+ 'Plugins/Samples/Common/OrthancPluginConnection.cpp',
+ 'Plugins/Samples/Common/OrthancPluginConnection.h',
+ 'Plugins/Samples/Common/SimplifiedOrthancDataset.cpp',
+ 'Plugins/Samples/Common/SimplifiedOrthancDataset.h',
'Resources/CMake/AutoGeneratedCode.cmake',
'Resources/CMake/BoostConfiguration.cmake',
'Resources/CMake/Compiler.cmake',
diff --git a/TODO b/TODO
index 2c738bb..c4af315 100644
--- a/TODO
+++ b/TODO
@@ -6,15 +6,16 @@ Orthanc for Whole-Slide Imaging
General
-------
-* Support sparse tiling (both in encoder and decoder)
+* Thoroughly test sparse tiling (both in encoder and decoder)
* Display physical scale in Web viewer
+* Viewer: Configure how missing tiles are displayed for sparse tiling
-----------
Performance
-----------
-* Larger cache with LRU recycling to improve viewer performance
+* Check out rapidjson: https://github.com/miloyip/nativejson-benchmark
-------------
@@ -29,5 +30,4 @@ Documentation
Packaging
---------
-* DebianMed (ITP #842168: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=842168)
-* Provide precompiled Windows binaries
+* Debian: Rename "Framework/Orthanc/" as "Resources/Orthanc/" in "debian/copyright"
diff --git a/ViewerPlugin/CMakeLists.txt b/ViewerPlugin/CMakeLists.txt
index f6b4d75..6f8ce3f 100644
--- a/ViewerPlugin/CMakeLists.txt
+++ b/ViewerPlugin/CMakeLists.txt
@@ -30,7 +30,7 @@ SET(OPENLAYERS_JS "" CACHE FILEPATH "Path to the system version of OpenLayers Ja
#####################################################################
SET(ORTHANC_WSI_DIR ${CMAKE_CURRENT_LIST_DIR}/..)
-SET(ORTHANC_ROOT ${ORTHANC_WSI_DIR}/Framework/Orthanc)
+SET(ORTHANC_ROOT ${ORTHANC_WSI_DIR}/Resources/Orthanc)
SET(USE_OPENJPEG_JP2 ON)
@@ -63,6 +63,8 @@ add_definitions(
-DORTHANC_ENABLE_DCMTK=0
-DORTHANC_ENABLE_LOGGING=0
-DORTHANC_ENABLE_MD5=0
+ -DORTHANC_ENABLE_PUGIXML=0
+ -DORTHANC_SANDBOXED=0
-DHAS_ORTHANC_EXCEPTION=1
)
@@ -156,6 +158,7 @@ EmbedResources(
#####################################################################
set(ORTHANC_WSI_SOURCES
+ DicomPyramidCache.cpp
Plugin.cpp
${ORTHANC_WSI_DIR}/Framework/DicomToolbox.cpp
${ORTHANC_WSI_DIR}/Framework/Enumerations.cpp
@@ -166,9 +169,6 @@ set(ORTHANC_WSI_SOURCES
${ORTHANC_WSI_DIR}/Framework/Inputs/PyramidWithRawTiles.cpp
${ORTHANC_WSI_DIR}/Framework/Jpeg2000Reader.cpp
${ORTHANC_WSI_DIR}/Framework/Jpeg2000Writer.cpp
- ${ORTHANC_WSI_DIR}/Framework/Messaging/IOrthancConnection.cpp
- ${ORTHANC_WSI_DIR}/Framework/Messaging/OrthancConnectionBase.cpp
- ${ORTHANC_WSI_DIR}/Framework/Messaging/PluginOrthancConnection.cpp
)
set(ORTHANC_CORE_SOURCES
@@ -186,7 +186,13 @@ set(ORTHANC_CORE_SOURCES
${ORTHANC_ROOT}/Core/Images/PngWriter.cpp
${ORTHANC_ROOT}/Core/Logging.cpp
${ORTHANC_ROOT}/Core/MultiThreading/Semaphore.cpp
+ ${ORTHANC_ROOT}/Core/SystemToolbox.cpp
${ORTHANC_ROOT}/Core/Toolbox.cpp
+ ${ORTHANC_ROOT}/Plugins/Samples/Common/DicomDatasetReader.cpp
+ ${ORTHANC_ROOT}/Plugins/Samples/Common/DicomPath.cpp
+ ${ORTHANC_ROOT}/Plugins/Samples/Common/FullOrthancDataset.cpp
+ ${ORTHANC_ROOT}/Plugins/Samples/Common/IOrthancConnection.cpp
+ ${ORTHANC_ROOT}/Plugins/Samples/Common/OrthancPluginConnection.cpp
${ORTHANC_ROOT}/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
)
@@ -199,7 +205,7 @@ if (MSVC)
add_definitions(-DORTHANC_USE_PRECOMPILED_HEADERS=1)
ADD_VISUAL_STUDIO_PRECOMPILED_HEADERS(
- "PrecompiledHeaders.h" "${ORTHANC_WSI_DIR}/Framework/Orthanc/Core/PrecompiledHeaders.cpp" ORTHANC_CORE_SOURCES)
+ "PrecompiledHeaders.h" "${ORTHANC_WSI_DIR}/Resources/Orthanc/Core/PrecompiledHeaders.cpp" ORTHANC_CORE_SOURCES)
ADD_VISUAL_STUDIO_PRECOMPILED_HEADERS(
"PrecompiledHeadersWSI.h" "${ORTHANC_WSI_DIR}/Framework/PrecompiledHeadersWSI.cpp" ORTHANC_WSI_SOURCES)
diff --git a/ViewerPlugin/DicomPyramidCache.cpp b/ViewerPlugin/DicomPyramidCache.cpp
new file mode 100644
index 0000000..16509f4
--- /dev/null
+++ b/ViewerPlugin/DicomPyramidCache.cpp
@@ -0,0 +1,156 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "../Framework/PrecompiledHeadersWSI.h"
+#include "DicomPyramidCache.h"
+
+#include <cassert>
+
+namespace OrthancWSI
+{
+ DicomPyramid* DicomPyramidCache::GetCachedPyramid(const std::string& seriesId)
+ {
+ // Mutex is assumed to be locked
+ DicomPyramid* pyramid = NULL;
+
+ // Is the series of interest already cached as a pyramid?
+ if (cache_.Contains(seriesId, pyramid))
+ {
+ if (pyramid == NULL)
+ {
+ throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+ }
+
+ // Tag the series as the most recently used
+ cache_.MakeMostRecent(seriesId);
+ }
+
+ return pyramid;
+ }
+
+
+ DicomPyramid& DicomPyramidCache::GetPyramid(const std::string& seriesId,
+ boost::mutex::scoped_lock& lock)
+ {
+ // Mutex is assumed to be locked
+
+ {
+ DicomPyramid* pyramid = GetCachedPyramid(seriesId);
+ if (pyramid != NULL)
+ {
+ return *pyramid;
+ }
+ }
+
+ // Unlock the mutex to construct the pyramid (this is a
+ // time-consuming operation, we don't want it to block other clients)
+ lock.unlock();
+
+ std::auto_ptr<DicomPyramid> pyramid
+ (new DicomPyramid(orthanc_, seriesId, true /* use metadata cache */));
+
+ {
+ // The pyramid is constructed: Store it into the cache
+ lock.lock();
+
+ DicomPyramid* cached = GetCachedPyramid(seriesId);
+ if (cached != NULL)
+ {
+ // The pyramid was already constructed by another request in
+ // between, reuse the cached value (the auto_ptr destroys
+ // the just-constructed pyramid)
+ return *cached;
+ }
+
+ if (cache_.GetSize() == maxSize_)
+ {
+ // The cache has grown too large: First delete the least
+ // recently used entry
+ DicomPyramid* oldest = NULL;
+ cache_.RemoveOldest(oldest);
+
+ if (oldest == NULL)
+ {
+ throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+ }
+ else
+ {
+ delete oldest;
+ }
+ }
+
+ // Now we have at least one free entry in the cache
+ assert(cache_.GetSize() < maxSize_);
+
+ // Add a new element to the cache and make it the most
+ // recently used entry
+ DicomPyramid* payload = pyramid.release();
+ cache_.Add(seriesId, payload);
+ return *payload;
+ }
+ }
+
+
+ DicomPyramidCache::DicomPyramidCache(OrthancPlugins::IOrthancConnection& orthanc,
+ size_t maxSize) :
+ orthanc_(orthanc),
+ maxSize_(maxSize)
+ {
+ }
+
+
+ DicomPyramidCache::~DicomPyramidCache()
+ {
+ while (!cache_.IsEmpty())
+ {
+ DicomPyramid* pyramid = NULL;
+ std::string seriesId = cache_.RemoveOldest(pyramid);
+
+ if (pyramid != NULL)
+ {
+ delete pyramid;
+ }
+ }
+ }
+
+
+ void DicomPyramidCache::Invalidate(const std::string& seriesId)
+ {
+ boost::mutex::scoped_lock lock(mutex_);
+
+ if (cache_.Contains(seriesId))
+ {
+ std::auto_ptr<DicomPyramid> pyramid(cache_.Invalidate(seriesId));
+
+ if (pyramid.get() == NULL)
+ {
+ throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+ }
+ }
+ }
+
+
+ DicomPyramidCache::Locker::Locker(DicomPyramidCache& cache,
+ const std::string& seriesId) :
+ lock_(cache.mutex_),
+ pyramid_(cache.GetPyramid(seriesId, lock_))
+ {
+ }
+}
diff --git a/ViewerPlugin/DicomPyramidCache.h b/ViewerPlugin/DicomPyramidCache.h
new file mode 100644
index 0000000..0c0fbaa
--- /dev/null
+++ b/ViewerPlugin/DicomPyramidCache.h
@@ -0,0 +1,70 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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 "../Framework/Inputs/DicomPyramid.h"
+#include "../Resources/Orthanc/Core/Cache/LeastRecentlyUsedIndex.h"
+
+#include <boost/thread/mutex.hpp>
+
+namespace OrthancWSI
+{
+ class DicomPyramidCache : public boost::noncopyable
+ {
+ private:
+ typedef Orthanc::LeastRecentlyUsedIndex<std::string, DicomPyramid*> Cache;
+
+ boost::mutex mutex_;
+ OrthancPlugins::IOrthancConnection& orthanc_;
+ size_t maxSize_;
+ Cache cache_;
+
+
+ DicomPyramid* GetCachedPyramid(const std::string& seriesId);
+
+ DicomPyramid& GetPyramid(const std::string& seriesId,
+ boost::mutex::scoped_lock& lock);
+
+ public:
+ DicomPyramidCache(OrthancPlugins::IOrthancConnection& orthanc,
+ size_t maxSize);
+
+ ~DicomPyramidCache();
+
+ void Invalidate(const std::string& seriesId);
+
+ class Locker : public boost::noncopyable
+ {
+ private:
+ boost::mutex::scoped_lock lock_;
+ DicomPyramid& pyramid_;
+
+ public:
+ Locker(DicomPyramidCache& cache,
+ const std::string& seriesId);
+
+ DicomPyramid& GetPyramid() const
+ {
+ return pyramid_;
+ }
+ };
+ };
+}
diff --git a/ViewerPlugin/Plugin.cpp b/ViewerPlugin/Plugin.cpp
index d68ed00..3eed2a9 100644
--- a/ViewerPlugin/Plugin.cpp
+++ b/ViewerPlugin/Plugin.cpp
@@ -19,95 +19,47 @@
#include "../Framework/PrecompiledHeadersWSI.h"
-#include "../Framework/Inputs/DicomPyramid.h"
+
+#include "DicomPyramidCache.h"
#include "../Framework/Jpeg2000Reader.h"
-#include "../Framework/Messaging/PluginOrthancConnection.h"
-#include "../Framework/Orthanc/Core/Images/PngWriter.h"
-#include "../Framework/Orthanc/Core/MultiThreading/Semaphore.h"
-#include "../Framework/Orthanc/Core/OrthancException.h"
-#include "../Framework/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.h"
+
+#include "../Resources/Orthanc/Core/Images/ImageProcessing.h"
+#include "../Resources/Orthanc/Core/Images/PngWriter.h"
+#include "../Resources/Orthanc/Core/MultiThreading/Semaphore.h"
+#include "../Resources/Orthanc/Core/OrthancException.h"
+#include "../Resources/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.h"
+#include "../Resources/Orthanc/Plugins/Samples/Common/OrthancPluginConnection.h"
#include <EmbeddedResources.h>
#include <cassert>
+OrthancPluginContext* context_ = NULL;
+std::auto_ptr<OrthancPlugins::OrthancPluginConnection> orthanc_;
+std::auto_ptr<OrthancWSI::DicomPyramidCache> cache_;
+std::auto_ptr<Orthanc::Semaphore> transcoderSemaphore_;
-namespace OrthancWSI
-{
- // TODO Add LRU recycling policy
- class DicomPyramidCache : public boost::noncopyable
- {
- private:
- boost::mutex mutex_;
- IOrthancConnection& orthanc_;
- std::auto_ptr<DicomPyramid> pyramid_;
-
- DicomPyramid& GetPyramid(const std::string& seriesId)
- {
- // Mutex is assumed to be locked
-
- if (pyramid_.get() == NULL ||
- pyramid_->GetSeriesId() != seriesId)
- {
- pyramid_.reset(new DicomPyramid(orthanc_, seriesId));
- }
-
- if (pyramid_.get() == NULL)
- {
- throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
- }
-
- return *pyramid_;
- }
-
- public:
- DicomPyramidCache(IOrthancConnection& orthanc) :
- orthanc_(orthanc)
- {
- }
-
- void Invalidate(const std::string& seriesId)
- {
- boost::mutex::scoped_lock lock(mutex_);
-
- if (pyramid_.get() != NULL &&
- pyramid_->GetSeriesId() == seriesId)
- {
- pyramid_.reset(NULL);
- }
- }
-
- class Locker : public boost::noncopyable
- {
- private:
- boost::mutex::scoped_lock lock_;
- DicomPyramid& pyramid_;
-
- public:
- Locker(DicomPyramidCache& cache,
- const std::string& seriesId) :
- lock_(cache.mutex_),
- pyramid_(cache.GetPyramid(seriesId))
- {
- }
- DicomPyramid& GetPyramid() const
- {
- return pyramid_;
- }
- };
- };
+static void AnswerSparseTile(OrthancPluginRestOutput* output,
+ unsigned int tileWidth,
+ unsigned int tileHeight)
+{
+ Orthanc::Image tile(Orthanc::PixelFormat_RGB24, tileWidth, tileHeight, false);
+
+ // Black (TODO parameter)
+ uint8_t red = 0;
+ uint8_t green = 0;
+ uint8_t blue = 0;
+ Orthanc::ImageProcessing::Set(tile, red, green, blue, 255);
+
+ // TODO Cache the tile
+ OrthancPluginCompressAndAnswerPngImage(context_, output, OrthancPluginPixelFormat_RGB24,
+ tile.GetWidth(), tile.GetHeight(),
+ tile.GetPitch(), tile.GetBuffer());
}
-OrthancPluginContext* context_ = NULL;
-
-std::auto_ptr<OrthancWSI::PluginOrthancConnection> orthanc_;
-std::auto_ptr<OrthancWSI::DicomPyramidCache> cache_;
-std::auto_ptr<Orthanc::Semaphore> transcoderSemaphore_;
-
-
static bool DisplayPerformanceWarning()
{
(void) DisplayPerformanceWarning; // Disable warning about unused function
@@ -130,23 +82,41 @@ void ServePyramid(OrthancPluginRestOutput* output,
OrthancWSI::DicomPyramidCache::Locker locker(*cache_, seriesId);
+ unsigned int tileWidth = locker.GetPyramid().GetTileWidth();
+ unsigned int tileHeight = locker.GetPyramid().GetTileHeight();
unsigned int totalWidth = locker.GetPyramid().GetLevelWidth(0);
unsigned int totalHeight = locker.GetPyramid().GetLevelHeight(0);
+ Json::Value sizes = Json::arrayValue;
Json::Value resolutions = Json::arrayValue;
+ Json::Value tilesCount = Json::arrayValue;
for (unsigned int i = 0; i < locker.GetPyramid().GetLevelCount(); i++)
{
- resolutions.append(static_cast<float>(totalWidth) /
- static_cast<float>(locker.GetPyramid().GetLevelWidth(i)));
+ unsigned int levelWidth = locker.GetPyramid().GetLevelWidth(i);
+ unsigned int levelHeight = locker.GetPyramid().GetLevelHeight(i);
+
+ resolutions.append(static_cast<float>(totalWidth) / static_cast<float>(levelWidth));
+
+ Json::Value s = Json::arrayValue;
+ s.append(levelWidth);
+ s.append(levelHeight);
+ sizes.append(s);
+
+ s = Json::arrayValue;
+ s.append(OrthancWSI::CeilingDivision(levelWidth, tileWidth));
+ s.append(OrthancWSI::CeilingDivision(levelHeight, tileHeight));
+ tilesCount.append(s);
}
Json::Value result;
result["ID"] = seriesId;
- result["TotalWidth"] = totalWidth;
- result["TotalHeight"] = totalHeight;
- result["TileWidth"] = locker.GetPyramid().GetTileWidth();
- result["TileHeight"] = locker.GetPyramid().GetTileHeight();
result["Resolutions"] = resolutions;
+ result["Sizes"] = sizes;
+ result["TileHeight"] = tileHeight;
+ result["TileWidth"] = tileWidth;
+ result["TilesCount"] = tilesCount;
+ result["TotalHeight"] = totalHeight;
+ result["TotalWidth"] = totalWidth;
std::string s = result.toStyledString();
OrthancPluginAnswerBuffer(context_, output, s.c_str(), s.size(), "application/json");
@@ -182,16 +152,17 @@ void ServeTile(OrthancPluginRestOutput* output,
{
OrthancWSI::DicomPyramidCache::Locker locker(*cache_, seriesId);
- compression = locker.GetPyramid().GetImageCompression();
format = locker.GetPyramid().GetPixelFormat();
tileWidth = locker.GetPyramid().GetTileWidth();
tileHeight = locker.GetPyramid().GetTileHeight();
- if (!locker.GetPyramid().ReadRawTile(tile,
+ if (!locker.GetPyramid().ReadRawTile(tile, compression,
static_cast<unsigned int>(level),
static_cast<unsigned int>(tileX),
static_cast<unsigned int>(tileY)))
{
+ // Handling of missing tile (for sparse tiling): TODO parameter?
+ // AnswerSparseTile(output, tileWidth, tileHeight); return;
throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource);
}
}
@@ -355,8 +326,8 @@ extern "C"
OrthancPluginSetDescription(context, "Provides a Web viewer of whole-slide microscopic images within Orthanc.");
- orthanc_.reset(new OrthancWSI::PluginOrthancConnection(context));
- cache_.reset(new OrthancWSI::DicomPyramidCache(*orthanc_));
+ orthanc_.reset(new OrthancPlugins::OrthancPluginConnection(context));
+ cache_.reset(new OrthancWSI::DicomPyramidCache(*orthanc_, 10 /* Number of pyramids to be cached - TODO parameter */));
OrthancPluginRegisterOnChangeCallback(context_, OnChangeCallback);
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/orthanc-wsi.git
More information about the debian-med-commit
mailing list