Compare commits

..

29 Commits

Author SHA1 Message Date
7bdbe5adc0 lablels 2025-02-01 11:20:50 +06:00
422cafb9c8 env for config, split multiple 2025-02-01 10:56:28 +06:00
0699bd6c78 orthanc .env 2025-01-28 09:46:07 +06:00
d9967941bc stone 2025-01-28 09:35:00 +06:00
7269c5e7e6 prefetching 2025-01-28 09:33:55 +06:00
995aae3cc5 improvements 2025-01-28 00:50:44 +06:00
b9cfd3152b minor 2025-01-28 00:17:37 +06:00
57b9ede73b syntax 2025-01-28 00:06:41 +06:00
f3534cd8b0 added missing ports for pg 2025-01-28 00:05:39 +06:00
ed5b1177a2 plugins 2025-01-27 23:57:11 +06:00
cf7a61b969 updates 2025-01-27 23:55:34 +06:00
6512f18019 changed orthanc 2025-01-27 14:32:18 +06:00
6e1a149429 split main and extra profiles 2025-01-27 13:01:26 +06:00
b1a1d01d83 added no-sharing tags 2025-01-27 11:36:13 +06:00
a56477ce0f minor 2025-01-27 11:24:49 +06:00
045df2ea34 nginx configs 2025-01-27 11:17:15 +06:00
c81f42d915 ohif js 2025-01-27 11:16:53 +06:00
ba0c95f982 minor 2025-01-27 11:01:14 +06:00
b5edddb606 split nginx into different configs 2025-01-27 10:57:22 +06:00
4320acfc12 formatting 2025-01-27 10:49:50 +06:00
6c34c6fdb7 completed migration of orthanc configs 2025-01-27 10:47:25 +06:00
50811817e7 split and moved orthanc into parts 2025-01-27 10:43:31 +06:00
6baef8072a minor 2025-01-27 10:35:41 +06:00
0c006e4268 remvoe unneeded 2025-01-27 10:32:53 +06:00
1317849541 refactored 2025-01-27 10:32:30 +06:00
a982063eaa reorganization 2025-01-27 10:29:39 +06:00
f439c4d02e from copilot 2025-01-27 10:21:03 +06:00
13a0da03d6 updated 2025-01-27 10:18:28 +06:00
2f32cb394f removed comments 2025-01-27 09:50:34 +06:00
23 changed files with 687 additions and 471 deletions

34
.env
View File

@ -1,29 +1,20 @@
# docker-compose environment file
#
# When you set the same environment variable in multiple files,
# heres the priority used by Compose to choose which value to use:
#
# 1. Compose file
# 2. Shell environment variables
# 3. Environment file
# 4. Dockerfile
# 5. Variable is not defined
#
# Nginx configuration
#
NGINX_DEFAULT_CONF=./config/nginx_ohif.conf
NGINX_DEFAULT_CONF=./config/ohif/nginx/default.conf
NGINX_OHIF_CONF=./config/ohif/nginx/ohif.conf
#
# OHIF Viewer
#
VIEWER_CONFIG=./config/ohif.js
OHIF_CONFIG=./config/ohif/ohif.js
OHIF_LOGO=./config/ohif/logo.png
#
# Orthanc core with plugins
#
ORTHANC_CONFIG=./config/orthanc.json
ORTHANC_OHIF=./config/orthanc_ohif.js
ORTHANC_CONFIG=./config/orthanc
ORTHANC_OHIF=./config/ohif/ohif.js
ORTHANC_DB_MNT=./volumes/orthanc_db
ORTHANC_LOG=./volumes/orthanc_logs
@ -32,11 +23,24 @@ ORTHANC_LOG=./volumes/orthanc_logs
#
POSTGRES_DATA_MNT=./volumes/pg_data
PGDATA=/var/lib/postgresql/data
PGPASSWORD=secret
POSTGRES_DB=orthanc
POSTGRES_PORT=5432
POSTGRES_USER=postgres
POSTGRES_PASSWORD=password
POSTGRES_HOST=postgres
TZ="Asia/Dhaka"
PGTZ="Asia/Dhaka"
PGADMIN_MAIL=admin@blackfish.dev
PGADMIN_PASS=secret
PGADMIN_SERVER=False
PGADMIN_MASTER_PASS=False
PGADMIN_PORT=5050
ORTHANC_AET=BLACKFISH
ORTHANC_USERNAME=blackfish
ORTHANC_PASSWORD=letmein
ORTHANC_TOOLS_MNT=./volumes/orthanc_tools

1
config/meddream/license Normal file
View File

@ -0,0 +1 @@
1

View File

@ -1,28 +0,0 @@
server {
listen 80;
# set client body size to 500M, this is to allow uploading of DICOMs, throws '413 request entity too large nginx' error otherwise #
client_max_body_size 500M;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# https://book.orthanc-server.com/faq/nginx.html#nginx
location /orthanc/ {
proxy_pass http://orthanc:8042;
proxy_set_header HOST $host;
proxy_set_header X-Real-IP $remote_addr;
rewrite /orthanc(.*) $1 break;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Origin' '*';
}
}

View File

