@cornerstonejs/dicom-image-loader
Version:
Cornerstone Image Loader for DICOM WADO-URI and WADO-RS and Local file
94 lines (93 loc) • 3.68 kB
JavaScript
import openJpegFactory from '@cornerstonejs/codec-openjpeg/decodewasmjs';
const openjpegWasm = new URL('@cornerstonejs/codec-openjpeg/decodewasm', import.meta.url);
const local = {
codec: undefined,
decoder: undefined,
decodeConfig: {},
};
export function initialize(decodeConfig) {
local.decodeConfig = decodeConfig;
if (local.codec) {
return Promise.resolve();
}
const openJpegModule = openJpegFactory({
locateFile: (f) => {
if (f.endsWith('.wasm')) {
return openjpegWasm.toString();
}
return f;
},
});
return new Promise((resolve, reject) => {
openJpegModule.then((instance) => {
local.codec = instance;
local.decoder = new instance.J2KDecoder();
resolve();
}, reject);
});
}
async function decodeAsync(compressedImageFrame, imageInfo) {
await initialize();
const decoder = local.decoder;
const encodedBufferInWASM = decoder.getEncodedBuffer(compressedImageFrame.length);
encodedBufferInWASM.set(compressedImageFrame);
decoder.decode();
const frameInfo = decoder.getFrameInfo();
const decodedBufferInWASM = decoder.getDecodedBuffer();
const imageFrame = new Uint8Array(decodedBufferInWASM.length);
imageFrame.set(decodedBufferInWASM);
const imageOffset = `x: ${decoder.getImageOffset().x}, y: ${decoder.getImageOffset().y}`;
const numDecompositions = decoder.getNumDecompositions();
const numLayers = decoder.getNumLayers();
const progessionOrder = ['unknown', 'LRCP', 'RLCP', 'RPCL', 'PCRL', 'CPRL'][decoder.getProgressionOrder() + 1];
const reversible = decoder.getIsReversible();
const blockDimensions = `${decoder.getBlockDimensions().width} x ${decoder.getBlockDimensions().height}`;
const tileSize = `${decoder.getTileSize().width} x ${decoder.getTileSize().height}`;
const tileOffset = `${decoder.getTileOffset().x}, ${decoder.getTileOffset().y}`;
const colorTransform = decoder.getColorSpace();
const decodedSize = `${decodedBufferInWASM.length.toLocaleString()} bytes`;
const compressionRatio = `${(decodedBufferInWASM.length / encodedBufferInWASM.length).toFixed(2)}:1`;
const encodedImageInfo = {
columns: frameInfo.width,
rows: frameInfo.height,
bitsPerPixel: frameInfo.bitsPerSample,
signed: frameInfo.isSigned,
bytesPerPixel: imageInfo.bytesPerPixel,
componentsPerPixel: frameInfo.componentCount,
};
const pixelData = getPixelData(frameInfo, decodedBufferInWASM);
const encodeOptions = {
imageOffset,
numDecompositions,
numLayers,
progessionOrder,
reversible,
blockDimensions,
tileSize,
tileOffset,
colorTransform,
decodedSize,
compressionRatio,
};
return {
...imageInfo,
pixelData,
imageInfo: encodedImageInfo,
encodeOptions,
...encodeOptions,
...encodedImageInfo,
};
}
function getPixelData(frameInfo, decodedBuffer) {
if (frameInfo.bitsPerSample > 8) {
if (frameInfo.isSigned) {
return new Int16Array(decodedBuffer.buffer, decodedBuffer.byteOffset, decodedBuffer.byteLength / 2);
}
return new Uint16Array(decodedBuffer.buffer, decodedBuffer.byteOffset, decodedBuffer.byteLength / 2);
}
if (frameInfo.isSigned) {
return new Int8Array(decodedBuffer.buffer, decodedBuffer.byteOffset, decodedBuffer.byteLength);
}
return new Uint8Array(decodedBuffer.buffer, decodedBuffer.byteOffset, decodedBuffer.byteLength);
}
export default decodeAsync;