├── docker ├── orthanc │ ├── .gitignore │ ├── .dockerignore │ ├── orthanc-defaults.json │ ├── filter-http-tools-reset.lua │ ├── env-var-non-standards.json │ ├── Dockerfile.builder-vcpkg │ ├── test_legacy.py │ ├── docker-entrypoint.sh │ ├── helpers.py │ ├── Dockerfile.runner-base │ ├── generateConfiguration.py │ ├── test-aliveness.py │ ├── generatePluginDoc.py │ ├── test_current.py │ ├── env-var-legacy.json │ ├── Dockerfile.builder-base │ └── plugins-def.json ├── integration-tests │ ├── .gitignore │ ├── .dockerignore │ ├── orthanc-tests │ │ ├── orthanc.json │ │ ├── wait-for-it.sh │ │ └── Dockerfile │ ├── sql-server │ │ ├── entrypoint.sh │ │ ├── Dockerfile │ │ └── create-database.sh │ ├── docker-compose.sqlite.yml │ ├── docker-compose.webdav.yml │ ├── docker-compose.ingest-transcoding.yml │ ├── docker-compose.wsi.yml │ ├── docker-compose.sqlite-compression.yml │ ├── docker-compose.transfers.yml │ ├── docker-compose.sqlite-recycling.yml │ ├── docker-compose.scu-transcoding.yml │ ├── docker-compose.cget.yml │ ├── docker-compose.dicomweb.yml │ ├── docker-compose.worklists.yml │ ├── docker-compose.odbc-sqlite.yml │ ├── orthanc-transcoding-tests │ │ └── Dockerfile │ ├── docker-compose.odbc-postgres.yml │ ├── orthanc-under-tests │ │ ├── odbc.ini │ │ ├── Dockerfile.mssql │ │ ├── Dockerfile │ │ └── orthanc.json │ ├── docker-compose.postgres-recycling.yml │ ├── docker-compose.postgres-read-committed.yml │ ├── docker-compose.postgres-serializable.yml │ ├── docker-compose.postgres-dicomweb.yml │ ├── docker-compose.odbc-mysql.yml │ ├── docker-compose.mysql.yml │ ├── docker-compose.tls-check-client.yml │ ├── docker-compose.odbc-sql-server.yml │ ├── docker-compose.tls-no-check-client.yml │ └── docker-compose.s3.yml └── SBOM.txt ├── .github ├── buildkitd.toml └── workflows │ ├── pre-build.yml │ ├── build-stone-wasm.yml │ ├── build-volview-dist.yml │ ├── build-macos-package.yml │ ├── build-windows-installer.yml │ ├── build-macos-binaries.yml │ ├── build-win-binaries.yml │ ├── run-docker-integ-tests.yml │ ├── build-all-dockers.yml │ └── all-builds.yml ├── WindowsInstaller ├── .gitignore ├── Resources │ ├── tcia.json │ ├── pixels-masker.json │ ├── Orthanc.ico │ ├── Osimis.ico │ ├── OrthancH.png │ ├── OsimisLogo.png │ ├── OsimisWizard.bmp │ ├── OsimisWizard.png │ ├── OrthancWizard.bmp │ ├── OrthancWizard.png │ ├── OrthancWizardLogo.bmp │ ├── OsimisLogoShadow.png │ ├── OsimisWizardLogo.bmp │ ├── delayed-deletion.json │ ├── indexer.json │ ├── advanced-storage.json │ ├── osimis-webviewer.json │ ├── worklists.json │ ├── orthanc-explorer-2.json │ ├── odbc.json │ ├── serve-folders.json │ ├── transfers.json │ ├── CMake │ │ ├── MinGW-W64-Toolchain32.cmake │ │ ├── DownloadPackage.cmake │ │ └── Compiler.cmake │ ├── mysql.json │ ├── dicomweb.json │ ├── webviewer.json │ ├── azure.json │ ├── postgresql.json │ ├── aws-s3.json │ ├── housekeeper.json │ ├── README.txt │ └── stone-webviewer.json ├── AppProcessMessages.iss ├── Dockerfile ├── Configuration │ ├── Toolbox.h │ ├── CMakeLists.txt │ ├── Toolbox.cpp │ └── PatchDefaultConfiguration.cpp ├── ciBuildWindowsInstaller.sh ├── NOTES.txt └── ServiceControl.iss ├── orthancBuildResources ├── startOrthanc.command ├── configMacOS.json └── readmeMacOS.txt ├── .gitignore ├── release-notes-docker-images.txt ├── UCLouvain ├── Toolbox.py └── CreateMacOSPackage.py ├── github-mirrors ├── sync-all.sh └── mirror-helpers.sh ├── release-procedure.txt ├── README-dockerhub.md ├── README.md └── bash-helpers.sh /docker/orthanc/.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | tmp/ -------------------------------------------------------------------------------- /.github/buildkitd.toml: -------------------------------------------------------------------------------- 1 | [worker.oci] 2 | max-parallelism = 4 -------------------------------------------------------------------------------- /WindowsInstaller/.gitignore: -------------------------------------------------------------------------------- 1 | orthanc.json 2 | *.exe 3 | 4 | -------------------------------------------------------------------------------- /WindowsInstaller/Resources/tcia.json: -------------------------------------------------------------------------------- 1 | { 2 | "Tcia" : { 3 | "Enable" : true 4 | } 5 | } -------------------------------------------------------------------------------- /docker/integration-tests/.gitignore: -------------------------------------------------------------------------------- 1 | orthanc-tests-repo 2 | orthanc-tests-repo-full 3 | orthanc-tests-repo-normal -------------------------------------------------------------------------------- /orthancBuildResources/startOrthanc.command: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd "$(dirname "$0")" 3 | ./Orthanc configMacOS.json 4 | -------------------------------------------------------------------------------- /WindowsInstaller/Resources/pixels-masker.json: -------------------------------------------------------------------------------- 1 | { 2 | "PixelsMasker" : { 3 | "Enable": false 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /docker/integration-tests/.dockerignore: -------------------------------------------------------------------------------- 1 | *.yml 2 | run-integration-tests.sh 3 | orthanc-tests-repo-normal/* 4 | orthanc-tests-repo-full/* -------------------------------------------------------------------------------- /docker/integration-tests/orthanc-tests/orthanc.json: -------------------------------------------------------------------------------- 1 | { 2 | "RemoteAccessAllowed": true, 3 | "AuthenticationEnabled": false 4 | } 5 | -------------------------------------------------------------------------------- /WindowsInstaller/Resources/Orthanc.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orthanc-server/orthanc-builder/HEAD/WindowsInstaller/Resources/Orthanc.ico -------------------------------------------------------------------------------- /WindowsInstaller/Resources/Osimis.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orthanc-server/orthanc-builder/HEAD/WindowsInstaller/Resources/Osimis.ico -------------------------------------------------------------------------------- /WindowsInstaller/Resources/OrthancH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orthanc-server/orthanc-builder/HEAD/WindowsInstaller/Resources/OrthancH.png -------------------------------------------------------------------------------- /WindowsInstaller/Resources/OsimisLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orthanc-server/orthanc-builder/HEAD/WindowsInstaller/Resources/OsimisLogo.png -------------------------------------------------------------------------------- /docker/orthanc/.dockerignore: -------------------------------------------------------------------------------- 1 | generatePluginDoc.py 2 | Dockerfile 3 | Dockerfile.runner-base 4 | Dockerfile.builder-base 5 | Dockerfile.builder-vcpkg -------------------------------------------------------------------------------- /WindowsInstaller/Resources/OsimisWizard.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orthanc-server/orthanc-builder/HEAD/WindowsInstaller/Resources/OsimisWizard.bmp -------------------------------------------------------------------------------- /WindowsInstaller/Resources/OsimisWizard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orthanc-server/orthanc-builder/HEAD/WindowsInstaller/Resources/OsimisWizard.png -------------------------------------------------------------------------------- /WindowsInstaller/Resources/OrthancWizard.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orthanc-server/orthanc-builder/HEAD/WindowsInstaller/Resources/OrthancWizard.bmp -------------------------------------------------------------------------------- /WindowsInstaller/Resources/OrthancWizard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orthanc-server/orthanc-builder/HEAD/WindowsInstaller/Resources/OrthancWizard.png -------------------------------------------------------------------------------- /WindowsInstaller/Resources/OrthancWizardLogo.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orthanc-server/orthanc-builder/HEAD/WindowsInstaller/Resources/OrthancWizardLogo.bmp -------------------------------------------------------------------------------- /WindowsInstaller/Resources/OsimisLogoShadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orthanc-server/orthanc-builder/HEAD/WindowsInstaller/Resources/OsimisLogoShadow.png -------------------------------------------------------------------------------- /WindowsInstaller/Resources/OsimisWizardLogo.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orthanc-server/orthanc-builder/HEAD/WindowsInstaller/Resources/OsimisWizardLogo.bmp -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | WindowsInstaller/Configuration/ThirdPartyDownloads/ 3 | *~ 4 | UCLouvain/__pycache__/ 5 | github-mirrors/mirrors/ 6 | github-mirrors/.env/ 7 | -------------------------------------------------------------------------------- /docker/integration-tests/sql-server/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #start SQL Server, start the script to create the DB 2 | /scripts/create-database.sh & 3 | /opt/mssql/bin/sqlservr 4 | -------------------------------------------------------------------------------- /WindowsInstaller/Resources/delayed-deletion.json: -------------------------------------------------------------------------------- 1 | { 2 | "DelayedDeletion" : { 3 | "Enable": false 4 | // "ThrottleDelayMs": 0, 5 | // "Path": "" 6 | } 7 | } -------------------------------------------------------------------------------- /release-notes-docker-images.txt: -------------------------------------------------------------------------------- 1 | Note: the release notes are now in Markdown and have moved here: https://github.com/orthanc-server/orthanc-builder/blob/master/release-notes-docker-images.md 2 | -------------------------------------------------------------------------------- /docker/integration-tests/docker-compose.sqlite.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | orthanc-under-tests: 4 | image: orthanc-under-tests 5 | 6 | orthanc-tests: 7 | image: orthanc-tests 8 | depends_on: 9 | - orthanc-under-tests 10 | 11 | -------------------------------------------------------------------------------- /docker/integration-tests/docker-compose.webdav.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | orthanc-under-tests: 4 | image: orthanc-under-tests 5 | 6 | orthanc-tests-webdav: 7 | image: orthanc-tests-webdav 8 | depends_on: 9 | - orthanc-under-tests 10 | 11 | -------------------------------------------------------------------------------- /WindowsInstaller/Resources/indexer.json: -------------------------------------------------------------------------------- 1 | { 2 | "Indexer" : { 3 | "Enable" : false, 4 | "Folders" : [], // List of folders to synchronize 5 | "Interval" : 10 // Delay between two synchronizations 6 | } 7 | } -------------------------------------------------------------------------------- /docker/integration-tests/sql-server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/mssql/server:2019-latest 2 | 3 | USER root 4 | RUN mkdir /scripts 5 | 6 | COPY create-database.sh /scripts/ 7 | COPY entrypoint.sh /scripts/ 8 | 9 | USER mssql 10 | ENTRYPOINT /bin/bash ./scripts/entrypoint.sh -------------------------------------------------------------------------------- /WindowsInstaller/Resources/advanced-storage.json: -------------------------------------------------------------------------------- 1 | { 2 | "AdvancedStorage" : { 3 | "Enable": false 4 | 5 | // more configurations options available ... check 6 | // https://github.com/orthanc-server/orthanc-advanced-storage/blob/master/Plugin/Configuration.json 7 | } 8 | } -------------------------------------------------------------------------------- /docker/integration-tests/docker-compose.ingest-transcoding.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | orthanc-under-tests: 4 | image: orthanc-transcoding-tests 5 | environment: 6 | # VERBOSE_STARTUP: "true" 7 | # VERBOSE_ENABLED: "true" 8 | GDCM_PLUGIN_ENABLED: "false" 9 | 10 | -------------------------------------------------------------------------------- /WindowsInstaller/Resources/osimis-webviewer.json: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | * WebViewer configuration. Check https://osimis.atlassian.net/wiki/spaces/OKB/pages/10321921/Osimis+Web+Viewer+-+Configuration+file 4 | for a description of all options 5 | **/ 6 | 7 | "WebViewer" : { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /WindowsInstaller/Resources/worklists.json: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | * Configuration of the ModalityWorklists plugin, that can be used 4 | * to serve DICOM modality worklists. 5 | **/ 6 | "Worklists" : { 7 | "Enable": false, 8 | "Database": "/var/lib/orthanc/worklists" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /docker/integration-tests/docker-compose.wsi.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | orthanc-under-tests: 4 | image: orthanc-under-tests 5 | environment: 6 | WSI_PLUGIN_ENABLED: "true" 7 | 8 | orthanc-tests-wsi: 9 | image: orthanc-tests-wsi 10 | depends_on: 11 | - orthanc-under-tests 12 | 13 | -------------------------------------------------------------------------------- /docker/integration-tests/docker-compose.sqlite-compression.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | orthanc-under-tests: 4 | image: orthanc-under-tests 5 | environment: 6 | - ORTHANC__STORAGE_COMPRESSION=true 7 | 8 | orthanc-tests: 9 | image: orthanc-tests 10 | depends_on: 11 | - orthanc-under-tests 12 | 13 | -------------------------------------------------------------------------------- /docker/orthanc/orthanc-defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "StorageDirectory" : "/var/lib/orthanc/db", 3 | 4 | "RemoteAccessAllowed": true, 5 | "AuthenticationEnabled": true, 6 | 7 | "HttpsCACertificates" : "/etc/ssl/certs/ca-certificates.crt", 8 | 9 | "Plugins" : ["/run/orthanc/plugins", "/usr/share/orthanc/plugins"] 10 | } 11 | -------------------------------------------------------------------------------- /WindowsInstaller/Resources/orthanc-explorer-2.json: -------------------------------------------------------------------------------- 1 | { 2 | "OrthancExplorer2" : { 3 | "Enable": true, 4 | "IsDefaultOrthancUI": true 5 | 6 | // more configurations options available ... check 7 | // https://github.com/orthanc-server/orthanc-explorer-2/blob/master/Plugin/DefaultConfiguration.json 8 | } 9 | } -------------------------------------------------------------------------------- /docker/integration-tests/docker-compose.transfers.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | orthanc-under-tests: 4 | image: orthanc-under-tests 5 | environment: 6 | TRANSFERS_PLUGIN_ENABLED: "true" 7 | 8 | orthanc-tests-transfers: 9 | image: orthanc-tests-transfers 10 | depends_on: 11 | - orthanc-under-tests 12 | 13 | -------------------------------------------------------------------------------- /docker/integration-tests/docker-compose.sqlite-recycling.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | orthanc-under-tests: 4 | image: orthanc-under-tests 5 | environment: 6 | ORTHANC__MAXIMUM_PATIENT_COUNT: "4" 7 | 8 | orthanc-tests-recycling: 9 | image: orthanc-tests-recycling 10 | depends_on: 11 | - orthanc-under-tests 12 | 13 | -------------------------------------------------------------------------------- /docker/orthanc/filter-http-tools-reset.lua: -------------------------------------------------------------------------------- 1 | function IncomingHttpRequestFilter(method, uri, ip, username, httpHeaders) 2 | 3 | if method == 'POST' and uri == '/tools/reset' then 4 | -- regenerate the /tmp/orthanc.json before reseting orthanc 5 | os.execute("cd /startup && python3 generateConfiguration.py") 6 | end 7 | 8 | return true 9 | end -------------------------------------------------------------------------------- /docker/integration-tests/docker-compose.scu-transcoding.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | orthanc-under-tests: 4 | image: orthanc-transcoding-tests 5 | environment: 6 | # VERBOSE_STARTUP: "true" 7 | # VERBOSE_ENABLED: "true" 8 | GDCM_PLUGIN_ENABLED: "false" 9 | entrypoint: "python3 /orthanc-tests/Tests/CheckScuTranscoding.py /usr/local/bin/Orthanc" 10 | 11 | -------------------------------------------------------------------------------- /docker/integration-tests/docker-compose.cget.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | orthanc-under-tests: 4 | image: orthanc-under-tests 5 | environment: 6 | VERBOSE_STARTUP: "true" 7 | # VERBOSE_ENABLED: "true" 8 | # GDCM_PLUGIN_ENABLED: "false" 9 | 10 | orthanc-tests-cget: 11 | image: orthanc-tests-cget 12 | depends_on: 13 | - orthanc-under-tests 14 | 15 | -------------------------------------------------------------------------------- /docker/integration-tests/docker-compose.dicomweb.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | orthanc-under-tests: 4 | image: orthanc-under-tests 5 | environment: 6 | # VERBOSE_STARTUP: "true" 7 | # VERBOSE_ENABLED: "true" 8 | GDCM_PLUGIN_ENABLED: "false" 9 | 10 | orthanc-tests-dicomweb: 11 | image: orthanc-tests-dicomweb 12 | depends_on: 13 | - orthanc-under-tests 14 | 15 | -------------------------------------------------------------------------------- /docker/integration-tests/docker-compose.worklists.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | orthanc-under-tests: 4 | image: orthanc-under-tests 5 | volumes: 6 | - wl-volume:/worklists:ro 7 | environment: 8 | ORTHANC__WORKLISTS__FILTER_ISSUER_AET: "false" 9 | 10 | orthanc-tests-worklists: 11 | image: orthanc-tests-worklists 12 | depends_on: 13 | - orthanc-under-tests 14 | volumes: 15 | - wl-volume:/tests/orthanc-tests//Database/Worklists/Working 16 | volumes: 17 | wl-volume: 18 | 19 | -------------------------------------------------------------------------------- /docker/integration-tests/docker-compose.odbc-sqlite.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | orthanc-under-tests: 4 | image: orthanc-under-tests 5 | environment: 6 | ORTHANC__ODBC__INDEX_CONNECTION_STRING: "DSN=sqlite3index" 7 | ORTHANC__ODBC__STORAGE_CONNECTION_STRING: "DSN=sqlite3storage" 8 | ORTHANC__ODBC__ENABLE_INDEX: "true" 9 | ORTHANC__ODBC__ENABLE_STORAGE: "true" 10 | # VERBOSE_ENABLED: "true" 11 | VERBOSE_STARTUP: "true" 12 | 13 | orthanc-tests: 14 | image: orthanc-tests 15 | depends_on: 16 | - orthanc-under-tests 17 | -------------------------------------------------------------------------------- /orthancBuildResources/configMacOS.json: -------------------------------------------------------------------------------- 1 | { 2 | // The reference of the Orthanc configuration file is available at: 3 | // https://orthanc.uclouvain.be/hg/orthanc/file/default/OrthancServer/Resources/Configuration.json 4 | "Name" : "MyOrthanc", 5 | 6 | // Load all the Orthanc plugins that are available in this folder: 7 | "Plugins" : [ "." ], 8 | 9 | // Orthanc Explorer 2 configuration. Reference is available at: 10 | // https://github.com/orthanc-server/orthanc-explorer-2/blob/master/Plugin/DefaultConfiguration.json 11 | "OrthancExplorer2" : { 12 | "Enable": true, 13 | "IsDefaultOrthancUI": false 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /docker/integration-tests/orthanc-transcoding-tests/Dockerfile: -------------------------------------------------------------------------------- 1 | ###################################### 2 | ARG IMAGE_UNDER_TEST=orthancteam/orthanc:latest 3 | FROM $IMAGE_UNDER_TEST 4 | 5 | RUN apt-get update 6 | RUN DEBIAN_FRONTEND=noninteractive apt-get --assume-yes install dcmtk mercurial 7 | RUN pip install httplib2 --break-system-package 8 | RUN pip install pillow --break-system-package 9 | 10 | WORKDIR / 11 | 12 | ARG ORTHANC_TESTS_REVISION=default 13 | RUN hg clone https://orthanc.uclouvain.be/hg/orthanc-tests/ -r $ORTHANC_TESTS_REVISION 14 | 15 | ENTRYPOINT python3 /orthanc-tests/Tests/CheckIngestTranscoding.py /usr/local/bin/Orthanc 16 | -------------------------------------------------------------------------------- /docker/integration-tests/sql-server/create-database.sh: -------------------------------------------------------------------------------- 1 | #run the setup script to create the DB and the schema in the DB 2 | #do this in a loop because the timing for when the SQL instance is ready is indeterminate 3 | echo "----------------- creating database ---------------------------------" 4 | 5 | for i in {1..50}; 6 | do 7 | /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P MyStrOngPa55word! -No -Q 'CREATE DATABASE orthanctest' 8 | if [ $? -eq 0 ] 9 | then 10 | echo "----------------- database created" 11 | break 12 | else 13 | echo "----------------- not ready yet..." 14 | sleep 1 15 | fi 16 | done -------------------------------------------------------------------------------- /WindowsInstaller/Resources/odbc.json: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | * Configuration to use ODBC instead of the default SQLite 4 | * back-end of Orthanc. 5 | **/ 6 | "Odbc" : { 7 | // Enable the use of ODBC to store the Orthanc index? 8 | "EnableIndex" : false, 9 | 10 | // Enable the use of ODBC to store the DICOM files? 11 | "EnableStorage" : false, 12 | 13 | // Connection string to the index database 14 | "IndexConnectionString" : "DSN=index", 15 | 16 | // Connection string to the storage area database 17 | "StorageConnectionString" : "DSN=storage" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /WindowsInstaller/Resources/serve-folders.json: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | * Configuration of the ServeFolders plugin, that can be used to 4 | * serve additional folders through the embedded Web server of 5 | * Orthanc. This is especially useful to avoid problems related to 6 | * the same-origin policy when developing Web applications in 7 | * JavaScript on the top of the REST API of Orthanc. 8 | * 9 | * The commented example would serve the documentation of the plugin 10 | * SDK at the URL http://localhost:8042/doc/index.html 11 | **/ 12 | "ServeFolders" : { 13 | // "/doc" : "/usr/share/doc/orthanc/OrthancPlugin" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /WindowsInstaller/Resources/transfers.json: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | * The following options control the configuration of the 4 | * transfers accelerator plugin for Orthanc. 5 | **/ 6 | 7 | "Transfers" : { 8 | "Threads" : 4, // Number of worker threads for one transfer 9 | "BucketSize" : 4096, // Optimal size for a bucket (in KB) 10 | "CacheSize" : 128, // Size of the memory cache to process DICOM files (in MB) 11 | "MaxPushTransactions" : 4, // Maximum number of simultaneous receptions in push mode 12 | "MaxHttpRetries" : 0 // Maximum number of HTTP retries for one bucket 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /docker/orthanc/env-var-non-standards.json: -------------------------------------------------------------------------------- 1 | { 2 | "ORTHANC__CASE_SENSITIVE_PN": "CaseSensitivePN", 3 | "ORTHANC__HTTPS_CA_CERTIFICATES": "HttpsCACertificates", 4 | "ORTHANC__STORE_MD5_FOR_ATTACHMENTS": "StoreMD5ForAttachments", 5 | 6 | "ORTHANC__ORTHANC_EXPLORER_2__IS_DEFAULT_ORTHANC_UI": "OrthancExplorer2.IsDefaultOrthancUI", 7 | "ORTHANC__ORTHANC_EXPLORER_2__ENABLE_LINK_TO_LEGACY_UI": "OrthancExplorer2.EnableLinkToLegacyUi", 8 | "OE2_ENABLED": "OrthancExplorer2.IsDefaultOrthancUI", 9 | 10 | "ORTHANC__POSTGRESQL": "PostgreSQL", 11 | 12 | "ORTHANC__MYSQL": "MySQL", 13 | "ORTHANC__MYSQL__SSL_CA_CERTIFICATES": "MySQL.SslCACertificates", 14 | 15 | "ORTHANC__OHIF": "OHIF" 16 | } 17 | -------------------------------------------------------------------------------- /docker/integration-tests/docker-compose.odbc-postgres.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | orthanc-under-tests: 4 | image: orthanc-under-tests 5 | depends_on: 6 | - odbc-pg-server 7 | environment: 8 | ORTHANC__ODBC__INDEX_CONNECTION_STRING: "DSN=postgres" 9 | ORTHANC__ODBC__STORAGE_CONNECTION_STRING: "DSN=postgres" 10 | ORTHANC__ODBC__ENABLE_INDEX: "true" 11 | ORTHANC__ODBC__ENABLE_STORAGE: "true" 12 | VERBOSE_ENABLED: "false" 13 | VERBOSE_STARTUP: "true" 14 | 15 | orthanc-tests: 16 | image: orthanc-tests 17 | depends_on: 18 | - orthanc-under-tests 19 | 20 | odbc-pg-server: 21 | image: postgres 22 | environment: 23 | POSTGRES_PASSWORD: "postgres" 24 | -------------------------------------------------------------------------------- /orthancBuildResources/readmeMacOS.txt: -------------------------------------------------------------------------------- 1 | This package contains Orthanc and its main plugins. 2 | 3 | QuickStart: 4 | ---------- 5 | 6 | Unzip this archive (do not run Orthanc from the zip archive). 7 | Double-click startOrthanc.command to launch a pre-configured Orthanc instance. 8 | Open a browser at http://localhost:8042 to reach the Orthanc Explorer. 9 | 10 | Open the upload page, you may drop a DICOM file. 11 | Once the DICOM file is uploaded, go back to the patients page and browse the study. 12 | Click on 'Osimis WebViewer' to visualize the study in the web browser. 13 | 14 | Going further: 15 | ------------- 16 | Read the Orthanc book to learn more about Orthanc configuration and advanced usage (https://book.orthanc-server.com) 17 | 18 | 19 | -------------------------------------------------------------------------------- /WindowsInstaller/Resources/CMake/MinGW-W64-Toolchain32.cmake: -------------------------------------------------------------------------------- 1 | # the name of the target operating system 2 | set(CMAKE_SYSTEM_NAME Windows) 3 | 4 | # which compilers to use for C and C++ 5 | set(CMAKE_C_COMPILER i686-w64-mingw32-gcc) 6 | set(CMAKE_CXX_COMPILER i686-w64-mingw32-g++) 7 | set(CMAKE_RC_COMPILER i686-w64-mingw32-windres) 8 | 9 | # here is the target environment located 10 | set(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32) 11 | 12 | # adjust the default behaviour of the FIND_XXX() commands: 13 | # search headers and libraries in the target environment, search 14 | # programs in the host environment 15 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 16 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 17 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 18 | -------------------------------------------------------------------------------- /docker/integration-tests/orthanc-under-tests/odbc.ini: -------------------------------------------------------------------------------- 1 | [sqlite3index] 2 | Driver=SQLite3 3 | Database=/tmp/test-odbc-index.sqlite 4 | 5 | [sqlite3storage] 6 | Driver=SQLite3 7 | Database=/tmp/test-odbc-storage.sqlite 8 | 9 | [postgres] 10 | Driver = PostgreSQL Unicode 11 | Servername = odbc-pg-server 12 | Database = postgres 13 | UserName = postgres 14 | Password = postgres 15 | Port = 5432 16 | 17 | [mysql8] 18 | Driver = MySQL ODBC 8.0 Unicode Driver 19 | Servername = odbc-mysql-server 20 | Database = orthanc 21 | UID = test-user 22 | PWD = foo 23 | Port = 3306 24 | 25 | [mssql18] 26 | Driver = ODBC Driver 18 for SQL Server 27 | Server = tcp:sql-server,1433 28 | Database = orthanctest 29 | -------------------------------------------------------------------------------- /docker/integration-tests/docker-compose.postgres-recycling.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | orthanc-under-tests: 4 | image: orthanc-under-tests 5 | depends_on: 6 | - pg 7 | environment: 8 | ORTHANC__MAXIMUM_PATIENT_COUNT: "4" 9 | 10 | ORTHANC__POSTGRESQL__HOST: "pg" 11 | ORTHANC__POSTGRESQL__DATABASE: "postgres" 12 | ORTHANC__POSTGRESQL__USERNAME: "postgres" 13 | ORTHANC__POSTGRESQL__PASSWORD: "postgres" 14 | ORTHANC__POSTGRESQL__ENABLE_INDEX: "true" 15 | ORTHANC__POSTGRESQL__ENABLE_STORAGE: "true" 16 | 17 | orthanc-tests-recycling: 18 | image: orthanc-tests-recycling 19 | depends_on: 20 | - orthanc-under-tests 21 | 22 | pg: 23 | image: postgres:17 24 | environment: 25 | POSTGRES_PASSWORD: "postgres" 26 | -------------------------------------------------------------------------------- /WindowsInstaller/Resources/mysql.json: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | * Configuration to use MySQL or MariaDB instead of the default 4 | * SQLite back-end of Orthanc. You will have to install the 5 | * "orthanc-mysql" package to take advantage of this feature. 6 | **/ 7 | "MySQL" : { 8 | // Enable the use of MySQL to store the Orthanc index? 9 | "EnableIndex" : false, 10 | 11 | // Enable the use of MySQL to store the DICOM files? 12 | "EnableStorage" : false, 13 | 14 | // Parameters of the MySLQ database 15 | "Host" : "localhost", 16 | "Port" : 3306, 17 | "Database" : "orthanc_db", 18 | "Username" : "orthanc_user", 19 | "Password" : "my_password", 20 | 21 | // Optional: Disable the locking of the MySQL database 22 | "Lock" : false 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /WindowsInstaller/Resources/dicomweb.json: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | * The following options control the configuration of the Orthanc 4 | * plugin adding support of WADO and DICOMweb. 5 | **/ 6 | 7 | "DicomWeb" : { 8 | "Enable" : true, // Whether DICOMweb support is enabled 9 | "Root" : "/dicom-web/", // Root URI of the DICOMweb API (for QIDO-RS, STOW-RS and WADO-RS) 10 | "EnableWado" : true, // Whether WADO-URI (aka. WADO) support is enabled 11 | "WadoRoot" : "/wado", // Root URI of the WADO-URI (aka. WADO) API 12 | //"Host" : "localhost:8042", // Hard-codes the name of the host for subsequent WADO-RS requests 13 | "Ssl" : false // Whether HTTPS should be used for subsequent WADO-RS requests 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /WindowsInstaller/Resources/webviewer.json: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | * The following options control the configuration of the Orthanc 4 | * Web Viewer plugin. 5 | **/ 6 | 7 | "WebViewer" : { 8 | /** 9 | * The location of the cache of the Web viewer. By default, the 10 | * cache is located inside the storage directory of Orthanc. 11 | **/ 12 | // "CachePath" : "/tmp/WebViewerCache", 13 | 14 | /** 15 | * The maximum size for the cached images, in megabytes. By 16 | * default, a cache of 100 MB is used. 17 | **/ 18 | // "CacheSize" : 10, 19 | 20 | /** 21 | * The number of threads that are used by the plugin to decode 22 | * the DICOM images. 23 | **/ 24 | // "Threads" : 4 25 | } 26 | } -------------------------------------------------------------------------------- /docker/integration-tests/docker-compose.postgres-read-committed.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | orthanc-under-tests: 4 | image: orthanc-under-tests 5 | depends_on: 6 | - pg 7 | environment: 8 | ORTHANC__POSTGRESQL__HOST: "pg" 9 | ORTHANC__POSTGRESQL__DATABASE: "postgres" 10 | ORTHANC__POSTGRESQL__USERNAME: "postgres" 11 | ORTHANC__POSTGRESQL__PASSWORD: "postgres" 12 | ORTHANC__POSTGRESQL__ENABLE_INDEX: "true" 13 | ORTHANC__POSTGRESQL__ENABLE_STORAGE: "true" 14 | 15 | ORTHANC__POSTGRESQL__TRANSACTION_MODE: "ReadCommitted" 16 | 17 | # VERBOSE_ENABLED: "true" 18 | 19 | orthanc-tests: 20 | image: orthanc-tests 21 | depends_on: 22 | - orthanc-under-tests 23 | 24 | pg: 25 | image: postgres:16 26 | environment: 27 | POSTGRES_PASSWORD: "postgres" 28 | -------------------------------------------------------------------------------- /docker/integration-tests/docker-compose.postgres-serializable.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | orthanc-under-tests: 4 | image: orthanc-under-tests 5 | depends_on: 6 | - pg 7 | environment: 8 | ORTHANC__POSTGRESQL__HOST: "pg" 9 | ORTHANC__POSTGRESQL__DATABASE: "postgres" 10 | ORTHANC__POSTGRESQL__USERNAME: "postgres" 11 | ORTHANC__POSTGRESQL__PASSWORD: "postgres" 12 | ORTHANC__POSTGRESQL__ENABLE_INDEX: "true" 13 | ORTHANC__POSTGRESQL__ENABLE_STORAGE: "true" 14 | 15 | ORTHANC__POSTGRESQL__TRANSACTION_MODE: "Serializable" 16 | 17 | # VERBOSE_ENABLED: "true" 18 | 19 | orthanc-tests: 20 | image: orthanc-tests 21 | depends_on: 22 | - orthanc-under-tests 23 | 24 | pg: 25 | image: postgres:14 26 | environment: 27 | POSTGRES_PASSWORD: "postgres" 28 | -------------------------------------------------------------------------------- /WindowsInstaller/Resources/azure.json: -------------------------------------------------------------------------------- 1 | { 2 | // "AzureBlobStorage" : { 3 | // "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=xxxxxxxxx;AccountKey=yyyyyyyy===;EndpointSuffix=core.windows.net", 4 | // "ContainerName" : "test-orthanc-storage-plugin", 5 | // //"CreateContainerIfNotExists": true, // available from version 1.2.0 6 | // //"RootPath": "", // see below 7 | // //"MigrationFromFileSystemEnabled": false, // see below 8 | // //"StorageStructure": "flat", // see below 9 | // //"EnableLegacyUnknownFiles": true, // optional: see below 10 | // //"StorageEncryption" : {}, // optional: see the section related to encryption 11 | // //"HybridMode": "Disabled" // optional: see the section related to Hybrid storage 12 | // } 13 | } -------------------------------------------------------------------------------- /docker/integration-tests/docker-compose.postgres-dicomweb.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | orthanc-under-tests: 4 | image: orthanc-under-tests 5 | depends_on: 6 | - pg 7 | environment: 8 | ORTHANC__POSTGRESQL__HOST: "pg" 9 | ORTHANC__POSTGRESQL__DATABASE: "postgres" 10 | ORTHANC__POSTGRESQL__USERNAME: "postgres" 11 | ORTHANC__POSTGRESQL__PASSWORD: "postgres" 12 | ORTHANC__POSTGRESQL__ENABLE_INDEX: "true" 13 | ORTHANC__POSTGRESQL__ENABLE_STORAGE: "true" 14 | 15 | ORTHANC__POSTGRESQL__TRANSACTION_MODE: "ReadCommitted" 16 | 17 | # VERBOSE_ENABLED: "true" 18 | VERBOSE_STARTUP: "true" 19 | GDCM_PLUGIN_ENABLED: "false" 20 | 21 | orthanc-tests-dicomweb: 22 | image: orthanc-tests-dicomweb 23 | depends_on: 24 | - orthanc-under-tests 25 | 26 | pg: 27 | image: postgres:16 28 | environment: 29 | POSTGRES_PASSWORD: "postgres" 30 | -------------------------------------------------------------------------------- /docker/integration-tests/orthanc-under-tests/Dockerfile.mssql: -------------------------------------------------------------------------------- 1 | FROM osimis/21.12.0-buster 2 | 3 | RUN apt-get update 4 | RUN apt-get --assume-yes install curl gnupg2 5 | 6 | RUN mkdir /downloads 7 | 8 | RUN curl https://packages.microsoft.com/keys/microsoft.asc > /downloads/microsoft.asc 9 | RUN curl https://packages.microsoft.com/config/debian/10/prod.list > /etc/apt/sources.list.d/mssql-release.list 10 | 11 | RUN apt-key add /downloads/microsoft.asc 12 | RUN apt-get update && \ 13 | ACCEPT_EULA=Y apt-get install -y msodbcsql17 unixodbc-dev && \ 14 | apt-get clean && \ 15 | rm -rf /var/lib/apt/lists/* 16 | 17 | # install gdcm and dcmtk that are used in a Lua scripts 18 | RUN apt-get --assume-yes update 19 | RUN DEBIAN_FRONTEND=noninteractive apt-get --assume-yes install dcmtk libgdcm-tools 20 | RUN DEBIAN_FRONTEND=noninteractive apt-get --assume-yes install odbc-postgresql 21 | 22 | COPY orthanc.json /etc/orthanc/orthanc.json 23 | COPY odbc.ini /etc/ 24 | -------------------------------------------------------------------------------- /WindowsInstaller/AppProcessMessages.iss: -------------------------------------------------------------------------------- 1 | // https://stackoverflow.com/a/44840244/881731 2 | // https://stackoverflow.com/a/32266687/881731 3 | 4 | type 5 | TMsg = record 6 | hwnd: HWND; 7 | message: UINT; 8 | wParam: Longint; 9 | lParam: Longint; 10 | time: DWORD; 11 | pt: TPoint; 12 | end; 13 | 14 | const 15 | PM_REMOVE = 1; 16 | 17 | function PeekMessage(var lpMsg: TMsg; hWnd: HWND; wMsgFilterMin, wMsgFilterMax, wRemoveMsg: UINT): BOOL; 18 | external 'PeekMessageA@user32.dll stdcall'; 19 | 20 | function TranslateMessage(const lpMsg: TMsg): BOOL; 21 | external 'TranslateMessage@user32.dll stdcall'; 22 | 23 | function DispatchMessage(const lpMsg: TMsg): Longint; 24 | external 'DispatchMessageA@user32.dll stdcall'; 25 | 26 | 27 | procedure AppProcessMessages(); 28 | var 29 | Msg: TMsg; 30 | begin 31 | while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do begin 32 | TranslateMessage(Msg); 33 | DispatchMessage(Msg); 34 | end; 35 | end; 36 | -------------------------------------------------------------------------------- /.github/workflows/pre-build.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | outputs: 4 | is_tag: 5 | value: ${{ jobs.pre_build.outputs.is_tag }} 6 | current_branch_tag: 7 | value: ${{ jobs.pre_build.outputs.current_branch_tag }} 8 | 9 | jobs: 10 | 11 | pre_build: 12 | name: pre_build 13 | runs-on: "ubuntu-latest" 14 | outputs: 15 | current_branch_tag: ${{steps.branch_name.outputs.current_branch_tag}} 16 | is_tag: ${{steps.branch_name.outputs.is_tag}} 17 | 18 | steps: 19 | - name: Get branch/tag name 20 | id: branch_name 21 | run: | 22 | echo "current_branch_tag=${GITHUB_REF_NAME}" >> $GITHUB_OUTPUT 23 | [[ "${GITHUB_REF_TYPE}" == "tag" ]] && echo "is_tag=true" >> $GITHUB_OUTPUT || echo "is_tag=false" >> $GITHUB_OUTPUT 24 | 25 | - name: Echo pre_build 26 | run: | 27 | echo ${{ steps.branch_name.outputs.is_tag }} ${{ steps.branch_name.outputs.current_branch_tag }} 28 | echo ${{ github.ref}} 29 | 30 | -------------------------------------------------------------------------------- /docker/integration-tests/docker-compose.odbc-mysql.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | orthanc-under-tests: 4 | image: orthanc-under-tests 5 | depends_on: 6 | - odbc-mysql-server 7 | environment: 8 | ORTHANC__ODBC__INDEX_CONNECTION_STRING: "DSN=mysql8" 9 | ORTHANC__ODBC__STORAGE_CONNECTION_STRING: "DSN=mysql8" 10 | ORTHANC__ODBC__ENABLE_INDEX: "true" 11 | ORTHANC__ODBC__ENABLE_STORAGE: "true" 12 | VERBOSE_ENABLED: "true" 13 | VERBOSE_STARTUP: "true" 14 | 15 | orthanc-tests: 16 | image: orthanc-tests 17 | depends_on: 18 | - orthanc-under-tests 19 | 20 | odbc-mysql-server: 21 | image: mysql:8.0 22 | command: 23 | [ 24 | mysqld, 25 | --default-authentication-plugin=mysql_native_password, 26 | --log-bin-trust-function-creators=1, 27 | ] 28 | environment: 29 | MYSQL_PASSWORD: foo 30 | MYSQL_USER: test-user 31 | MYSQL_DATABASE: orthanc 32 | MYSQL_ROOT_PASSWORD: foo-root 33 | -------------------------------------------------------------------------------- /docker/integration-tests/docker-compose.mysql.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | orthanc-under-tests: 4 | image: orthanc-under-tests 5 | depends_on: 6 | - mysql-server 7 | environment: 8 | ORTHANC__MYSQL__HOST: mysql-server 9 | ORTHANC__MYSQL__USERNAME: test-user 10 | ORTHANC__MYSQL__DATABASE: orthanc 11 | ORTHANC__MYSQL__PASSWORD: foo 12 | ORTHANC__MYSQL__ENABLE_INDEX: "true" 13 | ORTHANC__MYSQL__ENABLE_STORAGE: "true" 14 | VERBOSE_ENABLED: "false" 15 | 16 | orthanc-tests: 17 | image: orthanc-tests 18 | depends_on: 19 | - orthanc-under-tests 20 | 21 | mysql-server: 22 | image: mysql:8.0 23 | command: 24 | [ 25 | mysqld, 26 | --default-authentication-plugin=mysql_native_password, 27 | --log-bin-trust-function-creators=1, 28 | ] 29 | environment: 30 | MYSQL_PASSWORD: foo 31 | MYSQL_USER: test-user 32 | MYSQL_DATABASE: orthanc 33 | MYSQL_ROOT_PASSWORD: foo-root 34 | -------------------------------------------------------------------------------- /WindowsInstaller/Resources/postgresql.json: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | * Configuration to use PostgreSQL instead of the default SQLite 4 | * back-end of Orthanc. You will have to install the 5 | * "orthanc-postgresql" package to take advantage of this feature. 6 | **/ 7 | "PostgreSQL" : { 8 | // Enable the use of PostgreSQL to store the Orthanc index? 9 | "EnableIndex" : false, 10 | 11 | // Enable the use of PostgreSQL to store the DICOM files? 12 | "EnableStorage" : false, 13 | 14 | // Option 1: Specify explicit authentication parameters 15 | "Host" : "localhost", 16 | "Port" : 5432, 17 | "Database" : "orthanc_db", 18 | "Username" : "orthanc_user", 19 | "Password" : "my_password", 20 | 21 | // Option 2: Authenticate using PostgreSQL connection URI 22 | // "ConnectionUri" : "postgresql://orthanc_user:my_password@localhost:5432/orthanc_db", 23 | 24 | // Optional: Disable the locking of the PostgreSQL database 25 | "Lock" : false 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.github/workflows/build-stone-wasm.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | is_tag: 5 | description: 'Is a Git Tag' 6 | type: string 7 | required: true 8 | current_branch_tag: 9 | description: 'Git branch or Tag' 10 | type: string 11 | required: true 12 | stable_unstable: 13 | description: 'stable/unstable (currently not used)' 14 | type: string 15 | required: true 16 | secrets: 17 | aws_access_key_id: 18 | required: true 19 | aws_secret_access_key: 20 | required: true 21 | 22 | jobs: 23 | 24 | build-stone-wasm: 25 | name: build-stone-wasm 26 | runs-on: "ubuntu-latest" 27 | 28 | steps: 29 | 30 | - uses: actions/checkout@v3 31 | 32 | - name: Build Stone WASM 33 | run: ./build-stone-wasm.sh version=${{ inputs.stable_unstable }} workspace="${{github.workspace}}" 34 | env: 35 | AWS_ACCESS_KEY_ID: ${{ secrets.aws_access_key_id }} 36 | AWS_SECRET_ACCESS_KEY: ${{ secrets.aws_secret_access_key }} 37 | -------------------------------------------------------------------------------- /docker/integration-tests/docker-compose.tls-check-client.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | orthanc-under-tests: 4 | image: orthanc-under-tests 5 | volumes: 6 | - tls:/tls 7 | environment: 8 | VERBOSE_STARTUP: "true" 9 | VERBOSE_ENABLED: "true" 10 | ORTHANC__DICOM_TLS_CERTIFICATE: "/tls/dicom-tls-a.crt" 11 | ORTHANC__DICOM_TLS_PRIVATE_KEY: "/tls/dicom-tls-a.key" 12 | ORTHANC__DICOM_TLS_TRUSTED_CERTIFICATES: "/tls/dicom-tls-trusted.crt" 13 | ORTHANC__DICOM_TLS_REMOTE_CERTIFICATE_REQUIRED: "true" 14 | ORTHANC__EXECUTE_LUA_ENABLED: "true" 15 | ORTHANC__AUTHENTICATION_ENABLED: "false" 16 | 17 | orthanc-tests-tls-check-client: 18 | volumes: 19 | - tls:/tls 20 | image: orthanc-tests-tls-check-client 21 | depends_on: 22 | - orthanc-under-tests 23 | 24 | orthanc-tests-tls-check-client-generate-config: 25 | volumes: 26 | - tls:/tls 27 | image: orthanc-tests-tls-check-client-generate-config 28 | depends_on: 29 | - orthanc-under-tests 30 | 31 | volumes: 32 | tls: -------------------------------------------------------------------------------- /.github/workflows/build-volview-dist.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | is_tag: 5 | description: 'Is a Git Tag' 6 | type: string 7 | required: true 8 | current_branch_tag: 9 | description: 'Git branch or Tag' 10 | type: string 11 | required: true 12 | stable_unstable: 13 | description: 'stable/unstable (currently not used)' 14 | type: string 15 | required: true 16 | secrets: 17 | aws_access_key_id: 18 | required: true 19 | aws_secret_access_key: 20 | required: true 21 | 22 | jobs: 23 | 24 | build-volview-dist: 25 | name: build-volview-dist 26 | runs-on: "ubuntu-latest" 27 | 28 | steps: 29 | 30 | - uses: actions/checkout@v3 31 | 32 | - name: Build Volview dist 33 | run: ./build-volview-dist.sh version=${{ inputs.stable_unstable }} workspace="${{github.workspace}}" 34 | env: 35 | AWS_ACCESS_KEY_ID: ${{ secrets.aws_access_key_id }} 36 | AWS_SECRET_ACCESS_KEY: ${{ secrets.aws_secret_access_key }} 37 | -------------------------------------------------------------------------------- /docker/integration-tests/docker-compose.odbc-sql-server.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | orthanc-under-tests: 4 | image: orthanc-under-tests 5 | depends_on: 6 | - orthanc-db 7 | environment: 8 | ORTHANC__ODBC__INDEX_CONNECTION_STRING: "Driver={ODBC Driver 18 for SQL Server};Server=tcp:orthanc-db,1433;Database=orthanctest;Uid=sa;Pwd=MyStrOngPa55word!;Encrypt=yes;TrustServerCertificate=yes;Connection Timeout=30;" 9 | ORTHANC__ODBC__STORAGE_CONNECTION_STRING: "Driver={ODBC Driver 18 for SQL Server};Server=tcp:orthanc-db,1433;Database=orthanctest;Uid=sa;Pwd=MyStrOngPa55word!;Encrypt=yes;TrustServerCertificate=yes;Connection Timeout=30;" 10 | ORTHANC__ODBC__ENABLE_INDEX: "true" 11 | ORTHANC__ODBC__ENABLE_STORAGE: "true" 12 | VERBOSE_STARTUP: "true" 13 | VERBOSE_ENABLED: "false" 14 | 15 | orthanc-tests: 16 | image: orthanc-tests 17 | depends_on: 18 | - orthanc-under-tests 19 | 20 | orthanc-db: 21 | build: sql-server 22 | environment: 23 | ACCEPT_EULA: "Y" 24 | SA_PASSWORD: "MyStrOngPa55word!" 25 | -------------------------------------------------------------------------------- /.github/workflows/build-macos-package.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | is_tag: 5 | description: 'Is a Git Tag' 6 | type: string 7 | required: true 8 | current_branch_tag: 9 | description: 'Git branch or Tag' 10 | type: string 11 | required: true 12 | stable_unstable: 13 | description: 'stable/unstable' 14 | type: string 15 | required: true 16 | secrets: 17 | aws_access_key_id: 18 | required: true 19 | aws_secret_access_key: 20 | required: true 21 | 22 | jobs: 23 | 24 | build-macos-package: 25 | name: build-macos-package 26 | runs-on: "ubuntu-latest" 27 | 28 | steps: 29 | 30 | - uses: actions/checkout@v3 31 | 32 | - name: Build MacOS Package 33 | run: ./build-macos-package.sh is_tag=${{ inputs.is_tag }} stable_unstable=${{ inputs.stable_unstable }} current_branch_tag=${{ inputs.current_branch_tag }} 34 | env: 35 | AWS_ACCESS_KEY_ID: ${{ secrets.aws_access_key_id }} 36 | AWS_SECRET_ACCESS_KEY: ${{ secrets.aws_secret_access_key }} 37 | -------------------------------------------------------------------------------- /.github/workflows/build-windows-installer.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | is_tag: 5 | description: 'Is a Git Tag' 6 | type: string 7 | required: true 8 | current_branch_tag: 9 | description: 'Git branch or Tag' 10 | type: string 11 | required: true 12 | stable_unstable: 13 | description: 'stable/unstable (currently not used)' 14 | type: string 15 | required: true 16 | secrets: 17 | aws_access_key_id: 18 | required: true 19 | aws_secret_access_key: 20 | required: true 21 | 22 | jobs: 23 | 24 | build-windows-installer: 25 | name: build-windows-installer 26 | runs-on: "ubuntu-latest" 27 | 28 | steps: 29 | 30 | - uses: actions/checkout@v3 31 | 32 | - name: Build Windows installer 33 | run: ./ciBuildWindowsInstaller.sh ${{ inputs.is_tag }} ${{ inputs.current_branch_tag }} 34 | working-directory: ./WindowsInstaller 35 | env: 36 | AWS_ACCESS_KEY_ID: ${{ secrets.aws_access_key_id }} 37 | AWS_SECRET_ACCESS_KEY: ${{ secrets.aws_secret_access_key }} 38 | -------------------------------------------------------------------------------- /docker/integration-tests/orthanc-under-tests/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG IMAGE_UNDER_TEST=orthancteam/orthanc:latest 2 | FROM $IMAGE_UNDER_TEST 3 | 4 | # install gdcm and dcmtk that are used in a Lua scripts 5 | RUN apt-get --assume-yes update 6 | RUN DEBIAN_FRONTEND=noninteractive apt-get --assume-yes install dcmtk libgdcm-tools wget 7 | RUN DEBIAN_FRONTEND=noninteractive apt-get --assume-yes install odbc-postgresql unixodbc-dev 8 | RUN DEBIAN_FRONTEND=noninteractive apt-get --assume-yes install libsqliteodbc 9 | 10 | #### note: this is not functional yet to validate mysql with odbc 11 | # RUN DEBIAN_FRONTEND=noninteractive apt-get --assume-yes install apt-utils wget dpkg-dev lsb-release 12 | # WORKDIR /tmp 13 | # RUN wget https://repo.mysql.com/mysql-apt-config_0.8.20-1_all.deb 14 | # RUN DEBIAN_FRONTEND=noninteractive dpkg -i *.deb 15 | # RUN apt-get --assume-yes update 16 | # RUN DEBIAN_FRONTEND=noninteractive apt-get --assume-yes install mysql-community-client-plugins 17 | # RUN DEBIAN_FRONTEND=noninteractive apt-get --assume-yes install mysql-connector-odbc 18 | 19 | COPY orthanc.json /etc/orthanc/orthanc.json 20 | COPY odbc.ini /etc/ 21 | 22 | ENV DICOM_WEB_PLUGIN_ENABLED=true -------------------------------------------------------------------------------- /docker/integration-tests/docker-compose.tls-no-check-client.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | orthanc-under-tests: 4 | image: orthanc-under-tests 5 | volumes: 6 | - tls:/tls 7 | environment: 8 | VERBOSE_STARTUP: "true" 9 | VERBOSE_ENABLED: "true" 10 | ORTHANC__DICOM_TLS_ENABLED: "true" 11 | ORTHANC__DICOM_TLS_CERTIFICATE: "/tls/dicom-tls-a.crt" 12 | ORTHANC__DICOM_TLS_PRIVATE_KEY: "/tls/dicom-tls-a.key" 13 | # although this is not used, in 1.12.4, this is still required for outgoing connections 14 | ORTHANC__DICOM_TLS_TRUSTED_CERTIFICATES: "/tls/dicom-tls-trusted.crt" 15 | ORTHANC__DICOM_TLS_REMOTE_CERTIFICATE_REQUIRED: "false" 16 | ORTHANC__EXECUTE_LUA_ENABLED: "true" 17 | ORTHANC__AUTHENTICATION_ENABLED: "false" 18 | 19 | orthanc-tests-tls-no-check-client: 20 | volumes: 21 | - tls:/tls 22 | image: orthanc-tests-tls-no-check-client 23 | depends_on: 24 | - orthanc-under-tests 25 | 26 | orthanc-tests-tls-no-check-client-generate-config: 27 | volumes: 28 | - tls:/tls 29 | image: orthanc-tests-tls-no-check-client-generate-config 30 | depends_on: 31 | - orthanc-under-tests 32 | 33 | volumes: 34 | tls: -------------------------------------------------------------------------------- /UCLouvain/Toolbox.py: -------------------------------------------------------------------------------- 1 | # Orthanc - A Lightweight, RESTful DICOM Store 2 | # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics 3 | # Department, University Hospital of Liege, Belgium 4 | # Copyright (C) 2017-2023 Osimis S.A., Belgium 5 | # Copyright (C) 2024-2025 Orthanc Team SRL, Belgium 6 | # Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium 7 | # 8 | # This program is free software: you can redistribute it and/or 9 | # modify it under the terms of the GNU Lesser General Public License 10 | # as published by the Free Software Foundation, either version 3 of 11 | # the License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, but 14 | # WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public 19 | # License along with this program. If not, see 20 | # . 21 | 22 | 23 | def GetVersion(repo): 24 | if 'BuildbotVersion' in repo: 25 | return repo['BuildbotVersion'] 26 | else: 27 | return repo['stable'].split('-') [-1] 28 | -------------------------------------------------------------------------------- /github-mirrors/sync-all.sh: -------------------------------------------------------------------------------- 1 | set -ex 2 | 3 | # this scripts synchronizes the mercurial repositories from https://orthanc.uclouvain.be/hg/ 4 | # and the github mirrors on https://github.com/orgs/orthanc-mirrors/ 5 | # usage: 6 | # ./sync-all.sh 7 | 8 | # This script is running every day at 22 on the Github ARM 64 build slave 9 | # under user orthanc-mirrors' cron job. 10 | 11 | source mirror-helpers.sh 12 | 13 | if [ -d ".env" ]; then 14 | source .env/bin/activate 15 | else 16 | initVirtualEnv 17 | fi 18 | 19 | syncAllBranchesFromRepo orthanc 20 | syncAllBranchesFromRepo orthanc-authorization 21 | syncAllBranchesFromRepo orthanc-book 22 | syncAllBranchesFromRepo orthanc-databases 23 | syncAllBranchesFromRepo orthanc-dicomweb 24 | syncAllBranchesFromRepo orthanc-education 25 | syncAllBranchesFromRepo orthanc-gcp 26 | syncAllBranchesFromRepo orthanc-gdcm 27 | syncAllBranchesFromRepo orthanc-indexer 28 | syncAllBranchesFromRepo orthanc-imagej 29 | syncAllBranchesFromRepo orthanc-java 30 | syncAllBranchesFromRepo orthanc-neuro 31 | syncAllBranchesFromRepo orthanc-object-storage 32 | syncAllBranchesFromRepo orthanc-ohif 33 | syncAllBranchesFromRepo orthanc-python 34 | syncAllBranchesFromRepo orthanc-stone 35 | syncAllBranchesFromRepo orthanc-stl 36 | syncAllBranchesFromRepo orthanc-tcia 37 | syncAllBranchesFromRepo orthanc-tests 38 | syncAllBranchesFromRepo orthanc-transfers 39 | syncAllBranchesFromRepo orthanc-volview 40 | syncAllBranchesFromRepo orthanc-webviewer 41 | syncAllBranchesFromRepo orthanc-wsi 42 | 43 | -------------------------------------------------------------------------------- /WindowsInstaller/Resources/aws-s3.json: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | "AwsS3Storage" : { 4 | "BucketName": "test-orthanc-s3-plugin", 5 | "Region" : "eu-central-1", 6 | "AccessKey" : "AKXXX", // optional: if not specified, the plugin will use the default credentials manager (available from version 1.3.0) 7 | "SecretKey" : "RhYYYY", // optional: if not specified, the plugin will use the default credentials manager (available from version 1.3.0) 8 | "Endpoint": "", // optional: custom endpoint 9 | "ConnectionTimeout": 30, // optional: connection timeout in seconds 10 | "RequestTimeout": 1200, // optional: request timeout in seconds (max time to upload/download a file) 11 | "RootPath": "", // optional: see below 12 | "MigrationFromFileSystemEnabled": false, // optional: see below 13 | "StorageStructure": "flat", // optional: see below 14 | "EnableLegacyUnknownFiles": true, // optional: see below 15 | "VirtualAddressing": true, // optional: see the section related to MinIO 16 | "StorageEncryption" : {}, // optional: see the section related to encryption 17 | "HybridMode": "Disabled", // optional: see the section related to Hybrid storage 18 | "UseTransferManager": false, // optional: see below (available from version 2.3.0) 19 | "EnableAwsSdkLogs": false // optional: include AWS SDK logs in Orthanc logs 20 | } 21 | **/ 22 | } 23 | -------------------------------------------------------------------------------- /WindowsInstaller/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | 3 | ENV DEBIAN_FRONTEND noninteractive 4 | 5 | RUN dpkg --add-architecture i386 6 | RUN apt-get update 7 | RUN apt-get install -yq curl unrar unzip build-essential g++-mingw-w64 cmake python3 python3-pip vim mercurial wget software-properties-common apt-transport-https 8 | RUN wget -nc https://dl.winehq.org/wine-builds/winehq.key 9 | RUN apt-key add winehq.key 10 | RUN apt-add-repository https://dl.winehq.org/wine-builds/ubuntu/ 11 | RUN apt-get update 12 | # RUN sed -i "s/main/main contrib non-free/" etc/apt/sources.list 13 | RUN apt-get install -yq wine 14 | 15 | # innosetup 16 | # old url: "https://downloads.sourceforge.net/project/innounp/innounp/innounp%200.45/innounp045.rar?r=&ts=1439566551&use_mirror=skylineservers" 17 | 18 | RUN mkdir innosetup && \ 19 | cd innosetup && \ 20 | curl -fsSL -o innounp045.rar "https://orthanc.uclouvain.be/downloads/third-party-downloads/innounp045.rar" && \ 21 | unrar e innounp045.rar 22 | 23 | # old url: https://files.jrsoftware.org/is/5/isetup-5.5.8-unicode.exe 24 | RUN cd innosetup && \ 25 | curl -fsSL -o is-unicode.exe "https://orthanc.uclouvain.be/downloads/third-party-downloads/isetup-5.5.8-unicode.exe" && \ 26 | wine "./innounp.exe" -e "is-unicode.exe" 27 | 28 | RUN pip3 install requests 29 | 30 | COPY build-matrix.json / 31 | COPY WindowsInstaller/ /tmp/WindowsInstaller 32 | COPY UCLouvain/ /tmp/UCLouvain 33 | 34 | WORKDIR /tmp/WindowsInstaller 35 | 36 | ARG PLATFORM 37 | ARG VERSION 38 | 39 | RUN python3 --version 40 | RUN python3 -u ./CreateInstaller.py --matrix=/build-matrix.json --platform=${PLATFORM} --version=${VERSION} --from-docker 41 | -------------------------------------------------------------------------------- /docker/orthanc/Dockerfile.builder-vcpkg: -------------------------------------------------------------------------------- 1 | ########################## Orthanc builder vcpkg 2 | # image to compile Orthanc and its plugins dynamically 3 | ARG BASE_IMAGE_TAG=current 4 | FROM orthancteam/orthanc-builder-base:${BASE_IMAGE_TAG} AS orthanc-build-vcpkg 5 | 6 | # prerequisites (for VCPKG builds) 7 | RUN export DEBIAN_FRONTEND=noninteractive && \ 8 | apt-get --assume-yes update && \ 9 | apt-get --assume-yes install ninja-build && \ 10 | apt-get clean && \ 11 | rm -rf /var/lib/apt/lists/* 12 | 13 | WORKDIR / 14 | RUN git clone https://github.com/Microsoft/vcpkg.git && \ 15 | cd vcpkg/ && \ 16 | git checkout 2025.03.19 17 | 18 | WORKDIR /vcpkg 19 | # RUN ls -al /vcpkg 20 | RUN ./bootstrap-vcpkg.sh 21 | ENV VCPKG_FORCE_SYSTEM_BINARIES=1 22 | 23 | RUN mkdir ~/.vcpkg/ 24 | 25 | RUN ./vcpkg integrate install 26 | 27 | # patch the triplet to produce only release builds 28 | RUN bash -c '[[ $(uname -m) == "x86_64" ]] && echo "set(VCPKG_BUILD_TYPE release)" >> /vcpkg/triplets/x64-linux.cmake || echo "set(VCPKG_BUILD_TYPE release)" >> /vcpkg/triplets/community/arm64-linux.cmake' 29 | 30 | # object storage prerequisites 31 | RUN ./vcpkg install cryptopp 32 | 33 | 34 | ########################## Orthanc builder vcpkg-google 35 | 36 | FROM orthancteam/orthanc-builder-base:vcpkg-${BASE_IMAGE_TAG} AS orthanc-build-vcpkg-google 37 | 38 | WORKDIR /vcpkg 39 | RUN ./vcpkg install google-cloud-cpp[storage] 40 | 41 | ########################## Orthanc builder vcpkg-azure 42 | 43 | FROM orthancteam/orthanc-builder-base:vcpkg-${BASE_IMAGE_TAG} AS orthanc-build-vcpkg-azure 44 | 45 | WORKDIR /vcpkg 46 | RUN ./vcpkg install azure-core-cpp azure-storage-blobs-cpp 47 | 48 | -------------------------------------------------------------------------------- /WindowsInstaller/Resources/housekeeper.json: -------------------------------------------------------------------------------- 1 | { 2 | "Housekeeper": { 3 | 4 | // Enables/disables the plugin 5 | "Enable": false, 6 | 7 | // the Global Prooperty ID in which the plugin progress 8 | // is stored. Must be > 1024 and must not be used by 9 | // another plugin 10 | "GlobalPropertyId": 1025, 11 | 12 | // Forces execution even if the plugin did not detect 13 | // any changes in configuration 14 | "Force": false, 15 | 16 | // Delay (in seconds) between reconstruction of 2 studies 17 | // This avoids overloading Orthanc with the housekeeping 18 | // process and leaves room for other operations. 19 | "ThrottleDelay": 5, 20 | 21 | // Runs the plugin only at certain period of time. 22 | // If not specified, the plugin runs all the time 23 | // Examples: 24 | // to run between 0AM and 6AM everyday + every night 25 | // from 8PM to 12PM and 24h a day on the weekend: 26 | // "Schedule": { 27 | // "Monday": ["0-6", "20-24"], 28 | // "Tuesday": ["0-6", "20-24"], 29 | // "Wednesday": ["0-6", "20-24"], 30 | // "Thursday": ["0-6", "20-24"], 31 | // "Friday": ["0-6", "20-24"], 32 | // "Saturday": ["0-24"], 33 | // "Sunday": ["0-24"] 34 | // }, 35 | 36 | // configure events that can trigger a housekeeping processing 37 | "Triggers" : { 38 | "StorageCompressionChange": true, 39 | "MainDicomTagsChange": true, 40 | "UnnecessaryDicomAsJsonFiles": true 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /WindowsInstaller/Configuration/Toolbox.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Orthanc - A Lightweight, RESTful DICOM Store 3 | * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics 4 | * Department, University Hospital of Liege, Belgium 5 | * Copyright (C) 2017-2023 Osimis S.A., Belgium 6 | * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium 7 | * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium 8 | * 9 | * This program is free software: you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License as 11 | * published by the Free Software Foundation, either version 3 of the 12 | * License, or (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, but 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program. If not, see . 21 | **/ 22 | 23 | 24 | #pragma once 25 | 26 | #include 27 | #include 28 | 29 | std::wstring GetStringRegKey(const std::wstring& key, 30 | const std::wstring& name, 31 | const std::wstring& defaultValue); 32 | 33 | std::string GetStringRegKeyAnsi(const std::string& key, 34 | const std::string& name, 35 | const std::string& defaultValue); 36 | 37 | DWORD GetDWordRegKey(const std::wstring& key, 38 | const std::wstring& name, 39 | DWORD defaultValue); 40 | -------------------------------------------------------------------------------- /docker/orthanc/test_legacy.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from configurator import OrthancConfigurator 3 | 4 | 5 | class LegacyTest(unittest.TestCase): 6 | 7 | def test_default_config(self): 8 | c = OrthancConfigurator() 9 | c.mergeConfigFromDefaults() 10 | 11 | self.assertTrue(c.configuration["RemoteAccessAllowed"]) 12 | self.assertTrue(c.configuration["AuthenticationEnabled"]) 13 | 14 | 15 | def test_simple_env_vars_to_enable_plugin(self): 16 | c = OrthancConfigurator() 17 | c.mergeConfigFromEnvVar("WL_ENABLED", "true") 18 | 19 | self.assertIn("Worklists", c.getEnabledPlugins()) 20 | 21 | 22 | def test_simple_section_to_enable_plugin(self): 23 | c = OrthancConfigurator() 24 | worklistsConfig = { 25 | "Worklists" : { 26 | "Database" : "tutu" 27 | } 28 | } 29 | c.mergeConfigFromFile(worklistsConfig, "worklist.json") 30 | 31 | self.assertIn("Worklists", c.configuration) 32 | self.assertIn("Worklists", c.getEnabledPlugins()) 33 | 34 | 35 | def test_direct_secret(self): 36 | c = OrthancConfigurator() 37 | c.mergeConfigFromSecret("/run/secrets/PG_PASSWORD", "pg-password") 38 | 39 | self.assertIn("PostgreSQL", c.configuration) 40 | self.assertIn("PostgreSQL", c.getEnabledPlugins()) 41 | self.assertEqual("pg-password", c.configuration["PostgreSQL"]["Password"]) 42 | 43 | def test_indirect_secret(self): 44 | c = OrthancConfigurator() 45 | c.mergeConfigFromEnvVar("PG_PASSWORD_SECRET", "pg-password-file") 46 | c.mergeConfigFromSecret("/run/secrets/pg-password-file", "pg-password") 47 | 48 | self.assertIn("PostgreSQL", c.configuration) 49 | self.assertIn("PostgreSQL", c.getEnabledPlugins()) 50 | self.assertEqual("pg-password", c.configuration["PostgreSQL"]["Password"]) 51 | 52 | if __name__ == '__main__': 53 | unittest.main() -------------------------------------------------------------------------------- /docker/integration-tests/docker-compose.s3.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | orthanc-under-tests: 4 | image: orthanc-under-tests 5 | depends_on: 6 | minio: 7 | condition: service_healthy 8 | createbuckets: 9 | condition: service_healthy 10 | environment: 11 | ORTHANC__AWS_S3_STORAGE__BUCKET_NAME: "my-sample-bucket" 12 | ORTHANC__AWS_S3_STORAGE__REGION: "eu-west-1" 13 | ORTHANC__AWS_S3_STORAGE__ACCESS_KEY: "minio" 14 | ORTHANC__AWS_S3_STORAGE__SECRET_KEY: "miniopwd" 15 | ORTHANC__AWS_S3_STORAGE__ENDPOINT: "http://minio:9000" 16 | ORTHANC__AWS_S3_STORAGE__VIRTUAL_ADDRESSING: "false" 17 | # VERBOSE_ENABLED: "true" 18 | 19 | orthanc-tests: 20 | image: orthanc-tests 21 | depends_on: 22 | orthanc-under-tests: 23 | condition: service_started 24 | 25 | minio: 26 | command: server /data --console-address ":9001" 27 | image: minio/minio:RELEASE.2022-03-26T06-49-28Z 28 | ports: [9000:9000, 9001:9001] 29 | environment: 30 | MINIO_REGION: "eu-west-1" 31 | MINIO_ROOT_USER: "minio" 32 | MINIO_ROOT_PASSWORD: "miniopwd" 33 | healthcheck: 34 | test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] 35 | interval: 2s 36 | timeout: 1s 37 | retries: 3 38 | 39 | createbuckets: 40 | image: minio/mc:RELEASE.2022-03-17T20-25-06Z 41 | depends_on: 42 | minio: 43 | condition: service_healthy 44 | healthcheck: 45 | test: ["CMD-SHELL", "cat", "/tmp/initialized"] 46 | interval: 2s 47 | timeout: 1s 48 | retries: 10 49 | entrypoint: > 50 | /bin/sh -c " 51 | /usr/bin/mc alias set myminio http://minio:9000 minio miniopwd; 52 | /usr/bin/mc mb myminio/my-sample-bucket; 53 | /usr/bin/mc policy set public myminio/my-sample-bucket; 54 | touch /tmp/initialized; 55 | sleep 600; #otherwise the docker-compose exits once this container has completed !!! 56 | " 57 | -------------------------------------------------------------------------------- /github-mirrors/mirror-helpers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # rewrite pushd/popd such that they do not produce any output in bash functions (https://stackoverflow.com/questions/25288194/dont-display-pushd-popd-stack-across-several-bash-scripts-quiet-pushd-popd) 4 | pushd () { 5 | command pushd "$@" > /dev/null 6 | } 7 | 8 | popd () { 9 | command popd "$@" > /dev/null 10 | } 11 | 12 | script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 13 | 14 | initVirtualEnv() { 15 | python -m venv .env 16 | source .env/bin/activate 17 | pip install mercurial hg-git 18 | } 19 | 20 | firstCloneMercurialRepo() { # $1 = repo-name 21 | pushd $script_dir/mirrors/ 22 | hg clone https://orthanc.uclouvain.be/hg/$1 23 | 24 | cat << EOF >> $1/.hg/hgrc 25 | [extensions] 26 | hggit= 27 | hgext.bookmarks = 28 | EOF 29 | 30 | sed -i "/^default =/a\github = git+ssh://git@github.com:orthanc-mirrors/$1.git" $1/.hg/hgrc 31 | cat $1/.hg/hgrc 32 | pushd $script_dir/mirrors/$1 33 | 34 | hg bookmark master 35 | hg push github 36 | 37 | popd 38 | 39 | popd 40 | } 41 | 42 | syncRepoBranch() { # $1 = repo-name, $2 = branch-name 43 | pushd $script_dir/mirrors/$1 44 | 45 | # hg pull -u 46 | hg update -r $2 47 | # hg pull -u 48 | 49 | if [ "$2" == "default" ]; then 50 | hg bookmark master 51 | else 52 | hg bookmark branches/$2 53 | fi 54 | 55 | hg push github || true 56 | 57 | popd 58 | } 59 | 60 | listAllBranches() { # $1 = repo-name 61 | hg branches | awk '{print $1}' 62 | } 63 | 64 | syncAllBranchesFromRepo() { # $1 = repo-name 65 | 66 | if [ ! -d "$script_dir/mirrors/$1" ]; then 67 | firstCloneMercurialRepo $1 68 | fi 69 | 70 | pushd $script_dir/mirrors/$1 71 | 72 | hg pull -u 73 | 74 | # Get all active branch names and iterate through them 75 | hg branches | awk '{print $1}' | while read branch_name; do 76 | syncRepoBranch $1 "$branch_name" 77 | done 78 | 79 | popd 80 | } 81 | -------------------------------------------------------------------------------- /.github/workflows/build-macos-binaries.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | is_tag: 5 | description: 'Is a Git Tag' 6 | type: string 7 | required: true 8 | current_branch_tag: 9 | description: 'Git branch or Tag' 10 | type: string 11 | required: true 12 | stable_unstable: 13 | description: 'stable/unstable' 14 | type: string 15 | required: true 16 | secrets: 17 | aws_access_key_id: 18 | required: true 19 | aws_secret_access_key: 20 | required: true 21 | 22 | jobs: 23 | 24 | get-build-matrix: 25 | name: get-build-matrix 26 | runs-on: "ubuntu-latest" 27 | outputs: 28 | matrix: ${{ steps.set-matrix.outputs.matrix }} 29 | steps: 30 | # Required as the JSON input file needs to be read 31 | - uses: actions/checkout@v3 32 | 33 | - id: set-matrix 34 | uses: JoshuaTheMiller/conditional-build-matrix@main 35 | with: 36 | inputFile: 'build-matrix.json' 37 | filter: 'configs[?buildForMacOS]' 38 | 39 | - name: output 40 | run: | 41 | echo ${{steps.set-matrix.outputs.matrix}} 42 | 43 | build: 44 | name: build 45 | runs-on: "macos-15" 46 | needs: [get-build-matrix] 47 | strategy: 48 | fail-fast: false 49 | matrix: ${{fromJSON(needs.get-build-matrix.outputs.matrix)}} 50 | 51 | steps: 52 | - uses: actions/checkout@v3 53 | 54 | - name: Build if required 55 | id: build-binaries 56 | run: | 57 | pip3 install mercurial --break-system-packages 58 | ./build-macos-branch.sh version=${{ inputs.stable_unstable }} configName="${{matrix.name}}" workspace="${{github.workspace}}" 59 | env: 60 | AWS_ACCESS_KEY_ID: ${{ secrets.aws_access_key_id }} 61 | AWS_SECRET_ACCESS_KEY: ${{ secrets.aws_secret_access_key }} 62 | 63 | # - name: Setup tmate session 64 | # if: ${{ failure() }} 65 | # uses: mxschmitt/action-tmate@v3 66 | # with: 67 | # limit-access-to-actor: true 68 | # timeout-minutes: 20 69 | -------------------------------------------------------------------------------- /.github/workflows/build-win-binaries.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | is_tag: 5 | description: 'Is a Git Tag' 6 | type: string 7 | required: true 8 | current_branch_tag: 9 | description: 'Git branch or Tag' 10 | type: string 11 | required: true 12 | stable_unstable: 13 | description: 'stable/unstable' 14 | type: string 15 | required: true 16 | secrets: 17 | aws_access_key_id: 18 | required: true 19 | aws_secret_access_key: 20 | required: true 21 | 22 | jobs: 23 | 24 | get-build-matrix: 25 | name: get-build-matrix 26 | runs-on: "ubuntu-latest" 27 | outputs: 28 | matrix: ${{ steps.set-matrix.outputs.matrix }} 29 | steps: 30 | # Required as the JSON input file needs to be read 31 | - uses: actions/checkout@v3 32 | 33 | - id: set-matrix 34 | uses: JoshuaTheMiller/conditional-build-matrix@main 35 | with: 36 | inputFile: 'build-matrix.json' 37 | filter: 'configs[?buildForWin]' 38 | 39 | - name: output 40 | run: | 41 | echo ${{steps.set-matrix.outputs.matrix}} 42 | 43 | build: 44 | name: build 45 | runs-on: "windows-2022" 46 | needs: [get-build-matrix] 47 | strategy: 48 | fail-fast: false 49 | matrix: ${{fromJSON(needs.get-build-matrix.outputs.matrix)}} 50 | 51 | steps: 52 | - uses: actions/checkout@v3 53 | 54 | - name: Show python versions 55 | id: show-python-versions 56 | run: | 57 | bash -c "ls -al /c/hostedtoolcache/windows/Python/" 58 | 59 | - name: Build if required 60 | id: build-binaries 61 | run: | 62 | bash ./build-win-branch.sh version=${{ inputs.stable_unstable }} configName="${{matrix.name}}" workspace="${{github.workspace}}" 63 | env: 64 | AWS_ACCESS_KEY_ID: ${{ secrets.aws_access_key_id }} 65 | AWS_SECRET_ACCESS_KEY: ${{ secrets.aws_secret_access_key }} 66 | 67 | # - name: Setup tmate session 68 | # if: ${{ failure() }} 69 | # uses: mxschmitt/action-tmate@v3 70 | # with: 71 | # limit-access-to-actor: true 72 | # timeout-minutes: 20 73 | -------------------------------------------------------------------------------- /docker/orthanc/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -o errexit 3 | 4 | if [[ $# -ne 1 ]]; then 5 | echo "FATAL ERROR: docker-entrypoint.sh expects a single parameter: the path to the configuration files(s)" 6 | exit 2 7 | fi 8 | 9 | 10 | # DCMTK calls gethostid() when generating DICOM UIDs (used, e.g, in modifications/anonymizations). 11 | # When /etc/hostid is missing, the system tries to generate it from the IP of the system. 12 | # On some system, in particular circumstances, we have observed that the system performs a DNS query 13 | # to get the IP of the system. This DNS can timeout (after multiple with retries) and, in particular cases, 14 | # we have observed a delay of 40 seconds to generate a single DICOM UID in Orthanc. 15 | # Therefore, if /etc/hostid is missing, we generate it with a random number. This behaviour can still be deactivated by 16 | # defining GENERATE_HOST_ID_IF_MISSING=false. The host id can also be forced by defining FORCE_HOST_ID 17 | if [[ ! -z $FORCE_HOST_ID ]];then 18 | echo "Forcing hostid in /etc/hostid: $FORCE_HOST_ID" 19 | echo $FORCE_HOST_ID > /etc/hostid 20 | elif [[ ! $GENERATE_HOST_ID_IF_MISSING || $GENERATE_HOST_ID_IF_MISSING == true ]]; then 21 | if [[ ! -f /etc/hostid || $(< /etc/hostid) = 'not-generated' ]]; then 22 | host_id=$(printf '%x' $(shuf -i 268435456-4294967295 -n 1)) 23 | echo "Generating random hostid in /etc/hostid: $host_id" 24 | echo $host_id > /etc/hostid 25 | fi 26 | fi 27 | 28 | # generate the configuration file 29 | cd /startup 30 | python3 generateConfiguration.py 31 | 32 | if [[ $TRACE_ENABLED == true ]]; then 33 | verbosity=--trace 34 | elif [[ $VERBOSE_ENABLED == true ]]; then 35 | verbosity=--verbose 36 | fi 37 | 38 | if [[ ! -z $LOGDIR ]];then 39 | logoption=--logdir=$LOGDIR 40 | elif [[ ! -z $LOGFILE ]];then 41 | logoption=--logfile=$LOGFILE 42 | fi 43 | 44 | jobs="" 45 | if [[ $NO_JOBS == true ]]; then 46 | jobs=--no-jobs 47 | fi 48 | 49 | if [[ ! -z $BEFORE_ORTHANC_STARTUP_SCRIPT ]]; then 50 | echo "running custom startup script" 51 | $BEFORE_ORTHANC_STARTUP_SCRIPT 52 | fi 53 | 54 | if [[ $JAVA_PLUGIN_ENABLED == true ]]; then 55 | export LD_PRELOAD=/usr/lib/jvm/default-java/lib/server/libjvm.so 56 | fi 57 | 58 | argv=(Orthanc $verbosity $logoption $jobs "$@") 59 | echo "Startup command: exec \"${argv[*]}\"" >&2 60 | exec "${argv[@]}" 61 | -------------------------------------------------------------------------------- /release-procedure.txt: -------------------------------------------------------------------------------- 1 | 2 | The docker images and Windows installers are official releases and shall be versioned consistently (they should share the same package numbers and same content). 3 | These packages are numberd by YY.M[.r] where YY is the year, M is the month and r is the release counter for this month (starting at 1). 4 | 5 | 6 | # Upgrading packages 7 | 8 | Each time you want to release a new package (which means you'll upgrade the version of at least one component): 9 | 10 | - search for `CHANGE_VERSION` in the whole repo and look for lines containing the component(s) you're upgrading -> upgrade the versions. 11 | Note: all version numbers shall be in build-matrix.json (except for Windows Installer !) 12 | - search for `CHANGE_VERSION` in the whole repo and look for the package version numbers -> upgrade with YY.M[.r] 13 | - update the WindowsInstaller/Resources/README.txt with the new version numbers 14 | - update the docker/README-dockerhub.txt with the new version numbers (keep the previous version package list in the readme) 15 | - update the release-notes-docker-images.md 16 | - at this stage, you may commit and tag as explained before and let GitHub build the Docker images OR you may build manually with the commands below. 17 | - notify S. Jodogne that a new Windows Installer is available so he can update the download link on the Orthanc page (note, since 22.3.0, the latest 18 | windows installer is always copied under ...latest.exe and there's no need to update the Osimis website anymore) 19 | 20 | All version numbers shall be changed in build-matrix.json (and in release-notes-docker-images.md + README-dockerhub.md) 21 | 22 | List of CHANGE_VERSION_ variables: 23 | - CHANGE_VERSION_ORTHANC 24 | - CHANGE_VERSION_WVB 25 | - CHANGE_VERSION_TRANSFERS 26 | - CHANGE_VERSION_AUTH 27 | - CHANGE_VERSION_MYSQL 28 | - CHANGE_VERSION_ODBC 29 | - CHANGE_VERSION_INDEXER 30 | - CHANGE_VERSION_NEURO 31 | - CHANGE_VERSION_TCIA 32 | - CHANGE_VERSION_STONE_WEB_VIEWER 33 | - CHANGE_VERSION_GDCM 34 | - CHANGE_VERSION_ORTHANC_WEB_VIEWER 35 | - CHANGE_VERSION_DW 36 | - CHANGE_VERSION_PG 37 | - CHANGE_VERSION_WSI 38 | - CHANGE_VERSION_ORTHANC_EXPLORER_2 39 | - CHANGE_ORTHANC_TESTS_VERSION 40 | - CHANGE_VERSION_AZURE_OBJECT_STORAGE 41 | - CHANGE_VERSION_AWS_OBJECT_STORAGE 42 | - CHANGE_VERSION_GOOGLE_OBJECT_STORAGE 43 | - CHANGE_VERSION_VOLVIEW 44 | - CHANGE_VERSION_OHIF 45 | - CHANGE_VERSION_STL 46 | - CHANGE_VERSION_PYTHON 47 | - CHANGE_VERSION_EDUCATION 48 | - CHANGE_VERSION_ORTHANC_WORKLISTS 49 | - CHANGE_VERSION_PIXELS_MASKER 50 | -------------------------------------------------------------------------------- /WindowsInstaller/Configuration/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Orthanc - A Lightweight, RESTful DICOM Store 2 | # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics 3 | # Department, University Hospital of Liege, Belgium 4 | # Copyright (C) 2017-2023 Osimis S.A., Belgium 5 | # Copyright (C) 2024-2025 Orthanc Team SRL, Belgium 6 | # Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium 7 | # 8 | # This program is free software: you can redistribute it and/or 9 | # modify it under the terms of the GNU General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, but 14 | # WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program. If not, see . 20 | 21 | 22 | cmake_minimum_required (VERSION 2.8) 23 | 24 | set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/../Resources/CMake/MinGW-W64-Toolchain32.cmake) 25 | project(WindowsService) 26 | 27 | set(ALLOW_DOWNLOADS ON) 28 | set(STATIC_BUILD ON) 29 | 30 | include(CheckLibraryExists) 31 | include(${CMAKE_SOURCE_DIR}/../Resources/CMake/Compiler.cmake) 32 | include(${CMAKE_SOURCE_DIR}/../Resources/CMake/DownloadPackage.cmake) 33 | include(${CMAKE_SOURCE_DIR}/../Resources/CMake/BoostConfiguration.cmake) 34 | 35 | add_definitions( 36 | -DSERVICE_NAME="Orthanc" 37 | ) 38 | 39 | add_library(Toolbox STATIC 40 | Toolbox.cpp 41 | ${BOOST_SOURCES} 42 | ) 43 | 44 | add_executable(OrthancService 45 | WindowsService.cpp 46 | ) 47 | 48 | add_executable(PatchDefaultConfiguration 49 | PatchDefaultConfiguration.cpp 50 | ) 51 | 52 | target_link_libraries(OrthancService Toolbox) 53 | target_link_libraries(PatchDefaultConfiguration Toolbox) 54 | 55 | get_property(OrthancServiceLocation TARGET OrthancService PROPERTY LOCATION) 56 | get_property(PatchDefaultConfigurationLocation TARGET PatchDefaultConfiguration PROPERTY LOCATION) 57 | 58 | add_custom_command(TARGET OrthancService 59 | POST_BUILD 60 | COMMAND i686-w64-mingw32-strip ${OrthancServiceLocation} 61 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 62 | COMMENT "Stripping the symbols from the Windows service" VERBATIM 63 | ) 64 | 65 | add_custom_command(TARGET PatchDefaultConfiguration 66 | POST_BUILD 67 | COMMAND i686-w64-mingw32-strip ${PatchDefaultConfigurationLocation} 68 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 69 | COMMENT "Stripping the symbols from the configuration generator" VERBATIM 70 | ) 71 | -------------------------------------------------------------------------------- /.github/workflows/run-docker-integ-tests.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | is_tag: 5 | description: 'Is a Git Tag' 6 | type: string 7 | required: true 8 | current_branch_tag: 9 | description: 'Git branch or Tag' 10 | type: string 11 | required: true 12 | runner: 13 | description: 'Runner' 14 | type: string 15 | required: true 16 | runner_type: 17 | description: 'Runner type' 18 | type: string 19 | required: true 20 | platform: 21 | description: 'platform' 22 | type: string 23 | required: true 24 | stable_unstable: 25 | description: 'stable_unstable type' 26 | type: string 27 | required: true 28 | tests_group: 29 | description: 'tests group pg, others, full' 30 | type: string 31 | required: true 32 | image_type: 33 | description: 'image type: full, normal' 34 | type: string 35 | required: true 36 | 37 | jobs: 38 | run-integ-tests: 39 | name: run-integ-tests-${{ inputs.tests_group }}-${{ inputs.stable_unstable}} 40 | runs-on: ${{ inputs.runner }} 41 | steps: 42 | 43 | - name: Install Integration tests prerequisites 44 | # TODO: enable on ARM64 too 45 | if: inputs.runner_type == 'github-hosted' 46 | run: sudo apt-get install -y dcmtk 47 | 48 | - uses: actions/checkout@v3 49 | # TODO: enable on ARM64 too 50 | if: inputs.runner_type == 'github-hosted' 51 | 52 | - name: Pull image for integ tests 53 | # TODO: enable on ARM64 too 54 | if: inputs.runner_type == 'github-hosted' 55 | run: ./local-build.sh version=${{ inputs.stable_unstable }} platform=${{ inputs.platform }} image=full type=ci step=pull-before-test-image currentTag=${{ inputs.current_branch_tag }}-normal-${{ inputs.stable_unstable }} 56 | 57 | - name: Run normal image integration tests 58 | # TODO: enable on ARM64 too 59 | if: inputs.runner_type == 'github-hosted' 60 | run: ./run-integration-tests.sh version=${{ inputs.stable_unstable }} image=${{ inputs.image_type }} imageUnderTest=orthancteam/orthanc-pre-release:${{ inputs.current_branch_tag }}-${{ inputs.image_type }}-${{ inputs.stable_unstable }}-before-tests-amd64 testsGroup=${{ inputs.tests_group }} 61 | working-directory: ${{github.workspace}}/docker/integration-tests 62 | 63 | - name: Skipped for ARM64 64 | # TODO: enable on ARM64 too 65 | if: inputs.runner_type != 'github-hosted' 66 | run: echo "skipped on ARM 64" 67 | 68 | - name: Setup tmate session 69 | if: ${{ failure() }} 70 | uses: mxschmitt/action-tmate@v3 71 | with: 72 | limit-access-to-actor: true 73 | timeout-minutes: 20 74 | -------------------------------------------------------------------------------- /docker/SBOM.txt: -------------------------------------------------------------------------------- 1 | This Software Bill Of Material is manually generated. 2 | It was last generated for orthancteam/orthanc:25.6.4 images and lists only the 3 | primary dependencies of Orthanc; not its plugins. 4 | 5 | 6 | Orthanc third-parties library statically linked: 7 | 8 | DCMTK ; https://github.com/DCMTK/dcmtk ; 3.6.9 9 | Civetweb ; https://github.com/civetweb/civetweb ; 1.14 10 | OpenSSL ; https://github.com/openssl/openssl ; 3.1.4 11 | curl ; https://github.com/curl/curl ; 8.9.0 12 | 13 | Orthanc third-parties library dynamically linked (depending on the base image, currently: ubuntu 24.04): 14 | info extracted from "ldd /usr/local/bin/Orthanc" and "apt list | grep jsoncpp" 15 | 16 | JsonCpp ; https://github.com/open-source-parsers/jsoncpp ; 1.9.5-6build1 17 | SQLite ; https://github.com/sqlite/sqlite ; 3.45.1-1ubuntu2.3 18 | LibJpeg ; https://github.com/winlibs/libjpeg ; 8c-2ubuntu11 19 | Zlib ; https://github.com/madler/zlib ; 1.3.1+dfsg-1 20 | LibPNG ; https://github.com/pnggroup/libpng ; 1.6.43-5build1 21 | Lua ; https://github.com/lua/lua ; 5.4.6-3build2 22 | Pugixml ; https://github.com/zeux/pugixml ; 1.14-0.1build1 23 | Protobuf ; https://github.com/protocolbuffers/protobuf ; 3.21.12-8.2ubuntu0.1 24 | LibUuid ; https://github.com/util-linux/util-linux/tree/master/libuuid ; 2.39.3-9ubuntu6.2 25 | Boost ; https://github.com/boostorg/boost ; 1.83.0-2.1ubuntu3.1 26 | Libgcc & co ; https://github.com/gcc-mirror/gcc/tree/master/libgcc ; 14.2.0-4ubuntu2~24.04cross1 27 | LibIcu ; https://github.com/unicode-org/icu ; 74.2-1ubuntu3.1 28 | bzip2 ; https://gitlab.com/bzip2/bzip2 ; 1.0.8-5.1build0.1 29 | XZ ; https://sourceforge.net/projects/lzmautils/ ; 5.6.1+really5.4.5-1ubuntu0.2 30 | zstd ; https://github.com/facebook/zstd ; 1.5.5+dfsg2-2build1.1 31 | 32 | 33 | -------------------------------------------------------------------------------- /docker/orthanc/helpers.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import glob 4 | import json 5 | import typing 6 | 7 | 8 | class JsonPath: 9 | 10 | def __init__(self, path:str = None): 11 | if path is None or len(path) == 0: 12 | self.tokens = [] 13 | else: 14 | self.tokens = path.split(".") 15 | 16 | def first(self): 17 | if self.length() == 0: 18 | raise ValueError("Empty path") 19 | 20 | return self.tokens[0] 21 | 22 | def nexts(self, fromIndex=1): 23 | if self.length() < fromIndex: 24 | raise ValueError("Path too short") 25 | 26 | return JsonPath(".".join(self.tokens[fromIndex:])) 27 | 28 | def pop(self) -> str: 29 | if self.length() == 0: 30 | raise ValueError("Empty path") 31 | 32 | first = self.tokens[0] 33 | self.tokens = self.tokens[1:] 34 | return first 35 | 36 | def append(self, token: str): 37 | self.tokens.append(token) 38 | 39 | def length(self): 40 | return len(self.tokens) 41 | 42 | def __str__(self): 43 | return ".".join(self.tokens) 44 | 45 | def clone(self): 46 | return JsonPath(".".join(self.tokens)) 47 | 48 | 49 | verboseEnabled = False 50 | 51 | def enableVerboseModeForConfigGeneration(): 52 | global verboseEnabled 53 | verboseEnabled = True 54 | 55 | def logInfo(text: str): 56 | global verboseEnabled 57 | if verboseEnabled: 58 | print(text) 59 | 60 | def logWarning(text: str): 61 | print("WARNING: " + text) 62 | 63 | def logError(text: str): 64 | print("ERROR: " + text) 65 | 66 | 67 | def isEnvVarDefinedEmptyOrTrue(envVar: str) -> bool: 68 | return envVar in os.environ and (os.environ.get(envVar) == "" or os.environ.get(envVar) == "true") 69 | 70 | def isEnvVarTrue(envVar: str) -> bool: 71 | return os.environ.get(envVar, "false") == "true" 72 | 73 | 74 | # transforms QUERY_RETRIEVE_SIZE into QueryRetrieveSize 75 | def envVarToCamelCase(envVarName: str) -> str: 76 | name = "" 77 | for word in envVarName.split("_"): 78 | name = name + word[0] + word.lower()[1:] 79 | return name 80 | 81 | 82 | def removeCppCommentsFromJson(text: str): 83 | def replacer(match): 84 | s = match.group(0) 85 | if s.startswith('/'): 86 | return " " # note: a space and not an empty string 87 | else: 88 | return s 89 | pattern = re.compile( 90 | r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', 91 | re.DOTALL | re.MULTILINE 92 | ) 93 | return re.sub(pattern, replacer, text) 94 | 95 | def insertInDict(jsonPath: JsonPath, value: any) -> dict: 96 | 97 | if jsonPath.length() == 1: 98 | output = {} 99 | output[jsonPath.first()] = value 100 | return output 101 | else: 102 | output = {} 103 | output[jsonPath.first()] = insertInDict(jsonPath.nexts(1), value) 104 | return output 105 | 106 | 107 | -------------------------------------------------------------------------------- /WindowsInstaller/Configuration/Toolbox.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Orthanc - A Lightweight, RESTful DICOM Store 3 | * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics 4 | * Department, University Hospital of Liege, Belgium 5 | * Copyright (C) 2017-2023 Osimis S.A., Belgium 6 | * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium 7 | * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium 8 | * 9 | * This program is free software: you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License as 11 | * published by the Free Software Foundation, either version 3 of the 12 | * License, or (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, but 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program. If not, see . 21 | **/ 22 | 23 | 24 | #include "Toolbox.h" 25 | 26 | std::wstring GetStringRegKey(const std::wstring& key, 27 | const std::wstring& name, 28 | const std::wstring& defaultValue) 29 | { 30 | HKEY hKey; 31 | if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, key.c_str(), 0, KEY_READ, &hKey) != ERROR_SUCCESS) 32 | { 33 | return defaultValue; 34 | } 35 | 36 | WCHAR szBuffer[512]; 37 | DWORD dwBufferSize = sizeof(szBuffer); 38 | if (RegQueryValueExW(hKey, name.c_str(), 0, NULL, (LPBYTE)szBuffer, &dwBufferSize) != ERROR_SUCCESS) 39 | { 40 | RegCloseKey(hKey); 41 | return defaultValue; 42 | } 43 | 44 | RegCloseKey(hKey); 45 | return szBuffer; 46 | } 47 | 48 | 49 | std::string GetStringRegKeyAnsi(const std::string& key, 50 | const std::string& name, 51 | const std::string& defaultValue) 52 | { 53 | HKEY hKey; 54 | if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, key.c_str(), 0, KEY_READ, &hKey) != ERROR_SUCCESS) 55 | { 56 | return defaultValue; 57 | } 58 | 59 | CHAR szBuffer[512]; 60 | DWORD dwBufferSize = sizeof(szBuffer); 61 | if (RegQueryValueExA(hKey, name.c_str(), 0, NULL, (LPBYTE)szBuffer, &dwBufferSize) != ERROR_SUCCESS) 62 | { 63 | RegCloseKey(hKey); 64 | return defaultValue; 65 | } 66 | 67 | RegCloseKey(hKey); 68 | return szBuffer; 69 | } 70 | 71 | 72 | DWORD GetDWordRegKey(const std::wstring& key, 73 | const std::wstring& name, 74 | DWORD defaultValue) 75 | { 76 | HKEY hKey; 77 | if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, key.c_str(), 0, KEY_READ, &hKey) != ERROR_SUCCESS) 78 | { 79 | return defaultValue; 80 | } 81 | 82 | DWORD dwBufferSize(sizeof(DWORD)); 83 | DWORD nResult(0); 84 | if (RegQueryValueExW(hKey, name.c_str(), 0, NULL, 85 | reinterpret_cast(&nResult), &dwBufferSize) != ERROR_SUCCESS) 86 | { 87 | RegCloseKey(hKey); 88 | return defaultValue; 89 | } 90 | 91 | RegCloseKey(hKey); 92 | return nResult; 93 | } 94 | -------------------------------------------------------------------------------- /docker/orthanc/Dockerfile.runner-base: -------------------------------------------------------------------------------- 1 | ########################## orthanc-runner-base 2 | 3 | # base image to build and execute orthanc. 4 | # This image should contain only the packages that are common to both ! 5 | # The purpose of this intermediate image is to benefit from Docker cache. 6 | ARG BASE_UBUNTU_IMAGE=unknown 7 | FROM ubuntu:$BASE_UBUNTU_IMAGE 8 | 9 | # we had some issues with one of the mirror -> force it to the Belgian mirror 10 | # RUN rm /etc/apt/sources.list.d/debian.sources 11 | # RUN echo "deb http://ftp.be.debian.org/debian/ bookworm main" | tee /etc/apt/sources.list.d/belgium.mirror.list 12 | 13 | RUN export DEBIAN_FRONTEND=noninteractive && \ 14 | apt-get --assume-yes update && \ 15 | apt-get --assume-yes install --no-install-recommends python3 && \ 16 | apt-get --assume-yes install --no-install-recommends python3-dev && \ 17 | apt-get --assume-yes install --no-install-recommends python3-pip && \ 18 | apt-get --assume-yes install --no-install-recommends ca-certificates && \ 19 | apt-get --assume-yes install --no-install-recommends tzdata && \ 20 | apt-get --assume-yes install --no-install-recommends locales && \ 21 | apt-get --assume-yes install --no-install-recommends libcurl4 && \ 22 | apt-get --assume-yes install --no-install-recommends libboost-log1.83.0 libboost-filesystem1.83.0 libboost-locale1.83.0 libboost-regex1.83.0 libboost-system1.83.0 libboost-thread1.83.0 libboost-iostreams1.83.0 && \ 23 | apt-get --assume-yes install --no-install-recommends libjpeg62 && \ 24 | apt-get --assume-yes install --no-install-recommends libjsoncpp25 && \ 25 | apt-get --assume-yes install --no-install-recommends liblua5.4 && \ 26 | apt-get --assume-yes install --no-install-recommends libpng16-16 && \ 27 | apt-get --assume-yes install --no-install-recommends libpugixml1v5 && \ 28 | apt-get --assume-yes install --no-install-recommends libsqlite3-0 && \ 29 | apt-get --assume-yes install --no-install-recommends libssl3 && \ 30 | apt-get --assume-yes install --no-install-recommends libuuid1 && \ 31 | apt-get --assume-yes install --no-install-recommends lsb-base && \ 32 | apt-get --assume-yes install --no-install-recommends libpq5 && \ 33 | apt-get --assume-yes install --no-install-recommends libmysqlclient21 && \ 34 | apt-get --assume-yes install --no-install-recommends unixodbc && \ 35 | apt-get --assume-yes install --no-install-recommends libopenslide0 && \ 36 | apt-get --assume-yes install --no-install-recommends libcrypto++8 && \ 37 | apt-get --assume-yes install --no-install-recommends libcpprest && \ 38 | apt-get --assume-yes install --no-install-recommends libprotobuf32 && \ 39 | apt-get --assume-yes install --no-install-recommends pkg-config && \ 40 | apt-get --assume-yes install --no-install-recommends zlib1g && \ 41 | apt-get --assume-yes clean && \ 42 | rm --recursive --force /var/lib/apt/lists/* 43 | 44 | # disabled packages because of CVEs -> we use the static libraries instead 45 | # apt-get --assume-yes install --no-install-recommends libdcmtk17 && \ 46 | 47 | # Make sure the en_US locale has been generated (required for 48 | # case-insensitive comparison of strings with accents) 49 | RUN echo "en_US.UTF-8 UTF-8" > /etc/locale.gen 50 | RUN locale-gen 51 | -------------------------------------------------------------------------------- /WindowsInstaller/ciBuildWindowsInstaller.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # to run locally: ./ciBuildWindowsInstaller.sh false test local 4 | 5 | set -x #to debug the script 6 | set -e #to exit the script at the first failure 7 | 8 | 9 | is_tag=${1:-false} 10 | branch_tag_name=${2:-unknown} 11 | type=${3:-local} 12 | 13 | 14 | # the version must always be X.Y.Z 15 | if [[ $is_tag == "true" ]]; then 16 | version=$branch_tag_name 17 | else 18 | version=0.0.0 19 | fi 20 | 21 | if [[ $type == "local" ]]; then 22 | from_cache_arg= 23 | to_cache_arg= 24 | 25 | # when building locally, use Docker builder (easier to reuse local images) 26 | build="build" 27 | else 28 | from_cache_arg="--cache-from=orthancteam/orthanc-builder-base:win-installer" 29 | to_cache_arg="--cache-to=orthancteam/orthanc-builder-base:win-installer" 30 | 31 | # when building in CI, use buildx 32 | build="buildx build" 33 | fi 34 | 35 | add_host_cmd=--add-host=orthanc.uclouvain.be:130.104.229.21 36 | 37 | add_host_cmd=--add-host=orthanc.uclouvain.be:130.104.229.21 38 | 39 | # docker build --progress=plain -t installer-builder-32 -f Dockerfile --build-arg VERSION=$version --build-arg PLATFORM=32 .. 40 | 41 | docker $build \ 42 | $add_host_cmd \ 43 | --progress=plain -t installer-builder-32 \ 44 | --build-arg VERSION=$version \ 45 | --build-arg PLATFORM=32 \ 46 | $from_cache_arg \ 47 | $to_cache_arg \ 48 | -f Dockerfile \ 49 | .. 50 | 51 | 52 | # build Windows 32 bits 53 | dockerContainerId=$(docker create installer-builder-32) 54 | 55 | 56 | # copy the orthanc.json generated from the 32 bits version (we can't generate it with wine and Orthanc 64 bits) 57 | docker cp $dockerContainerId:/tmp/OrthancInstaller/orthanc.json . 58 | docker cp $dockerContainerId:/tmp/OrthancInstaller/OrthancInstaller-Win32.exe . 59 | docker rm $dockerContainerId 60 | 61 | # build Windows 64 bits 62 | docker $build \ 63 | $add_host_cmd \ 64 | --progress=plain -t installer-builder-64 \ 65 | --build-arg VERSION=$version \ 66 | --build-arg PLATFORM=64 \ 67 | $from_cache_arg \ 68 | $to_cache_arg \ 69 | -f Dockerfile \ 70 | .. 71 | 72 | 73 | dockerContainerId=$(docker create installer-builder-64) 74 | docker cp $dockerContainerId:/tmp/OrthancInstaller/OrthancInstaller-Win64.exe . 75 | docker rm $dockerContainerId 76 | 77 | 78 | # upload files to AWS 79 | ##################### 80 | 81 | # we first need to create the container before we can copy files to it 82 | export AWS_ACCESS_KEY_ID 83 | export AWS_SECRET_ACCESS_KEY 84 | awsContainerId=$(docker create $add_host_cmd -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY anigeo/awscli s3 --region eu-west-1 cp /tmp/ s3://public-files.orthanc.team/tmp-builds/win-installer/ --recursive --exclude "*" --include "OrthancInstaller*" --cache-control=max-age=1) 85 | 86 | # CHANGE_VERSION_WIN_INSTALLER 87 | docker cp OrthancInstaller-Win32.exe $awsContainerId:/tmp/OrthancInstaller-Win32-$branch_tag_name.exe 88 | docker cp OrthancInstaller-Win64.exe $awsContainerId:/tmp/OrthancInstaller-Win64-$branch_tag_name.exe 89 | 90 | if [[ $is_tag == "true" ]]; then 91 | docker cp OrthancInstaller-Win32.exe $awsContainerId:/tmp/OrthancInstaller-Win32-latest.exe 92 | docker cp OrthancInstaller-Win64.exe $awsContainerId:/tmp/OrthancInstaller-Win64-latest.exe 93 | fi 94 | 95 | # upload 96 | docker start -a $awsContainerId 97 | 98 | # remove container 99 | docker rm $awsContainerId 100 | -------------------------------------------------------------------------------- /docker/orthanc/generateConfiguration.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import glob 4 | import json 5 | import typing 6 | import tempfile 7 | import subprocess 8 | from envsubst import envsubst 9 | 10 | from helpers import JsonPath, logInfo, logWarning, logError, removeCppCommentsFromJson, isEnvVarDefinedEmptyOrTrue, enableVerboseModeForConfigGeneration 11 | from configurator import OrthancConfigurator 12 | 13 | 14 | configurator = OrthancConfigurator(folder = os.path.dirname(os.path.realpath(__file__))) 15 | 16 | if isEnvVarDefinedEmptyOrTrue("VERBOSE_STARTUP"): 17 | enableVerboseModeForConfigGeneration() 18 | 19 | if isEnvVarDefinedEmptyOrTrue("BUNDLE_DEBUG"): 20 | logWarning("You're using a deprecated env-var, you should use VERBOSE_STARTUP instead of BUNDLE_DEBUG") 21 | enableVerboseModeForConfigGeneration() 22 | 23 | 24 | ################# read all configuration files ################################ 25 | configFiles = [] 26 | 27 | logInfo("Discovering configuration files from /etc/orthanc/*.json") 28 | for filePath in glob.glob("/etc/orthanc/*.json"): 29 | configFiles.append(filePath) 30 | 31 | logInfo("Discovering configuration files from /run/secrets/*.json") 32 | for filePath in glob.glob("/run/secrets/*.json"): 33 | configFiles.append(filePath) 34 | 35 | for filePath in configFiles: 36 | logInfo("reading configuration from " + filePath) 37 | with open(filePath, "r") as f: 38 | content = f.read() 39 | 40 | # perform standard env var substitution before trying to read the json file (https://github.com/orthanc-server/orthanc-builder/issues/9) 41 | content = envsubst(content) 42 | try: 43 | cleanedContent = removeCppCommentsFromJson(content) 44 | configFromFile = json.loads(cleanedContent) 45 | except: 46 | logError("Unable to parse Json file '{f}'; check syntax".format(f = filePath)) 47 | 48 | configurator.mergeConfigFromFile(configFromFile, filePath) 49 | 50 | ################# read all environment variables ################################ 51 | 52 | logInfo("Analyzing environment variables") 53 | for envKey, envValue in os.environ.items(): 54 | 55 | configurator.mergeConfigFromEnvVar(envKey, envValue) 56 | 57 | ################# read all secrets ################################ 58 | 59 | logInfo("Analyzing secrets") 60 | 61 | for secretPath in glob.glob("/run/secrets/*"): 62 | logInfo("secret: " + secretPath) 63 | 64 | if os.path.isfile(secretPath): 65 | with open(secretPath, "r") as fp: 66 | secretValue = fp.read().rstrip("\n") 67 | 68 | configurator.mergeConfigFromSecret(secretPath, secretValue) 69 | 70 | ################# apply defaults that have not been set yet (from Orthanc and plugins) ################################ 71 | 72 | configurator.mergeConfigFromDefaults(moveSoFiles=True) 73 | 74 | 75 | logInfo("generated configuration file: " + json.dumps(configurator.configuration, indent=2)) 76 | 77 | if configurator.hasDeprecatedSettings: 78 | logWarning("************* you are using deprecated settings, these deprecated settings will be removed in June 2021 *************") 79 | 80 | if configurator.hasErrors: 81 | logError("There were some errors while preparing the configuration file for Orthanc.") 82 | exit(-1) 83 | 84 | 85 | configFilePath="/tmp/orthanc.json" 86 | logInfo("generating temporary configuration file in " + configFilePath) 87 | with open(configFilePath, "w+t") as fp: 88 | json.dump(configurator.configuration, fp=fp, indent=2) 89 | -------------------------------------------------------------------------------- /README-dockerhub.md: -------------------------------------------------------------------------------- 1 | # Orthanc for Docker 2 | Docker image with [Orthanc](https://www.orthanc-server.com/) and its official plugins. Orthanc is a lightweight, RESTful Vendor Neutral Archive for medical imaging. 3 | 4 | Note: the Orthanc version included in this image is exactly the same as the Orthanc included in the `jodogne/orthanc` image. However, 5 | this image contains a few plugins that are not included in the `jodogne/orthanc-plugins` image. Furthermore, 6 | this image provides an easy configuration through environment variables which is not the case of the `jodogne/orthanc` image. 7 | 8 | Starting from the `22.6.1` release, we are providing 2 types of images: 9 | - the default image with the usual tag: e.g `22.6.1` 10 | - the full image with a e.g `22.6.1-full` tag 11 | 12 | The default image is suitable for 99.9% of users. 13 | You should use the full image only if you need to use one of these: 14 | - the Azure Blob storage plugin 15 | - the Google Cloud storage plugin 16 | - the ODBC plugin with SQL Server (msodbcsql18 is preinstalled) 17 | 18 | Full documentation is available [here](https://book.orthanc-server.com/users/docker-orthancteam.html). 19 | 20 | Sample setups using this image are available [here](https://github.com/orthanc-server/orthanc-setup-samples/). 21 | 22 | Release notes are available [here](https://github.com/orthanc-server/orthanc-builder/blob/master/release-notes-docker-images.md) 23 | 24 | 25 | # packages content 26 | 27 | #### 25.12.3 Default image 28 | ``` 29 | component version 30 | --------------------------------------------- 31 | Orthanc server 1.12.10 32 | Serve folders plugin 1.12.10 33 | Connectivity check plugin 1.12.10 34 | Housekeeper plugin 1.12.10 35 | Delayed Deletion plugin 1.12.10 36 | Multitenant DICOM plugin 1.12.10 37 | Stone Web viewer plugin 2.6+266b0b912c35 38 | Osimis Web viewer plugin 1.4.3 39 | Python plugin 7.0 40 | Orthanc Web viewer plugin 2.10 41 | DICOMweb plugin 1.22 42 | PostgreSQL plugins 10.0 43 | MySQL plugins 5.2 44 | WSI Web viewer plugin 3.3 45 | Authorization plugin 0.10.3 46 | Transfers accelerator plugin 1.7 47 | GDCM plugin 1.8 48 | ODBC plugin 1.3 49 | TCIA plugin 1.2 50 | Orthanc Indexer plugin 1.1 51 | Orthanc neuroimaging plugin 1.1 52 | AWS S3 plugin 2.5.0 53 | Orthanc Explorer 2 1.10.1 54 | Kitware's VolView plugin 1.3 55 | OHIF plugin 1.7 56 | STL plugin 1.3 57 | Advanced Storage plugin 0.2.3 58 | Education plugin 1.1 59 | Worklists plugin 0.9.2 60 | Pixels masker plugin 0.1.1 61 | 62 | System components version 63 | --------------------------------------------- 64 | Base image Ubuntu version 24.04 (noble) 65 | Python 3.12 66 | Lua 5.4 67 | 68 | ``` 69 | 70 | #### 25.12.3-full image 71 | ``` 72 | additional component version 73 | --------------------------------------------- 74 | Azure Blob Storage plugin 2.3.1 75 | Google Cloud Storage plugin 2.5.1 76 | Java plugin 2.0 77 | ```` 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | This repo contains build instructions for the following components: 4 | 5 | - the `orthancteam/orthanc` Docker image 6 | - the Windows installer 7 | - the MacOS package (zip with Orthanc executable and plugins) 8 | 9 | The Docker image is rebuilt from scratch (Orthanc and all its plugins are compiled during the build process). 10 | Windows Installer and MacOS package are collecting build artifacts from the Orthanc buildbot server. 11 | 12 | # Where to find the releases ? 13 | 14 | ## stable releases 15 | 16 | - [Docker image (linux/amd64)](https://hub.docker.com/r/orthancteam/orthanc) 17 | - [Windows 64 bits installer](https://orthanc.uclouvain.be/downloads/windows-64/installers/index.html) 18 | - [Windows 32 bits installer](https://orthanc.uclouvain.be/downloads/windows-32/installers/index.html) 19 | - [MacOS package (Universal)](https://orthanc.uclouvain.be/downloads/macos/packages/universal/index.html) 20 | 21 | ## unstable releases (nightly builds) 22 | 23 | - [Docker image (linux/amd64)](https://hub.docker.com/r/orthancteam/orthanc-unstable) (`orthancteam/orthanc-unstable:master` image) 24 | 25 | 26 | - [MacOS package (Universal)](https://public-files.orthanc.team/MacOS-packages/Orthanc-MacOS-master-unstable.zip) 27 | 28 | 29 | **Notes**: 30 | 31 | - to build stable Docker images locally, use `./local-build.sh skipCommitChecks=1`. This produces `orthancteam/orthanc:current` images. 32 | - The MacOS package does not contain the WSI plugin that can currently be built only for Intel processors. 33 | 34 | ## building ARM 64 docker images 35 | 36 | You can use this repo to build `linux/arm64` docker images but we are currently not able to build them on our build slaves because, with QEMU emulation, a build would take more than 12 hours which is the limit of github actions. 37 | 38 | Hereunder, you'll find the full instructions to build ARM64 docker images on MacOS (note: this won't build Azure & Google object-storage plugins). Note, the StoneViewer build can last very long (multiple hours) because it is using an emulated container to build the WebAssembly code: 39 | ``` 40 | brew install jq 41 | brew install hg 42 | 43 | git clone https://github.com/orthanc-server/orthanc-builder.git 44 | cd orthanc-builder 45 | ./local-build.sh version=stable platform=linux/arm64 image=normal 46 | ``` 47 | 48 | This produces an image `orthancteam/orthanc:current`. 49 | 50 | 51 | # Continuous Builds 52 | 53 | - MacOS stable/unstable binaries and packages are rebuilt every night (if needed) and on every commit 54 | - Windows stable installers are rebuilt at every commit, they are available at: 55 | - [https://public-files.orthanc.team/tmp-builds/win-installer/OrthancInstaller-Win64-master.exe](https://public-files.orthanc.team/tmp-builds/win-installer/OrthancInstaller-Win64-master.exe) 56 | - Docker stable and unstable images are rebuilt every night and on every commit of this repo, they are available as: 57 | - `orthancteam/orthanc:master` 58 | - `orthancteam/orthanc-unstable:master` 59 | - Integration tests are run for every Docker build 60 | 61 | # Troubleshooting (for dev) 62 | 63 | - if a MacOS build fails, you may connect to the build slave thanks to `tmate`. Access is limited to approved actors with their SSH Github key. 64 | 65 | 66 | # Creating multi-platform image 67 | 68 | image=orthancteam/orthanc-pre-release 69 | tag=24.3.5 70 | docker manifest create $image:$tag $image:$tag-amd64 $image:$tag-arm64 71 | docker manifest annotate $image:$tag $image:$tag-amd64 --os linux --arch amd64 72 | docker manifest annotate $image:$tag $image:$tag-arm64 --os linux --arch arm64 73 | docker manifest push orthancteam/orthanc-pre-release:$tag 74 | 75 | -------------------------------------------------------------------------------- /UCLouvain/CreateMacOSPackage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Orthanc - A Lightweight, RESTful DICOM Store 4 | # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics 5 | # Department, University Hospital of Liege, Belgium 6 | # Copyright (C) 2017-2023 Osimis S.A., Belgium 7 | # Copyright (C) 2024-2025 Orthanc Team SRL, Belgium 8 | # Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium 9 | # 10 | # This program is free software: you can redistribute it and/or 11 | # modify it under the terms of the GNU Lesser General Public License 12 | # as published by the Free Software Foundation, either version 3 of 13 | # the License, or (at your option) any later version. 14 | # 15 | # This program is distributed in the hope that it will be useful, but 16 | # WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 | # Lesser General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Lesser General Public 21 | # License along with this program. If not, see 22 | # . 23 | 24 | 25 | import json 26 | import os 27 | import requests 28 | import sys 29 | import time 30 | import zipfile 31 | 32 | import Toolbox 33 | 34 | if len(sys.argv) != 3: 35 | print('Usage: %s [target ZIP] [version]' % sys.argv[0]) 36 | print('Example: %s /tmp/MacOS.zip 23.11.0' % sys.argv[0]) 37 | exit(-1) 38 | 39 | TARGET = sys.argv[1] 40 | PREFIX = 'Orthanc-MacOS-%s' % sys.argv[2] 41 | 42 | 43 | def AddContentToZip(archive, content, targetPath, isExecutable): 44 | info = zipfile.ZipInfo(os.path.join(PREFIX, targetPath)) 45 | info.compress_type = zipfile.ZIP_DEFLATED # If not set, no compression takes place 46 | info.date_time = time.localtime() 47 | 48 | if isExecutable: 49 | info.external_attr = 0o100755 << 16 # -rwxr-xr-x permissions (755 in octal) 50 | else: 51 | info.external_attr = 0o100644 << 16 # -rw-r--r-- permissions (644 in octal) 52 | 53 | archive.writestr(info, content) 54 | 55 | 56 | def AddFile(archive, sourcePath, targetPath = None, isExecutable = False): 57 | if targetPath == None: 58 | targetPath = os.path.basename(sourcePath) 59 | 60 | with open(os.path.join(BASE, sourcePath), 'rb') as f: 61 | AddContentToZip(archive, f.read(), targetPath, isExecutable) 62 | 63 | 64 | def DownloadFile(archive, url, targetPath = None, isExecutable = False): 65 | if targetPath == None: 66 | targetPath = url.split('/') [-1] 67 | 68 | print(' downloading: %s' % url) 69 | r = requests.get(url) 70 | r.raise_for_status() 71 | AddContentToZip(archive, r.content, targetPath, isExecutable) 72 | 73 | 74 | BASE = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') 75 | 76 | 77 | with open(os.path.join(BASE, 'build-matrix.json')) as f: 78 | matrix = json.loads(f.read()) 79 | 80 | 81 | with zipfile.ZipFile(TARGET, 'w', compression = zipfile.ZIP_DEFLATED) as archive: 82 | AddFile(archive, 'orthancBuildResources/readmeMacOS.txt', 'readme.txt') 83 | AddFile(archive, 'orthancBuildResources/configMacOS.json') 84 | AddFile(archive, 'orthancBuildResources/startOrthanc.command', isExecutable = True) 85 | AddFile(archive, 'WindowsInstaller/Resources/ca-certificates.crt') 86 | 87 | for project in matrix['configs']: 88 | if project['name'].startswith('XXXX'): # This is a documentation 89 | continue 90 | 91 | if not 'downloadsMacOS' in project: 92 | print('Skipping project without MacOS binaries: %s' % project['name']) 93 | continue 94 | 95 | version = Toolbox.GetVersion(project) 96 | 97 | for f in project['downloadsMacOS']: 98 | if isinstance(f, str): 99 | url = f.replace('${VERSION}', version) 100 | DownloadFile(archive, url) 101 | else: 102 | url = f['url'].replace('${VERSION}', version) 103 | DownloadFile(archive, url, f.get('target', None), f.get('executable', False)) 104 | -------------------------------------------------------------------------------- /docker/orthanc/test-aliveness.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # this scripts performs a readiness/aliveness check of orthanc by simply calling 4 | # the /changes route from inside the container. 5 | # ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ 6 | # when using mTLS at Orthanc level, it is impossible to use the built-in K8 HttpGet probes hence this script. 7 | # 8 | # usage: 9 | # ./test-aliveness.py --http_port=8042 --user=toto --pwd=tutu --http_scheme=http --certfile=/my/client.cert.pem --keyfile=/my/client.key.pem --keypwd=mykeypwd 10 | # the http_port, http_scheme, user and pwd arguments are extracted from the orthanc configuration file if not provided. 11 | # check https://docs.python.org/3/library/ssl.html#ssl.SSLContext.load_cert_chain for more details about the 3 cert arguments 12 | 13 | import urllib.request # we don't use the requests module to avoid forcing installation for everyone 14 | import sys 15 | import json 16 | import base64 17 | import ssl 18 | import argparse 19 | import traceback 20 | 21 | 22 | http_port = 8042 23 | headers = {} 24 | user = None 25 | pwd = None 26 | certfile = None 27 | keyfile = None 28 | keypwd = None 29 | http_scheme = 'http' 30 | 31 | parser = argparse.ArgumentParser() 32 | parser.add_argument('--http_port', type=int) 33 | parser.add_argument('--http_scheme', type=str) 34 | parser.add_argument('--user', type=str) 35 | parser.add_argument('--pwd', type=str) 36 | parser.add_argument('--certfile', type=str) 37 | parser.add_argument('--keyfile', type=str) 38 | parser.add_argument('--keypwd', type=str) 39 | 40 | args = parser.parse_args() 41 | 42 | # first try to read port number + user credentials from the configuration file 43 | try: 44 | with open('/tmp/orthanc.json', 'rb') as config_file: 45 | config = json.load(config_file) 46 | 47 | if 'HttpPort' in config: 48 | http_port = config['HttpPort'] 49 | 50 | if 'AuthenticationEnabled' in config and config['AuthenticationEnabled']: 51 | if 'RegisteredUsers' in config and len(config['RegisteredUsers']): 52 | if args.user: 53 | pwd = config['RegisteredUsers'].get(args.user, '') 54 | else: 55 | for u, p in config['RegisteredUsers'].items(): 56 | user = u 57 | pwd = p 58 | break 59 | 60 | if 'SslEnabled' in config and config['SslEnabled']: 61 | http_scheme = 'https' 62 | 63 | except: 64 | pass 65 | 66 | 67 | # override the values from the config file with the values from the command line 68 | 69 | if args.http_port: 70 | http_port = args.http_port 71 | 72 | if args.user: 73 | user = args.user 74 | 75 | if args.pwd: 76 | pwd = args.pwd 77 | 78 | if args.http_scheme: 79 | http_scheme = args.http_scheme 80 | 81 | if args.certfile: 82 | certfile = args.certfile 83 | http_scheme = 'https' 84 | 85 | if args.keyfile: 86 | keyfile = args.keyfile 87 | 88 | if args.keypwd: 89 | keypwd = args.keypwd 90 | 91 | try: 92 | ssl_context = None 93 | ssl_context = ssl.SSLContext() 94 | ssl_context.verify_mode = ssl.CERT_NONE # skip verification of server cert 95 | 96 | if certfile: 97 | ssl_context.load_cert_chain(certfile=certfile, keyfile=keyfile, password=keypwd) 98 | 99 | # In previous version, we were actually calling /system but it is actually not accessing the DB because 100 | # the DB version is cached -> call /changes instead 101 | req = urllib.request.Request(f'{http_scheme}://localhost:{http_port}/changes?last') 102 | 103 | if user and pwd: 104 | base_64_credentials = base64.b64encode(bytes(f"{user}:{pwd}", 'utf-8')) 105 | req.add_header('Authorization', 'Basic %s' % base_64_credentials.decode('utf-8')) 106 | 107 | with urllib.request.urlopen(req, context=ssl_context) as f: 108 | if f.status == 200: 109 | sys.exit(0) 110 | 111 | except Exception: 112 | print(traceback.format_exc()) 113 | sys.exit(1) 114 | -------------------------------------------------------------------------------- /docker/orthanc/generatePluginDoc.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import glob 4 | import json 5 | import typing 6 | import tempfile 7 | import subprocess 8 | import argparse 9 | 10 | from configurator import OrthancConfigurator 11 | 12 | # examples: 13 | # from docker/orthanc 14 | # python3 generatePluginDoc.py 15 | # python3 generatePluginDoc.py --folder ../orthanc-pro-builder --output html 16 | 17 | parser = argparse.ArgumentParser(description='Generates the plugins section of the documentation.') 18 | parser.add_argument('--folder', type=str, default=None, 19 | help='folder to parse (search plugins-def.json') 20 | parser.add_argument('--output', type=str, default="rst", 21 | help='output format (rst or html)') 22 | 23 | args = parser.parse_args() 24 | 25 | colWidths = [50, 50, 100] 26 | 27 | def printSeparatorLine(char): 28 | print("+" + char*colWidths[0] + "+" + char*colWidths[1] + "+" + char*colWidths[2] + "+") 29 | 30 | def fixedLengthString(length): 31 | return "{0:" + str(length) + "}" 32 | 33 | def printContentLine(cells): 34 | i = 0 35 | outputCells = [] 36 | for cell in cells: 37 | if cell is None: 38 | cell = "" 39 | outputCells.append(fixedLengthString(colWidths[i]-2).format(cell)) # -2 for the 2 white spaces around '|' 40 | 41 | i = i + 1 42 | 43 | print("| " + " | ".join(outputCells) + " |") 44 | 45 | 46 | configurator = OrthancConfigurator(args.folder) 47 | 48 | if args.output == "rst": 49 | 50 | printSeparatorLine("-") 51 | printContentLine(["Plugin", "Environment variable", "Default configuration"]) 52 | printSeparatorLine("=") 53 | 54 | for pluginName, pluginDef in configurator.pluginsDef.items(): 55 | if "section" in pluginDef: 56 | section = pluginDef["section"] 57 | else: 58 | section = pluginName 59 | 60 | cell0 = ["**" + pluginName + "**"] 61 | cell1 = ["``" + pluginDef["enablingEnvVar"] + "``"] 62 | cell2 = [".. code-block:: json", ""] 63 | 64 | if "enabledByDefault" in pluginDef and pluginDef["enabledByDefault"]: 65 | cell1.append("Note: enabled by default") 66 | 67 | if "nonStandardDefaults" in pluginDef: 68 | defaultSettings = { 69 | section: pluginDef["nonStandardDefaults"] 70 | } 71 | jsonString = json.dumps(defaultSettings, indent=2) 72 | 73 | for jsonLine in jsonString.split("\n"): 74 | cell2.append(" " + jsonLine) 75 | 76 | else: 77 | cell2 = [""] 78 | 79 | for l in range(max(len(c) for c in [cell0, cell1, cell2])): 80 | c0 = cell0[l] if l < len(cell0) else "" 81 | c1 = cell1[l] if l < len(cell1) else "" 82 | c2 = cell2[l] if l < len(cell2) else "" 83 | 84 | printContentLine([c0, c1, c2]) 85 | 86 | printSeparatorLine("-") 87 | 88 | elif args.output == "html": 89 | 90 | 91 | def printHtmlRow(el, cells): 92 | output = [] 93 | output.append("") 94 | for c in cells: 95 | output.append(f"<{el}>{c}") 96 | output.append("") 97 | print("".join(output)) 98 | 99 | print("") 100 | 101 | printHtmlRow("th", ["Plugin", "Environment variable", "Default configuration"]) 102 | 103 | for pluginName, pluginDef in configurator.pluginsDef.items(): 104 | if "section" in pluginDef: 105 | section = pluginDef["section"] 106 | else: 107 | section = pluginName 108 | 109 | cell0 = pluginName 110 | cell1 = pluginDef["enablingEnvVar"] 111 | cell2 = "" 112 | 113 | if "enabledByDefault" in pluginDef and pluginDef["enabledByDefault"]: 114 | cell1 = cell1 + "\nNote: enabled by default" 115 | 116 | if "nonStandardDefaults" in pluginDef: 117 | defaultSettings = { 118 | section: pluginDef["nonStandardDefaults"] 119 | } 120 | cell2 = json.dumps(defaultSettings, indent=2) 121 | 122 | # cell0 = "" + cell0 + "" 123 | cell0 = "" + cell0 + "" 124 | cell1 = "
" + cell1 + "
" 125 | cell2 = "
" + cell2 + "
" 126 | 127 | printHtmlRow("td", [cell0, cell1, cell2]) 128 | 129 | print("
") 130 | -------------------------------------------------------------------------------- /docker/orthanc/test_current.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import json 3 | from configurator import OrthancConfigurator 4 | 5 | 6 | class CurrentTest(unittest.TestCase): 7 | 8 | def test_default_config(self): 9 | c = OrthancConfigurator() 10 | c.mergeConfigFromDefaults() 11 | 12 | self.assertTrue(c.configuration["RemoteAccessAllowed"]) 13 | self.assertTrue(c.configuration["AuthenticationEnabled"]) 14 | 15 | def test_multiple_files(self): 16 | c = OrthancConfigurator() 17 | worklistsConfig = { 18 | "Worklists" : { 19 | "Database" : "tutu" 20 | } 21 | } 22 | pgConfig = { 23 | "PostgreSQL" : { 24 | "Host" : "host" 25 | } 26 | } 27 | 28 | c.mergeConfigFromFile(worklistsConfig, "worklists.json") 29 | c.mergeConfigFromFile(pgConfig, "pg.json") 30 | 31 | self.assertIn("Worklists", c.getEnabledPlugins()) 32 | self.assertIn("PostgreSQL", c.getEnabledPlugins()) 33 | 34 | 35 | def test_file_in_env_var(self): 36 | c = OrthancConfigurator() 37 | worklistsConfig = { 38 | "Worklists" : { 39 | "Database" : "tutu" 40 | } 41 | } 42 | configFileInString = json.dumps(worklistsConfig, indent=2) 43 | 44 | c.mergeConfigFromEnvVar("ORTHANC_JSON", configFileInString) 45 | 46 | self.assertIn("Worklists", c.getEnabledPlugins()) 47 | self.assertEqual("tutu", c.configuration["Worklists"]["Database"]) 48 | 49 | def test_simple_env_vars_to_enable_plugin(self): 50 | c = OrthancConfigurator() 51 | c.mergeConfigFromEnvVar("WORKLISTS_PLUGIN_ENABLED", "true") 52 | 53 | self.assertIn("Worklists", c.getEnabledPlugins()) 54 | 55 | def test_file_not_overwritten_by_plugin_default(self): 56 | c = OrthancConfigurator() 57 | pgConfig = { 58 | "PostgreSQL" : { 59 | "Password" : "pg-password", 60 | "Host" : "host" 61 | } 62 | } 63 | c.mergeConfigFromFile(pgConfig, "pg.json") 64 | c.mergeConfigFromDefaults() 65 | 66 | self.assertEqual("host", c.configuration["PostgreSQL"]["Host"]) 67 | self.assertEqual("pg-password", c.configuration["PostgreSQL"]["Password"]) 68 | self.assertEqual("postgres", c.configuration["PostgreSQL"]["Username"]) 69 | 70 | 71 | def test_simple_section_to_enable_plugin(self): 72 | c = OrthancConfigurator() 73 | worklistsConfig = { 74 | "Worklists" : { 75 | "Database" : "tutu" 76 | } 77 | } 78 | c.mergeConfigFromFile(worklistsConfig, "worklist.json") 79 | 80 | self.assertIn("Worklists", c.configuration) 81 | self.assertIn("Worklists", c.getEnabledPlugins()) 82 | 83 | def test_python_plugin_with_root_setting(self): 84 | c = OrthancConfigurator() 85 | config = { 86 | "PythonScript" : "tutu.py" 87 | } 88 | c.mergeConfigFromFile(config, "config.json") 89 | 90 | self.assertIn("Python", c.getEnabledPlugins()) 91 | 92 | 93 | def test_direct_secret(self): 94 | c = OrthancConfigurator() 95 | c.mergeConfigFromSecret("/run/secrets/ORTHANC__POSTGRESQL__PASSWORD", "pg-password") 96 | 97 | self.assertIn("PostgreSQL", c.configuration) 98 | self.assertIn("PostgreSQL", c.getEnabledPlugins()) 99 | self.assertEqual("pg-password", c.configuration["PostgreSQL"]["Password"]) 100 | 101 | def test_indirect_secret(self): 102 | c = OrthancConfigurator() 103 | c.mergeConfigFromEnvVar("ORTHANC__POSTGRESQL__PASSWORD_SECRET", "pg-password-file") 104 | c.mergeConfigFromSecret("/run/secrets/pg-password-file", "pg-password") 105 | 106 | self.assertIn("PostgreSQL", c.configuration) 107 | self.assertIn("PostgreSQL", c.getEnabledPlugins()) 108 | self.assertEqual("pg-password", c.configuration["PostgreSQL"]["Password"]) 109 | 110 | def test_gdcm_enabled_by_default(self): 111 | c = OrthancConfigurator() 112 | 113 | self.assertIn("Gdcm", c.getEnabledPlugins()) 114 | 115 | def test_disable_gdcm_by_env_var(self): 116 | c = OrthancConfigurator() 117 | c.mergeConfigFromEnvVar("GDCM_PLUGIN_ENABLED", "false") 118 | 119 | self.assertNotIn("Gdcm", c.getEnabledPlugins()) 120 | 121 | if __name__ == '__main__': 122 | unittest.main() -------------------------------------------------------------------------------- /WindowsInstaller/Configuration/PatchDefaultConfiguration.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Orthanc - A Lightweight, RESTful DICOM Store 3 | * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics 4 | * Department, University Hospital of Liege, Belgium 5 | * Copyright (C) 2017-2023 Osimis S.A., Belgium 6 | * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium 7 | * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium 8 | * 9 | * This program is free software: you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License as 11 | * published by the Free Software Foundation, either version 3 of the 12 | * License, or (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, but 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program. If not, see . 21 | **/ 22 | 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include "Toolbox.h" 29 | 30 | 31 | static std::streamsize GetStreamSize(std::istream& f) 32 | { 33 | // http://www.cplusplus.com/reference/iostream/istream/tellg/ 34 | f.seekg(0, std::ios::end); 35 | std::streamsize size = f.tellg(); 36 | f.seekg(0, std::ios::beg); 37 | 38 | return size; 39 | } 40 | 41 | 42 | static void ReadFile(std::string& content, 43 | const std::string& path) 44 | { 45 | boost::filesystem::ifstream f; 46 | f.open(path, std::ifstream::in | std::ifstream::binary); 47 | if (!f.good()) 48 | { 49 | throw std::runtime_error("Cannot open file"); 50 | } 51 | 52 | std::streamsize size = GetStreamSize(f); 53 | content.resize(size); 54 | if (size != 0) 55 | { 56 | f.read(reinterpret_cast(&content[0]), size); 57 | } 58 | 59 | f.close(); 60 | } 61 | 62 | 63 | static void WriteFile(const void* content, 64 | size_t size, 65 | const std::string& path) 66 | { 67 | boost::filesystem::ofstream f; 68 | f.open(path, std::ofstream::out | std::ofstream::binary); 69 | if (!f.good()) 70 | { 71 | throw std::runtime_error("Cannot write file"); 72 | } 73 | 74 | if (size != 0) 75 | { 76 | f.write(reinterpret_cast(content), size); 77 | 78 | if (!f.good()) 79 | { 80 | f.close(); 81 | throw std::runtime_error("Cannot write file"); 82 | } 83 | } 84 | 85 | f.close(); 86 | } 87 | 88 | 89 | 90 | static std::string Escape(const std::string& s) 91 | { 92 | std::string result; 93 | 94 | for (size_t i = 0; i < s.size(); i++) 95 | { 96 | if (s[i] == '"') 97 | { 98 | result += "\\\\\""; 99 | } 100 | else if (s[i] == '\\') 101 | { 102 | result += "\\\\\\\\"; 103 | } 104 | else 105 | { 106 | result += s[i]; 107 | } 108 | } 109 | 110 | return result; 111 | } 112 | 113 | 114 | int main() 115 | { 116 | try 117 | { 118 | std::string storageDir = GetStringRegKeyAnsi 119 | ("SOFTWARE\\Orthanc\\Orthanc Server", "OrthancDir", ""); 120 | 121 | std::string installDir = GetStringRegKeyAnsi 122 | ("SOFTWARE\\Orthanc\\Orthanc Server", "InstallDir", ""); 123 | 124 | std::string configuration; 125 | ReadFile(configuration, "orthanc.json"); 126 | 127 | configuration = boost::regex_replace( 128 | configuration, 129 | boost::regex("\"(Storage|Index)Directory\" : \"OrthancStorage\""), 130 | "\"\\1Directory\" : \"" + Escape(storageDir) + "\""); 131 | 132 | configuration = boost::regex_replace( 133 | configuration, 134 | boost::regex("\"Plugins\" : \\[\\s*\\]"), 135 | "\"Plugins\" : [ \"" + Escape(installDir + "\\Plugins") + "\" ]"); 136 | 137 | configuration = boost::regex_replace( 138 | configuration, 139 | boost::regex("\"HttpsCACertificates\" : \"\""), 140 | "\"HttpsCACertificates\" : \"" + Escape(installDir + "\\Configuration\\ca-certificates.crt") + "\""); 141 | 142 | WriteFile(configuration.c_str(), configuration.size(), "orthanc.json"); 143 | std::cerr << "Successfully patched the default Orthanc configuration" << std::endl; 144 | 145 | return 0; 146 | } 147 | catch (...) 148 | { 149 | std::cerr << "ERROR: Cannot patch the default Orthanc configuration" << std::endl; 150 | return -1; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /docker/integration-tests/orthanc-tests/wait-for-it.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Use this script to test if a given TCP host/port are available 3 | 4 | cmdname=$(basename $0) 5 | 6 | echoerr() { if [[ $QUIET -ne 1 ]]; then echo "$@" 1>&2; fi } 7 | 8 | usage() 9 | { 10 | cat << USAGE >&2 11 | Usage: 12 | $cmdname host:port [-s] [-t timeout] [-- command args] 13 | -h HOST | --host=HOST Host or IP under test 14 | -p PORT | --port=PORT TCP port under test 15 | Alternatively, you specify the host and port as host:port 16 | -s | --strict Only execute subcommand if the test succeeds 17 | -q | --quiet Don't output any status messages 18 | -t TIMEOUT | --timeout=TIMEOUT 19 | Timeout in seconds, zero for no timeout 20 | -- COMMAND ARGS Execute command with args after the test finishes 21 | USAGE 22 | exit 1 23 | } 24 | 25 | wait_for() 26 | { 27 | if [[ $TIMEOUT -gt 0 ]]; then 28 | echoerr "$cmdname: waiting $TIMEOUT seconds for $HOST:$PORT" 29 | else 30 | echoerr "$cmdname: waiting for $HOST:$PORT without a timeout" 31 | fi 32 | start_ts=$(date +%s) 33 | while : 34 | do 35 | if [[ $ISBUSY -eq 1 ]]; then 36 | nc -z $HOST $PORT 37 | result=$? 38 | else 39 | (echo > /dev/tcp/$HOST/$PORT) >/dev/null 2>&1 40 | result=$? 41 | fi 42 | if [[ $result -eq 0 ]]; then 43 | end_ts=$(date +%s) 44 | echoerr "$cmdname: $HOST:$PORT is available after $((end_ts - start_ts)) seconds" 45 | break 46 | fi 47 | sleep 1 48 | done 49 | return $result 50 | } 51 | 52 | wait_for_wrapper() 53 | { 54 | # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692 55 | if [[ $QUIET -eq 1 ]]; then 56 | timeout $BUSYTIMEFLAG $TIMEOUT $0 --quiet --child --host=$HOST --port=$PORT --timeout=$TIMEOUT & 57 | else 58 | timeout $BUSYTIMEFLAG $TIMEOUT $0 --child --host=$HOST --port=$PORT --timeout=$TIMEOUT & 59 | fi 60 | PID=$! 61 | trap "kill -INT -$PID" INT 62 | wait $PID 63 | RESULT=$? 64 | if [[ $RESULT -ne 0 ]]; then 65 | echoerr "$cmdname: timeout occurred after waiting $TIMEOUT seconds for $HOST:$PORT" 66 | fi 67 | return $RESULT 68 | } 69 | 70 | # process arguments 71 | while [[ $# -gt 0 ]] 72 | do 73 | case "$1" in 74 | *:* ) 75 | hostport=(${1//:/ }) 76 | HOST=${hostport[0]} 77 | PORT=${hostport[1]} 78 | shift 1 79 | ;; 80 | --child) 81 | CHILD=1 82 | shift 1 83 | ;; 84 | -q | --quiet) 85 | QUIET=1 86 | shift 1 87 | ;; 88 | -s | --strict) 89 | STRICT=1 90 | shift 1 91 | ;; 92 | -h) 93 | HOST="$2" 94 | if [[ $HOST == "" ]]; then break; fi 95 | shift 2 96 | ;; 97 | --host=*) 98 | HOST="${1#*=}" 99 | shift 1 100 | ;; 101 | -p) 102 | PORT="$2" 103 | if [[ $PORT == "" ]]; then break; fi 104 | shift 2 105 | ;; 106 | --port=*) 107 | PORT="${1#*=}" 108 | shift 1 109 | ;; 110 | -t) 111 | TIMEOUT="$2" 112 | if [[ $TIMEOUT == "" ]]; then break; fi 113 | shift 2 114 | ;; 115 | --timeout=*) 116 | TIMEOUT="${1#*=}" 117 | shift 1 118 | ;; 119 | --) 120 | shift 121 | CLI=("$@") 122 | break 123 | ;; 124 | --help) 125 | usage 126 | ;; 127 | *) 128 | echoerr "Unknown argument: $1" 129 | usage 130 | ;; 131 | esac 132 | done 133 | 134 | if [[ "$HOST" == "" || "$PORT" == "" ]]; then 135 | echoerr "Error: you need to provide a host and port to test." 136 | usage 137 | fi 138 | 139 | TIMEOUT=${TIMEOUT:-15} 140 | STRICT=${STRICT:-0} 141 | CHILD=${CHILD:-0} 142 | QUIET=${QUIET:-0} 143 | 144 | # check to see if timeout is from busybox? 145 | # check to see if timeout is from busybox? 146 | TIMEOUT_PATH=$(realpath $(which timeout)) 147 | if [[ $TIMEOUT_PATH =~ "busybox" ]]; then 148 | ISBUSY=1 149 | BUSYTIMEFLAG="-t" 150 | else 151 | ISBUSY=0 152 | BUSYTIMEFLAG="" 153 | fi 154 | 155 | if [[ $CHILD -gt 0 ]]; then 156 | wait_for 157 | RESULT=$? 158 | exit $RESULT 159 | else 160 | if [[ $TIMEOUT -gt 0 ]]; then 161 | wait_for_wrapper 162 | RESULT=$? 163 | else 164 | wait_for 165 | RESULT=$? 166 | fi 167 | fi 168 | 169 | if [[ $CLI != "" ]]; then 170 | if [[ $RESULT -ne 0 && $STRICT -eq 1 ]]; then 171 | echoerr "$cmdname: strict mode, refusing to execute subprocess" 172 | exit $RESULT 173 | fi 174 | exec "${CLI[@]}" 175 | else 176 | exit $RESULT 177 | fi -------------------------------------------------------------------------------- /docker/orthanc/env-var-legacy.json: -------------------------------------------------------------------------------- 1 | { 2 | "AC_ALLOW_REMOTE": "RemoteAccessAllowed", 3 | "AC_AUTHENTICATION_ENABLED": "AuthenticationEnabled", 4 | "AC_REGISTERED_USERS": "RegisteredUsers", 5 | "AUTHZ_WEBSERVICE": "Authorization.WebService", 6 | "AUTHZ_TOKEN_HTTP_HEADERS": "Authorization.TokenHttpHeaders", 7 | "AUTHZ_TOKEN_GET_ARGUMENTS": "Authorization.TokenGetArguments", 8 | "AUTHZ_UNCHECKED_RESOURCES": "Authorization.UncheckedResources", 9 | "AUTHZ_UNCHECKED_FOLDERS": "Authorization.UncheckedFolders", 10 | "AUTHZ_UNCHECKED_LEVELS": "Authorization.UncheckedLevels", 11 | "AZSTOR_ACC_KEY": "BlobStorage.AccountKey", 12 | "AZSTOR_ACC_NAME": "BlobStorage.AccountName", 13 | "AZSTOR_LICENSE_STRING": "BlobStorage.LicenseString", 14 | "AZSTOR_CONTAINER": "BlobStorage.ContainerName", 15 | "DICOM_AET": "DicomAet", 16 | "DICOM_AET_CHECK_ENABLED": "DicomCheckCalledAet", 17 | "DICOM_ALWAYS_ALLOW_ECHO_ENABLED": "DicomAlwaysAllowEcho", 18 | "DICOM_ALWAYS_ALLOW_STORE_ENABLED": "DicomAlwaysAllowStore", 19 | "DICOM_CHECK_MODALITY_HOST_ENABLED": "DicomCheckModalityHost", 20 | "DICOM_DICTIONARY": "Dictionary", 21 | "DICOM_MODALITIES": "DicomModalities", 22 | "DICOM_PORT": "DicomPort", 23 | "DICOM_QUERY_RETRIEVE_SIZE": "QueryRetrieveSize", 24 | "DICOM_SCP_TIMEOUT": "DicomScpTimeout", 25 | "DICOM_SCU_TIMEOUT": "DicomScuTimeout", 26 | "DICOM_STRICT_AET_COMPARISON_ENABLED": "StrictAetComparison", 27 | "DICOM_SYNCHRONOUS_CMOVE": "SynchronousCMove", 28 | "DICOM_UNKNOWN_SOP_CLASS_ACCEPTED": "UnknownSopClassAccepted", 29 | "DW_ROOT": "DicomWeb.Root", 30 | "DW_WADO_URI_ENABLED": "DicomWeb.EnableWado", 31 | "DW_WADO_URI_ROOT": "DicomWeb.WadoRoot", 32 | "DW_HOST": "DicomWeb.Host", 33 | "DW_TLS": "DicomWeb.Ssl", 34 | "DW_SERVERS": "DicomWeb.Servers", 35 | "DW_STOW_MAX_INSTANCES": "DicomWeb.StowMaxInstances", 36 | "DW_STOW_MAX_SIZE": "DicomWeb.StowMaxSize", 37 | "EXECUTE_LUA_ENABLED": "ExecuteLuaEnabled", 38 | "HTTP_CL_TIMEOUT": "HttpTimeout", 39 | "HTTP_CL_VERIFY_PEERS": "HttpsVerifyPeers", 40 | "HTTP_CL_CA_CERTS": "HttpsCACertificates", 41 | "HTTP_CL_PROXY": "HttpProxy", 42 | "HTTP_VERBOSE": "HttpVerbose", 43 | "HTTP_PORT": "HttpPort", 44 | "HTTP_KEEP_ALIVE": "KeepAlive", 45 | "HTTP_TCP_NODELAY": "TcpNoDelay", 46 | "HTTP_REQUEST_TIMEOUT": "HttpRequestTimeout", 47 | "IMPORT_OVERWRITE_INSTANCES": "OverwriteInstances", 48 | "LISTENER_LISTEN_ALL_ADDR": "RemoteAccessAllowed", 49 | "LOCALE": "Locale", 50 | "LUA_OPTIONS": "LuaOptions", 51 | "LUA_SCRIPTS": "LuaScripts", 52 | "PEERS": "OrthancPeers", 53 | "PG_PASSWORD": "PostgreSQL.Password", 54 | "PG_INDEX_ENABLED": "PostgreSQL.EnableIndex", 55 | "PG_STORAGE_ENABLED": "PostgreSQL.EnableStorage", 56 | "PG_HOST": "PostgreSQL.Host", 57 | "PG_PORT": "PostgreSQL.Port", 58 | "PG_DB": "PostgreSQL.Database", 59 | "PG_USER": "PostgreSQL.Username", 60 | "PG_SSL": "PostgreSQL.EnableSsl", 61 | "PG_LOCK": "PostgreSQL.Lock", 62 | "PLUGINS": "Plugins", 63 | "NAME": "Name", 64 | "SCHED_JOBS_HISTORY_SIZE": "JobsHistorySize", 65 | "SCHED_MAX_CONCURRENT_JOBS": "ConcurrentJobs", 66 | "SCHED_MAX_QUEUED_JOBS": "LimitJobs", 67 | "SCHED_SAVE_JOBS": "SaveJobs", 68 | "SERVEFOLDERS_ALLOW_CACHE": "ServeFolders.AllowCache", 69 | "SERVEFOLDERS_GENERATE_ETAGS": "ServeFolders.GenerateETag", 70 | "SERVEFOLDERS_EXTENSIONS": "ServeFolders.Extensions", 71 | "SERVEFOLDERS_FOLDERS": "ServeFolders.Folders", 72 | "STABLE_AGE": "StableAge", 73 | "STORAGE_ACCESS_ON_FIND": "StorageAccessOnFind", 74 | "STORAGE_DIR": "StorageDirectory", 75 | "STORAGE_MAX_SIZE": "MaximumStorageSize", 76 | "STORAGE_MAX_PATIENTS": "MaximumPatientCount", 77 | "STORE_DICOM": "StoreDicom", 78 | "TRANSFERS_THREADS": "Transfers.Threads", 79 | "TRANSFERS_RETRIES": "Transfers.MaxHttpRetries", 80 | "TRANSFERS_BUCKET_SIZE": "Transfers.BucketSize", 81 | "TRANSFERS_CACHE_SIZE": "Transfers.CacheSize", 82 | "TRANSFERS_MAX_PUSH_TRANSACTIONS": "Transfers.MaxPushTransactions", 83 | "USERMETADATA": "UserMetadata", 84 | "WL_STORAGE_DIR": "Worklists.Database", 85 | "WVB_ANNOTATIONS_STORAGE_ENABLED": "WebViewer.AnnotationStorageEnabled", 86 | "WVB_COMBINED_TOOL_ENABLED": "WebViewer.CombinedToolEnabled", 87 | "WVB_CROSS_HAIR_ENABLED": "WebViewer.CrossHairEnabled", 88 | "WVB_LANGUAGE": "WebViewer.DefaultLanguage", 89 | "WVB_DEFAULT_SELECTED_TOOL": "WebViewer.DefaultSelectedTool", 90 | "WVB_DOWNLOAD_AS_JPEG_ENABLED": "WebViewer.DownloadAsJpegEnabled", 91 | "WVB_INSTANCE_INFO_CACHE_ENABLED": "WebViewer.InstanceInfoCacheEnabled", 92 | "WVB_KEY_IMAGE_CAPTURE_ENABLED": "WebViewer.KeyImageCaptureEnabled", 93 | "WVB_KEYBOARD_SHORTCUTS_ENABLED": "WebViewer.KeyboardShortcutsEnabled", 94 | "WVB_OPEN_ALL_PATIENT_STUDIES": "WebViewer.OpenAllPatientStudies", 95 | "WVB_PRINT_ENABLED": "WebViewer.PrintEnabled", 96 | "WVB_REFERENCE_LINES_ENABLED": "WebViewer.ReferenceLinesEnabled", 97 | "WVB_SERIES_TO_IGNORE": "WebViewer.SeriesToIgnore", 98 | "WVB_STUDY_DOWNLOAD_ENABLED": "WebViewer.StudyDownloadEnabled", 99 | "WVB_SYNCHRONIZED_BROWSING_ENABLED": "WebViewer.SynchronizedBrowsingEnabled", 100 | "WVB_TOGGLE_OVERLAY_TEXT_BUTTON_ENABLED": "WebViewer.ToggleOverlayTextButtonEnabled", 101 | "WVB_VIDEO_ENABLED": "WebViewer.VideoDisplayEnabled" 102 | } -------------------------------------------------------------------------------- /WindowsInstaller/Resources/README.txt: -------------------------------------------------------------------------------- 1 | Using Orthanc 2 | ============= 3 | 4 | You have successfully installed the Windows installers of Orthanc! 5 | Orthanc is now running as a Windows service in the background. 6 | 7 | By default, Orthanc listens to incoming DICOM connections on TCP port 8 | 4242 and incoming HTTP connections on TCP port 8042. 9 | 10 | You can interact with Orthanc by opening its administrative Web 11 | interface, that is called "Orthanc Explorer". This can be done by 12 | clicking the link in the Start Menu or by opening your web browser at 13 | http://127.0.0.1:8042/app/explorer.html. Please remember that Orthanc 14 | Explorer does not support Microsoft Internet Explorer. 15 | 16 | 17 | Content of the package ${VERSION} 18 | -----------------------${VERSION_DASHES} 19 | 20 | Orthanc server ${ORTHANC} 21 | Serve folders plugin ${ORTHANC} 22 | Connectivity check plugin ${ORTHANC} 23 | Housekeeper plugin ${ORTHANC} 24 | Delayed Deletion plugin ${ORTHANC} 25 | Multitenant DICOM plugin ${ORTHANC} 26 | Stone Web viewer plugin ${ORTHANC_STONE} 27 | Osimis Web viewer plugin ${OSIMIS_VIEWER} 28 | Orthanc Web viewer plugin ${ORTHANC_WEBVIEWER} 29 | DICOMweb plugin ${ORTHANC_DICOMWEB} 30 | PostgreSQL plugins ${ORTHANC_POSTGRESQL} 31 | MySQL plugins ${ORTHANC_MYSQL} 32 | WSI Web viewer plugin ${ORTHANC_WSI} 33 | Transfers accelerator plugin ${ORTHANC_TRANSFERS} 34 | Authorization plugin ${ORTHANC_AUTH} 35 | GDCM decoder/transcoder plugin ${ORTHANC_GDCM} 36 | ODBC plugin ${ORTHANC_ODBC} 37 | TCIA plugin ${ORTHANC_TCIA} 38 | Orthanc Indexer plugin ${ORTHANC_INDEXER} 39 | Orthanc neuroimaging plugin ${ORTHANC_NEURO} 40 | Orthanc Explorer 2 ${ORTHANC_EXPLORER_2} 41 | Azure blob storage plugin ${ORTHANC_AZURE_STORAGE} (Win64 installers only !) 42 | Kitware's VolView plugin ${ORTHANC_VOLVIEW} 43 | OHIF plugin ${ORTHANC_OHIF} 44 | Python plugin ${ORTHANC_PYTHON} 45 | STL plugin ${ORTHANC_STL} 46 | AWS S3 plugin ${ORTHANC_AWS_STORAGE} 47 | Education plugin ${ORTHANC_EDUCATION} 48 | Worklists plugin ${ORTHANC_WORKLISTS} 49 | Pixels masker plugin ${ORTHANC_PIXELS_MASKER} 50 | 51 | 52 | 53 | Folders 54 | ------- 55 | 56 | * STORAGE: During the installation, you were asked to choose a storage 57 | folder where Orthanc stores its database. By default, this folder is 58 | "C:\Orthanc". Running the uninstaller will remove the Orthanc 59 | program files from your system, but it will not delete this storage 60 | folder. 61 | 62 | If you wish to delete the data Orthanc has saved, delete this 63 | storage folder (e.g. C:\Orthanc) after uninstalling Orthanc. Keep 64 | this in mind if you use Orthanc to store protected health 65 | information (PHI). 66 | 67 | * CONFIGURATION: The Orthanc configuration files can be found inside 68 | the folder "Configuration" within the installation directory. A 69 | shortcut to the configuration folder is present in the Start Menu to 70 | access and modify it more easily. 71 | 72 | * LOGS: The Orthanc log files can be found inside the folder "Logs" 73 | within the installation directory. 74 | 75 | * PLUGINS: By default, Orthanc will look within the "Plugins" folder 76 | within the installation directory to find its plugins. 77 | 78 | 79 | Troubleshooting 80 | --------------- 81 | 82 | 1. Verify that the service called "Orthanc" is running using the 83 | Services control panel (for quick access, launch the command 84 | "services.msc"). 85 | 86 | 2. Make sure you do not use Internet Explorer to open Orthanc 87 | Explorer, but rather Chrome or Firefox. 88 | 89 | 3. Verify that your firewall is configured to allow inbound 90 | connections to the TCP ports Orthanc is listening on (by default, 91 | 4242 and 8042). 92 | 93 | 4. Verify that no other applications are using the ports that Orthanc 94 | is listening on. For instance, Juniper is known to also use the 95 | port 4242 for its VPN solutions. 96 | 97 | 5. By default, remote access to Orthanc Explorer is disallowed for 98 | security reasons. Turn the option "RemoteAccessAllowed" to "true" 99 | in the Orthanc configuration file if you wish to access Orthanc 100 | from another computer. 101 | 102 | 6. Check the Orthanc logs in the "Logs" folder within the installation 103 | directory. 104 | 105 | 7. Check the Orthanc Book and associated FAQ: 106 | https://orthanc.uclouvain.be/book/ 107 | https://orthanc.uclouvain.be/book/faq.html 108 | 109 | 8. Post a request for help to the Orthanc Users group: 110 | https://discourse.orthanc-server.org/ 111 | 112 | 113 | Homepage 114 | -------- 115 | 116 | You can find more information at the official homepage of Orthanc: 117 | http://www.orthanc-server.com/ 118 | 119 | 120 | Note 121 | ---- 122 | 123 | The content of this file is adapted from the unofficial Windows 124 | installer of Orthanc developed by Lury: 125 | https://github.com/luryco/OrthancService/blob/master/InstallerAssets/README.txt 126 | -------------------------------------------------------------------------------- /WindowsInstaller/NOTES.txt: -------------------------------------------------------------------------------- 1 | 2 | Setup 3 | ===== 4 | 5 | General architecture 6 | -------------------- 7 | 8 | - The Windows installer is entirely built under Linux. 9 | 10 | - The installer is generated by InnoSetup 11 | (http://www.jrsoftware.org/isinfo.php) under Linux thanks to Wine. 12 | 13 | - The content of the installer is populated by a Python script, which 14 | downloads files from the Orthanc CIS (BuildBot - for core and 15 | official plugins), and from the Osimis CIS (Jenkins - for the Osimis 16 | Web viewer). 17 | 18 | - The Windows service is compiled with MinGW-W64 as a Windows 32 bit 19 | binary (including for Windows 64). 20 | 21 | - An additional tool called "PatchDefaultConfiguration" patches the 22 | default configuration file of Orthanc, in order to replace the 23 | "IndexDirectory" and "StorageDirectory" options by the choice of the 24 | user (this choice is stored as a Windows registry key). 25 | 26 | 27 | 28 | Configuration 29 | ------------- 30 | 31 | Install an Ubuntu 16.04 box (or anything similar) 32 | 33 | # sudo apt-get install build-essential g++-mingw-w64 wine cmake 34 | # wget http://www.jrsoftware.org/download.php/is.exe 35 | # wine ./is.exe 36 | 37 | NB: The error messages that might appear while invoking InnoSetup 38 | are Wine-related and can be safely ignored. 39 | 40 | 41 | Build 42 | ----- 43 | 44 | Windows 32 package: 45 | 46 | # rm -rf /tmp/WindowsInstaller 47 | # ./CreateInstaller.py --matrix=../build-matrix.json --platform=32 --version=22.4.0 48 | 49 | Windows 64 package: 50 | 51 | # rm -rf /tmp/WindowsInstaller 52 | # ./CreateInstaller.py --matrix=../build-matrix.json --platform=64 --version=22.4.0 53 | 54 | The resulting installers are located in "/tmp/WindowsInstaller/" 55 | 56 | 57 | 58 | Configuration files 59 | =================== 60 | 61 | The default configuration files are retrieved from the official Debian 62 | packages: 63 | 64 | # wget 'https://anonscm.debian.org/viewvc/debian-med/trunk/packages/orthanc-webviewer/trunk/debian/configuration/webviewer.json?view=co' -O Resources/webviewer.json 65 | # unix2dos Resources/webviewer.json 66 | 67 | # wget https://anonscm.debian.org/cgit/debian-med/orthanc-dicomweb.git/plain/debian/configuration/dicomweb.json -O Resources/dicomweb.json 68 | # unix2dos Resources/dicomweb.json 69 | 70 | # wget 'https://anonscm.debian.org/viewvc/debian-med/trunk/packages/orthanc-postgresql/trunk/debian/configuration/postgresql.json?view=co' -O Resources/postgresql.json 71 | # unix2dos Resources/postgresql.json 72 | 73 | # wget https://anonscm.debian.org/cgit/debian-med/orthanc.git/plain/debian/configuration/serve-folders.json -O Resources/serve-folders.json 74 | # unix2dos Resources/serve-folders.json 75 | 76 | # wget https://anonscm.debian.org/cgit/debian-med/orthanc.git/plain/debian/configuration/worklists.json -O Resources/worklists.json 77 | # unix2dos Resources/worklists.json 78 | 79 | # wget https://orthanc.uclouvain.be/hg/orthanc-stone/raw-file/StoneWebViewer-2.3/Applications/StoneWebViewer/WebApplication/configuration.json -O Resources/stone-webviewer.json 80 | # unix2dos Resources/stone-webviewer.json 81 | 82 | 83 | InnoSetup Bitmaps 84 | ================= 85 | 86 | Gimp 87 | ---- 88 | 89 | If you are making a BMP from within GIMP and are exporting to a BMP, 90 | use the following options: 91 | 92 | - Compatibility Options -> Do not write color space information 93 | - Advanced Options -> 24 bits (R8 G8 B8) 94 | 95 | Otherwise, InnoSetup will tag the BMP as unsupported... 96 | 97 | 98 | ImageMagick 99 | ----------- 100 | 101 | http://www.imagemagick.org/Usage/formats/#bmp 102 | 103 | # convert -resize 55x58 ./Resources/OsimisLogo.png -background white -alpha remove -flatten -alpha off BMP3:./Resources/OsimisWizardLogo.bmp 104 | # convert -resize 164x314 ./Resources/OsimisWizard.png -background white -alpha remove -flatten -alpha off BMP3:./Resources/OsimisWizard.bmp 105 | 106 | # convert -resize 55x58 ./Resources/OrthancH.png -background white -alpha remove -flatten -alpha off BMP3:./Resources/OrthancWizardLogo.bmp 107 | # convert -resize 164x314 ./Resources/OrthancWizard.png -background white -alpha remove -flatten -alpha off BMP3:./Resources/OrthancWizard.bmp 108 | 109 | 110 | Icons 111 | ----- 112 | 113 | http://www.imagemagick.org/Usage/thumbnails/#favicon 114 | 115 | # convert ./Resources/OsimisLogo.png -background white -alpha remove -flatten -alpha off -resize 256x256 \ 116 | -define icon:auto-resize="256,128,96,64,48,32,16" \ 117 | ./Resources/Osimis.ico 118 | 119 | => Bad smoothing, unfortunately... so: 120 | 121 | # convert ./Resources/OsimisLogoShadow.png -resize 256x256 /tmp/icon-256.png && 122 | convert /tmp/icon-256.png -filter Gaussian -define filter:sigma=.5 -resize 128x128 /tmp/icon-128.png && 123 | convert /tmp/icon-128.png -filter Gaussian -define filter:sigma=.5 -resize 64x64 /tmp/icon-64.png && 124 | convert /tmp/icon-64.png -filter Gaussian -define filter:sigma=.5 -resize 32x32 /tmp/icon-32.png && 125 | convert /tmp/icon-32.png -filter Gaussian -define filter:sigma=.5 -resize 16x16 /tmp/icon-16.png && 126 | convert /tmp/icon-16.png /tmp/icon-32.png /tmp/icon-64.png /tmp/icon-128.png /tmp/icon-256.png ./Resources/Osimis.ico 127 | 128 | # convert ./Resources/OrthancH.png -resize 256x256 /tmp/icon-256.png && 129 | convert /tmp/icon-256.png -filter Gaussian -define filter:sigma=.5 -resize 128x128 /tmp/icon-128.png && 130 | convert /tmp/icon-128.png -filter Gaussian -define filter:sigma=.5 -resize 64x64 /tmp/icon-64.png && 131 | convert /tmp/icon-64.png -filter Gaussian -define filter:sigma=.5 -resize 32x32 /tmp/icon-32.png && 132 | convert /tmp/icon-32.png -filter Gaussian -define filter:sigma=.5 -resize 16x16 /tmp/icon-16.png && 133 | convert /tmp/icon-16.png /tmp/icon-32.png /tmp/icon-64.png /tmp/icon-128.png /tmp/icon-256.png ./Resources/Orthanc.ico 134 | -------------------------------------------------------------------------------- /docker/integration-tests/orthanc-under-tests/orthanc.json: -------------------------------------------------------------------------------- 1 | // how to obtain this file: 2 | // in orthanc-tests: generate the configuration file with python2 ./GenerateConfigurationForTests.py 3 | // then, paste it here and: 4 | // - remove the Plugins section 5 | // - remove the PostgreSQL/MySQL/Odbc sections 6 | // - update the IP of OrthancPeers and DicomModalities: replace localhost by orthanc-tests for the first item 7 | // - update the Worklists.Database to "/worklists" 8 | { 9 | "AcceptedTransferSyntaxes": [ 10 | "1.2.840.10008.1.*" 11 | ], 12 | "AllowFindSopClassesInStudy": false, 13 | "AuthenticationEnabled": true, 14 | "BuiltinDecoderTranscoderOrder": "After", 15 | "CaseSensitivePN": false, 16 | "CheckRevisions": true, 17 | "ConcurrentJobs": 2, 18 | "DefaultEncoding": "Utf8", 19 | "DefaultPrivateCreator": "Lunit", 20 | "DeidentifyLogs": true, 21 | "DicomAet": "ORTHANC", 22 | "DicomAlwaysAllowEcho": true, 23 | "DicomAlwaysAllowFind": false, 24 | "DicomAlwaysAllowFindWorklist": false, 25 | "DicomAlwaysAllowGet": false, 26 | "DicomAlwaysAllowMove": false, 27 | "DicomAlwaysAllowStore": true, 28 | "DicomAssociationCloseDelay": 0, 29 | "DicomCheckCalledAet": false, 30 | "DicomCheckModalityHost": false, 31 | "DicomEchoChecksFind": false, 32 | "DicomLossyTranscodingQuality": 90, 33 | "DicomModalities": { 34 | "orthanctest": [ 35 | "ORTHANCTEST", 36 | "orthanc-tests", 37 | 5001 38 | ], 39 | "self": [ 40 | "ORTHANC", 41 | "127.0.0.1", 42 | 4242 43 | ] 44 | }, 45 | "DicomModalitiesInDatabase": false, 46 | "DicomPort": 4242, 47 | "DicomScpTimeout": 30, 48 | "DicomScuPreferredTransferSyntax": "1.2.840.10008.1.2.1", 49 | "DicomScuTimeout": 10, 50 | "DicomServerEnabled": true, 51 | "DicomThreadsCount": 4, 52 | "DicomTlsEnabled": false, 53 | "DicomTlsRemoteCertificateRequired": true, 54 | "DicomWeb": { 55 | "Servers": { 56 | "sample": [ 57 | "http://localhost:8042/dicom-web/", 58 | "alice", 59 | "orthanctest" 60 | ] 61 | } 62 | }, 63 | "Dictionary": { 64 | "0009,0010": [ 65 | "LO", 66 | "Private data element", 67 | 1, 68 | 1, 69 | "Lunit" 70 | ], 71 | "0009,1001": [ 72 | "DS", 73 | "Abnormality score", 74 | 1, 75 | 1, 76 | "Lunit" 77 | ], 78 | "00e1,10c2": [ 79 | "UI", 80 | "PET-CT Multi Modality Name", 81 | 1, 82 | 1, 83 | "ELSCINT1" 84 | ], 85 | "4321,1012": [ 86 | "LO", 87 | "RadioButton3", 88 | 1, 89 | 1, 90 | "RadioLogic" 91 | ], 92 | "7053,1003": [ 93 | "ST", 94 | "Original Image Filename", 95 | 1, 96 | 1, 97 | "Philips PET Private Group" 98 | ] 99 | }, 100 | "ExecuteLuaEnabled": true, 101 | "HttpCompressionEnabled": false, 102 | "HttpDescribeErrors": true, 103 | "HttpPort": 8042, 104 | "HttpProxy": "", 105 | "HttpRequestTimeout": 30, 106 | "HttpServerEnabled": true, 107 | "HttpThreadsCount": 50, 108 | "HttpTimeout": 2, 109 | "HttpVerbose": false, 110 | "HttpsCACertificates": "/etc/ssl/certs/ca-certificates.crt", 111 | "HttpsVerifyPeers": true, 112 | "IndexDirectory": "OrthancStorage", 113 | "IngestTranscodingOfCompressed": true, 114 | "IngestTranscodingOfUncompressed": true, 115 | "JobsHistorySize": 1000, 116 | "LimitFindInstances": 20, 117 | "LimitFindResults": 10, 118 | "LoadPrivateDictionary": true, 119 | "LogExportedResources": true, 120 | "LuaScripts": [], 121 | "MallocArenaMax": 5, 122 | "MaximumPatientCount": 0, 123 | "MaximumPduLength": 16384, 124 | "MaximumStorageCacheSize": 128, 125 | "MaximumStorageSize": 0, 126 | "MediaArchiveSize": 1, 127 | "MetricsEnabled": true, 128 | "Name": "MyOrthanc", 129 | "OrthancExplorerEnabled": true, 130 | "OrthancPeers": { 131 | "peer": [ 132 | "http://orthanc-tests:5000/", 133 | "alice", 134 | "orthanctest" 135 | ], 136 | "self": { 137 | "Password": "orthanctest", 138 | "Url": "http://127.0.0.1:8042/", 139 | "Username": "alice" 140 | }, 141 | "transfers-bidirectional": { 142 | "Password": "orthanctest", 143 | "RemoteSelf": "transfers-bidirectional", 144 | "Url": "http://localhost:8042/", 145 | "Username": "alice" 146 | }, 147 | "transfers-simple": { 148 | "Password": "orthanctest", 149 | "Url": "http://localhost:8042/", 150 | "Username": "alice" 151 | } 152 | }, 153 | "OrthancPeersInDatabase": false, 154 | "OverwriteInstances": true, 155 | "QueryRetrieveSize": 100, 156 | "RegisteredUsers": { 157 | "alice": "orthanctest" 158 | }, 159 | "RemoteAccessAllowed": true, 160 | "SaveJobs": false, 161 | "SslCertificate": "certificate.pem", 162 | "SslEnabled": false, 163 | "SslMinimumProtocolVersion": 4, 164 | "SslTrustedClientCertificates": "trustedClientCertificates.pem", 165 | "SslVerifyPeers": false, 166 | "StableAge": 1, 167 | "StorageAccessOnFind": "Always", 168 | "StorageCommitmentReportsSize": 100, 169 | "StorageCompression": false, 170 | "StorageDirectory": "OrthancStorage", 171 | "StoreDicom": true, 172 | "StoreMD5ForAttachments": true, 173 | "StrictAetComparison": false, 174 | "SyncStorageArea": false, 175 | "SynchronousCMove": false, 176 | "SynchronousZipStream": true, 177 | "TcpNoDelay": true, 178 | "TranscodeDicomProtocol": true, 179 | "UnknownSopClassAccepted": false, 180 | "UserContentType": {}, 181 | "UserMetadata": { 182 | "my-metadata": 1098 183 | }, 184 | "WebDavDeleteAllowed": true, 185 | "WebDavEnabled": true, 186 | "WebDavUploadAllowed": true, 187 | "Worklists": { 188 | "Database": "/worklists", 189 | "Enable": true 190 | }, 191 | "ZipLoaderThreads": 0 192 | } 193 | -------------------------------------------------------------------------------- /.github/workflows/build-all-dockers.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | is_tag: 5 | description: 'Is a Git Tag' 6 | type: string 7 | required: true 8 | current_branch_tag: 9 | description: 'Git branch or Tag' 10 | type: string 11 | required: true 12 | secrets: 13 | docker_hub_username: 14 | required: true 15 | docker_hub_token: 16 | required: true 17 | aws_access_key_id: 18 | required: true 19 | aws_secret_access_key: 20 | required: true 21 | 22 | 23 | 24 | jobs: 25 | build-docker-stable: 26 | # no need to build the stable image on branches 27 | if: ${{ github.ref == 'refs/heads/master' || inputs.is_tag == 'true' }} 28 | uses: ./.github/workflows/build-docker.yml 29 | with: 30 | runner: ${{ matrix.config.runner }} 31 | runner_type: ${{ matrix.config.runnerType }} 32 | platform: ${{ matrix.config.platform }} 33 | stable_unstable: ${{ matrix.config.stableUnstable }} 34 | current_branch_tag: ${{ inputs.current_branch_tag }} 35 | is_tag: ${{ inputs.is_tag }} 36 | secrets: 37 | docker_hub_username: ${{ secrets.docker_hub_username }} 38 | docker_hub_token: ${{ secrets.docker_hub_token }} 39 | aws_access_key_id: ${{ secrets.aws_access_key_id }} 40 | aws_secret_access_key: ${{ secrets.aws_secret_access_key }} 41 | 42 | strategy: 43 | fail-fast: false 44 | matrix: 45 | config: 46 | - { 47 | name: "linux/amd64", 48 | platform: "linux/amd64", 49 | stableUnstable: "stable", 50 | runner: "ubuntu-latest", 51 | runnerType: "github-hosted" 52 | } 53 | - { 54 | name: "linux/arm64", 55 | platform: "linux/arm64", 56 | stableUnstable: "stable", 57 | runner: "debian-arm64", 58 | runnerType: "self-hosted" 59 | } 60 | 61 | build-docker-unstable: 62 | if: ${{ inputs.is_tag != 'true' }} 63 | uses: ./.github/workflows/build-docker.yml 64 | with: 65 | runner: ${{ matrix.config.runner }} 66 | runner_type: ${{ matrix.config.runnerType }} 67 | platform: ${{ matrix.config.platform }} 68 | stable_unstable: ${{ matrix.config.stableUnstable }} 69 | current_branch_tag: ${{ inputs.current_branch_tag }} 70 | is_tag: ${{ inputs.is_tag }} 71 | secrets: 72 | docker_hub_username: ${{ secrets.docker_hub_username }} 73 | docker_hub_token: ${{ secrets.docker_hub_token }} 74 | aws_access_key_id: ${{ secrets.aws_access_key_id }} 75 | aws_secret_access_key: ${{ secrets.aws_secret_access_key }} 76 | 77 | strategy: 78 | fail-fast: false 79 | matrix: 80 | config: 81 | - { 82 | name: "linux/amd64", 83 | platform: "linux/amd64", 84 | stableUnstable: "unstable", 85 | runner: "ubuntu-latest", 86 | runnerType: "github-hosted" 87 | } 88 | - { 89 | name: "linux/arm64", 90 | platform: "linux/arm64", 91 | stableUnstable: "unstable", 92 | runner: "debian-arm64", 93 | runnerType: "self-hosted" 94 | } 95 | 96 | publish-manifest-stable: 97 | runs-on: "ubuntu-latest" 98 | needs: [build-docker-stable] 99 | 100 | steps: 101 | 102 | - uses: actions/checkout@v3 103 | 104 | - name: Login to DockerHub 105 | uses: docker/login-action@v2 106 | with: 107 | username: ${{ secrets.docker_hub_username }} 108 | password: ${{ secrets.docker_hub_token }} 109 | 110 | - name: Publish Dockerhub manifest normal image 111 | run: ./local-build.sh version=stable image=normal type=ci step=publish-manifest currentTag=${{ inputs.current_branch_tag }}-normal-stable pushTag=${{ inputs.current_branch_tag }} isTag=${{ inputs.is_tag }} 112 | 113 | - name: Publish Dockerhub manifest full image 114 | run: ./local-build.sh version=stable image=full type=ci step=publish-manifest currentTag=${{ inputs.current_branch_tag }}-full-stable pushTag=${{ inputs.current_branch_tag }}-full isTag=${{ inputs.is_tag }} 115 | 116 | - name: Publish Dockerhub manifest with latest tag for normal image 117 | if: inputs.is_tag == 'true' 118 | run: ./local-build.sh version=stable image=normal type=ci step=publish-manifest currentTag=${{ inputs.current_branch_tag }}-normal-stable pushTag=latest isTag=${{ inputs.is_tag }} 119 | 120 | - name: Publish Dockerhub manifest with latest tag for full image 121 | if: inputs.is_tag == 'true' 122 | run: ./local-build.sh version=stable image=full type=ci step=publish-manifest currentTag=${{ inputs.current_branch_tag }}-full-stable pushTag=latest-full isTag=${{ inputs.is_tag }} 123 | 124 | 125 | - name: Update DockerHub repo description 126 | uses: peter-evans/dockerhub-description@v3 127 | if: inputs.is_tag == 'true' 128 | with: 129 | username: ${{ secrets.docker_hub_username }} 130 | password: ${{ secrets.docker_hub_token }} 131 | repository: orthancteam/orthanc 132 | readme-filepath: README-dockerhub.md 133 | 134 | 135 | publish-manifest-unstable: 136 | runs-on: "ubuntu-latest" 137 | needs: [build-docker-unstable] 138 | 139 | steps: 140 | 141 | - uses: actions/checkout@v3 142 | 143 | - name: Login to DockerHub 144 | uses: docker/login-action@v2 145 | with: 146 | username: ${{ secrets.docker_hub_username }} 147 | password: ${{ secrets.docker_hub_token }} 148 | 149 | - name: Publish Dockerhub manifest normal image 150 | run: ./local-build.sh version=unstable image=normal type=ci step=publish-manifest currentTag=${{ inputs.current_branch_tag }}-normal-unstable pushTag=${{ inputs.current_branch_tag }} isTag=${{ inputs.is_tag }} 151 | 152 | - name: Publish Dockerhub manifest full image 153 | run: ./local-build.sh version=unstable image=full type=ci step=publish-manifest currentTag=${{ inputs.current_branch_tag }}-full-unstable pushTag=${{ inputs.current_branch_tag }}-full isTag=${{ inputs.is_tag }} -------------------------------------------------------------------------------- /docker/orthanc/Dockerfile.builder-base: -------------------------------------------------------------------------------- 1 | ########################## Orthanc builder base 2 | # image to compile Orthanc and its plugins dynamically 3 | ARG BASE_IMAGE_TAG=current 4 | FROM orthancteam/orthanc-runner-base:${BASE_IMAGE_TAG} 5 | 6 | ARG PLATFORM=linux/amd64 7 | 8 | RUN export DEBIAN_FRONTEND=noninteractive 9 | RUN apt-get --assume-yes update 10 | RUN apt-get --assume-yes install wget 11 | RUN apt-get --assume-yes install build-essential 12 | RUN apt-get --assume-yes install unzip 13 | RUN apt-get --assume-yes install uuid-dev 14 | RUN apt-get --assume-yes install apt-utils 15 | RUN apt-get --assume-yes install libcurl4-openssl-dev 16 | RUN apt-get --assume-yes install curl 17 | RUN apt-get --assume-yes install apt-transport-https 18 | RUN apt-get --assume-yes install liblua5.4-dev 19 | RUN apt-get --assume-yes install libgtest-dev 20 | RUN apt-get --assume-yes install libpng-dev 21 | RUN apt-get --assume-yes install libsqlite3-dev 22 | RUN apt-get --assume-yes install libjpeg-dev libboost-all-dev libwrap0-dev libcharls-dev libjsoncpp-dev libpugixml-dev 23 | RUN apt-get --assume-yes install git 24 | RUN apt-get --assume-yes install mercurial 25 | RUN apt-get --assume-yes install zip 26 | RUN apt-get --assume-yes install libpq-dev postgresql-server-dev-all 27 | RUN apt-get --assume-yes install python3-dev 28 | RUN apt-get --assume-yes install unixodbc-dev 29 | RUN apt-get --assume-yes install libgmock-dev 30 | RUN apt-get --assume-yes install protobuf-compiler 31 | RUN apt-get --assume-yes install default-libmysqlclient-dev 32 | RUN apt-get --assume-yes install zlib1g-dev 33 | 34 | 35 | RUN apt-get --assume-yes install cmake 36 | # RUN apt-get --assume-yes install awscli 37 | RUN if [ "$PLATFORM" = "linux/amd64" ]; then curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "/tmp/awscliv2.zip"; fi 38 | RUN if [ "$PLATFORM" = "linux/arm64" ]; then curl "https://awscli.amazonaws.com/awscli-exe-linux-aarch64.zip" -o "/tmp/awscliv2.zip"; fi 39 | WORKDIR /tmp 40 | RUN unzip awscliv2.zip 41 | RUN ./aws/install 42 | 43 | # for orthanc-stl plugin: 44 | RUN apt-get --assume-yes install libgl1-mesa-dev libxt-dev 45 | 46 | RUN apt-get --assume-yes install default-jdk 47 | 48 | # for orthanc-wsi and orthanc-education plugins: 49 | RUN apt-get --assume-yes install libopenslide0 50 | 51 | # # install a recent cmake version (required later by recent vcpkg versions that we don't use now !) 52 | # WORKDIR /tmp 53 | # RUN wget https://github.com/Kitware/CMake/releases/download/v3.23.1/cmake-3.23.1.tar.gz 54 | # RUN tar -zxvf cmake-3.23.1.tar.gz 55 | # WORKDIR /tmp/cmake-3.23.1 56 | # RUN ./bootstrap 57 | # RUN make -j 8 58 | # RUN make install 59 | RUN cmake --version 60 | 61 | # no need to clean apt-cache, it's a build image, we don't care about its size 62 | 63 | RUN mkdir -p /sources 64 | RUN mkdir -p /build 65 | RUN mkdir -p /scripts 66 | RUN mkdir -p /third-party-downloads 67 | 68 | # download most commonly used third-party files to avoid downloading too many files from UCLouvain servers when building 69 | WORKDIR /third-party-downloads 70 | RUN wget https://public-files.orthanc.team/third-party-downloads/VolView-4.1.1.tar.gz 71 | RUN wget https://public-files.orthanc.team/third-party-downloads/aws/aws-c-auth-0.7.1.tar.gz 72 | RUN wget https://public-files.orthanc.team/third-party-downloads/aws/aws-c-cal-0.6.1.tar.gz 73 | RUN wget https://public-files.orthanc.team/third-party-downloads/aws/aws-c-common-0.9.3.tar.gz 74 | RUN wget https://public-files.orthanc.team/third-party-downloads/aws/aws-c-compression-0.2.17.tar.gz 75 | RUN wget https://public-files.orthanc.team/third-party-downloads/aws/aws-c-event-stream-0.3.1.tar.gz 76 | RUN wget https://public-files.orthanc.team/third-party-downloads/aws/aws-c-http-0.7.11.tar.gz 77 | RUN wget https://public-files.orthanc.team/third-party-downloads/aws/aws-c-io-0.13.31.tar.gz 78 | RUN wget https://public-files.orthanc.team/third-party-downloads/aws/aws-c-mqtt-0.9.5.tar.gz 79 | RUN wget https://public-files.orthanc.team/third-party-downloads/aws/aws-c-s3-0.3.14.tar.gz 80 | RUN wget https://public-files.orthanc.team/third-party-downloads/aws/aws-c-sdkutils-0.1.11.tar.gz 81 | RUN wget https://public-files.orthanc.team/third-party-downloads/aws/aws-checksums-0.1.17.tar.gz 82 | RUN wget https://public-files.orthanc.team/third-party-downloads/aws/aws-crt-cpp-0.24.1.tar.gz 83 | RUN wget https://public-files.orthanc.team/third-party-downloads/aws/aws-sdk-cpp-1.11.178.tar.gz 84 | RUN wget https://public-files.orthanc.team/third-party-downloads/boost_1_83_0_bcpdigest-1.12.2.tar.gz 85 | RUN wget https://public-files.orthanc.team/third-party-downloads/boost_1_84_0_bcpdigest-1.12.3.tar.gz 86 | RUN wget https://public-files.orthanc.team/third-party-downloads/boost_1_85_0_bcpdigest-1.12.4.tar.gz 87 | RUN wget https://public-files.orthanc.team/third-party-downloads/boost_1_86_0_bcpdigest-1.12.5.tar.gz 88 | RUN wget https://public-files.orthanc.team/third-party-downloads/curl-8.5.0.tar.gz 89 | RUN wget https://public-files.orthanc.team/third-party-downloads/curl-8.9.0.tar.gz 90 | RUN wget https://public-files.orthanc.team/third-party-downloads/dcmtk-3.6.8.tar.gz 91 | RUN wget https://public-files.orthanc.team/third-party-downloads/gdcm-3.0.22.tar.gz 92 | RUN wget https://public-files.orthanc.team/third-party-downloads/jpegsrc.v9f.tar.gz 93 | RUN wget https://public-files.orthanc.team/third-party-downloads/jsoncpp-1.9.5.tar.gz 94 | RUN wget https://public-files.orthanc.team/third-party-downloads/libcsv-3.0.3.tar.gz 95 | RUN wget https://public-files.orthanc.team/third-party-downloads/libpng-1.6.40.tar.gz 96 | RUN wget https://public-files.orthanc.team/third-party-downloads/nifti_clib-3.0.0.tar.gz 97 | RUN wget https://public-files.orthanc.team/third-party-downloads/openssl-3.1.4.tar.gz 98 | RUN wget https://public-files.orthanc.team/third-party-downloads/protobuf-cpp-3.5.1.tar.gz 99 | RUN wget https://public-files.orthanc.team/third-party-downloads/pugixml-1.14.tar.gz 100 | RUN wget https://public-files.orthanc.team/third-party-downloads/sqlite-amalgamation-3460100.zip 101 | RUN wget https://public-files.orthanc.team/third-party-downloads/three.js-r154-sources.tar.gz 102 | RUN wget https://public-files.orthanc.team/third-party-downloads/VTK-7.1.1.tar.gz 103 | RUN wget https://public-files.orthanc.team/third-party-downloads/zlib-1.3.1.tar.gz 104 | 105 | # for python and java plugin 106 | RUN pip install pystache --break-system-packages 107 | 108 | COPY build-or-download.sh /scripts 109 | -------------------------------------------------------------------------------- /WindowsInstaller/Resources/stone-webviewer.json: -------------------------------------------------------------------------------- 1 | { 2 | "StoneWebViewer" : 3 | { 4 | /** 5 | * Defines how dates are displayed in the UI. If this option is not 6 | * set, the DICOM tags will be displayed as such. "DD" will be 7 | * replaced by the day, "MM" by the month, and "YYYY" by the year. 8 | **/ 9 | // "DateFormat" : "DD/MM/YYYY", 10 | 11 | /** 12 | * Defines how times are displayed in the UI. If this option is not 13 | * set, the DICOM tags will be displayed as such. "hh" will be 14 | * replaced by the hour, "mm" by the minutes, "ss" by the seconds 15 | * and ".f" by the fractions of seconds. 16 | **/ 17 | // "TimeFormat" : "hh:mm:ss.f", 18 | 19 | 20 | /** 21 | * This option allows you to define windowing presets. 22 | * For each preset, you must provide a name, the window width 23 | * and window center. 24 | **/ 25 | "WindowingPresets" : [ 26 | {"Name" : "CT Lung", "WindowCenter" : -400, "WindowWidth" : 1600}, 27 | {"Name" : "CT Abdomen", "WindowCenter" : 60, "WindowWidth" : 400}, 28 | {"Name" : "CT Bone", "WindowCenter" : 300, "WindowWidth" : 1500}, 29 | {"Name" : "CT Brain", "WindowCenter" : 40, "WindowWidth" : 80}, 30 | {"Name" : "CT Chest", "WindowCenter" : 40, "WindowWidth" : 400}, 31 | {"Name" : "CT Angio", "WindowCenter" : 300, "WindowWidth" : 600} 32 | ], 33 | 34 | /** 35 | * Enables/disables the combined tool. This is the default mode 36 | * for mouse interactions. The combined tool allows to access the 37 | * windowing, zoom and pan from a single mouse configuration. The 38 | * behaviour of the combined tool is defined in 39 | * CombinedToolBehaviour. The available mouse actions are 40 | * "Crosshair", "Windowing", "Pan", "Rotate", "Zoom" and 41 | * "MagnifyingGlass". 42 | **/ 43 | "CombinedToolEnabled" : true, 44 | "CombinedToolBehaviour" : { 45 | "LeftMouseButton" : "Windowing", 46 | "MiddleMouseButton" : "Pan", 47 | "RightMouseButton" : "Zoom" 48 | }, 49 | 50 | /** 51 | * Enables/disables the print button. 52 | **/ 53 | "PrintEnabled" : true, 54 | 55 | /** 56 | * Enables/disables the button to download a screenshot of the 57 | * active viewport as a JPEG file. 58 | **/ 59 | "DownloadAsJpegEnabled" : true, 60 | 61 | /** 62 | * Enables/disables the button to download the display study. 63 | * Only used if "OrthancApiRoot" is properly set. 64 | **/ 65 | "DownloadStudyEnabled" : true, 66 | 67 | /** 68 | * The allowed origin for messages corresponding to dynamic actions 69 | * triggered by another Web page using "window.postMessage()". The 70 | * special value "*" will allow any origin, which is an insecure 71 | * value to be used only during development. If this option is not 72 | * set, all the requests for dynamic actions will be rejected. 73 | * https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage 74 | **/ 75 | "ExpectedMessageOrigin" : "http://localhost:8042", 76 | 77 | /** 78 | * Root path of the DICOMweb server. This option is automatically 79 | * set by the Orthanc plugin if missing. 80 | **/ 81 | "DicomWebRoot" : "../dicom-web", 82 | 83 | /** 84 | * Set the size of the cache that stores the DICOM files. This 85 | * size is expressed in megabytes. The default value of 128MB 86 | * should work in most setups, except if very large multiframe 87 | * instances are encountered, which might for instance be the case 88 | * for mammography. Setting this parameter to zero will disable 89 | * the cache, which should only be done for testing. 90 | **/ 91 | "DicomCacheSize" : 128, 92 | 93 | /** 94 | * The following parameter can be set if running the Stone Web 95 | * viewer from Orthanc, but without using the associated plugin 96 | * (e.g. using the "Serve Folders" sample plugin). Using the 97 | * plugin would overwrite this setting. This will enable features 98 | * that are only available if the Orthanc REST API is accessible 99 | * (download of studies, and playing videos). This option is 100 | * typically used by the developers of Stone. 101 | **/ 102 | "OrthancApiRoot" : "..", 103 | 104 | /** 105 | * If option "DownloadDicomDir" is set to "true", the Stone Web 106 | * viewer will create DICOMDIR media archives (as generated by the 107 | * route "/studies/{id}/media" of Orthanc), instead of archives 108 | * containing a human-readable hierarchy of folders (as generated 109 | * by the route "/studies/{id}/archive"). 110 | **/ 111 | "DownloadDicomDir" : false, 112 | 113 | /** 114 | * By setting option "InstitutionLogo" to an URL containing an 115 | * image, this logo will be displayed at the bottom-left of the 116 | * Stone Web viewer. 117 | **/ 118 | "InstitutionLogo" : "", 119 | 120 | /** 121 | * Define a list of modality type that the viewer will ignore. 122 | **/ 123 | "SkipSeriesFromModalities": ["SR", "SEG", "PR"], 124 | 125 | /** 126 | * Whether to display the info panel at startup. Allowed values: 127 | * "Always", "Never", "User". With "User", the user can decide to 128 | * show or not the info panel in the user preferences panel (this 129 | * is implemented using a cookie). (New in Stone Web viewer 2.4) 130 | **/ 131 | "ShowInfoPanelAtStartup": "User", 132 | 133 | /** 134 | * Whether to give access to the user preferences window. (New in 135 | * Stone Web viewer 2.4) 136 | **/ 137 | "ShowUserPreferencesButton" : true, 138 | 139 | /** 140 | * Display a "not for diagnostic usage" disclaimer above the list 141 | * of studies/series. (New in Stone Web viewer 2.4) 142 | **/ 143 | "ShowNotForDiagnosticUsageDisclaimer": true, 144 | 145 | /** 146 | * HTTP headers to be set in each request to the DICOMweb server. 147 | * Note that the value of the headers can be taken from the 148 | * environment variables. 149 | **/ 150 | "DicomWebHttpHeaders" : { 151 | /* "Authorization" : "Bearer ${USER}" */ 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /WindowsInstaller/Resources/CMake/DownloadPackage.cmake: -------------------------------------------------------------------------------- 1 | macro(GetUrlFilename TargetVariable Url) 2 | string(REGEX REPLACE "^.*/" "" ${TargetVariable} "${Url}") 3 | endmacro() 4 | 5 | 6 | macro(GetUrlExtension TargetVariable Url) 7 | #string(REGEX REPLACE "^.*/[^.]*\\." "" TMP "${Url}") 8 | string(REGEX REPLACE "^.*\\." "" TMP "${Url}") 9 | string(TOLOWER "${TMP}" "${TargetVariable}") 10 | endmacro() 11 | 12 | 13 | 14 | ## 15 | ## Setup the patch command-line tool 16 | ## 17 | 18 | if (NOT ORTHANC_DISABLE_PATCH) 19 | if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows") 20 | set(PATCH_EXECUTABLE ${CMAKE_CURRENT_LIST_DIR}/../ThirdParty/patch/patch.exe) 21 | if (NOT EXISTS ${PATCH_EXECUTABLE}) 22 | message(FATAL_ERROR "Unable to find the patch.exe tool that is shipped with Orthanc") 23 | endif() 24 | 25 | else () 26 | find_program(PATCH_EXECUTABLE patch) 27 | if (${PATCH_EXECUTABLE} MATCHES "PATCH_EXECUTABLE-NOTFOUND") 28 | message(FATAL_ERROR "Please install the 'patch' standard command-line tool") 29 | endif() 30 | endif() 31 | endif() 32 | 33 | 34 | 35 | ## 36 | ## Check the existence of the required decompression tools 37 | ## 38 | 39 | if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows") 40 | find_program(ZIP_EXECUTABLE 7z 41 | PATHS 42 | "$ENV{ProgramFiles}/7-Zip" 43 | "$ENV{ProgramW6432}/7-Zip" 44 | ) 45 | 46 | if (${ZIP_EXECUTABLE} MATCHES "ZIP_EXECUTABLE-NOTFOUND") 47 | message(FATAL_ERROR "Please install the '7-zip' software (http://www.7-zip.org/)") 48 | endif() 49 | 50 | else() 51 | find_program(UNZIP_EXECUTABLE unzip) 52 | if (${UNZIP_EXECUTABLE} MATCHES "UNZIP_EXECUTABLE-NOTFOUND") 53 | message(FATAL_ERROR "Please install the 'unzip' package") 54 | endif() 55 | 56 | find_program(TAR_EXECUTABLE tar) 57 | if (${TAR_EXECUTABLE} MATCHES "TAR_EXECUTABLE-NOTFOUND") 58 | message(FATAL_ERROR "Please install the 'tar' package") 59 | endif() 60 | endif() 61 | 62 | 63 | macro(DownloadPackage MD5 Url TargetDirectory) 64 | if (NOT IS_DIRECTORY "${TargetDirectory}") 65 | GetUrlFilename(TMP_FILENAME "${Url}") 66 | 67 | set(TMP_PATH "${CMAKE_SOURCE_DIR}/ThirdPartyDownloads/${TMP_FILENAME}") 68 | if (NOT EXISTS "${TMP_PATH}") 69 | message("Downloading ${Url}") 70 | 71 | # This fixes issue 6: "I think cmake shouldn't download the 72 | # packages which are not in the system, it should stop and let 73 | # user know." 74 | # https://code.google.com/p/orthanc/issues/detail?id=6 75 | if (NOT STATIC_BUILD AND NOT ALLOW_DOWNLOADS) 76 | message(FATAL_ERROR "CMake is not allowed to download from Internet. Please set the ALLOW_DOWNLOADS option to ON") 77 | endif() 78 | 79 | file(DOWNLOAD "${Url}" "${TMP_PATH}" 80 | SHOW_PROGRESS EXPECTED_MD5 "${MD5}" 81 | TIMEOUT 60 INACTIVITY_TIMEOUT 60) 82 | else() 83 | message("Using local copy of ${Url}") 84 | endif() 85 | 86 | GetUrlExtension(TMP_EXTENSION "${Url}") 87 | #message(${TMP_EXTENSION}) 88 | message("Uncompressing ${TMP_FILENAME}") 89 | 90 | if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows") 91 | # How to silently extract files using 7-zip 92 | # http://superuser.com/questions/331148/7zip-command-line-extract-silently-quietly 93 | 94 | if (("${TMP_EXTENSION}" STREQUAL "gz") OR 95 | ("${TMP_EXTENSION}" STREQUAL "tgz") OR 96 | ("${TMP_EXTENSION}" STREQUAL "xz")) 97 | execute_process( 98 | COMMAND ${ZIP_EXECUTABLE} e -y ${TMP_PATH} 99 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 100 | RESULT_VARIABLE Failure 101 | OUTPUT_QUIET 102 | ) 103 | 104 | if (Failure) 105 | message(FATAL_ERROR "Error while running the uncompression tool") 106 | endif() 107 | 108 | if ("${TMP_EXTENSION}" STREQUAL "tgz") 109 | string(REGEX REPLACE ".tgz$" ".tar" TMP_FILENAME2 "${TMP_FILENAME}") 110 | elseif ("${TMP_EXTENSION}" STREQUAL "gz") 111 | string(REGEX REPLACE ".gz$" "" TMP_FILENAME2 "${TMP_FILENAME}") 112 | elseif ("${TMP_EXTENSION}" STREQUAL "xz") 113 | string(REGEX REPLACE ".xz" "" TMP_FILENAME2 "${TMP_FILENAME}") 114 | endif() 115 | 116 | execute_process( 117 | COMMAND ${ZIP_EXECUTABLE} x -y ${TMP_FILENAME2} 118 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 119 | RESULT_VARIABLE Failure 120 | OUTPUT_QUIET 121 | ) 122 | elseif ("${TMP_EXTENSION}" STREQUAL "zip") 123 | execute_process( 124 | COMMAND ${ZIP_EXECUTABLE} x -y ${TMP_PATH} 125 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 126 | RESULT_VARIABLE Failure 127 | OUTPUT_QUIET 128 | ) 129 | else() 130 | message(FATAL_ERROR "Support your platform here") 131 | endif() 132 | 133 | else() 134 | if ("${TMP_EXTENSION}" STREQUAL "zip") 135 | execute_process( 136 | COMMAND sh -c "${UNZIP_EXECUTABLE} -q ${TMP_PATH}" 137 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 138 | RESULT_VARIABLE Failure 139 | ) 140 | elseif (("${TMP_EXTENSION}" STREQUAL "gz") OR ("${TMP_EXTENSION}" STREQUAL "tgz")) 141 | #message("tar xvfz ${TMP_PATH}") 142 | execute_process( 143 | COMMAND sh -c "${TAR_EXECUTABLE} xfz ${TMP_PATH}" 144 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 145 | RESULT_VARIABLE Failure 146 | ) 147 | elseif ("${TMP_EXTENSION}" STREQUAL "bz2") 148 | execute_process( 149 | COMMAND sh -c "${TAR_EXECUTABLE} xfj ${TMP_PATH}" 150 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 151 | RESULT_VARIABLE Failure 152 | ) 153 | elseif ("${TMP_EXTENSION}" STREQUAL "xz") 154 | execute_process( 155 | COMMAND sh -c "${TAR_EXECUTABLE} xf ${TMP_PATH}" 156 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 157 | RESULT_VARIABLE Failure 158 | ) 159 | else() 160 | message(FATAL_ERROR "Unknown package format.") 161 | endif() 162 | endif() 163 | 164 | if (Failure) 165 | message(FATAL_ERROR "Error while running the uncompression tool") 166 | endif() 167 | 168 | if (NOT IS_DIRECTORY "${TargetDirectory}") 169 | message(FATAL_ERROR "The package was not uncompressed at the proper location. Check the CMake instructions.") 170 | endif() 171 | endif() 172 | endmacro() 173 | -------------------------------------------------------------------------------- /docker/integration-tests/orthanc-tests/Dockerfile: -------------------------------------------------------------------------------- 1 | # mercurial does not work anymore on jodogne/orthanc-tests -> use a specific image 2 | FROM ubuntu:22.04 AS ubuntu-hg 3 | 4 | RUN apt-get update 5 | RUN DEBIAN_FRONTEND=noninteractive apt-get --assume-yes install mercurial 6 | 7 | WORKDIR / 8 | 9 | ARG ORTHANC_TESTS_REVISION=default 10 | RUN hg clone https://orthanc.uclouvain.be/hg/orthanc-tests/ -r $ORTHANC_TESTS_REVISION 11 | 12 | ############################################################## 13 | FROM jodogne/orthanc-tests AS orthanc-tests 14 | RUN mkdir /tests 15 | WORKDIR /tests 16 | 17 | COPY --from=ubuntu-hg /orthanc-tests /tests/orthanc-tests 18 | RUN ls -al /tests/ 19 | RUN mkdir /tmp/orthanc-tests/ 20 | 21 | RUN mkdir /scripts 22 | COPY wait-for-it.sh /scripts 23 | 24 | ENTRYPOINT /scripts/wait-for-it.sh orthanc-under-tests:8042 -t 60 && python /tests/orthanc-tests/Tests/Run.py --server=orthanc-under-tests --force --docker -- -v 25 | 26 | ############################################################## 27 | FROM python:2.7 AS python2-7-base-image 28 | 29 | RUN apt-get update 30 | RUN DEBIAN_FRONTEND=noninteractive apt-get --assume-yes install dcmtk 31 | 32 | RUN pip install easywebdav 33 | RUN pip install httplib2 34 | RUN pip install pillow 35 | RUN pip install pydicom==1.4.1 36 | RUN pip install pynetdicom==1.5.6 37 | 38 | RUN mkdir /tests 39 | WORKDIR /tests 40 | 41 | COPY --from=ubuntu-hg /orthanc-tests /tests/orthanc-tests 42 | RUN ls -al /tests/ 43 | RUN mkdir /tmp/orthanc-tests/ 44 | 45 | RUN mkdir /scripts 46 | COPY wait-for-it.sh /scripts 47 | 48 | 49 | ############################################################## 50 | # at some point, the easywebdav installation broke after an update of python:3.11 -> we use a snapshot 51 | FROM orthancteam/python-snapshots:3.11-for-integ-tests AS python3-base-image 52 | 53 | RUN apt-get update 54 | RUN DEBIAN_FRONTEND=noninteractive apt-get --assume-yes install dcmtk 55 | 56 | RUN pip install httplib2 --break-system-package 57 | RUN pip install pillow --break-system-package 58 | RUN pip install pydicom==3.0.1 --break-system-package 59 | # TODO: upgrade to pynetdicom>=3.0.1 60 | RUN pip install pynetdicom==2.1.1 --break-system-package 61 | RUN pip install 'easywebdav @ git+https://github.com/Marpache9131/easywebdav@511967ec374061161f2b3b67fb7b164fcc78143c' --break-system-package 62 | 63 | # remove echoscu... from pynetdicom to make sure we use the ones from DCMTK 64 | RUN rm /usr/local/bin/findscu /usr/local/bin/storescu /usr/local/bin/echoscu /usr/local/bin/movescu /usr/local/bin/getscu 65 | 66 | RUN mkdir /tests 67 | WORKDIR /tests 68 | 69 | COPY --from=ubuntu-hg /orthanc-tests /tests/orthanc-tests 70 | RUN ls -al /tests/ 71 | RUN mkdir /tmp/orthanc-tests/ 72 | 73 | RUN mkdir /scripts 74 | COPY wait-for-it.sh /scripts 75 | 76 | ############################################################## 77 | FROM python3-base-image AS orthanc-tests-dicomweb 78 | 79 | ENTRYPOINT /scripts/wait-for-it.sh orthanc-under-tests:8042 -t 60 && python /tests/orthanc-tests/Plugins/DicomWeb/Run.py --server=orthanc-under-tests --force -- -v 80 | 81 | ############################################################## 82 | FROM orthanc-tests AS orthanc-tests-worklists 83 | 84 | ENTRYPOINT /scripts/wait-for-it.sh orthanc-under-tests:8042 -t 60 && python /tests/orthanc-tests/Plugins/Worklists/Run.py --server=orthanc-under-tests -- -v 85 | 86 | ############################################################## 87 | FROM orthanc-tests AS orthanc-tests-recycling 88 | 89 | ENTRYPOINT /scripts/wait-for-it.sh orthanc-under-tests:8042 -t 60 && python /tests/orthanc-tests/Plugins/Recycling/Run.py --server=orthanc-under-tests --force -- -v 90 | 91 | ############################################################## 92 | FROM orthanc-tests AS orthanc-tests-transfers 93 | 94 | ENTRYPOINT /scripts/wait-for-it.sh orthanc-under-tests:8042 -t 60 && python /tests/orthanc-tests/Plugins/Transfers/Run.py --server=orthanc-under-tests --force -- -v 95 | 96 | ############################################################## 97 | FROM python3-base-image AS orthanc-tests-wsi 98 | 99 | RUN apt-get update 100 | RUN DEBIAN_FRONTEND=noninteractive apt-get install -y libtiff-tools 101 | 102 | RUN mkdir /apps 103 | 104 | RUN wget https://orthanc.uclouvain.be/downloads/linux-standard-base/orthanc-wsi/3.3/OrthancWSIDicomToTiff --output-document /apps/OrthancWSIDicomToTiff --quiet 105 | RUN wget https://orthanc.uclouvain.be/downloads/linux-standard-base/orthanc-wsi/3.3/OrthancWSIDicomizer --output-document /apps/OrthancWSIDicomizer --quiet 106 | 107 | RUN chmod +x /apps/* 108 | 109 | ENTRYPOINT /scripts/wait-for-it.sh orthanc-under-tests:8042 -t 60 && python /tests/orthanc-tests/Plugins/WSI/Run.py --server=orthanc-under-tests --force --dicomizer=/apps/OrthancWSIDicomizer --to-tiff=/apps/OrthancWSIDicomToTiff -- -v 110 | 111 | ############################################################## 112 | FROM python3-base-image AS orthanc-tests-webdav 113 | 114 | ENTRYPOINT /scripts/wait-for-it.sh orthanc-under-tests:8042 -t 60 && python /tests/orthanc-tests/Plugins/WebDav/Run.py --server=orthanc-under-tests --force -- -v 115 | 116 | ############################################################## 117 | FROM python3-base-image AS orthanc-tests-cget 118 | 119 | ENTRYPOINT /scripts/wait-for-it.sh orthanc-under-tests:8042 -t 60 && python /tests/orthanc-tests/Plugins/CGet/Run.py --server=orthanc-under-tests --force -- -v 120 | 121 | ############################################################## 122 | FROM python3-base-image AS orthanc-tests-tls-no-check-client-generate-config 123 | WORKDIR /tls 124 | ENTRYPOINT python /tests/orthanc-tests/Tests/CheckDicomTls.py --config-no-check-client 125 | 126 | ############################################################## 127 | FROM python3-base-image AS orthanc-tests-tls-no-check-client 128 | WORKDIR /tls 129 | ENTRYPOINT /scripts/wait-for-it.sh orthanc-under-tests:8042 -t 60 && python /tests/orthanc-tests/Tests/CheckDicomTls.py --server=orthanc-under-tests --force -- -v OrthancNoCheckClient 130 | 131 | ############################################################## 132 | FROM python3-base-image AS orthanc-tests-tls-check-client-generate-config 133 | WORKDIR /tls 134 | ENTRYPOINT python /tests/orthanc-tests/Tests/CheckDicomTls.py --config-check-client 135 | 136 | ############################################################## 137 | FROM python3-base-image AS orthanc-tests-tls-check-client 138 | WORKDIR /tls 139 | ENTRYPOINT /scripts/wait-for-it.sh orthanc-under-tests:8042 -t 60 && python /tests/orthanc-tests/Tests/CheckDicomTls.py --server=orthanc-under-tests --force -- -v OrthancCheckClient 140 | -------------------------------------------------------------------------------- /bash-helpers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # rewrite pushd/popd such that they do not produce any output in bash functions (https://stackoverflow.com/questions/25288194/dont-display-pushd-popd-stack-across-several-bash-scripts-quiet-pushd-popd) 4 | pushd () { 5 | command pushd "$@" > /dev/null 6 | } 7 | 8 | popd () { 9 | command popd "$@" > /dev/null 10 | } 11 | 12 | 13 | getFromMatrix() { # $1 = name, $2 = field, $3 = defaultValue 14 | value=$(cat build-matrix.json | jq -r ".configs[] | select( .name == \"$1\").$2") 15 | if [[ $value == "null" ]]; then 16 | echo $3 17 | else 18 | echo $value 19 | fi 20 | } 21 | 22 | getIntegTestsRevision() { # $1 = stable/unstable 23 | value=$(cat build-matrix.json | jq -r ".integrationTests.$1") 24 | echo $value 25 | } 26 | 27 | getArtifactsMacOS() { # $1 = name, $2 = version (stable or unstable) 28 | if [[ $2 == "unstable" ]]; then 29 | 30 | artifacts=$(getFromMatrix $1 unstableArtifactsMacOS) 31 | 32 | if [[ $artifacts == "" ]]; then 33 | artifacts=$(getFromMatrix $1 artifactsMacOS) 34 | fi 35 | 36 | else 37 | 38 | artifacts=$(getFromMatrix $1 artifactsMacOS) 39 | 40 | fi 41 | 42 | echo $artifacts 43 | } 44 | 45 | getBranchTagToBuildMacOS() { # $1 = name, $2 = version (stable or unstable) 46 | if [[ $2 == "stable" ]]; then 47 | 48 | revision=$(getFromMatrix $1 stableMacOS) 49 | 50 | if [[ $revision == "" ]]; then 51 | revision=$(getFromMatrix $1 stable) 52 | fi 53 | 54 | else 55 | 56 | revision=$(getFromMatrix $1 unstableMacOS) 57 | 58 | if [[ $revision == "" ]]; then 59 | revision=$(getFromMatrix $1 unstable) 60 | fi 61 | 62 | fi 63 | 64 | echo $revision 65 | } 66 | 67 | getPrebuildStepMacOS() { # $1 = name, $2 = version (stable or unstable) 68 | if [[ $2 == "stable" ]]; then 69 | prebuild=$(getFromMatrix $1 preBuildStableMacOS "") 70 | else 71 | prebuild=$(getFromMatrix $1 preBuildUnstableMacOS "") 72 | fi 73 | 74 | echo $prebuild 75 | } 76 | 77 | getCustomBuildMacOS() { # $1 = name, $2 = version (stable or unstable) 78 | if [[ $2 == "stable" ]]; then 79 | prebuild=$(getFromMatrix $1 customBuildMacOS "") 80 | else 81 | prebuild=$(getFromMatrix $1 customBuildMacOS "") 82 | fi 83 | 84 | echo $prebuild 85 | } 86 | 87 | getArtifactsWin() { # $1 = name, $2 = version (stable or unstable) 88 | if [[ $2 == "unstable" ]]; then 89 | 90 | artifacts=$(getFromMatrix $1 unstableArtifactsWin) 91 | 92 | if [[ $artifacts == "" ]]; then 93 | artifacts=$(getFromMatrix $1 artifactsWin) 94 | fi 95 | 96 | else 97 | 98 | artifacts=$(getFromMatrix $1 artifactsWin) 99 | 100 | fi 101 | 102 | echo $artifacts 103 | } 104 | 105 | getBranchTagToBuildWin() { # $1 = name, $2 = version (stable or unstable) 106 | if [[ $2 == "stable" ]]; then 107 | 108 | revision=$(getFromMatrix $1 stableWin) 109 | 110 | if [[ $revision == "" ]]; then 111 | revision=$(getFromMatrix $1 stable) 112 | fi 113 | 114 | else 115 | 116 | revision=$(getFromMatrix $1 unstableWin) 117 | 118 | if [[ $revision == "" ]]; then 119 | revision=$(getFromMatrix $1 unstable) 120 | fi 121 | 122 | fi 123 | 124 | echo $revision 125 | } 126 | 127 | getPrebuildStepWin() { # $1 = name, $2 = version (stable or unstable) 128 | if [[ $2 == "stable" ]]; then 129 | prebuild=$(getFromMatrix $1 preBuildStableWin "") 130 | 131 | if [[ $prebuild == "" ]]; then 132 | prebuild=$(getFromMatrix $1 preBuildWin "") 133 | fi 134 | else 135 | prebuild=$(getFromMatrix $1 preBuildUnstableWin "") 136 | 137 | if [[ $prebuild == "" ]]; then 138 | prebuild=$(getFromMatrix $1 preBuildWin "") 139 | fi 140 | fi 141 | 142 | echo $prebuild 143 | } 144 | 145 | getCustomBuildWin() { # $1 = name, $2 = version (stable or unstable) 146 | if [[ $2 == "stable" ]]; then 147 | prebuild=$(getFromMatrix $1 customBuildWin "") 148 | else 149 | prebuild=$(getFromMatrix $1 customBuildWin "") 150 | fi 151 | 152 | echo $prebuild 153 | } 154 | 155 | 156 | getBranchTagToBuildDocker() { # $1 = name, $2 = version (stable or unstable) 157 | if [[ $2 == "stable" ]]; then 158 | 159 | revision=$(getFromMatrix $1 stableDocker) 160 | 161 | if [[ $revision == "" ]]; then 162 | revision=$(getFromMatrix $1 stable) 163 | fi 164 | 165 | else 166 | 167 | revision=$(getFromMatrix $1 unstableDocker) 168 | 169 | if [[ $revision == "" ]]; then 170 | revision=$(getFromMatrix $1 unstable) 171 | fi 172 | 173 | fi 174 | 175 | echo $revision 176 | } 177 | 178 | getBranchTagToBuildWin() { # $1 = name, $2 = version (stable or unstable) 179 | if [[ $2 == "stable" ]]; then 180 | 181 | revision=$(getFromMatrix $1 stableWin) 182 | 183 | if [[ $revision == "" ]]; then 184 | revision=$(getFromMatrix $1 stable) 185 | fi 186 | 187 | else 188 | 189 | revision=$(getFromMatrix $1 unstableWin) 190 | 191 | if [[ $revision == "" ]]; then 192 | revision=$(getFromMatrix $1 unstable) 193 | fi 194 | 195 | fi 196 | 197 | echo $revision 198 | } 199 | 200 | getHgCommitId() { # $1 = repo, $2 = branch/tag/revision 201 | commit_id=$(hg identify $1 -r $2) 202 | echo $commit_id 203 | } 204 | 205 | getGitCommitId() { # $1 = repo, $2 = branch/tag/revision 206 | tmp=$(mktemp -d -t git-check-last-commit-XXXXXXXXXXX) 207 | git clone --quiet --filter=blob:none --no-checkout $1 $tmp 208 | pushd $tmp 209 | git checkout $2 &> /dev/null 210 | local commit_id=$(git rev-parse $2) 211 | popd 212 | rm -rf $tmp 213 | 214 | echo $commit_id 215 | } 216 | 217 | getCommitId() { # $1 = name, $2 = version (stable or unstable), $3 = platform (macos/win/docker), $4 = skipCommitCheck (0/1), $5 = throttle (0/1) 218 | 219 | if [[ $3 == "macos" ]]; then 220 | revision=$(getBranchTagToBuildMacOS $1 $2) 221 | elif [[ $3 == "win" ]]; then 222 | revision=$(getBranchTagToBuildWin $1 $2) 223 | else 224 | revision=$(getBranchTagToBuildDocker $1 $2) 225 | fi 226 | 227 | if [[ $4 == "1" ]]; then 228 | echo $revision 229 | return 230 | fi 231 | 232 | if [[ $5 == "1" ]]; then 233 | # throttle on CI because we get a lot of bad gateway errors on UCLouvain server 234 | sleep 1 235 | fi 236 | 237 | # get the last commit id for this revision 238 | repo=$(getFromMatrix $1 repo) 239 | repoType=$(getFromMatrix $1 repoType) 240 | 241 | if [[ $repoType == "hg" ]]; then 242 | 243 | commit_id=$(getHgCommitId $repo $revision) 244 | 245 | elif [[ $repoType == "git" ]]; then 246 | 247 | commit_id=$(getGitCommitId $repo $revision) 248 | 249 | fi 250 | 251 | echo $commit_id 252 | } 253 | -------------------------------------------------------------------------------- /.github/workflows/all-builds.yml: -------------------------------------------------------------------------------- 1 | name: all-builds 2 | 3 | on: 4 | schedule: 5 | - cron: "0 23 * * *" 6 | push: 7 | branches: 8 | - '*' 9 | tags: 10 | - '*' 11 | 12 | pull_request: 13 | branches: [ master ] 14 | 15 | concurrency: 16 | group: branch-or-tag 17 | cancel-in-progress: ${{ startsWith(github.ref, 'refs/tags/') }} 18 | 19 | jobs: 20 | pre-build: 21 | uses: ./.github/workflows/pre-build.yml 22 | 23 | build-stone-wasm-stable: 24 | if: ${{ github.ref == 'refs/heads/master' || needs.pre-build.outputs.is_tag == 'true' }} 25 | needs: [pre-build] 26 | uses: ./.github/workflows/build-stone-wasm.yml 27 | with: 28 | is_tag: ${{ needs.pre-build.outputs.is_tag }} 29 | stable_unstable: stable 30 | current_branch_tag: ${{ needs.pre-build.outputs.current_branch_tag }} 31 | secrets: 32 | aws_access_key_id: ${{ secrets.OT_AWS_ACCESS_KEY_ID }} 33 | aws_secret_access_key: ${{ secrets.OT_AWS_SECRET_ACCESS_KEY }} 34 | 35 | build-stone-wasm-unstable: 36 | if: ${{ needs.pre-build.outputs.is_tag == 'false' }} 37 | needs: [pre-build] 38 | uses: ./.github/workflows/build-stone-wasm.yml 39 | with: 40 | is_tag: ${{ needs.pre-build.outputs.is_tag }} 41 | stable_unstable: unstable 42 | current_branch_tag: ${{ needs.pre-build.outputs.current_branch_tag }} 43 | secrets: 44 | aws_access_key_id: ${{ secrets.OT_AWS_ACCESS_KEY_ID }} 45 | aws_secret_access_key: ${{ secrets.OT_AWS_SECRET_ACCESS_KEY }} 46 | 47 | build-volview-dist-stable: 48 | if: ${{ github.ref == 'refs/heads/master' || needs.pre-build.outputs.is_tag == 'true' }} 49 | needs: [pre-build] 50 | uses: ./.github/workflows/build-volview-dist.yml 51 | with: 52 | is_tag: ${{ needs.pre-build.outputs.is_tag }} 53 | stable_unstable: stable 54 | current_branch_tag: ${{ needs.pre-build.outputs.current_branch_tag }} 55 | secrets: 56 | aws_access_key_id: ${{ secrets.OT_AWS_ACCESS_KEY_ID }} 57 | aws_secret_access_key: ${{ secrets.OT_AWS_SECRET_ACCESS_KEY }} 58 | 59 | build-volview-dist-unstable: 60 | if: ${{ needs.pre-build.outputs.is_tag == 'false' }} 61 | needs: [pre-build] 62 | uses: ./.github/workflows/build-volview-dist.yml 63 | with: 64 | is_tag: ${{ needs.pre-build.outputs.is_tag }} 65 | stable_unstable: unstable 66 | current_branch_tag: ${{ needs.pre-build.outputs.current_branch_tag }} 67 | secrets: 68 | aws_access_key_id: ${{ secrets.OT_AWS_ACCESS_KEY_ID }} 69 | aws_secret_access_key: ${{ secrets.OT_AWS_SECRET_ACCESS_KEY }} 70 | 71 | win-stable-build: 72 | if: ${{ github.ref == 'refs/heads/master' || needs.pre-build.outputs.is_tag == 'true' }} 73 | needs: [pre-build, build-stone-wasm-stable] 74 | uses: ./.github/workflows/build-win-binaries.yml 75 | with: 76 | is_tag: ${{ needs.pre-build.outputs.is_tag }} 77 | stable_unstable: stable 78 | current_branch_tag: ${{ needs.pre-build.outputs.current_branch_tag }} 79 | secrets: 80 | aws_access_key_id: ${{ secrets.OT_AWS_ACCESS_KEY_ID }} 81 | aws_secret_access_key: ${{ secrets.OT_AWS_SECRET_ACCESS_KEY }} 82 | 83 | win-unstable-build: 84 | if: ${{ needs.pre-build.outputs.is_tag == 'false' }} 85 | needs: [pre-build, build-stone-wasm-unstable] 86 | uses: ./.github/workflows/build-win-binaries.yml 87 | with: 88 | is_tag: ${{ needs.pre-build.outputs.is_tag }} 89 | stable_unstable: unstable 90 | current_branch_tag: ${{ needs.pre-build.outputs.current_branch_tag }} 91 | secrets: 92 | aws_access_key_id: ${{ secrets.OT_AWS_ACCESS_KEY_ID }} 93 | aws_secret_access_key: ${{ secrets.OT_AWS_SECRET_ACCESS_KEY }} 94 | 95 | macos-stable-build: 96 | if: ${{ github.ref == 'refs/heads/master' || needs.pre-build.outputs.is_tag == 'true' }} 97 | needs: [pre-build, build-stone-wasm-stable, build-volview-dist-stable] 98 | uses: ./.github/workflows/build-macos-binaries.yml 99 | with: 100 | is_tag: ${{ needs.pre-build.outputs.is_tag }} 101 | stable_unstable: stable 102 | current_branch_tag: ${{ needs.pre-build.outputs.current_branch_tag }} 103 | secrets: 104 | aws_access_key_id: ${{ secrets.OT_AWS_ACCESS_KEY_ID }} 105 | aws_secret_access_key: ${{ secrets.OT_AWS_SECRET_ACCESS_KEY }} 106 | 107 | macos-unstable-build: 108 | if: ${{ needs.pre-build.outputs.is_tag == 'false' }} 109 | needs: [pre-build, build-stone-wasm-unstable, build-volview-dist-unstable] 110 | uses: ./.github/workflows/build-macos-binaries.yml 111 | with: 112 | is_tag: ${{ needs.pre-build.outputs.is_tag }} 113 | stable_unstable: unstable 114 | current_branch_tag: ${{ needs.pre-build.outputs.current_branch_tag }} 115 | secrets: 116 | aws_access_key_id: ${{ secrets.OT_AWS_ACCESS_KEY_ID }} 117 | aws_secret_access_key: ${{ secrets.OT_AWS_SECRET_ACCESS_KEY }} 118 | 119 | 120 | macos-stable-package: 121 | if: ${{ github.ref == 'refs/heads/master' || needs.pre-build.outputs.is_tag == 'true' }} 122 | needs: [pre-build, macos-stable-build] 123 | uses: ./.github/workflows/build-macos-package.yml 124 | with: 125 | is_tag: ${{ needs.pre-build.outputs.is_tag }} 126 | stable_unstable: stable 127 | current_branch_tag: ${{ needs.pre-build.outputs.current_branch_tag }} 128 | secrets: 129 | aws_access_key_id: ${{ secrets.OT_AWS_ACCESS_KEY_ID }} 130 | aws_secret_access_key: ${{ secrets.OT_AWS_SECRET_ACCESS_KEY }} 131 | 132 | macos-unstable-package: 133 | if: ${{ needs.pre-build.outputs.is_tag == 'false' }} 134 | needs: [pre-build, macos-unstable-build] 135 | uses: ./.github/workflows/build-macos-package.yml 136 | with: 137 | is_tag: ${{ needs.pre-build.outputs.is_tag }} 138 | stable_unstable: unstable 139 | current_branch_tag: ${{ needs.pre-build.outputs.current_branch_tag }} 140 | secrets: 141 | aws_access_key_id: ${{ secrets.OT_AWS_ACCESS_KEY_ID }} 142 | aws_secret_access_key: ${{ secrets.OT_AWS_SECRET_ACCESS_KEY }} 143 | 144 | 145 | build-windows-installer: 146 | if: ${{ github.ref == 'refs/heads/master' || needs.pre-build.outputs.is_tag == 'true' }} 147 | needs: [pre-build, win-stable-build] #, TODO: build win binaries as well build-win-binaries-unstable] 148 | uses: ./.github/workflows/build-windows-installer.yml 149 | with: 150 | is_tag: ${{ needs.pre-build.outputs.is_tag }} 151 | stable_unstable: unstable 152 | current_branch_tag: ${{ needs.pre-build.outputs.current_branch_tag }} 153 | secrets: 154 | aws_access_key_id: ${{ secrets.OT_AWS_ACCESS_KEY_ID }} 155 | aws_secret_access_key: ${{ secrets.OT_AWS_SECRET_ACCESS_KEY }} 156 | 157 | 158 | build-docker: 159 | needs: [pre-build] 160 | uses: ./.github/workflows/build-all-dockers.yml 161 | with: 162 | is_tag: ${{ needs.pre-build.outputs.is_tag }} 163 | current_branch_tag: ${{ needs.pre-build.outputs.current_branch_tag }} 164 | secrets: 165 | docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }} 166 | docker_hub_token: ${{ secrets.DOCKERHUB_TOKEN }} 167 | aws_access_key_id: ${{ secrets.OT_AWS_ACCESS_KEY_ID }} 168 | aws_secret_access_key: ${{ secrets.OT_AWS_SECRET_ACCESS_KEY }} -------------------------------------------------------------------------------- /WindowsInstaller/Resources/CMake/Compiler.cmake: -------------------------------------------------------------------------------- 1 | # This file sets all the compiler-related flags 2 | 3 | if (CMAKE_CROSSCOMPILING) 4 | # Cross-compilation necessarily implies standalone and static build 5 | SET(STATIC_BUILD ON) 6 | SET(STANDALONE_BUILD ON) 7 | endif() 8 | 9 | if (CMAKE_COMPILER_IS_GNUCXX) 10 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-long-long -Wno-implicit-function-declaration") 11 | # --std=c99 makes libcurl not to compile 12 | # -pedantic gives a lot of warnings on OpenSSL 13 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -Wno-variadic-macros") 14 | 15 | if (CMAKE_CROSSCOMPILING) 16 | # http://stackoverflow.com/a/3543845/881731 17 | set(CMAKE_RC_COMPILE_OBJECT " -O coff -I ") 18 | endif() 19 | 20 | elseif (MSVC) 21 | # Use static runtime under Visual Studio 22 | # http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace 23 | # http://stackoverflow.com/a/6510446 24 | foreach(flag_var 25 | CMAKE_C_FLAGS_DEBUG 26 | CMAKE_CXX_FLAGS_DEBUG 27 | CMAKE_C_FLAGS_RELEASE 28 | CMAKE_CXX_FLAGS_RELEASE 29 | CMAKE_C_FLAGS_MINSIZEREL 30 | CMAKE_CXX_FLAGS_MINSIZEREL 31 | CMAKE_C_FLAGS_RELWITHDEBINFO 32 | CMAKE_CXX_FLAGS_RELWITHDEBINFO) 33 | string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") 34 | string(REGEX REPLACE "/MDd" "/MTd" ${flag_var} "${${flag_var}}") 35 | endforeach(flag_var) 36 | 37 | # Add /Zm256 compiler option to Visual Studio to fix PCH errors 38 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zm256") 39 | 40 | add_definitions( 41 | -D_CRT_SECURE_NO_WARNINGS=1 42 | -D_CRT_SECURE_NO_DEPRECATE=1 43 | ) 44 | 45 | if (MSVC_VERSION LESS 1600) 46 | # Starting with Visual Studio >= 2010 (i.e. macro _MSC_VER >= 47 | # 1600), Microsoft ships a standard-compliant 48 | # header. For earlier versions of Visual Studio, give access to a 49 | # compatibility header. 50 | # http://stackoverflow.com/a/70630/881731 51 | # https://en.wikibooks.org/wiki/C_Programming/C_Reference/stdint.h#External_links 52 | include_directories(${ORTHANC_ROOT}/Resources/ThirdParty/VisualStudio) 53 | endif() 54 | 55 | link_libraries(netapi32) 56 | endif() 57 | 58 | 59 | if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR 60 | ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR 61 | ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") 62 | set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--no-undefined") 63 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined") 64 | 65 | if (NOT DEFINED ENABLE_PLUGINS_VERSION_SCRIPT OR 66 | ENABLE_PLUGINS_VERSION_SCRIPT) 67 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--version-script=${ORTHANC_ROOT}/Plugins/Samples/Common/VersionScript.map") 68 | endif() 69 | 70 | # Remove the "-rdynamic" option 71 | # http://www.mail-archive.com/cmake@cmake.org/msg08837.html 72 | set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") 73 | link_libraries(uuid pthread rt) 74 | 75 | if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") 76 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed") 77 | set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--as-needed") 78 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--as-needed") 79 | add_definitions( 80 | -D_LARGEFILE64_SOURCE=1 81 | -D_FILE_OFFSET_BITS=64 82 | ) 83 | link_libraries(dl) 84 | endif() 85 | 86 | CHECK_INCLUDE_FILES(uuid/uuid.h HAVE_UUID_H) 87 | if (NOT HAVE_UUID_H) 88 | message(FATAL_ERROR "Please install the uuid-dev package") 89 | endif() 90 | 91 | elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") 92 | if (MSVC) 93 | message("MSVC compiler version = " ${MSVC_VERSION} "\n") 94 | # Starting Visual Studio 2013 (version 1800), it is not possible 95 | # to target Windows XP anymore 96 | if (MSVC_VERSION LESS 1800) 97 | add_definitions( 98 | -DWINVER=0x0501 99 | -D_WIN32_WINNT=0x0501 100 | ) 101 | endif() 102 | else() 103 | add_definitions( 104 | -DWINVER=0x0501 105 | -D_WIN32_WINNT=0x0501 106 | ) 107 | endif() 108 | 109 | add_definitions( 110 | -D_CRT_SECURE_NO_WARNINGS=1 111 | ) 112 | link_libraries(rpcrt4 ws2_32) 113 | 114 | if (CMAKE_COMPILER_IS_GNUCXX) 115 | # Some additional C/C++ compiler flags for MinGW 116 | SET(MINGW_NO_WARNINGS "-Wno-unused-function -Wno-unused-variable") 117 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${MINGW_NO_WARNINGS} -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast") 118 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MINGW_NO_WARNINGS}") 119 | 120 | # This is a patch for MinGW64 121 | SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--allow-multiple-definition -static-libgcc -static-libstdc++") 122 | SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--allow-multiple-definition -static-libgcc -static-libstdc++") 123 | 124 | CHECK_LIBRARY_EXISTS(winpthread pthread_create "" HAVE_WIN_PTHREAD) 125 | if (HAVE_WIN_PTHREAD) 126 | # This line is necessary to compile with recent versions of MinGW, 127 | # otherwise "libwinpthread-1.dll" is not statically linked. 128 | SET(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CXX_STANDARD_LIBRARIES} -Wl,-Bstatic -lstdc++ -lpthread -Wl,-Bdynamic") 129 | add_definitions(-DHAVE_WIN_PTHREAD=1) 130 | else() 131 | add_definitions(-DHAVE_WIN_PTHREAD=0) 132 | endif() 133 | endif() 134 | 135 | elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") 136 | SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -exported_symbols_list ${ORTHANC_ROOT}/Plugins/Samples/Common/ExportedSymbols.list") 137 | 138 | add_definitions( 139 | -D_XOPEN_SOURCE=1 140 | ) 141 | link_libraries(iconv) 142 | 143 | CHECK_INCLUDE_FILES(uuid/uuid.h HAVE_UUID_H) 144 | if (NOT HAVE_UUID_H) 145 | message(FATAL_ERROR "Please install the uuid-dev package") 146 | endif() 147 | 148 | endif() 149 | 150 | 151 | if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") 152 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --lsb-target-version=${LSB_TARGET_VERSION} -I${LSB_PATH}/include") 153 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --lsb-target-version=${LSB_TARGET_VERSION} -nostdinc++ -I${LSB_PATH}/include -I${LSB_PATH}/include/c++ -I${LSB_PATH}/include/c++/backward -fpermissive") 154 | SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --lsb-target-version=${LSB_TARGET_VERSION} -L${LSB_LIBPATH}") 155 | endif() 156 | 157 | 158 | if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") 159 | # In FreeBSD, the "/usr/local/" folder contains the ports and need to be imported 160 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I/usr/local/include") 161 | SET(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -I/usr/local/include") 162 | SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/local/lib") 163 | SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -L/usr/local/lib") 164 | endif() 165 | 166 | 167 | if (DEFINED ENABLE_PROFILING AND ENABLE_PROFILING) 168 | if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug") 169 | message(WARNING "Enabling profiling on a non-debug build will not produce full information") 170 | endif() 171 | 172 | if (CMAKE_COMPILER_IS_GNUCXX) 173 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg") 174 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pg") 175 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg") 176 | set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -pg") 177 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -pg") 178 | else() 179 | message(FATAL_ERROR "Don't know how to enable profiling on your configuration") 180 | endif() 181 | endif() 182 | 183 | 184 | if (STATIC_BUILD) 185 | add_definitions(-DORTHANC_STATIC=1) 186 | else() 187 | add_definitions(-DORTHANC_STATIC=0) 188 | endif() 189 | -------------------------------------------------------------------------------- /WindowsInstaller/ServiceControl.iss: -------------------------------------------------------------------------------- 1 | { 2 | This code comes from: https://stackoverflow.com/a/3219486/881731 3 | 4 | Modifications: 5 | - "string" in external functions has been replaced by "AnsiString": 6 | https://stackoverflow.com/a/9687888/881731 7 | - The "SERVICE_XXX_PENDING" status are taken into consideration 8 | in "IsServiceRunning()" 9 | } 10 | 11 | type 12 | SERVICE_STATUS = record 13 | dwServiceType : cardinal; 14 | dwCurrentState : cardinal; 15 | dwControlsAccepted : cardinal; 16 | dwWin32ExitCode : cardinal; 17 | dwServiceSpecificExitCode : cardinal; 18 | dwCheckPoint : cardinal; 19 | dwWaitHint : cardinal; 20 | end; 21 | HANDLE = cardinal; 22 | 23 | const 24 | SERVICE_QUERY_CONFIG = $1; 25 | SERVICE_CHANGE_CONFIG = $2; 26 | SERVICE_QUERY_STATUS = $4; 27 | SERVICE_START = $10; 28 | SERVICE_STOP = $20; 29 | SERVICE_ALL_ACCESS = $f01ff; 30 | SC_MANAGER_ALL_ACCESS = $f003f; 31 | SERVICE_WIN32_OWN_PROCESS = $10; 32 | SERVICE_WIN32_SHARE_PROCESS = $20; 33 | SERVICE_WIN32 = $30; 34 | SERVICE_INTERACTIVE_PROCESS = $100; 35 | SERVICE_BOOT_START = $0; 36 | SERVICE_SYSTEM_START = $1; 37 | SERVICE_AUTO_START = $2; 38 | SERVICE_DEMAND_START = $3; 39 | SERVICE_DISABLED = $4; 40 | SERVICE_DELETE = $10000; 41 | SERVICE_CONTROL_STOP = $1; 42 | SERVICE_CONTROL_PAUSE = $2; 43 | SERVICE_CONTROL_CONTINUE = $3; 44 | SERVICE_CONTROL_INTERROGATE = $4; 45 | SERVICE_STOPPED = $1; 46 | SERVICE_START_PENDING = $2; 47 | SERVICE_STOP_PENDING = $3; 48 | SERVICE_RUNNING = $4; 49 | SERVICE_CONTINUE_PENDING = $5; 50 | SERVICE_PAUSE_PENDING = $6; 51 | SERVICE_PAUSED = $7; 52 | 53 | { nt based service utilities } 54 | function OpenSCManager(lpMachineName, lpDatabaseName: AnsiString; dwDesiredAccess :cardinal): HANDLE; 55 | external 'OpenSCManagerA@advapi32.dll stdcall'; 56 | 57 | function OpenService(hSCManager :HANDLE;lpServiceName: AnsiString; dwDesiredAccess :cardinal): HANDLE; 58 | external 'OpenServiceA@advapi32.dll stdcall'; 59 | 60 | function CloseServiceHandle(hSCObject :HANDLE): boolean; 61 | external 'CloseServiceHandle@advapi32.dll stdcall'; 62 | 63 | function CreateService(hSCManager :HANDLE;lpServiceName, lpDisplayName: AnsiString;dwDesiredAccess,dwServiceType,dwStartType,dwErrorControl: cardinal;lpBinaryPathName,lpLoadOrderGroup: AnsiString; lpdwTagId : cardinal;lpDependencies,lpServiceStartName,lpPassword :AnsiString): cardinal; 64 | external 'CreateServiceA@advapi32.dll stdcall'; 65 | 66 | function DeleteService(hService :HANDLE): boolean; 67 | external 'DeleteService@advapi32.dll stdcall'; 68 | 69 | function StartNTService(hService :HANDLE;dwNumServiceArgs : cardinal;lpServiceArgVectors : cardinal) : boolean; 70 | external 'StartServiceA@advapi32.dll stdcall'; 71 | 72 | function ControlService(hService :HANDLE; dwControl :cardinal;var ServiceStatus :SERVICE_STATUS) : boolean; 73 | external 'ControlService@advapi32.dll stdcall'; 74 | 75 | function QueryServiceStatus(hService :HANDLE;var ServiceStatus :SERVICE_STATUS) : boolean; 76 | external 'QueryServiceStatus@advapi32.dll stdcall'; 77 | 78 | function QueryServiceStatusEx(hService :HANDLE;ServiceStatus :SERVICE_STATUS) : boolean; 79 | external 'QueryServiceStatus@advapi32.dll stdcall'; 80 | 81 | function GetLastError() : cardinal; 82 | external 'GetLastError@kernel32.dll stdcall'; 83 | 84 | function OpenServiceManager() : HANDLE; 85 | begin 86 | if UsingWinNT() = true then begin 87 | Result := OpenSCManager('','',SC_MANAGER_ALL_ACCESS); 88 | if Result = 0 then 89 | MsgBox('the servicemanager is not available', mbError, MB_OK) 90 | end 91 | else begin 92 | MsgBox('only nt based systems support services', mbError, MB_OK) 93 | Result := 0; 94 | end 95 | end; 96 | 97 | function IsServiceInstalled(ServiceName: string) : boolean; 98 | var 99 | hSCM : HANDLE; 100 | hService: HANDLE; 101 | begin 102 | hSCM := OpenServiceManager(); 103 | Result := false; 104 | if hSCM <> 0 then begin 105 | hService := OpenService(hSCM,ServiceName,SERVICE_QUERY_CONFIG); 106 | if hService <> 0 then begin 107 | Result := true; 108 | CloseServiceHandle(hService) 109 | end; 110 | CloseServiceHandle(hSCM) 111 | end 112 | end; 113 | 114 | function InstallService(FileName, ServiceName, DisplayName, Description : string;ServiceType,StartType :cardinal) : boolean; 115 | var 116 | hSCM : HANDLE; 117 | hService: HANDLE; 118 | begin 119 | hSCM := OpenServiceManager(); 120 | Result := false; 121 | if hSCM <> 0 then begin 122 | hService := CreateService(hSCM,ServiceName,DisplayName,SERVICE_ALL_ACCESS,ServiceType,StartType,0,FileName,'',0,'','',''); 123 | if hService <> 0 then begin 124 | Result := true; 125 | { Win2K & WinXP supports additional description text for services } 126 | if Description<> '' then 127 | RegWriteStringValue(HKLM,'System\CurrentControlSet\Services\' + ServiceName,'Description',Description); 128 | CloseServiceHandle(hService) 129 | end; 130 | CloseServiceHandle(hSCM) 131 | end 132 | end; 133 | 134 | function RemoveService(ServiceName: string) : boolean; 135 | var 136 | hSCM : HANDLE; 137 | hService: HANDLE; 138 | begin 139 | hSCM := OpenServiceManager(); 140 | Result := false; 141 | if hSCM <> 0 then begin 142 | hService := OpenService(hSCM,ServiceName,SERVICE_DELETE); 143 | if hService <> 0 then begin 144 | Result := DeleteService(hService); 145 | CloseServiceHandle(hService) 146 | end; 147 | CloseServiceHandle(hSCM) 148 | end 149 | end; 150 | 151 | function StartService(ServiceName: string) : boolean; 152 | var 153 | hSCM : HANDLE; 154 | hService: HANDLE; 155 | begin 156 | hSCM := OpenServiceManager(); 157 | Result := false; 158 | if hSCM <> 0 then begin 159 | hService := OpenService(hSCM,ServiceName,SERVICE_START); 160 | if hService <> 0 then begin 161 | Result := StartNTService(hService,0,0); 162 | CloseServiceHandle(hService) 163 | end; 164 | CloseServiceHandle(hSCM) 165 | end; 166 | end; 167 | 168 | function StopService(ServiceName: string) : boolean; 169 | var 170 | hSCM : HANDLE; 171 | hService: HANDLE; 172 | Status : SERVICE_STATUS; 173 | begin 174 | hSCM := OpenServiceManager(); 175 | Result := false; 176 | if hSCM <> 0 then begin 177 | hService := OpenService(hSCM,ServiceName,SERVICE_STOP); 178 | if hService <> 0 then begin 179 | Result := ControlService(hService,SERVICE_CONTROL_STOP,Status); 180 | CloseServiceHandle(hService) 181 | end; 182 | CloseServiceHandle(hSCM) 183 | end; 184 | end; 185 | 186 | function IsServiceRunning(ServiceName: string) : boolean; 187 | var 188 | hSCM : HANDLE; 189 | hService: HANDLE; 190 | Status : SERVICE_STATUS; 191 | begin 192 | hSCM := OpenServiceManager(); 193 | Result := false; 194 | if hSCM <> 0 then begin 195 | hService := OpenService(hSCM,ServiceName,SERVICE_QUERY_STATUS); 196 | if hService <> 0 then begin 197 | if QueryServiceStatus(hService,Status) then begin 198 | { Original code: "Status.dwCurrentState = SERVICE_RUNNING" } 199 | Result := ((Status.dwCurrentState <> SERVICE_STOPPED) AND 200 | (Status.dwCurrentState <> SERVICE_PAUSED)) 201 | end; 202 | CloseServiceHandle(hService) 203 | end; 204 | CloseServiceHandle(hSCM) 205 | end 206 | end; 207 | -------------------------------------------------------------------------------- /docker/orthanc/plugins-def.json: -------------------------------------------------------------------------------- 1 | { 2 | "Authorization" : { 3 | "enablingEnvVar" : "AUTHORIZATION_PLUGIN_ENABLED", 4 | "enablingEnvVarLegacy" : "AUTHZ_ENABLED", 5 | "libs" : ["libOrthancAuthorization.so"] 6 | }, 7 | 8 | "ConnectivityChecks" : { 9 | "enablingEnvVar" : "CONNECTIVITY_CHECKS_PLUGIN_ENABLED", 10 | "libs" : ["libConnectivityChecks.so"] 11 | }, 12 | 13 | "DicomWeb" : { 14 | "nonStandardDefaults" : { 15 | "Enable" : true 16 | }, 17 | "enablingEnvVar" : "DICOM_WEB_PLUGIN_ENABLED", 18 | "enablingEnvVarLegacy" : "DW_ENABLED", 19 | "libs" : ["libOrthancDicomWeb.so"] 20 | }, 21 | 22 | "Gdcm" : { 23 | "enabledByDefault": true, 24 | "nonStandardDefaults" : { 25 | "Throttling" : 4, 26 | "RestrictTransferSyntaxes" : [ 27 | "1.2.840.10008.1.2.4.90", 28 | "1.2.840.10008.1.2.4.91", 29 | "1.2.840.10008.1.2.4.92", 30 | "1.2.840.10008.1.2.4.93" 31 | ] 32 | }, 33 | "enablingEnvVar" : "GDCM_PLUGIN_ENABLED", 34 | "libs" : ["libOrthancGdcm.so"] 35 | }, 36 | 37 | "OrthancWebViewer" : { 38 | "section" : "WebViewer", 39 | "enablingEnvVarIsRequired": true, 40 | "enablingEnvVar" : "ORTHANC_WEB_VIEWER_PLUGIN_ENABLED", 41 | "enablingEnvVarLegacy" : "OWV_ENABLED", 42 | "libs" : ["libOrthancWebViewer.so"] 43 | }, 44 | 45 | "StoneWebViewer" : { 46 | "enablingEnvVarIsRequired": true, 47 | "enablingEnvVar" : "STONE_WEB_VIEWER_PLUGIN_ENABLED", 48 | "libs" : ["libStoneWebViewer.so"] 49 | }, 50 | 51 | "OsimisWebViewerBasic" : { 52 | "section" : "WebViewer", 53 | "enablingEnvVarIsRequired": true, 54 | "enablingEnvVar" : "OSIMIS_WEB_VIEWER1_PLUGIN_ENABLED", 55 | "enablingEnvVarLegacy" : "WVB_ENABLED", 56 | "libs" : ["libOsimisWebViewer.so"] 57 | }, 58 | 59 | "OsimisWebViewerBasicAlpha" : { 60 | "section" : "WebViewer", 61 | "enablingEnvVarIsRequired": true, 62 | "enablingEnvVar" : "OSIMIS_WEB_VIEWER1_ALPHA_PLUGIN_ENABLED", 63 | "enablingEnvVarLegacy" : "WVB_ALPHA_ENABLED", 64 | "libs" : ["libOsimisWebViewerAlpha.so"] 65 | }, 66 | 67 | "PostgreSQL" : { 68 | "enablingEnvVar" : "POSTGRESQL_PLUGIN_ENABLED", 69 | "enablingEnvVarLegacy" : "PG_ENABLED", 70 | "nonStandardDefaults" : { 71 | "EnableIndex": true, 72 | "EnableStorage": false, 73 | "Port": 5432, 74 | "Host": "HOST MUST BE DEFINED", 75 | "Database": "postgres", 76 | "Username": "postgres", 77 | "Password": "postgres", 78 | "EnableSsl": false, 79 | "Lock": false 80 | }, 81 | "libs" : ["libOrthancPostgreSQLIndex.so", "libOrthancPostgreSQLStorage.so"] 82 | }, 83 | 84 | "MySQL" : { 85 | "enablingEnvVar" : "MYSQL_PLUGIN_ENABLED", 86 | "enablingEnvVarLegacy" : "MYSQL_ENABLED", 87 | "nonStandardDefaults" : { 88 | "EnableIndex": true, 89 | "EnableStorage": false, 90 | "Port": 3306, 91 | "Host": "HOST MUST BE DEFINED", 92 | "Database": "mysql", 93 | "Username": "root", 94 | "Password": "mysql", 95 | "Lock": false 96 | }, 97 | "libs" : ["libOrthancMySQLIndex.so", "libOrthancMySQLStorage.so"] 98 | }, 99 | 100 | "Python" : { 101 | "enablingRootSetting": "PythonScript", 102 | "enablingEnvVar" : "PYTHON_PLUGIN_ENABLED", 103 | "libs" : ["libOrthancPython.so"] 104 | }, 105 | 106 | "ServeFolders" : { 107 | "enablingEnvVar" : "SERVE_FOLDERS_PLUGIN_ENABLED", 108 | "enablingEnvVarLegacy" : "SERVEFOLDERS_ENABLED", 109 | "libs" : ["libServeFolders.so"] 110 | }, 111 | 112 | "Transfers" : { 113 | "enablingEnvVar" : "TRANSFERS_PLUGIN_ENABLED", 114 | "enablingEnvVarLegacy" : "TRANSFERS_ENABLED", 115 | "libs" : ["libOrthancTransfers.so"] 116 | }, 117 | 118 | "Worklists" : { 119 | "nonStandardDefaults" : { 120 | "Enable" : true 121 | }, 122 | "enablingEnvVar" : "WORKLISTS_PLUGIN_ENABLED", 123 | "enablingEnvVarLegacy" : "WL_ENABLED", 124 | "libs" : ["libOrthancWorklists.so"] 125 | }, 126 | 127 | "Housekeeper" : { 128 | "nonStandardDefaults" : { 129 | "Enable" : true 130 | }, 131 | "enablingEnvVar" : "HOUSEKEEPER_PLUGIN_ENABLED", 132 | "libs" : ["libHousekeeper.so"] 133 | }, 134 | 135 | "DelayedDeletion" : { 136 | "nonStandardDefaults" : { 137 | "Enable" : true 138 | }, 139 | "enablingEnvVar" : "DELAYED_DELETION_PLUGIN_ENABLED", 140 | "libs" : ["libDelayedDeletion.so"] 141 | }, 142 | 143 | "MultitenantDicom" : { 144 | "enablingEnvVar" : "MULTITENANT_DICOM_PLUGIN_ENABLED", 145 | "libs" : ["libMultitenantDicom.so"] 146 | }, 147 | 148 | "AdvancedStorage" : { 149 | "nonStandardDefaults" : { 150 | "Enable" : true 151 | }, 152 | "enablingEnvVar" : "ADVANCED_STORAGE_PLUGIN_ENABLED", 153 | "libs" : ["libAdvancedStorage.so"] 154 | }, 155 | 156 | "Education" : { 157 | "nonStandardDefaults" : { 158 | "Enable" : true 159 | }, 160 | "enablingEnvVar" : "EDUCATION_PLUGIN_ENABLED", 161 | "libs" : ["libOrthancEducation.so"] 162 | }, 163 | 164 | "Wsi": { 165 | "enablingEnvVar" : "WSI_PLUGIN_ENABLED", 166 | "enablingEnvVarLegacy" : "WSI_ENABLED", 167 | "libs" : ["libOrthancWSI.so"] 168 | }, 169 | 170 | "Odbc" : { 171 | "enablingEnvVar" : "ODBC_PLUGIN_ENABLED", 172 | "nonStandardDefaults" : { 173 | "EnableIndex": true, 174 | "EnableStorage": false, 175 | "IndexConnectionString": "MUST BE DEFINED", 176 | "StorageConnectionString": "MUST BE DEFINED" 177 | }, 178 | "libs" : ["libOrthancOdbcIndex.so", "libOrthancOdbcStorage.so"] 179 | }, 180 | 181 | "Tcia": { 182 | "enablingEnvVar" : "TCIA_PLUGIN_ENABLED", 183 | "nonStandardDefaults" : { 184 | "Enable" : true 185 | }, 186 | "libs" : ["libOrthancTcia.so"] 187 | }, 188 | 189 | "Indexer": { 190 | "enablingEnvVar" : "INDEXER_PLUGIN_ENABLED", 191 | "nonStandardDefaults" : { 192 | "Enable" : true 193 | }, 194 | "libs" : ["libOrthancIndexer.so"] 195 | }, 196 | 197 | "Neuro": { 198 | "enablingEnvVar" : "NEURO_PLUGIN_ENABLED", 199 | "nonStandardDefaults" : { 200 | "Enable" : true 201 | }, 202 | "libs" : ["libOrthancNeuro.so"] 203 | }, 204 | 205 | "AzureBlobStorage": { 206 | "enablingEnvVar": "AZURE_BLOB_STORAGE_PLUGIN_ENABLED", 207 | "enablingEnvVarLegacy": "AZSTOR_ENABLED", 208 | "nonStandardDefaults": { 209 | "ConnectionString": "MUST BE DEFINED BY YOU", 210 | "ContainerName": "MUST BE DEFINED BY YOU" 211 | }, 212 | "libs": ["libOrthancAzureBlobStorage.so"] 213 | }, 214 | 215 | "AwsS3Storage": { 216 | "enablingEnvVar": "AWS_S3_STORAGE_PLUGIN_ENABLED", 217 | "nonStandardDefaults": { 218 | "BucketName": "MUST BE DEFINED BY YOU", 219 | "Region": "MUST BE DEFINED BY YOU" 220 | }, 221 | "libs": ["libOrthancAwsS3Storage.so"] 222 | }, 223 | 224 | "GoogleCloudStorage": { 225 | "enablingEnvVar": "GOOGLE_CLOUD_STORAGE_PLUGIN_ENABLED", 226 | "nonStandardDefaults": { 227 | "ServiceAccountFile": "MUST BE DEFINED BY YOU", 228 | "BucketName": "MUST BE DEFINED BY YOU" 229 | }, 230 | "libs": ["libOrthancGoogleCloudStorage.so"] 231 | }, 232 | 233 | "OrthancExplorer2": { 234 | "enabledByDefault": true, 235 | "enablingEnvVar" : "ORTHANC_EXPLORER_2_ENABLED", 236 | "nonStandardDefaults" : { 237 | "Enable" : true, 238 | "IsDefaultOrthancUI": true 239 | }, 240 | "libs" : ["libOrthancExplorer2.so"] 241 | }, 242 | 243 | "VolView": { 244 | "enablingEnvVar" : "VOLVIEW_PLUGIN_ENABLED", 245 | "libs" : ["libOrthancVolView.so"] 246 | }, 247 | 248 | "Ohif": { 249 | "enablingEnvVar" : "OHIF_PLUGIN_ENABLED", 250 | "libs" : ["libOrthancOHIF.so"] 251 | }, 252 | 253 | "STL": { 254 | "enablingEnvVar" : "STL_PLUGIN_ENABLED", 255 | "nonStandardDefaults" : { 256 | "Enable" : true 257 | }, 258 | "libs" : ["libOrthancSTL.so"] 259 | }, 260 | 261 | "Java": { 262 | "enablingEnvVar" : "JAVA_PLUGIN_ENABLED", 263 | "nonStandardDefaults" : { 264 | "Enable" : true, 265 | "Classpath": "MUST BE DEFINED BY YOU", 266 | "InitializationClass": "MUST BE DEFINED BY YOU" 267 | }, 268 | "libs" : ["libOrthancJava.so"] 269 | }, 270 | 271 | "PixelsMasker" : { 272 | "nonStandardDefaults" : { 273 | "Enable" : true 274 | }, 275 | "enablingEnvVar" : "PIXELS_MASKER_PLUGIN_ENABLED", 276 | "libs" : ["libOrthancPixelsMasker.so"] 277 | } 278 | 279 | } 280 | --------------------------------------------------------------------------------