@ -19,6 +19,14 @@ window.config = {
},
],
},
studyPrefetcher: {
enabled: true,
displaySetCount: 2,
maxNumPrefetchRequests: 8,
order: 'closest',
},
whiteLabeling: {
/* Used to replace the default Logo */
createLogoComponentFn: function (React) {

View File

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 71 KiB

View File

@ -0,0 +1,17 @@
server {
listen [::]:80 default_server;
listen 80;
proxy_intercept_errors off;
gzip on;
gzip_types text/css application/javascript application/json image/svg+xml;
gzip_comp_level 9;
etag on;
charset utf-8;
# max upload size
client_max_body_size 250M;
include /etc/nginx/enabled-sites/*.conf;
}

View File

@ -0,0 +1,42 @@
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
add_header Cross-Origin-Opener-Policy same-origin;
add_header Cross-Origin-Embedder-Policy require-corp;
add_header Cross-Origin-Resource-Policy same-origin;
add_header Cache-Control "no-store, no-cache, must-revalidate";
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# https://book.orthanc-server.com/faq/nginx.html#nginx
location /orthanc/ {
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
expires 0;
add_header Cache-Control private;
proxy_pass http://orthanc:8042/;
rewrite /orthanc(.*) $1 break;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Origin' '*';
}

237
config/ohif/ohif.js Normal file
View File

@ -0,0 +1,237 @@
window.config = {
extensions: [],
modes: [],
customizationService: {
// Shows a custom route -access via http://localhost:3000/custom
// helloPage: '@ohif/extension-default.customizationModule.helloPage',
},
showStudyList: false,
studyListFunctionsEnabled: false,
filterQueryParam: false,
investigationalUseDialog: {
option: "never",
},
whiteLabeling: {
/* Used to replace the default Logo */
createLogoComponentFn: function (React) {
return React.createElement("a", {
target: "_self",
rel: "noopener noreferrer",
className: "header-brand",
href: "/",
style: {
display: "block",
background: "url(logo.png)",
backgroundSize: "contain",
backgroundRepeat: "no-repeat",
width: "200px",
},
});
},
},
customizationService: {
cornerstoneOverlayTopLeft: {
id: "cornerstoneOverlayTopLeft",
items: [
{
id: "WindowLevel",
customizationType: "ohif.overlayItem.windowLevel",
},
{
id: "PatientName",
customizationType: "ohif.overlayItem",
label: "Pt:",
color: "white",
condition: ({ instance }) =>
instance && instance.PatientName && instance.PatientName.Alphabetic,
contentF: ({ instance, formatters: { formatPN } }) => {
if (
instance &&
instance.PatientName &&
instance.PatientName.Alphabetic
) {
return (
formatPN(instance.PatientName.Alphabetic) +
" " +
(instance.PatientSex ? "(" + instance.PatientSex + ")" : "")
);
} else {
return "N/A";
}
},
},
{
id: "PatientAge",
customizationType: "ohif.overlayItem",
label: "Age:",
color: "white",
title: "Patient's Age",
condition: ({ instance }) => instance && instance.PatientAge,
contentF: ({ instance }) => instance.PatientAge,
},
{
id: "ID",
customizationType: "ohif.overlayItem",
label: "ID:",
color: "white",
title: "Patient PID",
condition: ({ instance }) => instance && instance.PatientID,
contentF: ({ instance }) => instance.PatientID,
},
],
},
},
// some windows systems have issues with more than 3 web workers
maxNumberOfWebWorkers: 3,
// below flag is for performance reasons, but it might not work for all servers
omitQuotationForMultipartRequest: true,
showWarningMessageForCrossOrigin: true,
showCPUFallbackMessage: true,
showLoadingIndicator: true,
strictZSpacingForVolumeViewport: true,
maxNumRequests: {
interaction: 100,
thumbnail: 75,
// Prefetch number is dependent on the http protocol. For http 2 or
// above, the number of requests can be go a lot higher.
prefetch: 25,
},
httpErrorHandler: (error) => {
// This is 429 when rejected from the public idc sandbox too often.
if (error.status) {
console.warn(error.status);
} else {
console.warn(error);
}
},
hotkeys: [
{
commandName: "incrementActiveViewport",
label: "Next Viewport",
keys: ["right"],
},
{
commandName: "decrementActiveViewport",
label: "Previous Viewport",
keys: ["left"],
},
{ commandName: "rotateViewportCW", label: "Rotate Right", keys: ["r"] },
{ commandName: "rotateViewportCCW", label: "Rotate Left", keys: ["l"] },
{ commandName: "invertViewport", label: "Invert", keys: ["i"] },
{
commandName: "flipViewportHorizontal",
label: "Flip Horizontally",
keys: ["h"],
},
{
commandName: "flipViewportVertical",
label: "Flip Vertically",
keys: ["v"],
},
{ commandName: "scaleUpViewport", label: "Zoom In", keys: ["+"] },
{ commandName: "scaleDownViewport", label: "Zoom Out", keys: ["-"] },
{ commandName: "fitViewportToWindow", label: "Zoom to Fit", keys: ["="] },
{ commandName: "resetViewport", label: "Reset", keys: ["space"] },
{ commandName: "nextImage", label: "Next Image", keys: ["down"] },
{ commandName: "previousImage", label: "Previous Image", keys: ["up"] },
// {
// commandName: 'previousViewportDisplaySet',
// label: 'Previous Series',
// keys: ['pagedown'],
// },
// {
// commandName: 'nextViewportDisplaySet',
// label: 'Next Series',
// keys: ['pageup'],
// },
{
commandName: "setToolActive",
commandOptions: { toolName: "Zoom" },
label: "Zoom",
keys: ["z"],
},
// ~ Window level presets
{
commandName: "windowLevelPreset1",
label: "W/L Preset 1",
keys: ["1"],
},
{
commandName: "windowLevelPreset2",
label: "W/L Preset 2",
keys: ["2"],
},
{
commandName: "windowLevelPreset3",
label: "W/L Preset 3",
keys: ["3"],
},
{
commandName: "windowLevelPreset4",
label: "W/L Preset 4",
keys: ["4"],
},
{
commandName: "windowLevelPreset5",
label: "W/L Preset 5",
keys: ["5"],
},
{
commandName: "windowLevelPreset6",
label: "W/L Preset 6",
keys: ["6"],
},
{
commandName: "windowLevelPreset7",
label: "W/L Preset 7",
keys: ["7"],
},
{
commandName: "windowLevelPreset8",
label: "W/L Preset 8",
keys: ["8"],
},
{
commandName: "windowLevelPreset9",
label: "W/L Preset 9",
keys: ["9"],
},
],
routerBasename: "/ohif/",
dataSources: [
{
friendlyName: "BlackFish DICOMweb",
namespace: "@ohif/extension-default.dataSourcesModule.dicomweb",
sourceName: "dicomweb",
configuration: {
name: "orthanc",
wadoUriRoot: "../dicom-web",
qidoRoot: "../dicom-web",
wadoRoot: "../dicom-web",
qidoSupportsIncludeField: false,
supportsReject: false,
imageRendering: "wadors",
thumbnailRendering: "wadors",
enableStudyLazyLoad: true,
supportsFuzzyMatching: false,
supportsWildcard: true,
staticWado: true,
singlepart: "bulkdata,pdf,video",
acceptHeader: [
"multipart/related; type=application/octet-stream; transfer-syntax=*",
],
},
},
],
defaultDataSourceName: "dicomweb",
};

View File

@ -0,0 +1,18 @@
{
"DicomWeb": {
"Enable": true,
"Root": "/dicom-web/",
"PublicRoot": "/dicom-web/",
"EnableWado": true,
"WadoRoot": "/wado",
"Ssl": false,
"Servers": {
//"main": ["http://orthanc:8042/dicom-web/"]
},
"QidoCaseSensitive": true,
"MetadataWorkerThreadsCount": 10,
"EnableMetadataCache": true,
"StudiesMetadata": "Full",
"SeriesMetadata": "Full"
}
}

View File

@ -0,0 +1,6 @@
{
"Dictionary": {
"1971,0010": ["CS", "PBSender", 1, 1, "BlackFish"],
"1971,1001": ["LO", "DicomSenderID", 1, 1, "BlackFish"]
}
}

View File

@ -0,0 +1,76 @@
{
"OrthancExplorer2": {
"CustomTitle": "BlackFish PACS",
"IsDefaultOrthancUI": true,
"Theme": "light",
"UiOptions": {
"EnableOpenInMedDreamViewer": false,
"EnableOpenInOhifViewer3": true,
"EnableOpenInVolView": true,
"EnableStudyList": true,
"EnableDownloadZip": true,
"EnableLinkToLegacyUi": false,
"ShowOrthancName": false,
"DateFormat": "dd/MM/yyyy",
"EnableDownloadDicomFile": true,
"EnableModification": true,
"DefaultShareDuration": 0,
"EnableApiViewMenu": true,
"EnableEditLabels": true,
"EnableViewerQuickButton": true,
"EnableReportQuickButton": false,
"StudyListSearchMode": "search-button",
"StudyListContentIfNoSearch": "empty",
"MaxStudiesDisplayed": 150,
"PageLoadSize": 50,
"MaxMyJobsHistorySize": 5,
"UploadReportTags": [
"PatientName",
"StudyDescription",
"PatientID",
"AccessionNumber",
"StudyDate"
],
"UploadReportMaxTags": 2,
"PatientMainTags": [
"PatientID",
"PatientName",
"PatientBirthDate",
"PatientSex",
"OtherPatientIDs"
],
"StudyMainTags": [
"StudyDate",
"StudyTime",
"StudyDescription",
"AccessionNumber",
"StudyID",
"StudyInstanceUID",
"RequestingPhysician",
"ReferringPhysicianName",
"Department",
"ReportingDoctor",
"InstitutionName"
],
"SeriesMainTags": [
"SeriesDate",
"SeriesTime",
"SeriesDescription",
"SeriesNumber",
"BodyPartExamined",
"ProtocolName",
"SeriesInstanceUID"
],
"StudyListColumns": [
"PatientBirthDate",
"PatientName",
"PatientID",
"StudyDescription",
"StudyDate",
"modalities",
"AccessionNumber",
"seriesAndInstancesCount"
]
}
}
}

View File

@ -0,0 +1,25 @@
{
"Housekeeper": {
"Enable": true,
"GlobalPropertyId": 1971,
"Force": false,
"ThrottleDelay": 15,
"Schedule": {
"Monday": ["3-6"],
"Tuesday": ["3-6"],
"Wednesday": ["3-6"],
"Thursday": ["3-6"],
"Friday": ["3-6"],
"Saturday": ["3-6"],
"Sunday": ["3-6"]
},
"Triggers": {
"StorageCompressionChange": true,
"MainDicomTagsChange": true,
"UnnecessaryDicomAsJsonFiles": true,
"IngestTranscodingChange": true,
"DicomWebCacheChange": true
},
"LimitMainDicomTagsReconstructLevel": "Study"
}
}

View File

@ -0,0 +1,5 @@
{
"DicomModalities": {
// "sample" : [ "STORESCP", "127.0.0.1", 2000 ]
}
}

View File

@ -0,0 +1,13 @@
{
"MultitenantDicom" : {
"Servers" : [
{
"AET" : "BLKFSHIN",
"Port" : 4243,
"Labels" : [ "BLACKFISH_CHENNAI" ],
"LabelsConstraint" : "All",
"LabelsStoreLevels" : [ "Patient", "Study" ]
}
]
}
}

5
config/orthanc/ohif.json Normal file
View File

@ -0,0 +1,5 @@
{
"OHIF": {
"UserConfiguration": "/usr/local/share/orthanc/ohif.js"
}
}

View File

@ -1,7 +1,11 @@
{
"Name": "PixelBridge",
"Name": "${ORTHANC_NAME:-BlackFish}",
"StorageDirectory": "/var/lib/orthanc/db",
"IndexDirectory": "/var/lib/orthanc/db",
"DicomServerEnabled": true,
"DicomAet": "${DICOM_AET:-BLACKFISH}",
"DicomCheckCalledAet": false,
"DicomPort": ${DICOM_PORT:-4242},
"StorageCompression": true,
"MaximumStorageSize": 0,
"MaximumPatientCount": 0,
@ -11,9 +15,6 @@
"/usr/share/orthanc/plugins",
"/usr/local/share/orthanc/plugins"
],
"OHIF": {
"UserConfiguration": "/usr/local/share/orthanc/ohif.js"
},
"ExtraMainDicomTags": {
"Instance": [
"Rows",
@ -74,45 +75,31 @@
]
},
"ConcurrentJobs": 8,
"HttpServerEnabled": true,
"OrthancExplorerEnabled": true,
"HttpPort": 8042,
"HttpDescribeErrors": true,
"HttpCompressionEnabled": true,
"WebDavEnabled": true,
"WebDavDeleteAllowed": false,
"WebDavUploadAllowed": true,
"DicomServerEnabled": true,
"DicomAet": "BLACKFISH",
"DicomCheckCalledAet": false,
"DicomPort": 4242,
"DefaultEncoding": "Utf8",
"AcceptedTransferSyntaxes": [
"1.2.840.10008.1.*"
],
"DeflatedTransferSyntaxAccepted" : true,
"JpegTransferSyntaxAccepted" : true,
"Jpeg2000TransferSyntaxAccepted" : true,
"JpegLosslessTransferSyntaxAccepted" : true,
"JpipTransferSyntaxAccepted" : true,
"DeflatedTransferSyntaxAccepted": true,
"JpegTransferSyntaxAccepted": true,
"Jpeg2000TransferSyntaxAccepted": true,
"JpegLosslessTransferSyntaxAccepted": true,
"JpipTransferSyntaxAccepted": true,
"UnknownSopClassAccepted": false,
"DicomScpTimeout": 30,
"RemoteAccessAllowed": true,
"SslEnabled": false,
"SslCertificate": "certificate.pem",
"SslMinimumProtocolVersion": 4,
"SslVerifyPeers": false,
"SslTrustedClientCertificates": "trustedClientCertificates.pem",
"AuthenticationEnabled": false,
"RegisteredUsers": {
"dicom": "letmein"
},
"DicomTlsEnabled": false,
"DicomTlsRemoteCertificateRequired": true,
"DicomAlwaysAllowEcho": true,
@ -122,9 +109,6 @@
"DicomAlwaysAllowGet": false,
"DicomAlwaysAllowMove": false,
"DicomCheckModalityHost": false,
"DicomModalities": {
// "sample" : [ "STORESCP", "127.0.0.1", 2000 ]
},
"DicomModalitiesInDatabase": false,
"DicomEchoChecksFind": false,
"DicomScuTimeout": 10,
@ -132,13 +116,11 @@
"DicomThreadsCount": 4,
"OrthancPeers": {},
"OrthancPeersInDatabase": false,
"HttpProxy": "",
"HttpVerbose": false,
"HttpTimeout": 60,
"HttpsVerifyPeers": false,
"HttpsCACertificates": "/etc/ssl/certs/ca-certificates.crt",
"UserMetadata": {
// "Sample" : 1024
},
@ -146,7 +128,6 @@
// "sample" : 1024
// "sample2" : [ 1025, "application/pdf" ]
},
"StableAge": 60,
"StrictAetComparison": false,
"StoreMD5ForAttachments": true,
@ -161,11 +142,6 @@
"QueryRetrieveSize": 100,
"CaseSensitivePN": false,
"LoadPrivateDictionary": true,
"Dictionary" : {
"0011,1060" : [ "LO", "InnowaveUploaderID", 1, 1, "InowavePrivateGroup"],
"1971,0010" : [ "CS", "PBSender", 1, 1, "PixelBridge"],
"1971,1001" : [ "LO", "DicomSenderID", 1, 1, "PixelBridge"]
},
"SynchronousCMove": true,
"JobsHistorySize": 10,
"SaveJobs": true,
@ -175,7 +151,7 @@
"MetricsEnabled": true,
"ExecuteLuaEnabled": false,
"HttpRequestTimeout": 30,
"DefaultPrivateCreator": "PixelBridge",
"DefaultPrivateCreator": "BlackFish",
"StorageCommitmentReportsSize": 100,
"TranscodeDicomProtocol": true,
"BuiltinDecoderTranscoderOrder": "After",
@ -194,87 +170,5 @@
"Warnings": {
"W001_TagsBeingReadFromStorage": true,
"W002_InconsistentDicomTagsInDb": true
},
"StoneWebViewer": {
/**
* Enables/disables the print button.
**/
"PrintEnabled": false,
/**
* Enables/disables the button to download a screenshot of the
* active viewport as a JPEG file.
**/
"DownloadAsJpegEnabled": false,
/**
* Enables/disables the button to download the display study.
* Only used if "OrthancApiRoot" is properly set.
**/
"DownloadStudyEnabled": false,
/**
* If option "DownloadDicomDir" is set to "true", the Stone Web
* viewer will create DICOMDIR media archives (as generated by the
* route "/studies/{id}/media" of Orthanc), instead of archives
* containing a human-readable hierarchy of folders (as generated
* by the route "/studies/{id}/archive").
**/
"DownloadDicomDir": false,
/**
* By setting option "InstitutionLogo" to an URL containing an
* image, this logo will be displayed at the bottom-left of the
* Stone Web viewer.
**/
"InstitutionLogo": "",
/**
* Whether to display the info panel at startup. Allowed values:
* "Always", "Never", "User". With "User", the user can decide to
* show or not the info panel in the user preferences panel (this
* is implemented using a cookie). (New in Stone Web viewer 2.4)
**/
"ShowInfoPanelAtStartup": "Never",
/**
* Whether to give access to the user preferences window. (New in
* Stone Web viewer 2.4)
**/
"ShowUserPreferencesButton": true,
/**
* Display a "not for diagnostic usage" disclaimer above the list
* of studies/series. (New in Stone Web viewer 2.4)
**/
"ShowNotForDiagnosticUsageDisclaimer": false
},
"DicomWeb": {
"Enable": true,
"Root": "/dicom-web/",
"PublicRoot": "/dicom-web/",
"EnableWado": true,
"WadoRoot": "/wado",
"Ssl": false,
"Servers": {
"main": [
"http://pacs.mylabctg.com:8042/dicom-web/"
]
},
"QidoCaseSensitive": true,
"MetadataWorkerThreadsCount": 10,
"EnableMetadataCache": true,
"StudiesMetadata": "Full",
"SeriesMetadata": "Full"
},
"OrthancExplorer2": {
"Enable": true,
"IsDefaultOrthancUI": true
},
"PostgreSQL": {
"EnableIndex": true,
"EnableStorage": false, // DICOM files are stored in the Orthanc container in /var/lib/orthanc/db/
"Host": "postgres", // the name of the PostgreSQL container
"Port": 5432,
"Database": "orthanc", // default database name in PostgreSQL container (no need to create it)
"Username": "postgres", // default user name in PostgreSQL container (no need to create it)
"Password": "password"
}
}

