OHIF Viewer Images Won't Load - Permission Problems?

I installed docker-compose on my Ubuntu laptop so that I can test out Orthanc/Ohif locally and get it working first, and right out of the box, images won’t load. I git cloned the repo and spun up the docker containers with the docker-compose.yml from minimal-setup/keycloak as is (no changes).

I uploaded some DICOM imaging and the clicked on “View in OHIF” and the OHIF Viewer opened, but no images loaded.

I checked the orthanc-auth-service container logs, and I saw (over and over):

INFO:root:get user profile: {"token_key":"Authorization","token_value":"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6bnVsbCwicmVzb3VyY2VzIjpbeyJkaWNvbV91aWQiOiIxLjIuODQwLjExNDIwMi40LjE0OTcwODc2MC45NjM3MzQyMTAuMTUzNDY4MjI4Ny4xMjc1OTI3NjQ5Iiwib3J0aGFuY19pZCI6IjgwM2EwNDlhLWNlZjExMWVmLWQ0YmNjOGY1LTQ1ZWM2ZDkzLTNmYzM4YzQwIiwidXJsIjpudWxsLCJsZXZlbCI6InN0dWR5In1dLCJ0eXBlIjoidmlld2VyLWluc3RhbnQtbGluayIsImV4cGlyYXRpb25fZGF0ZSI6IjIwMjQtMDQtMTdUMDA6NTc6MDguODE0NDQyKzAwOjAwIiwidmFsaWRpdHlfZHVyYXRpb24iOjM2MDB9.LWWsqqnk1i37KOPFzgMul5Pq94t42ktCAe0LMaS2se8","server_id":null}
INFO:     172.18.0.5:42098 - "POST /user/get-profile HTTP/1.1" 400 Bad Request

The Ohif container didn’t show any issues. Just lots of browser info and http 200 status.

The Orthanc container, lots going on:

