# HG changeset patch # User Sebastien Jodogne # Date 1448369155 -3600 # Node ID 9a6de24209cf29ad72aff756b02480bca244ff8b # Parent 8e5600e699c0f5fa685c3c8050c84e505c2aa850# Parent 87c069c94ac92c30d24186af62050124cb557d52 integration mainline->worklists diff -r 8e5600e699c0 -r 9a6de24209cf NEWS --- a/NEWS Mon Nov 23 17:15:19 2015 +0100 +++ b/NEWS Tue Nov 24 13:45:55 2015 +0100 @@ -30,14 +30,20 @@ Plugins ------- -* New functions "OrthancPluginDicomInstanceToJson()" and "OrthancPluginDicomBufferToJson()" -* New function "OrthancPluginRegisterErrorCode()" to declare custom error codes -* New function "OrthancPluginRegisterDictionaryTag()" to declare custom DICOM tags -* New function "OrthancPluginRestApiGet2()" to provide HTTP headers when calling Orthanc API -* New "OrthancStarted", "OrthancStopped", "UpdatedAttachment" - and "UpdatedMetadata" events in change callbacks +* New functions: + - "OrthancPluginDicomInstanceToJson()" to convert DICOM to JSON + - "OrthancPluginDicomBufferToJson()" to convert DICOM to JSON + - "OrthancPluginRegisterErrorCode()" to declare custom error codes + - "OrthancPluginRegisterDictionaryTag()" to declare custom DICOM tags + - "OrthancPluginRestApiGet2()" to provide HTTP headers when calling Orthanc API + - "OrthancPluginGetInstanceOrigin()" to know through which mechanism an instance was received +* New events in change callbacks: + - "OrthancStarted" + - "OrthancStopped" + - "UpdatedAttachment" + - "UpdatedMetadata" * "/system" URI gives information about the plugins used for storage area and DB back-end -* Plugin callbacks should now return explicit "OrthancPluginErrorCode" instead of integers +* Plugin callbacks must now return explicit "OrthancPluginErrorCode" (instead of integers) Lua --- diff -r 8e5600e699c0 -r 9a6de24209cf OrthancServer/DicomInstanceToStore.h --- a/OrthancServer/DicomInstanceToStore.h Mon Nov 23 17:15:19 2015 +0100 +++ b/OrthancServer/DicomInstanceToStore.h Tue Nov 24 13:45:55 2015 +0100 @@ -171,6 +171,11 @@ void SetPluginsOrigin(); + RequestOrigin GetRequestOrigin() const + { + return origin_; + } + const char* GetRemoteAet() const; void SetBuffer(const std::string& dicom) diff -r 8e5600e699c0 -r 9a6de24209cf Plugins/Engine/OrthancPlugins.cpp --- a/Plugins/Engine/OrthancPlugins.cpp Mon Nov 23 17:15:19 2015 +0100 +++ b/Plugins/Engine/OrthancPlugins.cpp Tue Nov 24 13:45:55 2015 +0100 @@ -429,6 +429,7 @@ sizeof(int32_t) != sizeof(OrthancPluginDicomToJsonFormat) || sizeof(int32_t) != sizeof(_OrthancPluginDatabaseAnswerType) || sizeof(int32_t) != sizeof(OrthancPluginIdentifierConstraint) || + sizeof(int32_t) != sizeof(OrthancPluginInstanceOrigin) || static_cast(OrthancPluginDicomToJsonFlags_IncludeBinary) != static_cast(DicomToJsonFlags_IncludeBinary) || static_cast(OrthancPluginDicomToJsonFlags_IncludePrivateTags) != static_cast(DicomToJsonFlags_IncludePrivateTags) || static_cast(OrthancPluginDicomToJsonFlags_IncludeUnknownTags) != static_cast(DicomToJsonFlags_IncludeUnknownTags) || @@ -1158,6 +1159,10 @@ return; } + case _OrthancPluginService_GetInstanceOrigin: // New in Orthanc 0.9.5 + *p.resultOrigin = Plugins::Convert(instance.GetRequestOrigin()); + return; + default: throw OrthancException(ErrorCode_InternalError); } @@ -1597,6 +1602,7 @@ case _OrthancPluginService_GetInstanceSimplifiedJson: case _OrthancPluginService_HasInstanceMetadata: case _OrthancPluginService_GetInstanceMetadata: + case _OrthancPluginService_GetInstanceOrigin: AccessDicomInstance(service, parameters); return true; diff -r 8e5600e699c0 -r 9a6de24209cf Plugins/Engine/PluginsEnumerations.cpp --- a/Plugins/Engine/PluginsEnumerations.cpp Mon Nov 23 17:15:19 2015 +0100 +++ b/Plugins/Engine/PluginsEnumerations.cpp Tue Nov 24 13:45:55 2015 +0100 @@ -279,6 +279,31 @@ } + OrthancPluginInstanceOrigin Convert(RequestOrigin origin) + { + switch (origin) + { + case RequestOrigin_DicomProtocol: + return OrthancPluginInstanceOrigin_DicomProtocol; + + case RequestOrigin_Http: + return OrthancPluginInstanceOrigin_RestApi; + + case RequestOrigin_Lua: + return OrthancPluginInstanceOrigin_Lua; + + case RequestOrigin_Plugins: + return OrthancPluginInstanceOrigin_Plugin; + + case RequestOrigin_Unknown: + return OrthancPluginInstanceOrigin_Unknown; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + + #if !defined(ORTHANC_ENABLE_DCMTK) || ORTHANC_ENABLE_DCMTK != 0 DcmEVR Convert(OrthancPluginValueRepresentation vr) { diff -r 8e5600e699c0 -r 9a6de24209cf Plugins/Engine/PluginsEnumerations.h --- a/Plugins/Engine/PluginsEnumerations.h Mon Nov 23 17:15:19 2015 +0100 +++ b/Plugins/Engine/PluginsEnumerations.h Tue Nov 24 13:45:55 2015 +0100 @@ -65,6 +65,8 @@ IdentifierConstraintType Convert(OrthancPluginIdentifierConstraint constraint); + OrthancPluginInstanceOrigin Convert(RequestOrigin origin); + #if !defined(ORTHANC_ENABLE_DCMTK) || ORTHANC_ENABLE_DCMTK != 0 DcmEVR Convert(OrthancPluginValueRepresentation vr); #endif diff -r 8e5600e699c0 -r 9a6de24209cf Plugins/Include/orthanc/OrthancCPlugin.h --- a/Plugins/Include/orthanc/OrthancCPlugin.h Mon Nov 23 17:15:19 2015 +0100 +++ b/Plugins/Include/orthanc/OrthancCPlugin.h Tue Nov 24 13:45:55 2015 +0100 @@ -445,6 +445,7 @@ _OrthancPluginService_GetInstanceSimplifiedJson = 4004, _OrthancPluginService_HasInstanceMetadata = 4005, _OrthancPluginService_GetInstanceMetadata = 4006, + _OrthancPluginService_GetInstanceOrigin = 4007, /* Services for plugins implementing a database back-end */ _OrthancPluginService_RegisterDatabaseBackend = 5000, @@ -701,15 +702,29 @@ **/ typedef enum { - OrthancPluginIdentifierConstraint_Equal, /*!< Equal */ - OrthancPluginIdentifierConstraint_SmallerOrEqual, /*!< Less or equal */ - OrthancPluginIdentifierConstraint_GreaterOrEqual, /*!< More or equal */ - OrthancPluginIdentifierConstraint_Wildcard, /*!< Case-sensitive wildcard matching (with * and ?) */ + OrthancPluginIdentifierConstraint_Equal = 1, /*!< Equal */ + OrthancPluginIdentifierConstraint_SmallerOrEqual = 2, /*!< Less or equal */ + OrthancPluginIdentifierConstraint_GreaterOrEqual = 3, /*!< More or equal */ + OrthancPluginIdentifierConstraint_Wildcard = 4, /*!< Case-sensitive wildcard matching (with * and ?) */ _OrthancPluginIdentifierConstraint_INTERNAL = 0x7fffffff } OrthancPluginIdentifierConstraint; + /** + * The origin of a DICOM instance that has been received by Orthanc. + **/ + typedef enum + { + OrthancPluginInstanceOrigin_Unknown = 1, /*!< Unknown origin */ + OrthancPluginInstanceOrigin_DicomProtocol = 2, /*!< Instance received through DICOM protocol */ + OrthancPluginInstanceOrigin_RestApi = 3, /*!< Instance received through REST API of Orthanc */ + OrthancPluginInstanceOrigin_Plugin = 4, /*!< Instance added to Orthanc by a plugin */ + OrthancPluginInstanceOrigin_Lua = 5, /*!< Instance added to Orthanc by a Lua script */ + + _OrthancPluginInstanceOrigin_INTERNAL = 0x7fffffff + } OrthancPluginInstanceOrigin; + /** * @brief A memory buffer allocated by the core system of Orthanc. @@ -962,7 +977,8 @@ sizeof(int32_t) != sizeof(OrthancPluginValueRepresentation) || sizeof(int32_t) != sizeof(OrthancPluginDicomToJsonFormat) || sizeof(int32_t) != sizeof(OrthancPluginDicomToJsonFlags) || - sizeof(int32_t) != sizeof(OrthancPluginIdentifierConstraint)) + sizeof(int32_t) != sizeof(OrthancPluginIdentifierConstraint) || + sizeof(int32_t) != sizeof(OrthancPluginInstanceOrigin)) { /* Mismatch in the size of the enumerations */ return 0; @@ -1910,11 +1926,12 @@ typedef struct { - char** resultStringToFree; - const char** resultString; - int64_t* resultInt64; - const char* key; - OrthancPluginDicomInstance* instance; + char** resultStringToFree; + const char** resultString; + int64_t* resultInt64; + const char* key; + OrthancPluginDicomInstance* instance; + OrthancPluginInstanceOrigin* resultOrigin; /* New in Orthanc 0.9.5 SDK */ } _OrthancPluginAccessDicomInstance; @@ -4249,6 +4266,39 @@ } + /** + * @brief Get the origin of a DICOM file. + * + * This function returns the origin of a DICOM instance that has been received by Orthanc. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param instance The instance of interest. + * @return The origin of the instance. + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginInstanceOrigin OrthancPluginGetInstanceOrigin( + OrthancPluginContext* context, + OrthancPluginDicomInstance* instance) + { + OrthancPluginInstanceOrigin origin; + + _OrthancPluginAccessDicomInstance params; + memset(¶ms, 0, sizeof(params)); + params.resultOrigin = &origin; + params.instance = instance; + + if (context->InvokeService(context, _OrthancPluginService_GetInstanceOrigin, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return OrthancPluginInstanceOrigin_Unknown; + } + else + { + return origin; + } + } + + #ifdef __cplusplus } #endif diff -r 8e5600e699c0 -r 9a6de24209cf Plugins/Samples/AutomatedJpeg2kCompression/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Samples/AutomatedJpeg2kCompression/CMakeLists.txt Tue Nov 24 13:45:55 2015 +0100 @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 2.8) + +project(Basic) + +set(SAMPLES_ROOT ${CMAKE_SOURCE_DIR}/..) +include(${SAMPLES_ROOT}/Common/OrthancPlugins.cmake) + +add_library(AutomatedJpeg2kCompression SHARED Plugin.cpp) diff -r 8e5600e699c0 -r 9a6de24209cf Plugins/Samples/AutomatedJpeg2kCompression/Plugin.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Samples/AutomatedJpeg2kCompression/Plugin.cpp Tue Nov 24 13:45:55 2015 +0100 @@ -0,0 +1,162 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#include + +#include + +static OrthancPluginContext* context_ = NULL; + + +static bool ReadFile(std::string& result, + const std::string& path) +{ + OrthancPluginMemoryBuffer tmp; + if (OrthancPluginReadFile(context_, &tmp, path.c_str()) == OrthancPluginErrorCode_Success) + { + result.assign(reinterpret_cast(tmp.data), tmp.size); + OrthancPluginFreeMemoryBuffer(context_, &tmp); + return true; + } + else + { + return false; + } +} + + +OrthancPluginErrorCode OnStoredCallback(OrthancPluginDicomInstance* instance, + const char* instanceId) +{ + char buffer[1024]; + sprintf(buffer, "Just received a DICOM instance of size %d and ID %s from origin %d (AET %s)", + (int) OrthancPluginGetInstanceSize(context_, instance), instanceId, + OrthancPluginGetInstanceOrigin(context_, instance), + OrthancPluginGetInstanceRemoteAet(context_, instance)); + OrthancPluginLogInfo(context_, buffer); + + if (OrthancPluginGetInstanceOrigin(context_, instance) == OrthancPluginInstanceOrigin_Plugin) + { + // Do not compress twice the same file + return OrthancPluginErrorCode_Success; + } + + // Write the uncompressed DICOM content to some temporary file + std::string uncompressed = "uncompressed-" + std::string(instanceId) + ".dcm"; + OrthancPluginErrorCode error = OrthancPluginWriteFile(context_, uncompressed.c_str(), + OrthancPluginGetInstanceData(context_, instance), + OrthancPluginGetInstanceSize(context_, instance)); + if (error) + { + return error; + } + + // Remove the original DICOM instance + std::string uri = "/instances/" + std::string(instanceId); + error = OrthancPluginRestApiDelete(context_, uri.c_str()); + if (error) + { + return error; + } + + // Path to the temporary file that will contain the compressed DICOM content + std::string compressed = "compressed-" + std::string(instanceId) + ".dcm"; + + // Compress to JPEG2000 using gdcm + std::string command1 = "gdcmconv --j2k " + uncompressed + " " + compressed; + + // Generate a new SOPInstanceUID for the JPEG2000 file, as gdcmconv + // does not do this by itself + std::string command2 = "dcmodify --no-backup -gin " + compressed; + + // Make the required system calls + system(command1.c_str()); + system(command2.c_str()); + + // Read the result of the JPEG2000 compression + std::string j2k; + bool ok = ReadFile(j2k, compressed); + + // Remove the two temporary files + remove(compressed.c_str()); + remove(uncompressed.c_str()); + + if (!ok) + { + return OrthancPluginErrorCode_Plugin; + } + + // Upload the JPEG2000 file through the REST API + OrthancPluginMemoryBuffer tmp; + if (OrthancPluginRestApiPost(context_, &tmp, "/instances", j2k.c_str(), j2k.size())) + { + ok = false; + } + + if (ok) + { + OrthancPluginFreeMemoryBuffer(context_, &tmp); + } + + return ok ? OrthancPluginErrorCode_Success : OrthancPluginErrorCode_Plugin; +} + + +extern "C" +{ + ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* c) + { + context_ = c; + + /* Check the version of the Orthanc core */ + if (OrthancPluginCheckVersion(c) == 0) + { + char info[1024]; + sprintf(info, "Your version of Orthanc (%s) must be above %d.%d.%d to run this plugin", + context_->orthancVersion, + ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER, + ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER, + ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER); + OrthancPluginLogError(context_, info); + return -1; + } + + OrthancPluginRegisterOnStoredInstanceCallback(context_, OnStoredCallback); + + return 0; + } + + + ORTHANC_PLUGINS_API void OrthancPluginFinalize() + { + } + + + ORTHANC_PLUGINS_API const char* OrthancPluginGetName() + { + return "sample-jpeg2k"; + } + + + ORTHANC_PLUGINS_API const char* OrthancPluginGetVersion() + { + return "0.0"; + } +} diff -r 8e5600e699c0 -r 9a6de24209cf Plugins/Samples/Basic/Plugin.c --- a/Plugins/Samples/Basic/Plugin.c Mon Nov 23 17:15:19 2015 +0100 +++ b/Plugins/Samples/Basic/Plugin.c Tue Nov 24 13:45:55 2015 +0100 @@ -262,8 +262,9 @@ char* json; static int first = 1; - sprintf(buffer, "Just received a DICOM instance of size %d and ID %s from AET %s", + sprintf(buffer, "Just received a DICOM instance of size %d and ID %s from origin %d (AET %s)", (int) OrthancPluginGetInstanceSize(context, instance), instanceId, + OrthancPluginGetInstanceOrigin(context, instance), OrthancPluginGetInstanceRemoteAet(context, instance)); OrthancPluginLogWarning(context, buffer); diff -r 8e5600e699c0 -r 9a6de24209cf Plugins/Samples/ModalityWorklists/Plugin.cpp --- a/Plugins/Samples/ModalityWorklists/Plugin.cpp Mon Nov 23 17:15:19 2015 +0100 +++ b/Plugins/Samples/ModalityWorklists/Plugin.cpp Tue Nov 24 13:45:55 2015 +0100 @@ -25,6 +25,7 @@ #include #include #include +#include static OrthancPluginContext* context_ = NULL; static std::string folder_; @@ -93,7 +94,6 @@ } - static bool GetQueryDicom(Json::Value& value, const OrthancPluginWorklistQuery* query) { @@ -113,6 +113,12 @@ } +static void ToLowerCase(std::string& s) +{ + std::transform(s.begin(), s.end(), s.begin(), tolower); +} + + OrthancPluginErrorCode Callback(OrthancPluginWorklistAnswers* answers, const OrthancPluginWorklistQuery* query, const char* remoteAet, @@ -138,7 +144,9 @@ if (is_regular_file(it->status())) { std::string extension = boost::filesystem::extension(it->path()); - if (!strcasecmp(".wl", extension.c_str())) + ToLowerCase(extension); + + if (extension == ".wl") { OrthancPluginErrorCode error = MatchWorklist(answers, query, it->path().string()); if (error)