UNPKG

@abasb75/dicom-pixel-decoder

Version:

a powerfull javascript dicom pixel data decoder

365 lines (364 loc) 19.6 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; import DecodedImage from "./DecodedImage"; import JPEG2000 from "./JPEG2000"; import JPEGBaselineLossyProcess2_12bit from "./JPEGBaselineLossyProcess2_12bit"; import JPEGBaselineLossyProcess1_8bit from "./JPEGBaselineLossyProcess1_8bit"; import JPEGLS from "./JPEGLS"; import JPEGLossLess from "./JPEGLossLess"; import UncompressDecoderr from "./Uncompressed"; import changeTypedArray from "./Utilities/changeTypedArray"; import getIsArrayPixelHasValidType from "./Utilities/getIsArrayPixelHasValidType"; import getMinMax from "./Utilities/getMinMax"; import getMinMaxAfterScale from "./Utilities/getMinMaxAfterScale"; import RLE from "./RLE"; import HTJ2K from "./HTJ2K"; import ybrFullToRgba from "./Utilities/ybrFull"; import ybrFull422ToRgba from "./Utilities/ybrFull422"; import applyPlanerConfiguration from "./Utilities/planerConfiguration"; import UnSyntaxed from "./UnSyntaxed"; import invertMonochrome1 from "./Utilities/invertMonoChrome1"; var Decoder = /** @class */ (function () { function Decoder() { } Object.defineProperty(Decoder, "decode", { enumerable: false, configurable: true, writable: true, value: function (pixelData, options) { return __awaiter(this, void 0, void 0, function () { var transferSyntaxUID, decodedPixelData, _a, image, i; return __generator(this, function (_b) { switch (_b.label) { case 0: transferSyntaxUID = options.transferSyntaxUID; decodedPixelData = null; _a = transferSyntaxUID; switch (_a) { case "1.2.840.10008.1.2": return [3 /*break*/, 1]; case "1.2.840.10008.1.2.1": return [3 /*break*/, 1]; case "1.2.840.10008.1.2.1.99": return [3 /*break*/, 1]; case "1.2.840.10008.1.2.2": return [3 /*break*/, 1]; case "1.2.840.10008.1.2.4.50": return [3 /*break*/, 2]; case "1.2.840.10008.1.2.4.51": return [3 /*break*/, 4]; case "1.2.840.10008.1.2.4.52": return [3 /*break*/, 4]; case "1.2.840.10008.1.2.4.53": return [3 /*break*/, 4]; case "1.2.840.10008.1.2.4.54": return [3 /*break*/, 4]; case "1.2.840.10008.1.2.4.55": return [3 /*break*/, 4]; case "1.2.840.10008.1.2.4.56": return [3 /*break*/, 4]; case "1.2.840.10008.1.2.4.58": return [3 /*break*/, 4]; case "1.2.840.10008.1.2.4.59": return [3 /*break*/, 4]; case "1.2.840.10008.1.2.4.60": return [3 /*break*/, 4]; case "1.2.840.10008.1.2.4.61": return [3 /*break*/, 4]; case "1.2.840.10008.1.2.4.62": return [3 /*break*/, 4]; case "1.2.840.10008.1.2.4.63": return [3 /*break*/, 4]; case "1.2.840.10008.1.2.4.64": return [3 /*break*/, 4]; case "1.2.840.10008.1.2.4.57": return [3 /*break*/, 6]; case "1.2.840.10008.1.2.4.65": return [3 /*break*/, 6]; case "1.2.840.10008.1.2.4.66": return [3 /*break*/, 6]; case "1.2.840.10008.1.2.4.70": return [3 /*break*/, 6]; case "1.2.840.10008.1.2.4.80": return [3 /*break*/, 8]; case "1.2.840.10008.1.2.4.81": return [3 /*break*/, 8]; case "1.2.840.10008.1.2.4.90": return [3 /*break*/, 10]; case "1.2.840.10008.1.2.4.91": return [3 /*break*/, 10]; case "1.2.840.10008.1.2.4.92": return [3 /*break*/, 10]; case "1.2.840.10008.1.2.4.93": return [3 /*break*/, 10]; case '3.2.840.10008.1.2.4.96': return [3 /*break*/, 12]; case "1.2.840.10008.1.2.4.201": return [3 /*break*/, 12]; case "1.2.840.10008.1.2.4.202": return [3 /*break*/, 12]; case "1.2.840.10008.1.2.4.203": return [3 /*break*/, 12]; case "1.2.840.10008.1.2.5": return [3 /*break*/, 14]; } return [3 /*break*/, 16]; case 1: decodedPixelData = UncompressDecoderr.decode(pixelData); return [3 /*break*/, 18]; case 2: return [4 /*yield*/, JPEGBaselineLossyProcess1_8bit.decode(pixelData, options)]; case 3: decodedPixelData = _b.sent(); return [3 /*break*/, 18]; case 4: return [4 /*yield*/, JPEGBaselineLossyProcess2_12bit.decode(pixelData, options)]; case 5: decodedPixelData = _b.sent(); return [3 /*break*/, 18]; case 6: return [4 /*yield*/, JPEGLossLess.decode(pixelData, options)]; case 7: decodedPixelData = _b.sent(); return [3 /*break*/, 18]; case 8: return [4 /*yield*/, JPEGLS.decode(pixelData)]; case 9: decodedPixelData = _b.sent(); return [3 /*break*/, 18]; case 10: return [4 /*yield*/, JPEG2000.decode(pixelData)]; case 11: decodedPixelData = _b.sent(); return [3 /*break*/, 18]; case 12: return [4 /*yield*/, HTJ2K.decode(pixelData)]; case 13: decodedPixelData = _b.sent(); return [3 /*break*/, 18]; case 14: return [4 /*yield*/, RLE.decode(pixelData, options)]; case 15: decodedPixelData = _b.sent(); return [3 /*break*/, 18]; case 16: return [4 /*yield*/, UnSyntaxed.decode(pixelData, options)]; case 17: decodedPixelData = _b.sent(); _b.label = 18; case 18: decodedPixelData = Decoder._toSutibleTypedArray(decodedPixelData, options); if (!decodedPixelData) return [2 /*return*/, null]; if (!decodedPixelData) { return [2 /*return*/, null]; } image = new DecodedImage(transferSyntaxUID, options.columns || 0, options.rows || 0, decodedPixelData); if (options.pixelRepresentation === 1 && options.bitsStored) { for (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 [2 /*return*/, image]; } }); }); } }); Object.defineProperty(Decoder, "_setLUT", { enumerable: false, configurable: true, writable: true, value: function (image, options) { if (options.windowCenter && options.windowWidth) { var windowWidth = options.windowWidth; var windowCenter = options.windowCenter; image.windowWidth = windowWidth; image.windowCenter = windowCenter; image.max = windowCenter - 0.5 + windowWidth / 2; image.min = windowCenter - 0.5 - windowWidth / 2; return; } var _a = image.getMinMax(), min = _a.min, max = _a.max; image.windowWidth = max - min; image.windowCenter = min + image.windowWidth / 2; } }); Object.defineProperty(Decoder, "_applyScaling", { enumerable: false, configurable: true, writable: true, value: function (image, options) { var _a = getMinMax(image.pixelData), min = _a.min, max = _a.max; image.min = min; image.max = max; var rescaleSlope = options.rescaleSlope, rescaleIntercept = options.rescaleIntercept; console.log('scaling module', rescaleSlope, rescaleIntercept); if (typeof rescaleSlope !== "number" || typeof rescaleIntercept !== "number") { return image.pixelData; } var _b = getMinMaxAfterScale(min, max, rescaleSlope, rescaleIntercept), minAfterScale = _b.minAfterScale, maxAfterScale = _b.maxAfterScale; console.log({ minAfterScale: minAfterScale, maxAfterScale: maxAfterScale }); if (min === minAfterScale && max === maxAfterScale) { return image.pixelData; } var isValidType = getIsArrayPixelHasValidType(image.pixelData, minAfterScale || 0, maxAfterScale || 0); image.min = minAfterScale; image.max = maxAfterScale; var _decodedPixelData = isValidType ? image.pixelData : changeTypedArray(image.pixelData, image.min || 0, image.max || 0); for (var i = 0; i < _decodedPixelData.length; i++) { _decodedPixelData[i] = _decodedPixelData[i] * rescaleSlope + rescaleIntercept; } return _decodedPixelData; } }); Object.defineProperty(Decoder, "_applyColorSpace", { enumerable: false, configurable: true, writable: true, value: function (image, options) { if (image.photometricInterpretation === 'MONOCHROME1') { image.pixelData = invertMonochrome1(image); } if (['RGB', 'YBR'].includes(options.photometricInterpretation) && options.planarConfiguration) { image.pixelData = applyPlanerConfiguration(image.pixelData); } if (options.photometricInterpretation === "YBR_FULL") { image.pixelData = ybrFullToRgba(image.pixelData, options); } else if (options.photometricInterpretation === "YBR_FULL_422") { image.pixelData = ybrFull422ToRgba(image.pixelData, options); } } }); Object.defineProperty(Decoder, "_toSutibleTypedArray", { enumerable: false, configurable: true, writable: true, value: function (pixelData, options) { var bitsAllocated = options.bitsAllocated; var offset = pixelData.byteOffset; var length = pixelData.byteLength; console.log({ options: options, bitsAllocated: bitsAllocated, pixelData: pixelData }); 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) { var buffer8 = new Uint8Array(pixelData); var bits = new Uint8Array((options.rows || 0) * (options.columns || 0)); for (var i = 0; i < buffer8.length; i++) { for (var j = 0; j < 8; j++) { bits[i * 8 + j] = (buffer8[i] >> (j)) & 1; } } return bits; } } }); Object.defineProperty(Decoder, "_endianFixer", { enumerable: false, configurable: true, writable: true, value: function (data, bigEndian) { if (bigEndian === void 0) { bigEndian = false; } if (!bigEndian) { return data; } if (data instanceof Uint16Array || data instanceof Int16Array) { for (var i = 0; i < data.byteLength; i++) { data[i] = ((data[i] & 0xff) << 8) | ((data[i] >> 8) & 0xff); } } return data; } }); Object.defineProperty(Decoder, "_fixSize", { enumerable: false, configurable: true, writable: true, value: function (pixelData, options) { var rows = (options === null || options === void 0 ? void 0 : options.rows) || 0; var columns = (options === null || options === void 0 ? void 0 : 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; } var 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; } var newPixelsArray = null; var 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 = -3.4e38; } else if (pixelData instanceof Float64Array) { newPixelsArray = new Float64Array(newLen); minimum = -1.8e308; } if (!newPixelsArray) return pixelData; for (var i = 0; i < newLen; i++) { newPixelsArray[i] = (i < pixelData.length) ? pixelData[i] : minimum; } return newPixelsArray; } }); return Decoder; }()); export default Decoder;