I0416 23:58:29.147716          HTTP-38 PluginsManager.cpp:161] (plugins) Linking Series "e530fb8b-46f426ae-5e00030d-601ba70b-b08967e0" to its parent Study "803a049a-cef111ef-d4bcc8f5-45ec6d93-3fc38c40"
I0416 23:58:29.147735          HTTP-38 OrthancPlugins.cpp:3221] (plugins) Plugin making REST GET call on URI /instances/ed6a9f83-7304606f-04fdd2e9-e9ab4898-41fcbf17 (built-in API)
I0416 23:58:29.150367          HTTP-38 PluginsManager.cpp:161] (plugins) Linking Instance "ed6a9f83-7304606f-04fdd2e9-e9ab4898-41fcbf17" to its parent Series "e530fb8b-46f426ae-5e00030d-601ba70b-b08967e0"
I0416 23:58:29.150421          HTTP-38 PluginsManager.cpp:161] (plugins) Testing whether access to study "803a049a-cef111ef-d4bcc8f5-45ec6d93-3fc38c40" is allowed with a resource token
I0416 23:58:29.150506          HTTP-38 PluginsManager.cpp:161] (plugins) New HTTP request to: http://orthanc-auth-service:8000/tokens/validate (timeout: 10s)
I0416 23:58:29.154614          HTTP-38 PluginsManager.cpp:161] (plugins) HTTP status code 200 in 4 ms after POST request on: http://orthanc-auth-service:8000/tokens/validate
I0416 23:58:29.154864          HTTP-38 PluginsManager.cpp:161] (plugins) Testing whether access to study "803a049a-cef111ef-d4bcc8f5-45ec6d93-3fc38c40" is allowed with a resource token -> granted
I0416 23:58:29.154985          HTTP-38 OrthancPlugins.cpp:2475] (plugins) Delegating HTTP request to plugin for URI: /dicom-web/studies/1.2.840.114202.4.149708760.963734210.1534682287.1275927649/series/1.3.12.2.1107.5.2.19.145069.2023122716130076820674112.0.0.0/instances/1.3.12.2.1107.5.2.19.145069.2023122716130122565674135/frames/1
I0416 23:58:29.155090          HTTP-38 OrthancPlugins.cpp:4058] (plugins) Plugin making REST POST call to URI /tools/find (after plugins)
I0416 23:58:29.155203          HTTP-38 OrthancPlugins.cpp:2475] (plugins) Delegating HTTP request to plugin for URI: /tools/find
I0416 23:58:29.155386          HTTP-38 PluginsManager.cpp:161] (plugins) New HTTP request to: http://orthanc-auth-service:8000/user/get-profile (timeout: 10s)
I0416 23:58:29.158907          HTTP-38 PluginsManager.cpp:161] (plugins) HTTP status code 400 in 3 ms after POST request on: http://orthanc-auth-service:8000/user/get-profile
E0416 23:58:29.158955          HTTP-38 PluginsManager.cpp:153] Error in HTTP request, received HTTP status 400 (Bad Request) after POST request on: http://orthanc-auth-service:8000/user/get-profile
I0416 23:58:29.159155          HTTP-38 OrthancPlugins.cpp:3278] (plugins) Plugin making REST POST call on URI /tools/lookup (built-in API)
I0416 23:58:29.164407          HTTP-38 PluginsManager.cpp:161] (plugins) Testing whether access to study "803a049a-cef111ef-d4bcc8f5-45ec6d93-3fc38c40" is allowed with a resource token
I0416 23:58:29.164531          HTTP-38 PluginsManager.cpp:161] (plugins) New HTTP request to: http://orthanc-auth-service:8000/tokens/validate (timeout: 10s)
I0416 23:58:29.167835          HTTP-38 PluginsManager.cpp:161] (plugins) HTTP status code 200 in 3 ms after POST request on: http://orthanc-auth-service:8000/tokens/validate
I0416 23:58:29.168039          HTTP-38 PluginsManager.cpp:161] (plugins) Testing whether access to study "803a049a-cef111ef-d4bcc8f5-45ec6d93-3fc38c40" is allowed with a resource token -> granted
I0416 23:58:29.168104          HTTP-38 OrthancPlugins.cpp:3278] (plugins) Plugin making REST POST call on URI /tools/find (built-in API)
I0416 23:58:29.174573          HTTP-38 ServerContext.cpp:1561] Number of candidate resources after fast DB filtering on main DICOM tags: 1
I0416 23:58:29.177872          HTTP-38 ServerContext.cpp:1709] Number of matching resources: 1
I0416 23:58:29.178172          HTTP-38 PluginsManager.cpp:161] (plugins) DICOMweb RetrieveFrames on ed6a9f83-7304606f-04fdd2e9-e9ab4898-41fcbf17, frames: 1 
I0416 23:58:29.178235          HTTP-38 OrthancPlugins.cpp:3221] (plugins) Plugin making REST GET call on URI /instances/ed6a9f83-7304606f-04fdd2e9-e9ab4898-41fcbf17/metadata/TransferSyntax (built-in API)
I0416 23:58:29.179699          HTTP-38 OrthancPlugins.cpp:3221] (plugins) Plugin making REST GET call on URI /instances/ed6a9f83-7304606f-04fdd2e9-e9ab4898-41fcbf17/file (built-in API)
I0416 23:58:29.180883          HTTP-38 StorageCache.cpp:127] Read attachment "b47b13f5-5458-4a02-9778-4a804313eb7e" with content type 1 from cache
E0416 23:58:29.182982          HTTP-38 OrthancException.cpp:61] Bad file format: Cannot access a raw frame
E0416 23:58:29.183258          HTTP-38 PluginsErrorDictionary.cpp:100] Exception inside the plugin engine: Bad file format
I0416 23:58:29.896931          HTTP-39 HttpServer.cpp:1262] (http) GET /dicom-web/studies/1.2.840.114202.4.149708760.963734210.1534682287.1275927649/series/1.3.12.2.1107.5.2.19.145069.2023122716130076820674112.0.0.0/instances/1.3.12.2.1107.5.2.19.145069.2023122716130078035974115/frames/1
I0416 23:58:29.897270          HTTP-39 PluginsManager.cpp:161] (plugins) New HTTP request to: http://orthanc-auth-service:8000/user/get-profile (timeout: 10s)
I0416 23:58:29.901545          HTTP-39 PluginsManager.cpp:161] (plugins) HTTP status code 400 in 4 ms after POST request on: http://orthanc-auth-service:8000/user/get-profile
E0416 23:58:29.901573          HTTP-39 PluginsManager.cpp:153] Error in HTTP request, received HTTP status 400 (Bad Request) after POST request on: http://orthanc-auth-service:8000/user/get-profile
I0416 23:58:29.901697          HTTP-39 PluginsManager.cpp:161] (plugins) Testing whether user has the required permissions 'all|view' based on the HTTP header 'Authorization' required to match '^/dicom-web/studies/([.0-9]+)/series/([.0-9]+)/instances/([.0-9]+)(|/|/frames/.*|/rendered|/metadata|/bulk/.*)(|/)$' -> not granted
I0416 23:58:29.904259          HTTP-39 OrthancPlugins.cpp:3221] (plugins) Plugin making REST GET call on URI /instances/e3639796-6fe2c365-de157e5f-cc448ae5-03b72be2 (built-in API)
I0416 23:58:29.906861          HTTP-39 PluginsManager.cpp:161] (plugins) Linking Instance "e3639796-6fe2c365-de157e5f-cc448ae5-03b72be2" to its parent Series "e530fb8b-46f426ae-5e00030d-601ba70b-b08967e0"
I0416 23:58:29.906898          HTTP-39 PluginsManager.cpp:161] (plugins) Testing whether access to study "803a049a-cef111ef-d4bcc8f5-45ec6d93-3fc38c40" is allowed with a resource token
I0416 23:58:29.906933          HTTP-39 PluginsManager.cpp:161] (plugins) Testing whether access to study "803a049a-cef111ef-d4bcc8f5-45ec6d93-3fc38c40" is allowed with a resource token -> granted
I0416 23:58:29.906996          HTTP-39 OrthancPlugins.cpp:2475] (plugins) Delegating HTTP request to plugin for URI: /dicom-web/studies/1.2.840.114202.4.149708760.963734210.1534682287.1275927649/series/1.3.12.2.1107.5.2.19.145069.2023122716130076820674112.0.0.0/instances/1.3.12.2.1107.5.2.19.145069.2023122716130078035974115/frames/1
I0416 23:58:29.907086          HTTP-39 OrthancPlugins.cpp:4058] (plugins) Plugin making REST POST call to URI /tools/find (after plugins)
I0416 23:58:29.907156          HTTP-39 OrthancPlugins.cpp:2475] (plugins) Delegating HTTP request to plugin for URI: /tools/find
I0416 23:58:29.907279          HTTP-39 PluginsManager.cpp:161] (plugins) New HTTP request to: http://orthanc-auth-service:8000/user/get-profile (timeout: 10s)
I0416 23:58:29.910626          HTTP-39 PluginsManager.cpp:161] (plugins) HTTP status code 400 in 3 ms after POST request on: http://orthanc-auth-service:8000/user/get-profile
E0416 23:58:29.910657          HTTP-39 PluginsManager.cpp:153] Error in HTTP request, received HTTP status 400 (Bad Request) after POST request on: http://orthanc-auth-service:8000/user/get-profile
I0416 23:58:29.910795          HTTP-39 OrthancPlugins.cpp:3278] (plugins) Plugin making REST POST call on URI /tools/lookup (built-in API)
I0416 23:58:29.917252          HTTP-39 PluginsManager.cpp:161] (plugins) Testing whether access to study "803a049a-cef111ef-d4bcc8f5-45ec6d93-3fc38c40" is allowed with a resource token
I0416 23:58:29.917287          HTTP-39 PluginsManager.cpp:161] (plugins) Testing whether access to study "803a049a-cef111ef-d4bcc8f5-45ec6d93-3fc38c40" is allowed with a resource token -> granted
I0416 23:58:29.917315          HTTP-39 OrthancPlugins.cpp:3278] (plugins) Plugin making REST POST call on URI /tools/find (built-in API)
I0416 23:58:29.922150          HTTP-39 ServerContext.cpp:1561] Number of candidate resources after fast DB filtering on main DICOM tags: 1
I0416 23:58:29.923591          HTTP-39 ServerContext.cpp:1709] Number of matching resources: 1
I0416 23:58:29.923769          HTTP-39 PluginsManager.cpp:161] (plugins) DICOMweb RetrieveFrames on e3639796-6fe2c365-de157e5f-cc448ae5-03b72be2, frames: 1 
I0416 23:58:29.923789          HTTP-39 OrthancPlugins.cpp:3221] (plugins) Plugin making REST GET call on URI /instances/e3639796-6fe2c365-de157e5f-cc448ae5-03b72be2/metadata/TransferSyntax (built-in API)
I0416 23:58:29.924479          HTTP-39 OrthancPlugins.cpp:3221] (plugins) Plugin making REST GET call on URI /instances/e3639796-6fe2c365-de157e5f-cc448ae5-03b72be2/file (built-in API)
I0416 23:58:29.925160          HTTP-39 StorageCache.cpp:127] Read attachment "f6f48d6e-0202-4cb7-96ac-8636770f1a9a" with content type 1 from cache
E0416 23:58:29.926190          HTTP-39 OrthancException.cpp:61] Bad file format: Cannot access a raw frame
E0416 23:58:29.926335          HTTP-39 PluginsErrorDictionary.cpp:100] Exception inside the plugin engine: Bad file format
I0416 23:58:30.265051          HTTP-40 HttpServer.cpp:1262] (http) GET /dicom-web/studies/1.2.840.114202.4.149708760.963734210.1534682287.1275927649/series/1.3.12.2.1107.5.2.19.145069.2023122716130076820674112.0.0.0/instances/1.3.12.2.1107.5.2.19.145069.2023122716130076242274109/frames/1
I0416 23:58:30.265350          HTTP-40 PluginsManager.cpp:161] (plugins) New HTTP request to: http://orthanc-auth-service:8000/user/get-profile (timeout: 10s)
I0416 23:58:30.270006          HTTP-40 PluginsManager.cpp:161] (plugins) HTTP status code 400 in 4 ms after POST request on: http://orthanc-auth-service:8000/user/get-profile
E0416 23:58:30.270049          HTTP-40 PluginsManager.cpp:153] Error in HTTP request, received HTTP status 400 (Bad Request) after POST request on: http://orthanc-auth-service:8000/user/get-profile
I0416 23:58:30.270305          HTTP-40 PluginsManager.cpp:161] (plugins) Testing whether user has the required permissions 'all|view' based on the HTTP header 'Authorization' required to match '^/dicom-web/studies/([.0-9]+)/series/([.0-9]+)/instances/([.0-9]+)(|/|/frames/.*|/rendered|/metadata|/bulk/.*)(|/)$' -> not granted
I0416 23:58:30.270424          HTTP-40 OrthancPlugins.cpp:3221] (plugins) Plugin making REST GET call on URI /instances/82687d19-cf4b2840-b28bbe3d-2fec321b-f2a457c3 (built-in API)
I0416 23:58:30.273949          HTTP-40 PluginsManager.cpp:161] (plugins) Linking Instance "82687d19-cf4b2840-b28bbe3d-2fec321b-f2a457c3" to its parent Series "e530fb8b-46f426ae-5e00030d-601ba70b-b08967e0"
I0416 23:58:30.274007          HTTP-40 PluginsManager.cpp:161] (plugins) Testing whether access to study "803a049a-cef111ef-d4bcc8f5-45ec6d93-3fc38c40" is allowed with a resource token
I0416 23:58:30.274041          HTTP-40 PluginsManager.cpp:161] (plugins) Testing whether access to study "803a049a-cef111ef-d4bcc8f5-45ec6d93-3fc38c40" is allowed with a resource token -> granted
I0416 23:58:30.274140          HTTP-40 OrthancPlugins.cpp:2475] (plugins) Delegating HTTP request to plugin for URI: /dicom-web/studies/1.2.840.114202.4.149708760.963734210.1534682287.1275927649/series/1.3.12.2.1107.5.2.19.145069.2023122716130076820674112.0.0.0/instances/1.3.12.2.1107.5.2.19.145069.2023122716130076242274109/frames/1
I0416 23:58:30.274316          HTTP-40 OrthancPlugins.cpp:4058] (plugins) Plugin making REST POST call to URI /tools/find (after plugins)
I0416 23:58:30.274430          HTTP-40 OrthancPlugins.cpp:2475] (plugins) Delegating HTTP request to plugin for URI: /tools/find
I0416 23:58:30.274657          HTTP-40 PluginsManager.cpp:161] (plugins) New HTTP request to: http://orthanc-auth-service:8000/user/get-profile (timeout: 10s)
I0416 23:58:30.278971          HTTP-40 PluginsManager.cpp:161] (plugins) HTTP status code 400 in 4 ms after POST request on: http://orthanc-auth-service:8000/user/get-profile
E0416 23:58:30.279056          HTTP-40 PluginsManager.cpp:153] Error in HTTP request, received HTTP status 400 (Bad Request) after POST request on: http://orthanc-auth-service:8000/user/get-profile
I0416 23:58:30.279334          HTTP-40 OrthancPlugins.cpp:3278] (plugins) Plugin making REST POST call on URI /tools/lookup (built-in API)
I0416 23:58:30.286904          HTTP-40 PluginsManager.cpp:161] (plugins) Testing whether access to study "803a049a-cef111ef-d4bcc8f5-45ec6d93-3fc38c40" is allowed with a resource token
I0416 23:58:30.286973          HTTP-40 PluginsManager.cpp:161] (plugins) Testing whether access to study "803a049a-cef111ef-d4bcc8f5-45ec6d93-3fc38c40" is allowed with a resource token -> granted
I0416 23:58:30.287111          HTTP-40 OrthancPlugins.cpp:3278] (plugins) Plugin making REST POST call on URI /tools/find (built-in API)
I0416 23:58:30.295582          HTTP-40 ServerContext.cpp:1561] Number of candidate resources after fast DB filtering on main DICOM tags: 1
I0416 23:58:30.298450          HTTP-40 ServerContext.cpp:1709] Number of matching resources: 1
I0416 23:58:30.298775          HTTP-40 PluginsManager.cpp:161] (plugins) DICOMweb RetrieveFrames on 82687d19-cf4b2840-b28bbe3d-2fec321b-f2a457c3, frames: 1 
I0416 23:58:30.298816          HTTP-40 OrthancPlugins.cpp:3221] (plugins) Plugin making REST GET call on URI /instances/82687d19-cf4b2840-b28bbe3d-2fec321b-f2a457c3/metadata/TransferSyntax (built-in API)
I0416 23:58:30.300270          HTTP-40 OrthancPlugins.cpp:3221] (plugins) Plugin making REST GET call on URI /instances/82687d19-cf4b2840-b28bbe3d-2fec321b-f2a457c3/file (built-in API)
I0416 23:58:30.301786          HTTP-40 StorageCache.cpp:127] Read attachment "32b1830d-38d7-4cc0-bd01-855183c53d34" with content type 1 from cache
E0416 23:58:30.303841          HTTP-40 OrthancException.cpp:61] Bad file format: Cannot access a raw frame
E0416 23:58:30.304102          HTTP-40 PluginsErrorDictionary.cpp:100] Exception inside the plugin engine: Bad file format

