UNPKG

@abasb75/dicom-pixel-decoder

Version:

A lightweight DICOM image decoder.

960 lines (937 loc) 32.7 kB
var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); // src/Utilities/getMinMax.ts function getMinMax(arrayPixel) { let min = arrayPixel[0]; let max = arrayPixel[0]; for (let i = 1; i < arrayPixel.length; i++) { const pixel = arrayPixel[i]; if (pixel < min) min = pixel; if (pixel > max) max = pixel; } return { min, max }; } var getMinMax_default = getMinMax; // src/Utilities/PaletteColor.ts var PaletteColor = class _PaletteColor { static applyPaletteColor(pixelData, paletteColorData) { if (!paletteColorData || !paletteColorData.red || !paletteColorData.blue || !paletteColorData.green) { return pixelData; } if (!paletteColorData.red.littleEndian && paletteColorData.red.bitsPerEntry === 16 && pixelData instanceof Uint8Array) { for (let i = 0; i < pixelData.byteLength; i += 2) { const pixel1 = pixelData[i]; const pixel2 = pixelData[i + 1]; pixelData[i] = pixel2; pixelData[i + 1] = pixel1; } } const redPixels = _PaletteColor.paletteDataToPixel(pixelData, paletteColorData.red); const greenPixels = _PaletteColor.paletteDataToPixel(pixelData, paletteColorData.green); const bluePixels = _PaletteColor.paletteDataToPixel(pixelData, paletteColorData.blue); if (!redPixels || !greenPixels || !bluePixels) { return pixelData; } let _pixelData = null; if (paletteColorData.red.bitsPerEntry === 16) { _pixelData = new Uint16Array(pixelData.length * 3); } else { _pixelData = new Uint8Array(pixelData.length * 3); } for (let i = 0; i < pixelData.length; i++) { _pixelData[i * 3] = redPixels[i]; _pixelData[i * 3 + 1] = greenPixels[i]; _pixelData[i * 3 + 2] = bluePixels[i]; } return _pixelData; } static paletteDataToPixel(pixelData, colorData) { if (!colorData.data) { return null; } let _pixelData = new Array(pixelData.length); for (let i = 0; i < pixelData.length; i++) { let pixel = pixelData[i]; if (pixel < colorData.firstInputValueMapped) { pixel = 0; } else if (pixel > colorData.firstInputValueMapped + colorData.lutEntries - 1) { pixel = colorData.lutEntries - 1; } else { pixel = pixel - colorData.firstInputValueMapped; } _pixelData[i] = colorData.data[pixel]; } return _pixelData; } }; var PaletteColor_default = PaletteColor; // src/Utilities/PixelSpacing.ts var PixelSpacing = class _PixelSpacing { static apply(pixelData, pixelSpacing, width, hieght, samplePerPixel) { if (!pixelSpacing || !Array.isArray(pixelSpacing)) { return { pixelData, pixelSpacing, width, hieght }; } if (pixelSpacing.length > 2 || pixelSpacing[0] === pixelSpacing[1]) { return { pixelData, pixelSpacing, width, hieght }; } const xPixelSpacing = pixelSpacing[1]; const yPixelSpacing = pixelSpacing[0]; if (xPixelSpacing > yPixelSpacing) { return _PixelSpacing.xScaling( pixelData, xPixelSpacing, yPixelSpacing, width, hieght, samplePerPixel ); } return _PixelSpacing.yScaling( pixelData, xPixelSpacing, yPixelSpacing, width, hieght, samplePerPixel ); } // untested static yScaling(pixelData, xPixelSpacing, yPixelSpacing, width, hieght, samplePerPixel) { const scaledX = yPixelSpacing / xPixelSpacing; const newHieght = Math.floor(hieght * scaledX); const _pixelData = new pixelData.constructor(width * newHieght * samplePerPixel); for (let i = 0; i < width; i++) { for (let j = 0; j < newHieght; j++) { const base = i * width * j; if (j === 0) { for (let k = 0; k < samplePerPixel; k++) { _pixelData[i + k] = pixelData[i + k]; } continue; } const targetPixelIndex = Math.round(i * hieght / newHieght); for (let k = 0; k < samplePerPixel; k++) { _pixelData[base + j + k] = pixelData[i * width * targetPixelIndex + k]; } } } return { pixelData: _pixelData, width, hieght: newHieght }; } static xScaling(pixelData, xPixelSpacing, yPixelSpacing, width, hieght, samplePerPixel) { const scaledX = xPixelSpacing / yPixelSpacing; const newWidth = Math.floor(width * scaledX); const _pixelData = new pixelData.constructor(newWidth * hieght * samplePerPixel); for (let j = 0; j < hieght; j++) { for (let i = 0; i < newWidth; i++) { const baseTarget = j * newWidth; const baseSource = j * width; if (i === 0) { for (let k = 0; k < samplePerPixel; k++) { _pixelData[baseTarget + i + k] = pixelData[baseSource + i + k]; } continue; } const targetPixelIndex = Math.round(i * width / newWidth); for (let k = 0; k < samplePerPixel; k++) { _pixelData[baseTarget + i + k] = pixelData[baseSource + targetPixelIndex + k]; } } } return { pixelData: _pixelData, width: newWidth, hieght }; } }; var PixelSpacing_default = PixelSpacing; // src/DecodedImage.ts var DecodedImage = class { constructor(transferSyntax, width, height, pixelData) { __publicField(this, "transferSyntax"); __publicField(this, "width"); __publicField(this, "height"); __publicField(this, "min"); __publicField(this, "max"); __publicField(this, "windowWidth"); __publicField(this, "windowCenter"); __publicField(this, "pixelData"); __publicField(this, "photometricInterpretation"); __publicField(this, "pixelModule"); __publicField(this, "scalingModule"); __publicField(this, "voiLUTModule"); __publicField(this, "arrayType"); __publicField(this, "littleEndian", true); __publicField(this, "pixelTypes", "Integer"); this.transferSyntax = transferSyntax; this.width = width; this.height = height; this.pixelData = pixelData; } getMinMax() { return getMinMax_default(this.pixelData); } getLUT() { return { ...this.getMinMax(), windowWidth: this.windowWidth, windowCenter: this.windowCenter }; } applyPaletteColor(paleteData) { if (paleteData) { this.pixelData = PaletteColor_default.applyPaletteColor( this.pixelData, paleteData ); Decoder_default._setLUT(this, { ...this.pixelModule, ...this.scalingModule, ...this.voiLUTModule, littleEndian: this.littleEndian, transferSyntaxUID: this.transferSyntax, isFloat: this.pixelTypes === "Float" }); } } applySpacing() { const scaled = PixelSpacing_default.apply( this.pixelData, this.pixelModule?.pixelSpacing, this.width, this.height, this.pixelModule?.samplesPerPixel || 1 ); this.pixelData = scaled.pixelData; this.width = scaled.width; this.height = scaled.hieght; } }; var DecodedImage_default = DecodedImage; // src/Decoders/JPEG2000.ts import { decode } from "@abasb75/jpeg2000-decoder"; var JPEG2000 = class { static async decode(pixelData) { const buffer = new Uint8Array(pixelData.buffer, pixelData.byteOffset, pixelData.byteLength).buffer; const decoded = await decode(buffer); return decoded.decodedBuffer; } }; var JPEG2000_default = JPEG2000; // src/Decoders/JPEGBaselineLossyProcess1_8bit.ts import turboJPEGDecoder from "@abasb75/turbojpeg-codec/decode"; import JpegImage from "@abasb75/jpegjs"; var turboJPEG = null; var JPEGBaselineLossyProcess1_8bit = class _JPEGBaselineLossyProcess1_8bit { static async decode(pixelData, options) { try { if (options.bitsAllocated === 8 && [3, 4].includes(options.samplesPerPixel)) { return _JPEGBaselineLossyProcess1_8bit.browser(pixelData); } else { return _JPEGBaselineLossyProcess1_8bit.jpegJS(pixelData, options); } } catch { const data = await _JPEGBaselineLossyProcess1_8bit.turboJpeg(pixelData); return data; } } static async jpegJS(pixelData, options) { const jpeg2 = new JpegImage(); jpeg2.parse(new Uint8Array(pixelData.buffer)); if (options.bitsAllocated > 8) { return jpeg2.getData16(options.columns, options.rows); } return jpeg2.getData(options.columns, options.rows); } static async browser(pixelData) { if (typeof document === "undefined") { if (typeof createImageBitmap !== "undefined" && typeof OffscreenCanvas !== "undefined") { return await this.browserV2(pixelData); } return await _JPEGBaselineLossyProcess1_8bit.turboJpeg(pixelData); } const createImage = (imageData2) => new Promise((resolve, reject) => { var img2 = document.createElement("img"); img2.src = imageData2; img2.onload = () => { resolve(img2); }; img2.onerror = () => { reject(); }; }); const buffer = new Uint8Array(pixelData.buffer, pixelData.byteOffset, pixelData.byteLength).slice().buffer; var blob = new Blob([buffer], { type: "image/jpeg" }); var urlCreator = window.URL || window.webkitURL; var imageUrl = urlCreator.createObjectURL(blob); const img = await createImage(imageUrl); const canvas = document.createElement("canvas"); canvas.height = img.height; canvas.width = img.width; const context = canvas.getContext("2d"); context?.drawImage(img, 0, 0); const imageData = context?.getImageData(0, 0, img.width, img.height); return new Uint8Array(imageData?.data?.buffer); } static async browserV2(pixelData) { const buffer = new Uint8Array(pixelData.buffer, pixelData.byteOffset, pixelData.byteLength).slice().buffer; const blob = new Blob([buffer], { type: "image/jpeg" }); const imageBitmap = await createImageBitmap(blob); const canvas = new OffscreenCanvas(imageBitmap.width, imageBitmap.height); const ctx = canvas.getContext("2d"); if (!ctx) { throw new Error("Could not get OffscreenCanvasRenderingContext2D"); } ctx.drawImage(imageBitmap, 0, 0); const imageData = ctx.getImageData(0, 0, imageBitmap.width, imageBitmap.height); return new Uint8Array(imageData.data.buffer); } static async turboJpeg(pixelData) { if (!turboJPEG) { turboJPEG = await turboJPEGDecoder(); } const iterations = 1; const decoder3 = new turboJPEG.JPEGDecoder(); const encodedBitStream = new Uint8Array(pixelData.buffer); const encodedBuffer = decoder3.getEncodedBuffer(encodedBitStream.length); encodedBuffer.set(encodedBitStream); for (let i = 0; i < iterations; i++) { decoder3.decode(); } const frameInfo = decoder3.getFrameInfo(); var decodedBuffer = decoder3.getDecodedBuffer(); return decodedBuffer; } }; var JPEGBaselineLossyProcess1_8bit_default = JPEGBaselineLossyProcess1_8bit; // src/Decoders/JPEGBaselineLossyProcess2_12bit.ts var JPEGBaselineLossyProcess2_12bit = class extends JPEGBaselineLossyProcess1_8bit_default { static async decode(pixelData, options) { return this.jpegJS(pixelData, options); } }; var JPEGBaselineLossyProcess2_12bit_default = JPEGBaselineLossyProcess2_12bit; // src/Decoders/JPEGLS.ts import CharLSDecoder from "@abasb75/charls/decode"; var decoder = null; var decode2 = null; var JPEGLS = class { static async decode(pixelData) { if (!decoder || !decode2) { decoder = await CharLSDecoder(); decode2 = decoder.decode; } const buffer = new Uint8Array(pixelData.buffer, pixelData.byteOffset, pixelData.byteLength).slice(); const decoded = await decode2(buffer); return decoded?.data; } }; var JPEGLS_default = JPEGLS; // src/Decoders/JPEGLossLess.ts import * as jpeg from "jpeg-lossless-decoder-js"; var decoder2 = null; var JPEGLossLess = class { static async decode(pixelData, options) { if (!decoder2) { const Decoder3 = jpeg.Decoder; decoder2 = new Decoder3(); } const decoded = decoder2.decode( pixelData.buffer, pixelData.byteOffset, pixelData.byteLength, options.bitsAllocated === 8 ? 1 : 2 ); return decoded; } }; var JPEGLossLess_default = JPEGLossLess; // src/Decoders/Uncompressed.ts var UncompressedDecoder = class { // only convert dataview to uint8 now static decode(pixelData) { let arrayBuffer = pixelData.buffer; return new Uint8Array(arrayBuffer); } }; var Uncompressed_default = UncompressedDecoder; // src/Utilities/changeTypedArray.ts function changeTypedArray(pixelArray, minAfterScale, maxAfterScale) { if (Number.isInteger(minAfterScale) && Number.isInteger(maxAfterScale)) { if (minAfterScale >= 0 && minAfterScale <= 255) { return new Uint8Array(pixelArray); } else if (minAfterScale >= 0 && minAfterScale <= 65535) { return new Uint16Array(pixelArray); } else if (minAfterScale >= 0 && maxAfterScale <= 4294967295) { return new Uint32Array(pixelArray); } else if (minAfterScale >= -128 && minAfterScale <= 127) { return new Int8Array(pixelArray); } else if (minAfterScale >= -32768 && minAfterScale <= 32767) { return new Int16Array(pixelArray); } else if (minAfterScale >= -2147483648 && maxAfterScale <= 2147483647) { return new Int32Array(pixelArray); } } return new Float32Array(pixelArray); } var changeTypedArray_default = changeTypedArray; // src/Utilities/getIsArrayPixelHasValidType.ts function getIsArrayPixelHasValidType(arrayPixel, min, max) { if (arrayPixel instanceof Uint8Array) { if (min < 0 || max > 255) { return false; } } else if (arrayPixel instanceof Int8Array) { if (min < -128 || max > 127) { return false; } } else if (arrayPixel instanceof Uint16Array) { if (min < 0 || max > 65535) { return false; } } else if (arrayPixel instanceof Int16Array) { if (min < -32768 || max > 32767) { return false; } } return true; } var getIsArrayPixelHasValidType_default = getIsArrayPixelHasValidType; // src/Utilities/getMinMaxAfterScale.ts function getMinMaxAfterScale(min, max, rescaleSlope, rescaleIntercept) { if (typeof rescaleSlope !== "number" || typeof rescaleIntercept !== "number") { return { min, max }; } return { minAfterScale: min * rescaleSlope + rescaleIntercept, maxAfterScale: max * rescaleSlope + rescaleIntercept }; } var getMinMaxAfterScale_default = getMinMaxAfterScale; // src/Decoders/RLE.ts import * as dicomRle from "dicom-rle"; var RLE = class { static decode(pixelData, options) { const { rows, columns, samplesPerPixel, bitsAllocated, planarConfiguration } = options; if (!rows || !columns || !samplesPerPixel) { return null; } const decoder3 = new dicomRle.RleDecoder(); const decoded = decoder3.decode(new Uint8Array(pixelData.buffer), { height: rows, width: columns, samplesPerPixel, bitsAllocated, planarConfiguration }); return decoded; } }; var RLE_default = RLE; // src/Decoders/HTJ2K.ts import OpenJPHDecoder from "@abasb75/openjph/decode"; var openjphDecoder = null; var HTJ2K = class { static async decode(pixelData) { if (!openjphDecoder) { openjphDecoder = await OpenJPHDecoder(); } const uint8Array = new Uint8Array(pixelData.buffer); const iterations = 1; const decodeLevel = 0; const decoder3 = new openjphDecoder.HTJ2KDecoder(); const encodedBuffer = decoder3.getEncodedBuffer(uint8Array.length); encodedBuffer.set(uint8Array); decoder3.readHeader(); for (let i = 0; i < iterations; i++) { decoder3.decodeSubResolution(decodeLevel); } const frameInfo = decoder3.getFrameInfo(); const decodedBuffer = decoder3.getDecodedBuffer(); console.log({ frameInfo }); return decodedBuffer; } }; var HTJ2K_default = HTJ2K; // src/Utilities/ybrFull.ts function yrbFullToRgba(pixelData, pixelModule) { const { columns, rows, planarConfiguration } = pixelModule; if (!columns || !rows) { return pixelData; } if (pixelData.length !== columns * rows * 3) { return pixelData; } const pixelCounts = rows * columns; const _pixelData = new Uint8ClampedArray(pixelCounts * 4); if (planarConfiguration === 1) { for (let i = 0; i < pixelCounts; i++) { const y = pixelData[i]; const cb = pixelData[pixelCounts + i]; const cr = pixelData[pixelCounts * 2 + i]; _pixelData[i * 4] = y + 1.402 * (cr - 128); _pixelData[i * 4 + 1] = y - 0.34414 * (cb - 128) - 0.71414 * (cr - 128); _pixelData[i * 4 + 2] = y + 1.772 * (cb - 128); _pixelData[i * 4 + 3] = 255; } } else { for (let i = 0; i < pixelCounts; i++) { const y = pixelData[i * 3]; const cb = pixelData[i * 3 + 1]; const cr = pixelData[i * 3 + 2]; _pixelData[i * 4] = y + 1.402 * (cr - 128); _pixelData[i * 4 + 1] = y - 0.34414 * (cb - 128) - 0.71414 * (cr - 128); _pixelData[i * 4 + 2] = y + 1.772 * (cb - 128); _pixelData[i * 4 + 3] = 255; } } return new Uint8Array(_pixelData); } var ybrFull_default = yrbFullToRgba; // src/Utilities/ybrFull422.ts function ybrFull422ToRgba(pixelData, pixelModule) { const { columns, rows } = pixelModule; if (!columns || !rows) { return pixelData; } const pixelCounts = rows * columns; if (pixelData.length !== 2 * pixelCounts) { return pixelData; } const _pixelData = new Uint8ClampedArray(pixelCounts * 4); let ybrIndex = 0; for (let i = 0; i < pixelCounts; i += 2) { const y1 = pixelData[ybrIndex++]; const y2 = pixelData[ybrIndex++]; const cb = pixelData[ybrIndex++]; const cr = pixelData[ybrIndex++]; _pixelData[i * 4] = y1 + 1.402 * (cr - 128); _pixelData[i * 4 + 1] = y1 - 0.34414 * (cb - 128) - 0.71414 * (cr - 128); _pixelData[i * 4 + 2] = y1 + 1.772 * (cb - 128); _pixelData[i * 4 + 3] = 255; _pixelData[i * 4 + 4] = y2 + 1.402 * (cr - 128); _pixelData[i * 4 + 5] = y2 - 0.34414 * (cb - 128) - 0.71414 * (cr - 128); _pixelData[i * 4 + 6] = y2 + 1.772 * (cb - 128); _pixelData[i * 4 + 7] = 255; } return new Uint16Array(_pixelData); } var ybrFull422_default = ybrFull422ToRgba; // src/Utilities/planerConfiguration.ts function applyPlanerConfiguration(pixelData) { if (pixelData.length % 3 !== 0) { return pixelData; } const pixelCounts = pixelData.length / 3; const _pixelData = new Uint8ClampedArray(pixelCounts * 4); for (let i = 0; i < pixelCounts; i++) { _pixelData[i * 4] = pixelData[i]; _pixelData[i * 4 + 1] = pixelData[pixelCounts + i]; _pixelData[i * 4 + 2] = pixelData[2 * pixelCounts + i]; _pixelData[i * 4 + 3] = 255; } return new Uint8Array(_pixelData); } var planerConfiguration_default = applyPlanerConfiguration; // src/Decoders/UnSyntaxed.ts var UnSyntaxed = class { // for unsupported transfer syntax // TODO: need to logic for identifying image type static async decode(pixelData, options) { console.warn("image has no transfersyntax or supported syntax."); const { columns, rows } = options; const bitsAllocated = options.bitsAllocated ? options.bitsAllocated : 8; if (!columns || !rows) { throw new Error("image has not sepefected width & row!"); } if (pixelData.byteLength) { options.bitsAllocated = bitsAllocated || 8; return Uncompressed_default.decode(pixelData); } } }; var UnSyntaxed_default = UnSyntaxed; // src/Utilities/invertMonoChrome1.ts function invertMonochrome1(image) { const { min, max } = image.getMinMax(); for (let i = 0; i < image.pixelData.length; i++) { image.pixelData[i] = max - (image.pixelData[i] + min); } return image.pixelData; } var invertMonoChrome1_default = invertMonochrome1; // src/Decoder.ts var Decoder2 = class _Decoder { static async decode(pixelData, options) { const transferSyntaxUID = options.transferSyntaxUID; let decodedPixelData = null; switch (transferSyntaxUID) { case "1.2.840.10008.1.2": case "1.2.840.10008.1.2.1": case "1.2.840.10008.1.2.1.99": case "1.2.840.10008.1.2.2": decodedPixelData = Uncompressed_default.decode(pixelData); break; case "1.2.840.10008.1.2.4.50": decodedPixelData = await JPEGBaselineLossyProcess1_8bit_default.decode(pixelData, options); break; case "1.2.840.10008.1.2.4.51": case "1.2.840.10008.1.2.4.52": /**untested */ case "1.2.840.10008.1.2.4.53": case "1.2.840.10008.1.2.4.54": /**untested */ case "1.2.840.10008.1.2.4.55": case "1.2.840.10008.1.2.4.56": /**untested */ case "1.2.840.10008.1.2.4.58": /**untested */ case "1.2.840.10008.1.2.4.59": /**untested */ case "1.2.840.10008.1.2.4.60": /**untested */ case "1.2.840.10008.1.2.4.61": /**untested */ case "1.2.840.10008.1.2.4.62": /**untested */ case "1.2.840.10008.1.2.4.63": /**untested */ case "1.2.840.10008.1.2.4.64": decodedPixelData = await JPEGBaselineLossyProcess2_12bit_default.decode(pixelData, options); break; case "1.2.840.10008.1.2.4.57": case "1.2.840.10008.1.2.4.65": /**untested */ case "1.2.840.10008.1.2.4.66": /**untested */ case "1.2.840.10008.1.2.4.70": decodedPixelData = await JPEGLossLess_default.decode(pixelData, options); break; case "1.2.840.10008.1.2.4.80": case "1.2.840.10008.1.2.4.81": decodedPixelData = await JPEGLS_default.decode(pixelData); break; case "1.2.840.10008.1.2.4.90": case "1.2.840.10008.1.2.4.91": case "1.2.840.10008.1.2.4.92": /**untested */ case "1.2.840.10008.1.2.4.93": decodedPixelData = await JPEG2000_default.decode(pixelData); break; case "3.2.840.10008.1.2.4.96": /**untested */ case "1.2.840.10008.1.2.4.201": case "1.2.840.10008.1.2.4.202": /**untested */ case "1.2.840.10008.1.2.4.203": decodedPixelData = await HTJ2K_default.decode(pixelData); break; case "1.2.840.10008.1.2.5": decodedPixelData = await RLE_default.decode(pixelData, options); break; default: decodedPixelData = await UnSyntaxed_default.decode(pixelData, options); } decodedPixelData = _Decoder._toSutibleTypedArray(decodedPixelData, options); if (!decodedPixelData) return null; if (!decodedPixelData) { return null; } const image = new DecodedImage_default( transferSyntaxUID, options.columns || 0, options.rows || 0, decodedPixelData ); if (options.pixelRepresentation === 1 && options.bitsStored) { for (let i = 0; i < image.pixelData.length; i++) { image.pixelData[i] = image.pixelData[i] << 32 - options.bitsStored >> 32 - options.bitsStored; } } image.photometricInterpretation = options.photometricInterpretation; _Decoder._applyColorSpace(image, options); image.pixelData = _Decoder._applyScaling(image, options); _Decoder._setLUT(image, options); image.pixelData = _Decoder._fixSize(image.pixelData, options); return image; } static _setLUT(image, options) { if (options.windowCenter && options.windowWidth) { let windowWidth = options.windowWidth; let windowCenter = options.windowCenter; if (Array.isArray(windowWidth)) { windowWidth = windowWidth.length ? windowWidth[0] : 0; } options; if (Array.isArray(windowCenter)) { windowCenter = windowCenter.length ? windowCenter[0] : 0; } image.windowWidth = windowWidth; image.windowCenter = windowCenter; image.max = windowCenter - 0.5 + windowWidth / 2; image.min = windowCenter - 0.5 - windowWidth / 2; return; } const { min, max } = image.getMinMax(); image.windowWidth = max - min; image.windowCenter = min + image.windowWidth / 2; } static _applyScaling(image, options) { const { min, max } = image.getMinMax(); image.min = min; image.max = max; const { rescaleSlope, rescaleIntercept } = options; if (typeof rescaleSlope !== "number" || typeof rescaleIntercept !== "number") { return image.pixelData; } const { minAfterScale, maxAfterScale } = getMinMaxAfterScale_default( min, max, rescaleSlope, rescaleIntercept ); if (min === minAfterScale && max === maxAfterScale) { return image.pixelData; } const isValidType = getIsArrayPixelHasValidType_default( image.pixelData, minAfterScale || 0, maxAfterScale || 0 ); image.min = minAfterScale; image.max = maxAfterScale; const _decodedPixelData = isValidType ? image.pixelData : changeTypedArray_default( image.pixelData, image.min || 0, image.max || 0 ); for (let i = 0; i < _decodedPixelData.length; i++) { _decodedPixelData[i] = _decodedPixelData[i] * rescaleSlope + rescaleIntercept; } return _decodedPixelData; } static _applyColorSpace(image, options) { if (image.photometricInterpretation === "MONOCHROME1") { image.pixelData = invertMonoChrome1_default( image ); } if (["RGB", "YBR"].includes(options.photometricInterpretation) && options.planarConfiguration) { image.pixelData = planerConfiguration_default(image.pixelData); } if (options.photometricInterpretation === "YBR_FULL") { image.pixelData = ybrFull_default(image.pixelData, options); } else if (options.photometricInterpretation === "YBR_FULL_422") { image.pixelData = ybrFull422_default(image.pixelData, options); } } static _toSutibleTypedArray(pixelData, options) { const { bitsAllocated } = options; const offset = pixelData.byteOffset; const length = pixelData.byteLength; if (bitsAllocated > 32) { return new Float64Array( pixelData.buffer, offset, length / 8 ); } else if (bitsAllocated > 16) { if (options.isFloat) { return _Decoder._endianFixer( new Float32Array( pixelData.buffer, offset, length / 4 ), !options.littleEndian ); } if (options.pixelRepresentation === 0) { return _Decoder._endianFixer( new Uint32Array( pixelData.buffer, offset, length / 4 ), !options.littleEndian ); } return _Decoder._endianFixer( new Float32Array( pixelData.buffer, offset, length / 4 ), !options.littleEndian ); } else if (bitsAllocated > 8) { if (options.pixelRepresentation === 0) { return _Decoder._endianFixer( new Uint16Array( pixelData.buffer, offset, length / 2 ), !options.littleEndian ); } return _Decoder._endianFixer( new Int16Array( pixelData.buffer, offset, length / 2 ), !options.littleEndian ); } else if (bitsAllocated === 8) { if (options.pixelRepresentation === 0) { return _Decoder._endianFixer( new Uint8Array(pixelData), !options.littleEndian ); } return _Decoder._endianFixer( new Int8Array(pixelData), !options.littleEndian ); } else if (bitsAllocated === 1) { const buffer8 = new Uint8Array(pixelData); const bits = new Uint8Array((options.rows || 0) * (options.columns || 0)); for (let i = 0; i < buffer8.length; i++) { for (let j = 0; j < 8; j++) { bits[i * 8 + j] = buffer8[i] >> j & 1; } } return bits; } } static _endianFixer(data, bigEndian = false) { if (!bigEndian) { return data; } if (data instanceof Uint16Array || data instanceof Int16Array) { for (let i = 0; i < data.byteLength; i++) { data[i] = (data[i] & 255) << 8 | data[i] >> 8 & 255; } } return data; } static _fixSize(pixelData, options) { const rows = options?.rows || 0; const columns = options?.columns || 0; if (rows * columns === pixelData.length) { return pixelData; } else if (3 * rows * columns === pixelData.length) { return pixelData; } else if (4 * rows * columns === pixelData.length) { return pixelData; } let newLen = null; if (pixelData.length < rows * columns) { newLen = columns * rows; } else if (pixelData.length < 3 * rows * columns) { newLen = 3 * columns * rows; } else { newLen = 4 * columns * rows; } let newPixelsArray = null; let minimum = 0; if (pixelData instanceof Int8Array) { newPixelsArray = new Int8Array(newLen); minimum = -128; } else if (pixelData instanceof Uint8Array) { newPixelsArray = new Uint8Array(newLen); } else if (pixelData instanceof Int16Array) { newPixelsArray = new Int16Array(newLen); minimum = -32768; } else if (pixelData instanceof Uint16Array) { newPixelsArray = new Uint16Array(newLen); } else if (pixelData instanceof Int32Array) { newPixelsArray = new Int32Array(newLen); minimum = -2147483648; } else if (pixelData instanceof Uint32Array) { newPixelsArray = new Uint32Array(newLen); } else if (pixelData instanceof Float32Array) { newPixelsArray = new Float32Array(newLen); minimum = -34e37; } else if (pixelData instanceof Float64Array) { newPixelsArray = new Float64Array(newLen); minimum = -Infinity; } if (!newPixelsArray) return pixelData; for (let i = 0; i < newLen; i++) { newPixelsArray[i] = i < pixelData.length ? pixelData[i] : minimum; } return newPixelsArray; } }; var Decoder_default = Decoder2; // src/decode.ts async function decode3(pixelData, options) { let pixelDataView; if (pixelData instanceof ArrayBuffer) { pixelDataView = new DataView(pixelData); } else { pixelDataView = pixelData; } const image = await Decoder_default.decode(pixelDataView, options); image.pixelModule = { pixelMeasuresSequence: options.pixelMeasuresSequence, photometricInterpretation: options.photometricInterpretation, numberOfFrames: options.numberOfFrames, pixelRepresentation: options.pixelRepresentation, pixelSpacing: options.pixelSpacing, spacingBetweenSlices: options.spacingBetweenSlices, rows: options.rows, columns: options.columns, bitsAllocated: options.bitsAllocated, highBit: options.highBit, bitsStored: options.bitsStored, samplesPerPixel: options.samplesPerPixel, pixelDataProviderURL: options.pixelDataProviderURL, pixelPaddingRangeLimit: options.pixelPaddingRangeLimit, extendedOffsetTable: options.extendedOffsetTable, extendedOffsetTableLengths: options.extendedOffsetTableLengths, pixelAspectRatio: options.pixelAspectRatio, planarConfiguration: options.planarConfiguration, redPaletteColorLookupTableDescriptor: options.redPaletteColorLookupTableDescriptor, greenPaletteColorLookupTableDescriptor: options.greenPaletteColorLookupTableDescriptor, bluePaletteColorLookupTableDescriptor: options.bluePaletteColorLookupTableDescriptor, alphaPaletteColorLookupTableDescriptor: options.alphaPaletteColorLookupTableDescriptor, redPaletteColorLookupTableData: options.redPaletteColorLookupTableData, greenPaletteColorLookupTableData: options.greenPaletteColorLookupTableData, bluePaletteColorLookupTableData: options.bluePaletteColorLookupTableData, alphaPaletteColorLookupTableData: options.alphaPaletteColorLookupTableData, segmentedRedPaletteColorLookupTableData: options.segmentedRedPaletteColorLookupTableData, segmentedGreenPaletteColorLookupTableData: options.segmentedGreenPaletteColorLookupTableData, segmentedBluePaletteColorLookupTableData: options.segmentedBluePaletteColorLookupTableData, segmentedAlphaPaletteColorLookupTableData: options.segmentedAlphaPaletteColorLookupTableData }; image.pixelTypes = options.isFloat ? "Float" : "Integer"; return image; } var decode_default = decode3; export { decode_default as decode };