View File

@ -0,0 +1,11 @@
{
"PostgreSQL": {
"EnableIndex": true,
"EnableStorage": false,
"Host": "postgres",
"Port": 5432,
"Database": "orthanc",
"Username": "postgres",
"Password": "password"
}
}

View File

@ -0,0 +1,6 @@
{
"AuthenticationEnabled": false,
"RegisteredUsers": {
"blackfish": "letmein"
}
}

20
config/orthanc/stone.json Normal file
View File

@ -0,0 +1,20 @@
{
"StoneWebViewer": {
"DateFormat": "DD/MM/YYYY",
"PrintEnabled": false,
"CombinedToolEnabled": true,
"CombinedToolBehaviour": {
"LeftMouseButton": "Windowing",
"MiddleMouseButton": "Pan",
"RightMouseButton": "Zoom"
},
"DownloadAsJpegEnabled": false,
"DownloadStudyEnabled": false,
"DownloadDicomDir": false,
"InstitutionLogo": "",
"ShowInfoPanelAtStartup": "Never",
"ShowUserPreferencesButton": true,
"ShowNotForDiagnosticUsageDisclaimer": false,
"DicomCacheSize": 256
}
}

View File

@ -0,0 +1,7 @@
{
"WebViewer": {
"CachePath": "WebViewerCache",
"CacheSize": 128,
"Threads": 4
}
}