It seems like this isn’t an OHIF issue, but is a permissions issue with Orthanc/Keycloak?

For clarification, I also tried disabling OHIF and enabling the OHIF plugin, and two images loaded, the rest did not, and I checked the logs and see the same errors. Here is docker-compose.yml with the plugin enabled (everything exactly as is):

# SPDX-FileCopyrightText: 2022 - 2024 Orthanc Team SRL <info@orthanc.team>
#
# SPDX-License-Identifier: CC0-1.0

version: "3"
services:

  nginx:
    image: orthancteam/orthanc-nginx:24.2.0
    depends_on: [orthanc, orthanc-auth-service, keycloak]
    restart: unless-stopped
    ports: ["80:80"]
# if setting ENABLE_HTTPS: "true" env var, uncomment the following 4 lines and comment the line with 'ports: ["80:80"]'
#    ports: ["443:443"]
#    volumes:
#      - /.../crt.pem:/etc/nginx/tls/crt.pem
#      - /.../key.pem:/etc/nginx/tls/key.pem
    environment:
      ENABLE_ORTHANC: "true"
      ENABLE_KEYCLOAK: "true"
      ENABLE_ORTHANC_TOKEN_SERVICE: "false"
      ENABLE_HTTPS: "false"
# to use OHIF-plugin: you don't need the OHIF reverse proxy
      ENABLE_OHIF: "false"

  orthanc:
