@cornerstonejs/core
Version:
Cornerstone3D Core
111 lines (110 loc) • 4.65 kB
JavaScript
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))),
};
}