View File

@ -1,256 +0,0 @@
/**
* SPDX-FileCopyrightText: 2023-2024 Sebastien Jodogne, UCLouvain, Belgium,
* and 2018-2024 Open Health Imaging Foundation
* SPDX-License-Identifier: MIT
*/
window.config = {
extensions: [],
modes: [],
customizationService: {
// Shows a custom route -access via http://localhost:3000/custom
// helloPage: '@ohif/extension-default.customizationModule.helloPage',
},
showStudyList: false,
investigationalUseDialog: {
option: 'never',
},
whiteLabeling: {
/* Used to replace the default Logo */
createLogoComponentFn: function (React) {
return React.createElement("a", {
target: "_self",
rel: "noopener noreferrer",
className: "header-brand",
href: "/",
style: {
display: "block",
background: "url(logo.png)",
backgroundSize: "contain",
backgroundRepeat: "no-repeat",
width: "200px",
},
});
},
},
customizationService: {
cornerstoneOverlayTopLeft: {
id: 'cornerstoneOverlayTopLeft',
items: [
{
id: 'WindowLevel',
customizationType: 'ohif.overlayItem.windowLevel',
},
{
id: 'PatientName',
customizationType: 'ohif.overlayItem',
label: 'Pt:',
color: 'white',
condition: ({ instance }) =>
instance &&
instance.PatientName &&
instance.PatientName.Alphabetic,
contentF: ({ instance, formatters: { formatPN } }) => {
if (instance && instance.PatientName && instance.PatientName.Alphabetic) {
return formatPN(instance.PatientName.Alphabetic) + ' ' + (instance.PatientSex ? '(' + instance.PatientSex + ')' : '');
} else {
return 'N/A';
}
},
},
{
id: 'PatientAge',
customizationType: 'ohif.overlayItem',
label: 'Age:',
color: 'white',
title: "Patient's Age",
condition: ({ instance }) => instance && instance.PatientAge,
contentF: ({ instance }) => instance.PatientAge,
},
{
id: 'ID',
customizationType: 'ohif.overlayItem',
label: 'ID:',
color: 'white',
title: 'Patient PID',
condition: ({ instance }) => instance && instance.PatientID,
contentF: ({ instance }) => instance.PatientID,
},
],
},
},
// some windows systems have issues with more than 3 web workers
maxNumberOfWebWorkers: 3,
// below flag is for performance reasons, but it might not work for all servers
omitQuotationForMultipartRequest: true,
showWarningMessageForCrossOrigin: true,
showCPUFallbackMessage: true,
showLoadingIndicator: true,
strictZSpacingForVolumeViewport: true,
maxNumRequests: {
interaction: 100,
thumbnail: 75,
// Prefetch number is dependent on the http protocol. For http 2 or
// above, the number of requests can be go a lot higher.
prefetch: 25,
},
// filterQueryParam: false,
httpErrorHandler: error => {
// This is 429 when rejected from the public idc sandbox too often.
if (error.status) {
console.warn(error.status);
} else {
console.warn(error);
}
},
hotkeys: [
{
commandName: 'incrementActiveViewport',
label: 'Next Viewport',
keys: ['right'],
},
{
commandName: 'decrementActiveViewport',
label: 'Previous Viewport',
keys: ['left'],
},
{ commandName: 'rotateViewportCW', label: 'Rotate Right', keys: ['r'] },
{ commandName: 'rotateViewportCCW', label: 'Rotate Left', keys: ['l'] },
{ commandName: 'invertViewport', label: 'Invert', keys: ['i'] },
{
commandName: 'flipViewportHorizontal',
label: 'Flip Horizontally',
keys: ['h'],
},
{
commandName: 'flipViewportVertical',
label: 'Flip Vertically',
keys: ['v'],
},
{ commandName: 'scaleUpViewport', label: 'Zoom In', keys: ['+'] },
{ commandName: 'scaleDownViewport', label: 'Zoom Out', keys: ['-'] },
{ commandName: 'fitViewportToWindow', label: 'Zoom to Fit', keys: ['='] },
{ commandName: 'resetViewport', label: 'Reset', keys: ['space'] },
{ commandName: 'nextImage', label: 'Next Image', keys: ['down'] },
{ commandName: 'previousImage', label: 'Previous Image', keys: ['up'] },
// {
// commandName: 'previousViewportDisplaySet',
// label: 'Previous Series',
// keys: ['pagedown'],
// },
// {
// commandName: 'nextViewportDisplaySet',
// label: 'Next Series',
// keys: ['pageup'],
// },
{
commandName: 'setToolActive',
commandOptions: { toolName: 'Zoom' },
label: 'Zoom',
keys: ['z'],
},
// ~ Window level presets
{
commandName: 'windowLevelPreset1',
label: 'W/L Preset 1',
keys: ['1'],
},
{
commandName: 'windowLevelPreset2',
label: 'W/L Preset 2',
keys: ['2'],
},
{
commandName: 'windowLevelPreset3',
label: 'W/L Preset 3',
keys: ['3'],
},
{
commandName: 'windowLevelPreset4',
label: 'W/L Preset 4',
keys: ['4'],
},
{
commandName: 'windowLevelPreset5',
label: 'W/L Preset 5',
keys: ['5'],
},
{
commandName: 'windowLevelPreset6',
label: 'W/L Preset 6',
keys: ['6'],
},
{
commandName: 'windowLevelPreset7',
label: 'W/L Preset 7',
keys: ['7'],
},
{
commandName: 'windowLevelPreset8',
label: 'W/L Preset 8',
keys: ['8'],
},
{
commandName: 'windowLevelPreset9',
label: 'W/L Preset 9',
keys: ['9'],
},
],
};
/**
* SPDX-FileCopyrightText: 2023-2024 Sebastien Jodogne, UCLouvain, Belgium,
* and 2018-2024 Open Health Imaging Foundation
* SPDX-License-Identifier: MIT
*/
window.config.routerBasename = '/ohif/';
if (true) {
window.config.dataSources = [
{
friendlyName: 'Orthanc DICOMweb',
namespace: '@ohif/extension-default.dataSourcesModule.dicomweb',
sourceName: 'dicomweb',
configuration: {
name: 'orthanc',
wadoUriRoot: '../dicom-web',
qidoRoot: '../dicom-web',
wadoRoot: '../dicom-web',
qidoSupportsIncludeField: false,
supportsReject: false,
imageRendering: 'wadors',
thumbnailRendering: 'wadors',
enableStudyLazyLoad: true,
supportsFuzzyMatching: false,
supportsWildcard: true,
staticWado: true,
singlepart: 'bulkdata,pdf,video',
acceptHeader: ['multipart/related; type=application/octet-stream; transfer-syntax=*']
}
}
];
window.config.defaultDataSourceName = 'dicomweb';
} else {
window.config.showStudyList = false;
window.config.dataSources = [
{
friendlyName: 'Orthanc DICOM JSON',
namespace: '@ohif/extension-default.dataSourcesModule.dicomjson',
sourceName: 'dicomjson',
configuration: {
name: 'json',
},
}
];
window.config.defaultDataSourceName = 'dicomjson';
}

