UNPKG

@cornerstonejs/core

Version:
111 lines (110 loc) 4.65 kB
import { vec3 } from 'gl-matrix'; import { MetadataModules } from '../enums/index.js'; import { peerImport } from '../init.js'; import * as metaData from '../metaData.js'; import microscopyViewportCss from '../constants/microscopyViewportCss.js'; import imageIdToURI from './imageIdToURI.js'; const overlayCssId = 'wsiViewportOverlayCss'; export async function getDicomMicroscopyViewer() { return peerImport('dicom-microscopy-viewer'); } export function addWSIMiniNavigationOverlayCss() { if (document.getElementById(overlayCssId)) { return; } const overlayCss = document.createElement('style'); overlayCss.innerText = microscopyViewportCss; overlayCss.setAttribute('id', overlayCssId); document.getElementsByTagName('head')[0].append(overlayCss); } export function getWSIImageDataMetadata(args) { const { metadataDicomweb, imageIds, imageIndex = 0 } = args; const maxImage = metadataDicomweb.reduce((currentMax, image) => { return currentMax?.NumberOfFrames < image.NumberOfFrames ? image : currentMax; }); const { TotalPixelMatrixColumns: columns, TotalPixelMatrixRows: rows, ImageOrientationSlide, ImagedVolumeWidth: width, ImagedVolumeHeight: height, ImagedVolumeDepth: depth, } = maxImage; const imagePlaneModule = metaData.get(MetadataModules.IMAGE_PLANE, imageIds[imageIndex]); let rowCosines = ImageOrientationSlide.slice(0, 3); let columnCosines = ImageOrientationSlide.slice(3, 6); if (rowCosines == null || columnCosines == null) { rowCosines = [1, 0, 0]; columnCosines = [0, 1, 0]; } const rowCosineVec = vec3.fromValues(rowCosines[0], rowCosines[1], rowCosines[2]); const colCosineVec = vec3.fromValues(columnCosines[0], columnCosines[1], columnCosines[2]); const scanAxisNormal = vec3.create(); vec3.cross(scanAxisNormal, rowCosineVec, colCosineVec); const { XOffsetInSlideCoordinateSystem = 0, YOffsetInSlideCoordinateSystem = 0, ZOffsetInSlideCoordinateSystem = 0, } = maxImage.TotalPixelMatrixOriginSequence?.[0] || {}; const origin = [ XOffsetInSlideCoordinateSystem, YOffsetInSlideCoordinateSystem, ZOffsetInSlideCoordinateSystem, ]; const xSpacing = width / columns; const ySpacing = height / rows; const zSpacing = depth; const xVoxels = columns; const yVoxels = rows; const zVoxels = 1; return { bitsAllocated: 8, numberOfComponents: 3, origin, direction: [...rowCosineVec, ...colCosineVec, ...scanAxisNormal], dimensions: [xVoxels, yVoxels, zVoxels], spacing: [xSpacing, ySpacing, zSpacing], hasPixelSpacing: !!(width && height), numVoxels: xVoxels * yVoxels * zVoxels, imagePlaneModule, }; } export async function loadWSIData(args) { const { imageIds, client, dicomMicroscopyViewer } = args; const DicomMicroscopyViewer = dicomMicroscopyViewer || (await getDicomMicroscopyViewer()); let frameOfReferenceUID = null; const metadataDicomweb = imageIds.map((imageId) => { const imageMetadata = client.getDICOMwebMetadata(imageId); Object.defineProperty(imageMetadata, 'isMultiframe', { value: imageMetadata.isMultiframe, enumerable: false, }); Object.defineProperty(imageMetadata, 'frameNumber', { value: undefined, enumerable: false, }); const imageType = imageMetadata['00080008']?.Value; if (imageType?.length === 1) { imageMetadata['00080008'].Value = imageType[0].split('\\'); } const imageFrameOfReference = imageMetadata['00200052']?.Value?.[0]; if (!frameOfReferenceUID) { frameOfReferenceUID = imageFrameOfReference; } else if (imageFrameOfReference !== frameOfReferenceUID) { imageMetadata['00200052'].Value = [frameOfReferenceUID]; } return imageMetadata; }); const volumeImages = []; metadataDicomweb.forEach((metadata) => { const image = new DicomMicroscopyViewer.metadata.VLWholeSlideMicroscopyImage({ metadata, }); const imageFlavor = image.ImageType[2]; if (imageFlavor === 'VOLUME' || imageFlavor === 'THUMBNAIL') { volumeImages.push(image); } }); return { volumeImages, metadataDicomweb, metadata: getWSIImageDataMetadata({ metadataDicomweb: volumeImages, imageIds, }), frameOfReferenceUID, imageURISet: new Set(imageIds.map((imageId) => imageIdToURI(imageId))), }; }