# to use OHIF-plugin:  use the master-unstable image
    image: orthancteam/orthanc-pre-release:master-unstable
#    image: orthancteam/orthanc:24.3.3
    volumes:
      - orthanc-storage:/var/lib/orthanc/db
    depends_on: [orthanc-db]
    restart: unless-stopped
    environment:
      STONE_WEB_VIEWER_PLUGIN_ENABLED: "true"
      DICOM_WEB_PLUGIN_ENABLED: "true"
      # to use OHIF-plugin:  make sure to have a "OHIF" config and use "dicom-web" source
      OHIF_PLUGIN_ENABLED: "true"
      ORTHANC__POSTGRESQL__HOST: "orthanc-db"
      VERBOSE_ENABLED: "true"
      VERBOSE_STARTUP: "true"
      ORTHANC_JSON: |
        {
          "Name": "Orthanc",
          "OrthancExplorer2": {
            "IsDefaultUI": true,
            "UiOptions": {
              "EnableShares": true,
              "DefaultShareDuration": 0,
              "ShareDurations": [0, 7, 15, 30, 90, 365],
              "EnableOpenInOhifViewer3": true,
              // to use OHIF-plugin:  use http://localhost/orthanc/ohif/
              "OhifViewer3PublicRoot": "http://localhost/orthanc/ohif/"
              //"OhifViewer3PublicRoot": "http://localhost/ohif/"
            },
            "Tokens" : {
              "InstantLinksValidity": 3600,
              "ShareType": "ohif-viewer-publication"
            },
            "Keycloak" : {
              "Enable": true,
              "Url": "http://localhost/keycloak/",
              "Realm": "orthanc",
              "ClientId": "orthanc"
            }
          },
          "AuthenticationEnabled": false,     // because it is handled by the authorization plugin
          "Authorization": {
            "WebServiceRootUrl": "http://orthanc-auth-service:8000/",
            "WebServiceUsername": "share-user",
            "WebServicePassword": "change-me",
            // to use OHIF-plugin:  make sure to include "ohif" in the list
            "StandardConfigurations" : [
              "osimis-web-viewer",
              "stone-webviewer",
              "orthanc-explorer-2",
              "ohif"
            ],
            "TokenHttpHeaders" : [ "api-key" ],
            "CheckedLevel": "studies"
          },
          "DicomWeb": {
            "Enable": true,
            "PublicRoot": "/orthanc/dicom-web/"
          }
          // to use OHIF-plugin:  make sure to have a "OHIF" config and use "dicom-web" source
          , "OHIF": {
            "DataSource": "dicom-web",
            "RouterBasename": "/orthanc/ohif/"
          }
        }

  orthanc-auth-service:
    image: orthancteam/orthanc-auth-service:24.2.0
    # always disable port mapping in production !!!
    # ports: ["8000:8000"]
    # permissions can be customized in the permissions.json file
    volumes:
      - ./permissions.jsonc:/orthanc_auth_service/permissions.json
    depends_on: [keycloak]
    restart: unless-stopped
    environment:
      SECRET_KEY: "change-me-I-am-a-secret-key"
      ENABLE_KEYCLOAK: "true"