View File

@ -1,88 +1,158 @@
services:
postgres:
image: postgres:17
image: postgres:alpine
container_name: postgres
networks:
- pacs
volumes:
- ${POSTGRES_DATA_MNT}:${PGDATA}
environment:
- PGPASSWORD='secret'
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
- PGDATA=${PGDATA}
- PGTZ=${PGTZ}
healthcheck:
test: [ "CMD", "pg_isready", "-q", "-d", "${DB_DATABASE}", "-U", "${DB_USERNAME}" ]
retries: 3
timeout: 5s
pgadmin:
depends_on:
- postgres
container_name: pgadmin
image: dpage/pgadmin4
restart: unless-stopped
environment:
PGADMIN_DEFAULT_EMAIL: admin@blackfish.dev
PGADMIN_DEFAULT_PASSWORD: password
profiles: [main, extra]
ports:
- 5050:88
- "5432:5432"
networks:
pacs:
aliases:
- postgres
environment:
PGPASSWORD: ${PGPASSWORD}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
PGDATA: ${PGDATA}
PGTZ: ${PGTZ}
POSTGRES_HOST_AUTH_METHOD: "trust"
volumes:
- ${POSTGRES_DATA_MNT}:${PGDATA}:Z
healthcheck:
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
start_period: 20s
interval: 30s
retries: 5
timeout: 5s
restart: unless-stopped
orthanc:
container_name: orthanc
image: jodogne/orthanc-plugins
profiles: [main, extra]
image: orthancteam/orthanc
ports:
- 8042:8042
- 4242:4242
- "8042:8042"
- "4242:4242"
volumes:
# configuration file
- ${ORTHANC_CONFIG:-./config/orthanc.json}:/etc/orthanc/orthanc.json:ro
# storage volume for raw dicoms
- ${ORTHANC_DB_MNT:-./volumes/orthanc_db}:/var/lib/orthanc/db
- ${ORTHANC_OHIF:-./config/orthanc_ohif.js}:/usr/local/share/orthanc/ohif.js:ro
- ${ORTHANC_LOG:-./volumes/orthanc_logs}:/etc/orthanc/logs
- ${ORTHANC_CONFIG:-./config/orthanc}:/etc/orthanc/:ro
- ${ORTHANC_DB_MNT:-./volumes/orthanc_db}:/var/lib/orthanc/db:Z
- ${ORTHANC_OHIF:-./config/ohif/ohif.js}:/usr/local/share/orthanc/ohif.js:ro
- ${ORTHANC_LOG:-./volumes/orthanc_logs}:/var/log/orthanc
env_file:
- orthanc.env
environment:
VERBOSE_ENABLED: "true"
VERBOSE_STARTUP: "true"
DICOM_WEB_PLUGIN_ENABLED: "true"
OHIF_PLUGIN_ENABLED: "true"
VOLVIEW_PLUGIN_ENABLED: "true"
restart: always
ORTHANC__DICOM_AET: "${ORTHANC_AET}"
ORTHANC__POSTGRESQL__HOST: "${POSTGRES_HOST}"
restart: unless-stopped
networks:
- pacs
pacs:
aliases:
- orthanc
depends_on:
- postgres
ohif:
container_name: ohif
image: ohif/viewer
profiles: [main, extra]
image: ohif/app:v3.9.2
ports:
- 3000:80
- "3000:80"
environment:
- APP_CONFIG:/usr/share/nginx/html/app-config.js
APP_CONFIG: /usr/share/nginx/html/app-config.js
volumes:
- ${NGINX_DEFAULT_CONF}:/etc/nginx/conf.d/default.conf:ro
- ${VIEWER_CONFIG}:/usr/share/nginx/html/app-config.js:ro
- ./logo.png:/usr/share/nginx/html/logo.png:ro
restart: always
- ${NGINX_OHIF_CONF}:/etc/nginx/enabled-sites/ohif.conf:ro
- ${OHIF_CONFIG}:/usr/share/nginx/html/app-config.js:ro
- ${OHIF_LOGO}:/usr/share/nginx/html/logo.png:ro
restart: unless-stopped
depends_on:
- orthanc
networks:
- pacs
pacs:
aliases:
- ohif
meddream:
image: meddream/dicom-viewer:8.5.0
restart: always
profiles: [extra]
container_name: meddream
restart: unless-stopped
ports:
- "80:8080"
depends_on:
- orthanc
- postgres
networks:
- pacs
pacs:
aliases:
- meddream
volumes:
- ./config/meddream/application.properties:/opt/meddream/application.properties:ro
#- ./config/meddream/license:/opt/meddream/license:ro
- ./config/meddream/system.json:/opt/meddream/sys/settings/system.json:ro
orthanctoolsjs:
profiles: [extra]
image: salimkanoun/orthanctoolsjs
restart: unless-stopped
ports:
- "4000:4000"
volumes:
- ${ORTHANC_TOOLS_MNT:-./volumes/orthanc_tools}:/OrthancToolsJs/data
environment:
TZ: "${TZ}"
ORTHANC_ADDRESS: "http://orthanc"
ORTHANC_PORT: "8042"
ORTHANC_USERNAME: "${ORTHANC_USERNAME}"
ORTHANC_PASSWORD: "${ORTHANC_PASSWORD}"
REDIS_HOST: "redis"
REDIS_PORT: "6379"
REDIS_PASSWORD: ""
DB_USERNAME: "${POSTGRES_USER}"
DB_PASSWORD: "${POSTGRES_PASSWORD}"
DB_HOST: "${POSTGRES_HOST}"
DB_PORT: ${POSTGRES_PORT}
DB_NAME: ${POSTGRES_DB}
DOMAIN_PROTOCOL: "http"
DOMAIN_ADDRESS: "localhost:4000"
depends_on:
- redis
- orthanc
- postgres
networks:
pacs:
aliases:
- orthanctoolsjs
redis:
profiles: [extra]
image: redis:alpine
networks:
pacs:
aliases:
- redis
pgadmin:
container_name: pgadmin
profiles: [extra]
image: dpage/pgadmin4:latest
restart: unless-stopped
environment:
PGADMIN_DEFAULT_EMAIL: ${PGADMIN_MAIL}
PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASS}
PGADMIN_CONFIG_SERVER_MODE: ${PGADMIN_SERVER}
PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED: ${PGADMIN_MASTER_PASS}
PGADMIN_LISTEN_PORT: ${PGADMIN_PORT}
ports:
- "${PGADMIN_PORT}:${PGADMIN_PORT}"
depends_on:
- postgres
networks:
pacs:
aliases:
- pgadmin
networks:
pacs:
external: true

