changeset 6114:61e298df01be

added the skeleton of a C++ plugin
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 20 May 2025 09:48:38 +0200
parents 4e7f565e2604
children 9d94f6744753
files OrthancServer/Plugins/Samples/CppSkeleton/CMakeLists.txt OrthancServer/Plugins/Samples/CppSkeleton/EmbeddedResources/app.js OrthancServer/Plugins/Samples/CppSkeleton/NOTES.txt OrthancServer/Plugins/Samples/CppSkeleton/Plugin.cpp OrthancServer/Plugins/Samples/CppSkeleton/Resources/SyncOrthancFolder.py
diffstat 5 files changed, 468 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancServer/Plugins/Samples/CppSkeleton/CMakeLists.txt	Tue May 20 09:48:38 2025 +0200
@@ -0,0 +1,200 @@
+# Orthanc - A Lightweight, RESTful DICOM Store
+# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+# Department, University Hospital of Liege, Belgium
+# Copyright (C) 2017-2023 Osimis S.A., Belgium
+# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium
+# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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/>.
+
+
+cmake_minimum_required(VERSION 2.8)
+
+project(OrthancSkeleton)
+
+set(ORTHANC_PLUGIN_VERSION "mainline")
+set(ORTHANC_PLUGIN_NAME "skeleton")
+
+if (ORTHANC_PLUGIN_VERSION STREQUAL "mainline")
+  set(ORTHANC_FRAMEWORK_DEFAULT_VERSION "mainline")
+  set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "hg")
+else()
+  set(ORTHANC_FRAMEWORK_DEFAULT_VERSION "1.12.7")
+  set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "web")
+endif()
+
+
+# Parameters of the build
+set(STATIC_BUILD OFF CACHE BOOL "Static build of the third-party libraries (necessary for Windows)")
+set(STANDALONE_BUILD ON CACHE BOOL "Standalone build (all the resources are embedded, necessary for releases)")
+set(ALLOW_DOWNLOADS OFF CACHE BOOL "Allow CMake to download packages")
+set(ORTHANC_FRAMEWORK_SOURCE "${ORTHANC_FRAMEWORK_DEFAULT_SOURCE}" CACHE STRING "Source of the Orthanc framework (can be \"system\", \"hg\", \"archive\", \"web\" or \"path\")")
+set(ORTHANC_FRAMEWORK_VERSION "${ORTHANC_FRAMEWORK_DEFAULT_VERSION}" CACHE STRING "Version of the Orthanc framework")
+set(ORTHANC_FRAMEWORK_ARCHIVE "" CACHE STRING "Path to the Orthanc archive, if ORTHANC_FRAMEWORK_SOURCE is \"archive\"")
+set(ORTHANC_FRAMEWORK_ROOT "" CACHE STRING "Path to the Orthanc source directory, if ORTHANC_FRAMEWORK_SOURCE is \"path\"")
+
+
+# Advanced parameters to fine-tune linking against system libraries
+set(USE_SYSTEM_ORTHANC_SDK ON CACHE BOOL "Use the system version of the Orthanc plugin SDK")
+set(ORTHANC_FRAMEWORK_STATIC OFF CACHE BOOL "If linking against the Orthanc framework system library, indicates whether this library was statically linked")
+mark_as_advanced(ORTHANC_FRAMEWORK_STATIC)
+
+
+# Download and setup the Orthanc framework
+if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "path")
+  include(${ORTHANC_FRAMEWORK_ROOT}/../Resources/CMake/DownloadOrthancFramework.cmake)
+else()
+  include(${CMAKE_SOURCE_DIR}/Resources/Orthanc/CMake/DownloadOrthancFramework.cmake)
+endif()
+
+
+if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "system")
+  if (ORTHANC_FRAMEWORK_USE_SHARED)
+    include(FindBoost)
+    find_package(Boost COMPONENTS filesystem regex thread)
+
+    if (NOT Boost_FOUND)
+      message(FATAL_ERROR "Unable to locate Boost on this system")
+    endif()
+
+    link_libraries(${Boost_LIBRARIES} jsoncpp)
+  endif()
+
+  link_libraries(${ORTHANC_FRAMEWORK_LIBRARIES})
+else()
+  include(${ORTHANC_FRAMEWORK_ROOT}/../Resources/CMake/OrthancFrameworkParameters.cmake)
+
+  set(ENABLE_LOCALE OFF)         # Disable support for locales (notably in Boost)
+  set(ENABLE_MODULE_JOBS OFF CACHE INTERNAL "")
+  set(ENABLE_MODULE_DICOM ON CACHE INTERNAL "")
+
+  include(${ORTHANC_FRAMEWORK_ROOT}/../Resources/CMake/OrthancFrameworkConfiguration.cmake)
+  include_directories(${ORTHANC_FRAMEWORK_ROOT})
+endif()
+
+
+if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "path")
+  include(${ORTHANC_FRAMEWORK_ROOT}/../../OrthancServer/Plugins/Samples/Common/OrthancPluginsExports.cmake)
+  include_directories(${ORTHANC_FRAMEWORK_ROOT}/../../OrthancServer/Plugins/Samples/Common/)
+
+  set(ORTHANC_PLUGINS_SOURCES
+    ${ORTHANC_FRAMEWORK_ROOT}/../../OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
+    )
+else()
+  include(${CMAKE_SOURCE_DIR}/Resources/Orthanc/Plugins/OrthancPluginsExports.cmake)
+  include_directories(${CMAKE_SOURCE_DIR}/Resources/Orthanc/Plugins/)
+
+  set(ORTHANC_PLUGINS_SOURCES
+    ${CMAKE_SOURCE_DIR}/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp
+    )
+endif()
+
+
+# Check that the Orthanc SDK headers are available
+if (STATIC_BUILD OR NOT USE_SYSTEM_ORTHANC_SDK)
+  if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "path")
+    include_directories(${ORTHANC_FRAMEWORK_ROOT}/../../OrthancServer/Plugins/Include)
+  else()
+    include_directories(${CMAKE_SOURCE_DIR}/Resources/Orthanc/Sdk-1.0.0)
+  endif()
+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()
+
+
+if (STANDALONE_BUILD)
+  add_definitions(
+    -DORTHANC_STANDALONE=1
+    )
+  set(EMBEDDED_RESOURCES
+    PLUGIN_RESOURCES ${CMAKE_SOURCE_DIR}/EmbeddedResources/
+    )
+else()
+  add_definitions(
+    -DORTHANC_STANDALONE=0
+    -DPLUGIN_RESOURCES_PATH="${CMAKE_SOURCE_DIR}/EmbeddedResources/"
+    )
+endif()
+
+
+message("Setting the version of the library to ${ORTHANC_PLUGIN_VERSION}")
+
+add_definitions(
+  -DHAS_ORTHANC_EXCEPTION=1
+  -DORTHANC_PLUGIN_NAME="${ORTHANC_PLUGIN_NAME}"
+  -DORTHANC_PLUGIN_VERSION="${ORTHANC_PLUGIN_VERSION}"
+  )
+
+EmbedResources(
+  ${EMBEDDED_RESOURCES}
+  )
+
+if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR
+    ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR
+    ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
+  link_libraries(rt)
+elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
+  SET(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CXX_STANDARD_LIBRARIES} -lws2_32")
+
+  execute_process(
+    COMMAND
+    ${PYTHON_EXECUTABLE} ${ORTHANC_FRAMEWORK_ROOT}/../Resources/WindowsResources.py
+    ${ORTHANC_PLUGIN_VERSION} "OrthancSkeleton" OrthancSkeleton.dll "Skeleton plugin for Orthanc"
+    ERROR_VARIABLE Failure
+    OUTPUT_FILE ${AUTOGENERATED_DIR}/Version.rc
+    )
+
+  if (Failure)
+    message(FATAL_ERROR "Error while computing the version information: ${Failure}")
+  endif()
+
+  list(APPEND AUTOGENERATED_SOURCES  ${AUTOGENERATED_DIR}/Version.rc)
+endif()
+
+
+add_custom_target(
+  AutogeneratedTarget
+  DEPENDS
+  ${AUTOGENERATED_SOURCES}
+  )
+
+add_library(OrthancSkeleton
+  SHARED
+  ${AUTOGENERATED_SOURCES}
+  ${ORTHANC_CORE_SOURCES}
+  ${ORTHANC_PLUGINS_SOURCES}
+
+  # Your source files
+  ${CMAKE_SOURCE_DIR}/Plugin.cpp
+  )
+
+add_dependencies(OrthancSkeleton AutogeneratedTarget)
+
+
+set_target_properties(OrthancSkeleton PROPERTIES
+  VERSION ${ORTHANC_PLUGIN_VERSION}
+  SOVERSION ${ORTHANC_PLUGIN_VERSION})
+
+install(
+  TARGETS OrthancSkeleton
+  RUNTIME DESTINATION lib    # Destination for Windows
+  LIBRARY DESTINATION share/orthanc/plugins    # Destination for Linux
+  )
+
+if (COMMAND DefineSourceBasenameForTarget)
+  DefineSourceBasenameForTarget(OrthancSkeleton)
+endif()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancServer/Plugins/Samples/CppSkeleton/EmbeddedResources/app.js	Tue May 20 09:48:38 2025 +0200
@@ -0,0 +1,1 @@
+console.log('Hello, world!');
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancServer/Plugins/Samples/CppSkeleton/NOTES.txt	Tue May 20 09:48:38 2025 +0200
@@ -0,0 +1,43 @@
+
+Content
+=======
+
+This folder contains a sample, minimal C++ plugin for Orthanc that
+supports multiple target architectures. This skeleton also illustrates
+how to properly include the Orthanc Framework and how to use embedded
+resources.
+
+
+Build instructions
+==================
+
+To compile for developers:
+
+$ mkdir Build
+$ cd Build
+$ cmake .. \
+        -DORTHANC_FRAMEWORK_ROOT=${PWD}/../../../../../OrthancFramework/Sources \
+        -DORTHANC_FRAMEWORK_SOURCE=path \
+        -DUSE_SYSTEM_ORTHANC_SDK=OFF
+$ make -j4
+
+
+Shipping to users
+=================
+
+If shipping the plugin to users (i.e., non-developers), you would have
+to prepare your project by typing:
+
+$ ./Resources/SyncOrthancFolder.py
+
+The resulting content of the "./Resources/Orthanc/" must be included
+in your project.
+
+Evidently, do not forget to adapt the values in "CMakeLists.txt"
+
+The users would then use the following build instructions:
+
+$ mkdir Build
+$ cd Build
+$ cmake .. -DALLOW_DOWNLOADS=ON -DUSE_SYSTEM_ORTHANC_SDK=OFF
+$ make -j4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancServer/Plugins/Samples/CppSkeleton/Plugin.cpp	Tue May 20 09:48:38 2025 +0200
@@ -0,0 +1,121 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2023 Osimis S.A., Belgium
+ * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium
+ * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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 <Logging.h>
+#include <OrthancPluginCppWrapper.h>
+
+#if ORTHANC_STANDALONE == 1
+#  include <EmbeddedResources.h>
+#else
+#  include <SystemToolbox.h>
+#endif
+
+
+static void GetEmbeddedResource(std::string& target,
+                                const std::string& path)
+{
+#if ORTHANC_STANDALONE == 0
+  Orthanc::SystemToolbox::ReadFile(target, Orthanc::SystemToolbox::InterpretRelativePath(PLUGIN_RESOURCES_PATH, path));
+#else
+  const std::string s = "/" + path;
+  Orthanc::EmbeddedResources::GetDirectoryResource(target, Orthanc::EmbeddedResources::PLUGIN_RESOURCES, s.c_str());
+#endif
+}
+
+
+static bool DisplayPerformanceWarning()
+{
+  (void) DisplayPerformanceWarning;   // Disable warning about unused function
+  LOG(WARNING) << "Performance warning in plugin: "
+               << "Non-release build, runtime debug assertions are turned on";
+  return true;
+}
+
+
+extern "C"
+{
+  ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context)
+  {
+    OrthancPlugins::SetGlobalContext(context, ORTHANC_PLUGIN_NAME);
+
+#if ORTHANC_FRAMEWORK_VERSION_IS_ABOVE(1, 12, 4)
+    Orthanc::Logging::InitializePluginContext(context, ORTHANC_PLUGIN_NAME);
+#elif ORTHANC_FRAMEWORK_VERSION_IS_ABOVE(1, 7, 2)
+    Orthanc::Logging::InitializePluginContext(context);
+#else
+    Orthanc::Logging::Initialize(context);
+#endif
+
+    assert(DisplayPerformanceWarning());
+
+    Orthanc::Logging::EnableInfoLevel(true);
+
+    /* Check the version of the Orthanc core */
+    if (OrthancPluginCheckVersion(context) == 0)
+    {
+      char info[1024];
+      sprintf(info, "Your version of Orthanc (%s) must be above %d.%d.%d to run this plugin",
+              context->orthancVersion,
+              ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER,
+              ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER,
+              ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER);
+      OrthancPluginLogError(context, info);
+      return -1;
+    }
+
+    OrthancPlugins::SetDescription(ORTHANC_PLUGIN_NAME, "Skeleton of a C++ plugin Orthanc.");
+
+    try
+    {
+      std::string s;
+      GetEmbeddedResource(s, "app.js");
+      LOG(WARNING) << s;
+    }
+    catch (Orthanc::OrthancException& e)
+    {
+      LOG(ERROR) << "Exception while initializing the plugin: " << e.What();
+      return -1;
+    }
+
+    return 0;
+  }
+
+
+  ORTHANC_PLUGINS_API void OrthancPluginFinalize()
+  {
+    LOG(WARNING) << "Finalizing the skeleton plugin";
+    Orthanc::Logging::Finalize();
+  }
+
+
+  ORTHANC_PLUGINS_API const char* OrthancPluginGetName()
+  {
+    return ORTHANC_PLUGIN_NAME;
+  }
+
+
+  ORTHANC_PLUGINS_API const char* OrthancPluginGetVersion()
+  {
+    return ORTHANC_PLUGIN_VERSION;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancServer/Plugins/Samples/CppSkeleton/Resources/SyncOrthancFolder.py	Tue May 20 09:48:38 2025 +0200
@@ -0,0 +1,103 @@
+#!/usr/bin/python3
+
+# Orthanc - A Lightweight, RESTful DICOM Store
+# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+# Department, University Hospital of Liege, Belgium
+# Copyright (C) 2017-2023 Osimis S.A., Belgium
+# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium
+# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+#
+# This program is free software: you can redistribute it and/or
+# modify it under the terms of the GNU Affero General Public License
+# as published by the Free Software Foundation, either version 3 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Affero General Public License for more details.
+# 
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+#
+# This maintenance script updates the content of the "Orthanc" folder
+# to match the latest version of the Orthanc source code.
+#
+
+import multiprocessing
+import os
+import stat
+import urllib.request
+
+TARGET = os.path.join(os.path.dirname(__file__), 'Orthanc')
+PLUGIN_SDK_VERSION = '1.0.0'
+REPOSITORY = 'https://orthanc.uclouvain.be/hg/%s/raw-file'
+
+FILES = [
+    ('orthanc', 'OrthancFramework/Resources/CMake/AutoGeneratedCode.cmake', 'CMake'),
+    ('orthanc', 'OrthancFramework/Resources/CMake/Compiler.cmake', 'CMake'),
+    ('orthanc', 'OrthancFramework/Resources/CMake/DownloadOrthancFramework.cmake', 'CMake'),
+    ('orthanc', 'OrthancFramework/Resources/CMake/DownloadPackage.cmake', 'CMake'),
+    ('orthanc', 'OrthancFramework/Resources/EmbedResources.py', 'CMake'),
+
+    ('orthanc', 'OrthancFramework/Resources/Toolchains/LinuxStandardBaseToolchain.cmake', 'Toolchains'),
+    ('orthanc', 'OrthancFramework/Resources/Toolchains/MinGW-W64-Toolchain32.cmake', 'Toolchains'),
+    ('orthanc', 'OrthancFramework/Resources/Toolchains/MinGW-W64-Toolchain64.cmake', 'Toolchains'),
+    ('orthanc', 'OrthancFramework/Resources/Toolchains/MinGWToolchain.cmake', 'Toolchains'),
+
+    ('orthanc', 'OrthancServer/Plugins/Samples/Common/ExportedSymbolsPlugins.list', 'Plugins'),
+    ('orthanc', 'OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp', 'Plugins'),
+    ('orthanc', 'OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.h', 'Plugins'),
+    ('orthanc', 'OrthancServer/Plugins/Samples/Common/OrthancPluginException.h', 'Plugins'),
+    ('orthanc', 'OrthancServer/Plugins/Samples/Common/OrthancPluginsExports.cmake', 'Plugins'),
+    ('orthanc', 'OrthancServer/Plugins/Samples/Common/VersionScriptPlugins.map', 'Plugins'),
+]
+
+SDK = [
+    'orthanc/OrthancCPlugin.h',
+]
+
+
+def Download(x):
+    repository = x[0]
+    branch = x[1]
+    source = x[2]
+    target = os.path.join(TARGET, x[3])
+    print(target)
+
+    try:
+        os.makedirs(os.path.dirname(target))
+    except:
+        pass
+
+    url = '%s/%s/%s' % (REPOSITORY % repository, branch, source)
+
+    with open(target, 'wb') as f:
+        try:
+            f.write(urllib.request.urlopen(url).read())
+        except:
+            print('ERROR: %s' % url)
+            raise
+
+
+commands = []
+
+for f in FILES:
+    commands.append([ f[0],
+                      'default',
+                      f[1],
+                      os.path.join(f[2], os.path.basename(f[1])) ])
+
+for f in SDK:
+    commands.append([
+        'orthanc',
+        'Orthanc-%s' % PLUGIN_SDK_VERSION,
+        'Plugins/Include/%s' % f,
+        'Sdk-%s/%s' % (PLUGIN_SDK_VERSION, f)
+    ])
+
+
+pool = multiprocessing.Pool(10)  # simultaneous downloads
+pool.map(Download, commands)