#      ENABLE_KEYCLOAK_API_KEYS: "true"
#      KEYCLOAK_CLIENT_SECRET: "change-me-I-am-a-secret-you-get-in-keycloak-admin-ui"
      PUBLIC_ORTHANC_ROOT: "http://localhost/orthanc/"
      PUBLIC_LANDING_ROOT: "http://localhost/orthanc/ui/app/token-landing.html"
      # to use OHIF-plugin:  make sure to use http://localhost/orthanc/ohif/
#      PUBLIC_OHIF_ROOT: "http://localhost/ohif/"
      PUBLIC_OHIF_ROOT: "http://localhost/orthanc/ohif/"
      USERS: |
        {
          "share-user": "change-me"
        }

  orthanc-db:
    image: postgres:14
    restart: unless-stopped
    volumes: ["orthanc-db:/var/lib/postgresql/data"]
    environment:
      POSTGRES_HOST_AUTH_METHOD: "trust"

# to use OHIF-plugin: you don't need this container
#  ohif:
#    image: orthancteam/ohif-v3:24.2.0
#  uncomment if you want to customize ohif configuration
#    volumes:
#      - ./ohif-app-config.js:/usr/share/nginx/html/app-config.js
#    restart: unless-stopped


  keycloak:
    image: orthancteam/orthanc-keycloak:24.2.0
    depends_on: [keycloak-db]
    restart: unless-stopped
