@abasb75/dicom-pixel-decoder
Version:
a powerfull javascript dicom pixel data decoder
365 lines (364 loc) • 19.6 kB
JavaScript
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;