35
orthanc.env Normal file
View File

@ -0,0 +1,35 @@
VERBOSE_STARTUP=true
#VERBOSE_ENABLED=true
ORTHANC__POSTGRESQL__HOST=orthanc-db
ORTHANC__POSTGRESQL__TRANSACTION_MODE=ReadCommitted
ORTHANC__POSTGRESQL__INDEX_CONNECTIONS_COUNT=10
ORTHANC__OVERWRITE_INSTANCES=true
#ORTHANC__DICOM_MODALITIES={"pacs": ["PACS", "pacs", 4242]}
ORTHANC__DICOM_WEB__SERVERS={"pacs": ["http://orthanc:8042/dicom-web/"]}
ORTHANC__DICOM_WEB__SERIES_METADATA="Full"
ORTHANC__DICOM_WEB__STUDIES_METADATA="Full"
ORTHANC__DICOM_WEB__METADATA_WORKER_THREADS_COUNT=4
ORTHANC__STONE_WEB_VIEWER__DATE_FORMAT: "DD/MM/YYYY"
ORTHANC__AUTHENTICATION_ENABLED: "false"
ORTHANC__NAME="BlackFish"
POSTGRESQL_PLUGIN_ENABLED=true
LOGDIR="/var/log/orthanc"
VERBOSE_ENABLED=true
VERBOSE_STARTUP=true
DICOM_WEB_PLUGIN_ENABLED=true
OHIF_PLUGIN_ENABLED=true
VOLVIEW_PLUGIN_ENABLED=true
ORTHANC_WEB_VIEWER_PLUGIN_ENABLED=true
STONE_WEB_VIEWER_PLUGIN_ENABLED=true
HOUSEKEEPER_PLUGIN_ENABLED=true
ORTHANC_EXPLORER_2_ENABLED=true
#PYTHON_PLUGIN_ENABLED=true
#TRANSFERS_PLUGIN_ENABLED=true
#WORKLISTS_PLUGIN_ENABLED=true
#MULTITENANT_DICOM_PLUGIN_ENABLED=true
#INDEXER_PLUGIN_ENABLED=true
#OSIMIS_WEB_VIEWER1_PLUGIN_ENABLED=true