#    healthcheck:
#      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
    environment:
      KEYCLOAK_ADMIN: "admin"
      KEYCLOAK_ADMIN_PASSWORD: "change-me"
      KC_DB: "postgres"
      KC_DB_URL: "jdbc:postgresql://keycloak-db:5432/keycloak"
      KC_DB_USERNAME: "keycloak"
      KC_DB_PASSWORD: "keycloak"
      # KC_HOSTNAME_URL: "https://mydomain.com/keycloak"
      # KC_HOSTNAME_ADMIN_URL: "https://mydomain.com/keycloak"

  keycloak-db:
    image: postgres:14
    restart: unless-stopped
    volumes: ["keycloak-db:/var/lib/postgresql/data"]
    environment:
      POSTGRES_PASSWORD: "keycloak"
      POSTGRES_USER: "keycloak"
      POSTGRES_DB: "keycloak"

volumes:
  orthanc-storage:
  orthanc-db:
  keycloak-db:

An update. I just tried minimal-setup/basic-auth as is, and I have the same issue where a couple of images load, but the rest don’t. I checked the orthanc-auth-service container logs and I didn’t see anything abnormal. But in the Orthanc container logs:

W0417 01:42:15.354111           HTTP-5 ServerContext.cpp:2626] W001: Accessing Dicom tags from storage when accessing study : 0008,0060;0008,0201
W0417 01:42:15.638148           HTTP-5 ServerContext.cpp:2626] W001: Accessing Dicom tags from storage when accessing study : 0008,0060;0008,0201
E0417 01:42:23.169777           HTTP-3 OrthancException.cpp:61] Bad file format: Cannot access a raw frame
E0417 01:42:23.170036           HTTP-3 PluginsErrorDictionary.cpp:100] Exception inside the plugin engine: Bad file format
E0417 01:42:24.526862           HTTP-6 OrthancException.cpp:61] Bad file format: Cannot access a raw frame
E0417 01:42:24.527153           HTTP-6 PluginsErrorDictionary.cpp:100] Exception inside the plugin engine: Bad file format
E0417 01:42:59.253587        SAVE-JOBS PluginsManager.cpp:153] Exception in database back-end: Database could not serialize access due to concurrent update, the transaction should be retried

