From 4d97e9e881f626aef51c0e072f4a858fd89f0294 Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 10 Nov 2025 11:15:52 +0000 Subject: [PATCH] Enhance DICOM 3D loader to fallback to 2D loader for standard web images and handle 'https' URLs --- anatomy/static/js/anatomy.js | 51 +++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/anatomy/static/js/anatomy.js b/anatomy/static/js/anatomy.js index 493c17b3..9f3164f3 100644 --- a/anatomy/static/js/anatomy.js +++ b/anatomy/static/js/anatomy.js @@ -602,16 +602,41 @@ async function setUpDicom3d(element) { // but avoid forcing wadouri: for standard web images (png/jpg/etc) because // the dicom parser will fail when given non-DICOM files. For such images // return the raw URL so the appropriate web-image loader can handle them. + // If any image looks like a plain web image (png/jpg/etc) prefer the + // existing 2D cornerstone loader which handles http(s) image schemes. + // This avoids a situation where the 3D dicom loader has no handler for + // the 'https' scheme and throws "No image loader found for scheme 'https'". + const looksLikeWebImage = (u) => { + if (!u) return false; + try { u = u.trim(); } catch (e) {} + if (u.startsWith('data:image')) return true; + if (u.match(/\.(png|jpe?g|gif|bmp|webp)$/i)) return true; + return false; + }; + + if (images.some(looksLikeWebImage)) { + // Fallback: use the 2D cornerstone loader which has web-image handling + // and is more tolerant of raw http(s) URLs. We reuse the project's + // dicomViewer helper (it expects a jQuery element). + console.warn('setUpDicom3d: contains web-image(s) — falling back to 2D loader'); + try { + // annotations are not available in this scope in the 3d code path; pass + // undefined for annotations and let the loader handle it. + dicomViewer.loadCornerstone($(element), null, images, undefined, images.length > 5); + // store a lightweight marker so callers can inspect what happened + element._cornerstone3d = { fallback: 'cornerstone2d', imageCount: images.length }; + return element._cornerstone3d; + } catch (err) { + console.warn('Fallback 2D loader failed; will continue to try 3D loader', err); + // fallthrough to attempt 3D loading below + } + } + const imageIds = images.map((url) => { url = url.trim(); // if it's already a scheme we pass through if (/^(wadouri:|base64:|data:|http:|https:)/i.test(url)) return url; - // If the URL looks like a regular web image, don't treat it as DICOM - if (url.match(/\.(png|jpe?g|gif|bmp|webp)$/i)) { - return url; - } - // default: treat as wadouri (likely a DICOM file) return `wadouri:${url}`; }); @@ -629,7 +654,21 @@ async function setUpDicom3d(element) { } } - await viewport.setStack(imageIds, 0); + try { + await viewport.setStack(imageIds, 0); + } catch (err) { + // If the 3D loader fails because it doesn't know how to load 'https' + // URLs, fallback to the 2D cornerstone loader which handles web images. + console.warn('viewport.setStack failed, attempting 2D fallback:', err); + try { + dicomViewer.loadCornerstone($(element), null, images, undefined, images.length > 5); + element._cornerstone3d = { fallback: 'cornerstone2d', imageCount: images.length }; + return element._cornerstone3d; + } catch (err2) { + console.error('2D fallback also failed:', err2); + throw err; // rethrow original error + } + } viewport.render();