This error is not related to permissions. Your DICOM file is probably invalid (it seems it declares a frame index that is not available in the file).

So please first try with a file that is know to be valid to isolate problems. You can download a valid sample file e.g from here.

I tried the sample file and it worked. I was getting confused about the 400 error and thought it was permissions, but it seems that it has to do with unreadability or corruption. That leaves me with more questions. For example, why does the Orthanc Viewer plugin (v3) work for those specific DICOM images in the jodogne/orthanc-plugins container (I had tried this repo’s setup)?

Does it depend on the OHIF Viewer what it can/can’t read? Is there software that can convert the DICOM images to compatible DICOM images?

Here is an example of the properties of one of the images. I have an MRI of the head and MRA of the head/neck that I want to view:
Screenshot from 2024-04-17 11-47-51

Furthermore, if I load the images in this viewer here, it works 100% fine.

I am still trying to figure out what is wrong with the configuration so that my specific images won’t load.

I figured out that the image ohif/app is where I can get this viewer. I spun up containers with the default settings from this repo, and verified that I could see most of my images. There were 3 “spin” multi-images that wouldn’t load (from head/neck MRA). Then I figured out how to change ohif/viewer (old image) to ohif/app (new image) by modifying the ohif.js file to have this instead (I found the local_orthanc.js file contents and based it off that here):

console.log("LOCAL CONFIG LOADED");

window.config = {
  routerBasename: '/',
  extensions: [],
  modes: [],
  customizationService: {
    dicomUploadComponent:
      '@ohif/extension-cornerstone.customizationModule.cornerstoneDicomUploadComponent',
  },
  showStudyList: true,
  maxNumberOfWebWorkers: 3,
  showLoadingIndicator: true,
  showWarningMessageForCrossOrigin: true,
  showCPUFallbackMessage: true,
  strictZSpacingForVolumeViewport: true,
  // filterQueryParam: false,
  defaultDataSourceName: 'dicomweb',
  dataSources: [
    {
      friendlyName: 'dcmjs DICOMWeb Server',
      namespace: '@ohif/extension-default.dataSourcesModule.dicomweb',
      sourceName: 'dicomweb',
      configuration: {
        name: 'DCM4CHEE',
        wadoUriRoot: '/orthanc/wado',
        qidoRoot: '/orthanc/dicom-web',
        wadoRoot: '/orthanc/dicom-web',
        qidoSupportsIncludeField: true,
        supportsReject: true,
        imageRendering: 'wadors',
        thumbnailRendering: 'wadors',
        enableStudyLazyLoad: true,
        useBulkDataURI: false,
        supportsFuzzyMatching: true,
        supportsWildcard: true,
        dicomUploadEnabled: true,
      },
    },
    {
      friendlyName: 'dicom json',
      namespace: '@ohif/extension-default.dataSourcesModule.dicomjson',
      sourceName: 'dicomjson',
      configuration: {
        name: 'json',
      },
    },
    {
      friendlyName: 'dicom local',
      namespace: '@ohif/extension-default.dataSourcesModule.dicomlocal',
      sourceName: 'dicomlocal',
      configuration: {},
    },
  ],
  httpErrorHandler: error => {
    // This is 429 when rejected from the public idc sandbox too often.
    console.warn(error.status);

    // Could use services manager here to bring up a dialog/modal if needed.
    console.warn('test, navigate to https://ohif.org/');
  },
  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: 'flipViewportVertical',
      label: 'Flip Horizontally',
      keys: ['h'],
    },
    {
      commandName: 'flipViewportHorizontal',
      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: 'setZoomTool', 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'],
    },
  ],
};

Now I am able to view my images with zero issues, and it also runs very fast (isn’t laggy at all). My guess is that I need to use wado as a data source? That’s what this configuration does.

1 Like