UNPKG

ami-cjs.js

Version:

<p align="center"> <img src="https://cloud.githubusercontent.com/assets/214063/23213764/78ade038-f90c-11e6-8208-4fcade5f3832.png" width="60%"> </p>

967 lines (813 loc) 36.1 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _parsers = require('./parsers.volume'); var _parsers2 = _interopRequireDefault(_parsers); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // ftp://medical.nema.org/MEDICAL/Dicom/2014c/output/chtml/part05/sect_6.2.html/ // Slicer way to handle images // should follow it... // 897 if ( (this->IndexSeriesInstanceUIDs[k] != idxSeriesInstanceUID && this->IndexSeriesInstanceUIDs[k] >= 0 && idxSeriesInstanceUID >= 0) || // 898 (this->IndexContentTime[k] != idxContentTime && this->IndexContentTime[k] >= 0 && idxContentTime >= 0) || // 899 (this->IndexTriggerTime[k] != idxTriggerTime && this->IndexTriggerTime[k] >= 0 && idxTriggerTime >= 0) || // 900 (this->IndexEchoNumbers[k] != idxEchoNumbers && this->IndexEchoNumbers[k] >= 0 && idxEchoNumbers >= 0) || // 901 (this->IndexDiffusionGradientOrientation[k] != idxDiffusionGradientOrientation && this->IndexDiffusionGradientOrientation[k] >= 0 && idxDiffusionGradientOrientation >= 0) || // 902 (this->IndexSliceLocation[k] != idxSliceLocation && this->IndexSliceLocation[k] >= 0 && idxSliceLocation >= 0) || // 903 (this->IndexImageOrientationPatient[k] != idxImageOrientationPatient && this->IndexImageOrientationPatient[k] >= 0 && idxImageOrientationPatient >= 0) ) // 904 { // 905 continue; // 906 } /** * Imports ***/ var DicomParser = require('dicom-parser'); var Jpeg = require('jpeg-lossless-decoder-js'); var JpegBaseline = require('../../external/scripts/jpeg'); var Jpx = require('../../external/scripts/jpx'); /** * Dicom parser is a combination of utilities to get a VJS image from dicom files. *scripts * Relies on dcmjs, jquery, HTML5 fetch API, HTML5 promise API. * * @module parsers/dicom * * @param arrayBuffer {arraybuffer} - List of files to be parsed. It is urls from which * VJS.parsers.dicom can pull the data from. */ var ParsersDicom = function (_ParsersVolume) { _inherits(ParsersDicom, _ParsersVolume); function ParsersDicom(data, id) { _classCallCheck(this, ParsersDicom); var _this = _possibleConstructorReturn(this, (ParsersDicom.__proto__ || Object.getPrototypeOf(ParsersDicom)).call(this)); _this._id = id; _this._arrayBuffer = data.buffer; var byteArray = new Uint8Array(_this._arrayBuffer); // catch error // throw error if any! _this._dataSet = null; try { _this._dataSet = DicomParser.parseDicom(byteArray); } catch (e) { window.console.log(e); throw 'parsers.dicom could not parse the file'; } return _this; } // image/frame specific _createClass(ParsersDicom, [{ key: 'seriesInstanceUID', value: function seriesInstanceUID() { return this._dataSet.string('x0020000e'); } }, { key: 'studyInstanceUID', value: function studyInstanceUID() { return this._dataSet.string('x0020000d'); } }, { key: 'modality', value: function modality() { return this._dataSet.string('x00080060'); } }, { key: 'segmentationType', value: function segmentationType() { return this._dataSet.string('x00620001'); } }, { key: 'segmentationSegments', value: function segmentationSegments() { var segmentationSegments = []; var segmentSequence = this._dataSet.elements.x00620002; if (!segmentSequence) { return segmentationSegments; } for (var i = 0; i < segmentSequence.items.length; i++) { var recommendedDisplayCIELab = this._recommendedDisplayCIELab(segmentSequence.items[i]); var segmentationCode = this._segmentationCode(segmentSequence.items[i]); var segmentNumber = segmentSequence.items[i].dataSet.uint16('x00620004'); var segmentLabel = segmentSequence.items[i].dataSet.string('x00620005'); var segmentAlgorithmType = segmentSequence.items[i].dataSet.string('x00620008'); segmentationSegments.push({ recommendedDisplayCIELab: recommendedDisplayCIELab, segmentationCodeDesignator: segmentationCode['segmentationCodeDesignator'], segmentationCodeValue: segmentationCode['segmentationCodeValue'], segmentationCodeMeaning: segmentationCode['segmentationCodeMeaning'], segmentNumber: segmentNumber, segmentLabel: segmentLabel, segmentAlgorithmType: segmentAlgorithmType }); } return segmentationSegments; } }, { key: '_segmentationCode', value: function _segmentationCode(segment) { var segmentationCodeDesignator = 'unknown'; var segmentationCodeValue = 'unknown'; var segmentationCodeMeaning = 'unknown'; var element = segment.dataSet.elements.x00082218; if (element && element.items && element.items.length > 0) { segmentationCodeDesignator = element.items[0].dataSet.string('x00080102'); segmentationCodeValue = element.items[0].dataSet.string('x00080100'); segmentationCodeMeaning = element.items[0].dataSet.string('x00080104'); } return { segmentationCodeDesignator: segmentationCodeDesignator, segmentationCodeValue: segmentationCodeValue, segmentationCodeMeaning: segmentationCodeMeaning }; } }, { key: '_recommendedDisplayCIELab', value: function _recommendedDisplayCIELab(segment) { if (!segment.dataSet.elements.x0062000d) { return null; } var offset = segment.dataSet.elements.x0062000d.dataOffset; var length = segment.dataSet.elements.x0062000d.length; var byteArray = segment.dataSet.byteArray.slice(offset, offset + length); // https://www.dabsoft.ch/dicom/3/C.10.7.1.1/ var CIELabScaled = new Uint16Array(length / 2); for (var i = 0; i < length / 2; i++) { CIELabScaled[i] = (byteArray[2 * i + 1] << 8) + byteArray[2 * i]; } var CIELabNormalized = [CIELabScaled[0] / 65535 * 100, CIELabScaled[1] / 65535 * 255 - 128, CIELabScaled[2] / 65535 * 255 - 128]; return CIELabNormalized; } }, { key: 'sopInstanceUID', value: function sopInstanceUID() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; // 2005140f only works for siemens // which is the real one? var sopInstanceUID = this._findStringEverywhere('x2005140f', 'x00080018', frameIndex); return sopInstanceUID; } }, { key: 'transferSyntaxUID', value: function transferSyntaxUID() { return this._dataSet.string('x00020010'); } }, { key: 'photometricInterpretation', value: function photometricInterpretation() { return this._dataSet.string('x00280004'); } }, { key: 'planarConfiguration', value: function planarConfiguration() { var planarConfiguration = this._dataSet.uint16('x00280006'); if (typeof planarConfiguration === 'undefined') { planarConfiguration = null; } return planarConfiguration; } }, { key: 'samplesPerPixel', value: function samplesPerPixel() { return this._dataSet.uint16('x00280002'); } }, { key: 'numberOfFrames', value: function numberOfFrames() { var numberOfFrames = this._dataSet.intString('x00280008'); // need something smarter! if (typeof numberOfFrames === 'undefined') { numberOfFrames = null; } return numberOfFrames; } }, { key: 'numberOfChannels', value: function numberOfChannels() { var numberOfChannels = 1; var photometricInterpretation = this.photometricInterpretation(); if (!(photometricInterpretation !== 'RGB' && photometricInterpretation !== 'PALETTE COLOR' && photometricInterpretation !== 'YBR_FULL' && photometricInterpretation !== 'YBR_FULL_422' && photometricInterpretation !== 'YBR_PARTIAL_422' && photometricInterpretation !== 'YBR_PARTIAL_420' && photometricInterpretation !== 'YBR_RCT')) { numberOfChannels = 3; } // make sure we return a number! (not a string!) return numberOfChannels; } }, { key: 'invert', value: function invert() { var photometricInterpretation = this.photometricInterpretation(); return photometricInterpretation === 'MONOCHROME1' ? true : false; } }, { key: 'imageOrientation', value: function imageOrientation() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; // expect frame index to start at 0! var imageOrientation = this._findStringEverywhere('x00209116', 'x00200037', frameIndex); // format image orientation ('1\0\0\0\1\0') to array containing 6 numbers if (imageOrientation) { // make sure we return a number! (not a string!) // might not need to split (floatString + index) imageOrientation = imageOrientation.split('\\').map(Number); } return imageOrientation; } }, { key: 'referencedSegmentNumber', value: function referencedSegmentNumber() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var referencedSegmentNumber = -1; var referencedSegmentNumberElement = this._findInGroupSequence('x52009230', 'x0062000a', frameIndex); if (referencedSegmentNumberElement !== null) { referencedSegmentNumber = referencedSegmentNumberElement.uint16('x0062000b'); } return referencedSegmentNumber; } }, { key: 'pixelAspectRatio', value: function pixelAspectRatio() { var pixelAspectRatio = [this._dataSet.intString('x00280034', 0), this._dataSet.intString('x00280034', 1)]; // need something smarter! if (typeof pixelAspectRatio[0] === 'undefined') { pixelAspectRatio = null; } // make sure we return a number! (not a string!) return pixelAspectRatio; } }, { key: 'imagePosition', value: function imagePosition() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var imagePosition = this._findStringEverywhere('x00209113', 'x00200032', frameIndex); // format image orientation ('1\0\0\0\1\0') to array containing 6 numbers if (imagePosition) { // make sure we return a number! (not a string!) imagePosition = imagePosition.split('\\').map(Number); } return imagePosition; } }, { key: 'instanceNumber', value: function instanceNumber() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var instanceNumber = null; // first look for frame! // per frame functionnal group sequence var perFrameFunctionnalGroupSequence = this._dataSet.elements.x52009230; if (typeof perFrameFunctionnalGroupSequence !== 'undefined') { if (perFrameFunctionnalGroupSequence.items[frameIndex].dataSet.elements.x2005140f) { var planeOrientationSequence = perFrameFunctionnalGroupSequence.items[frameIndex].dataSet.elements.x2005140f.items[0].dataSet; instanceNumber = planeOrientationSequence.intString('x00200013'); } else { instanceNumber = this._dataSet.intString('x00200013'); if (typeof instanceNumber === 'undefined') { instanceNumber = null; } } } else { // should we default to undefined?? // default orientation instanceNumber = this._dataSet.intString('x00200013'); if (typeof instanceNumber === 'undefined') { instanceNumber = null; } } return instanceNumber; } }, { key: 'pixelSpacing', value: function pixelSpacing() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; // expect frame index to start at 0! var pixelSpacing = this._findStringEverywhere('x00289110', 'x00280030', frameIndex); // format image orientation ('1\0\0\0\1\0') to array containing 6 numbers // should we default to undefined?? if (pixelSpacing) { // make sure we return array of numbers! (not strings!) pixelSpacing = pixelSpacing.split('\\').map(Number); } return pixelSpacing; } }, { key: 'rows', value: function rows() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var rows = this._dataSet.uint16('x00280010'); if (typeof rows === 'undefined') { rows = null; // print warning at least... } return rows; } }, { key: 'columns', value: function columns() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var columns = this._dataSet.uint16('x00280011'); if (typeof columns === 'undefined') { columns = null; // print warning at least... } return columns; } }, { key: 'pixelType', value: function pixelType() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; // 0 integer, 1 float // dicom only support integers return 0; } }, { key: 'pixelRepresentation', value: function pixelRepresentation() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var pixelRepresentation = this._dataSet.uint16('x00280103'); return pixelRepresentation; } }, { key: 'bitsAllocated', value: function bitsAllocated() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; // expect frame index to start at 0! var bitsAllocated = this._dataSet.uint16('x00280100'); return bitsAllocated; } }, { key: 'highBit', value: function highBit() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; // expect frame index to start at 0! var highBit = this._dataSet.uint16('x00280102'); return highBit; } }, { key: 'rescaleIntercept', value: function rescaleIntercept() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; return this._findFloatStringInFrameGroupSequence('x00289145', 'x00281052', frameIndex); } }, { key: 'rescaleSlope', value: function rescaleSlope() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; return this._findFloatStringInFrameGroupSequence('x00289145', 'x00281053', frameIndex); } }, { key: 'windowCenter', value: function windowCenter() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; return this._findFloatStringInFrameGroupSequence('x00289132', 'x00281050', frameIndex); } }, { key: 'windowWidth', value: function windowWidth() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; return this._findFloatStringInFrameGroupSequence('x00289132', 'x00281051', frameIndex); } }, { key: 'sliceThickness', value: function sliceThickness() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; return this._findFloatStringInFrameGroupSequence('x00289110', 'x00180050', frameIndex); } }, { key: 'spacingBetweenSlices', value: function spacingBetweenSlices() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var spacing = this._dataSet.intString('x00180088'); if (typeof spacing === 'undefined') { spacing = null; } return spacing; } }, { key: 'dimensionIndexValues', value: function dimensionIndexValues() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var dimensionIndexValues = null; // try to get it from enhanced MR images // per-frame functionnal group sequence var perFrameFunctionnalGroupSequence = this._dataSet.elements.x52009230; if (typeof perFrameFunctionnalGroupSequence !== 'undefined') { var frameContentSequence = perFrameFunctionnalGroupSequence.items[frameIndex].dataSet.elements.x00209111; if (frameContentSequence !== undefined && frameContentSequence !== null) { frameContentSequence = frameContentSequence.items[0].dataSet; var dimensionIndexValuesElt = frameContentSequence.elements.x00209157; if (dimensionIndexValuesElt !== undefined && dimensionIndexValuesElt !== null) { // /4 because UL var nbValues = dimensionIndexValuesElt.length / 4; dimensionIndexValues = []; for (var i = 0; i < nbValues; i++) { dimensionIndexValues.push(frameContentSequence.uint32('x00209157', i)); } } } } return dimensionIndexValues; } }, { key: 'inStackPositionNumber', value: function inStackPositionNumber() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var inStackPositionNumber = null; // try to get it from enhanced MR images // per-frame functionnal group sequence var perFrameFunctionnalGroupSequence = this._dataSet.elements.x52009230; if (typeof perFrameFunctionnalGroupSequence !== 'undefined') { // NOT A PHILIPS TRICK! var philipsPrivateSequence = perFrameFunctionnalGroupSequence.items[frameIndex].dataSet.elements.x00209111.items[0].dataSet; inStackPositionNumber = philipsPrivateSequence.uint32('x00209057'); } else { inStackPositionNumber = null; } console.log('instack position ' + inStackPositionNumber); return inStackPositionNumber; } }, { key: 'stackID', value: function stackID() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var stackID = null; // try to get it from enhanced MR images // per-frame functionnal group sequence var perFrameFunctionnalGroupSequence = this._dataSet.elements.x52009230; if (typeof perFrameFunctionnalGroupSequence !== 'undefined') { // NOT A PHILIPS TRICK! var philipsPrivateSequence = perFrameFunctionnalGroupSequence.items[frameIndex].dataSet.elements.x00209111.items[0].dataSet; stackID = philipsPrivateSequence.intString('x00209056'); } else { stackID = null; } return stackID; } }, { key: 'extractPixelData', value: function extractPixelData() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; // decompress var decompressedData = this._decodePixelData(frameIndex); var numberOfChannels = this.numberOfChannels(); if (numberOfChannels > 1) { return this._convertColorSpace(decompressedData); } else { return decompressedData; } } }, { key: 'minMaxPixelData', value: function minMaxPixelData() { var pixelData = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; var minMax = [65535, -32768]; var numPixels = pixelData.length; for (var index = 0; index < numPixels; index++) { var spv = pixelData[index]; minMax[0] = Math.min(minMax[0], spv); minMax[1] = Math.max(minMax[1], spv); } return minMax; } // // private methods // }, { key: '_findInGroupSequence', value: function _findInGroupSequence(sequence, subsequence, index) { var functionalGroupSequence = this._dataSet.elements[sequence]; if (typeof functionalGroupSequence !== 'undefined') { var inSequence = functionalGroupSequence.items[index].dataSet.elements[subsequence]; if (typeof inSequence !== 'undefined') { return inSequence.items[0].dataSet; } } return null; } }, { key: '_findStringInGroupSequence', value: function _findStringInGroupSequence(sequence, subsequence, tag, index) { // index = 0 if shared!!! var dataSet = this._findInGroupSequence(sequence, subsequence, index); if (dataSet !== null) { return dataSet.string(tag); } return null; } }, { key: '_findStringInFrameGroupSequence', value: function _findStringInFrameGroupSequence(subsequence, tag, index) { return this._findStringInGroupSequence('x52009229', subsequence, tag, 0) || this._findStringInGroupSequence('x52009230', subsequence, tag, index); } }, { key: '_findStringEverywhere', value: function _findStringEverywhere(subsequence, tag, index) { var targetString = this._findStringInFrameGroupSequence(subsequence, tag, index); if (targetString === null) { targetString = this._dataSet.string(tag); } if (typeof targetString === 'undefined') { targetString = null; } return targetString; } }, { key: '_findFloatStringInGroupSequence', value: function _findFloatStringInGroupSequence(sequence, subsequence, tag, index) { var dataInGroupSequence = this._dataSet.floatString(tag); // try to get it from enhanced MR images // per-frame functionnal group if (typeof dataInGroupSequence === 'undefined') { dataInGroupSequence = this._findInGroupSequence(sequence, subsequence, index); if (dataInGroupSequence !== null) { return dataInGroupSequence.floatString(tag); } else { return null; } } return dataInGroupSequence; } }, { key: '_findFloatStringInFrameGroupSequence', value: function _findFloatStringInFrameGroupSequence(subsequence, tag, index) { return this._findFloatStringInGroupSequence('x52009229', subsequence, tag, 0) || this._findFloatStringInGroupSequence('x52009230', subsequence, tag, index); } }, { key: '_decodePixelData', value: function _decodePixelData() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; // if compressed..? var transferSyntaxUID = this.transferSyntaxUID(); // find compression scheme if (transferSyntaxUID === '1.2.840.10008.1.2.4.90' || // JPEG 2000 Lossless transferSyntaxUID === '1.2.840.10008.1.2.4.91') { // JPEG 2000 Lossy // JPEG 2000 return this._decodeJ2K(frameIndex); } else if (transferSyntaxUID === '1.2.840.10008.1.2.4.57' || // JPEG Lossless, Nonhierarchical (Processes 14) transferSyntaxUID === '1.2.840.10008.1.2.4.70') { // JPEG Lossless, Nonhierarchical (Processes 14 [Selection 1]) // JPEG LOSSLESS return this._decodeJPEGLossless(frameIndex); } else if (transferSyntaxUID === '1.2.840.10008.1.2.4.50' || // JPEG Baseline lossy process 1 (8 bit) transferSyntaxUID === '1.2.840.10008.1.2.4.51') { // JPEG Baseline lossy process 2 & 4 (12 bit) // JPEG Baseline return this._decodeJPEGBaseline(frameIndex); } else if (transferSyntaxUID === '1.2.840.10008.1.2' || // Implicit VR Little Endian transferSyntaxUID === '1.2.840.10008.1.2.1') { // Explicit VR Little Endian // get data return this._decodeUncompressed(frameIndex); } else if (transferSyntaxUID === '1.2.840.10008.1.2.2') { // Explicit VR Big Endian // get data var frame = this._decodeUncompressed(frameIndex); // and sawp it! return this._swapFrame(frame); } else { throw 'no decoder for transfer syntax ' + transferSyntaxUID; } } }, { key: '_decodeJ2K', value: function _decodeJ2K() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var encodedPixelData = DicomParser.readEncapsulatedPixelData(this._dataSet, this._dataSet.elements.x7fe00010, frameIndex); // let pixelDataElement = this._dataSet.elements.x7fe00010; // let pixelData = new Uint8Array(this._dataSet.byteArray.buffer, pixelDataElement.dataOffset, pixelDataElement.length); var jpxImage = new Jpx(); // https://github.com/OHIF/image-JPEG2000/issues/6 // It currently returns either Int16 or Uint16 based on whether the codestream is signed or not. jpxImage.parse(encodedPixelData); // let j2kWidth = jpxImage.width; // let j2kHeight = jpxImage.height; var componentsCount = jpxImage.componentsCount; if (componentsCount !== 1) { throw 'JPEG2000 decoder returned a componentCount of ${componentsCount}, when 1 is expected'; } var tileCount = jpxImage.tiles.length; if (tileCount !== 1) { throw 'JPEG2000 decoder returned a tileCount of ${tileCount}, when 1 is expected'; } var tileComponents = jpxImage.tiles[0]; var pixelData = tileComponents.items; // window.console.log(j2kWidth, j2kHeight); return pixelData; } // from cornerstone }, { key: '_decodeJPEGLossless', value: function _decodeJPEGLossless() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var encodedPixelData = DicomParser.readEncapsulatedPixelData(this._dataSet, this._dataSet.elements.x7fe00010, frameIndex); var pixelRepresentation = this.pixelRepresentation(frameIndex); var bitsAllocated = this.bitsAllocated(frameIndex); var byteOutput = bitsAllocated <= 8 ? 1 : 2; var decoder = new Jpeg.lossless.Decoder(); var decompressedData = decoder.decode(encodedPixelData.buffer, encodedPixelData.byteOffset, encodedPixelData.length, byteOutput); if (pixelRepresentation === 0) { if (byteOutput === 2) { return new Uint16Array(decompressedData.buffer); } else { // untested! return new Uint8Array(decompressedData.buffer); } } else { return new Int16Array(decompressedData.buffer); } } }, { key: '_decodeJPEGBaseline', value: function _decodeJPEGBaseline() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var encodedPixelData = DicomParser.readEncapsulatedPixelData(this._dataSet, this._dataSet.elements.x7fe00010, frameIndex); var rows = this.rows(frameIndex); var columns = this.columns(frameIndex); var bitsAllocated = this.bitsAllocated(frameIndex); var jpegBaseline = new JpegBaseline(); jpegBaseline.parse(encodedPixelData); if (bitsAllocated === 8) { return jpegBaseline.getData(columns, rows); } else if (bitsAllocated === 16) { return jpegBaseline.getData16(columns, rows); } } }, { key: '_decodeUncompressed', value: function _decodeUncompressed() { var frameIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var pixelRepresentation = this.pixelRepresentation(frameIndex); var bitsAllocated = this.bitsAllocated(frameIndex); var pixelDataElement = this._dataSet.elements.x7fe00010; var pixelDataOffset = pixelDataElement.dataOffset; var numberOfChannels = this.numberOfChannels(); var numPixels = this.rows(frameIndex) * this.columns(frameIndex) * numberOfChannels; var frameOffset = 0; var buffer = this._dataSet.byteArray.buffer; if (pixelRepresentation === 0 && bitsAllocated === 8) { // unsigned 8 bit frameOffset = pixelDataOffset + frameIndex * numPixels; return new Uint8Array(buffer, frameOffset, numPixels); } else if (pixelRepresentation === 0 && bitsAllocated === 16) { // unsigned 16 bit frameOffset = pixelDataOffset + frameIndex * numPixels * 2; return new Uint16Array(buffer, frameOffset, numPixels); } else if (pixelRepresentation === 1 && bitsAllocated === 16) { // signed 16 bit frameOffset = pixelDataOffset + frameIndex * numPixels * 2; return new Int16Array(buffer, frameOffset, numPixels); } else if (pixelRepresentation === 0 && bitsAllocated === 32) { // unsigned 32 bit frameOffset = pixelDataOffset + frameIndex * numPixels * 4; return new Uint32Array(buffer, frameOffset, numPixels); } else if (pixelRepresentation === 0 && bitsAllocated === 1) { var newBuffer = new ArrayBuffer(numPixels); var newArray = new Uint8Array(newBuffer); frameOffset = pixelDataOffset + frameIndex * numPixels; var index = 0; var bitStart = frameIndex * numPixels; var bitEnd = frameIndex * numPixels + numPixels; var byteStart = Math.floor(bitStart / 8); var bitStartOffset = bitStart - byteStart * 8; var byteEnd = Math.ceil(bitEnd / 8); var targetBuffer = new Uint8Array(buffer, pixelDataOffset); for (var i = byteStart; i <= byteEnd; i++) { while (bitStartOffset < 8) { switch (bitStartOffset) { case 0: newArray[index] = targetBuffer[i] & 0x0001; break; case 1: newArray[index] = targetBuffer[i] >>> 1 & 0x0001; break; case 2: newArray[index] = targetBuffer[i] >>> 2 & 0x0001; break; case 3: newArray[index] = targetBuffer[i] >>> 3 & 0x0001; break; case 4: newArray[index] = targetBuffer[i] >>> 4 & 0x0001; break; case 5: newArray[index] = targetBuffer[i] >>> 5 & 0x0001; break; case 6: newArray[index] = targetBuffer[i] >>> 6 & 0x0001; break; case 7: newArray[index] = targetBuffer[i] >>> 7 & 0x0001; break; default: break; } bitStartOffset++; index++; // if return.. if (index >= numPixels) { return newArray; } } bitStartOffset = 0; } } } }, { key: '_convertColorSpace', value: function _convertColorSpace(uncompressedData) { var rgbData = null; var photometricInterpretation = this.photometricInterpretation(); var planarConfiguration = this.planarConfiguration(); if (photometricInterpretation === 'RGB' && planarConfiguration === 0) { // ALL GOOD, ALREADY ORDERED // planar or non planar planarConfiguration rgbData = uncompressedData; } else if (photometricInterpretation === 'RGB' && planarConfiguration === 1) { if (uncompressedData instanceof Int8Array) { rgbData = new Int8Array(uncompressedData.length); } else if (uncompressedData instanceof Uint8Array) { rgbData = new Uint8Array(uncompressedData.length); } else if (uncompressedData instanceof Int16Array) { rgbData = new Int16Array(uncompressedData.length); } else if (uncompressedData instanceof Uint16Array) { rgbData = new Uint16Array(uncompressedData.length); } else { throw 'unsuported typed array: ${uncompressedData}'; } var numPixels = uncompressedData.length / 3; var rgbaIndex = 0; var rIndex = 0; var gIndex = numPixels; var bIndex = numPixels * 2; for (var i = 0; i < numPixels; i++) { rgbData[rgbaIndex++] = uncompressedData[rIndex++]; // red rgbData[rgbaIndex++] = uncompressedData[gIndex++]; // green rgbData[rgbaIndex++] = uncompressedData[bIndex++]; // blue } } else if (photometricInterpretation === 'YBR_FULL') { if (uncompressedData instanceof Int8Array) { rgbData = new Int8Array(uncompressedData.length); } else if (uncompressedData instanceof Uint8Array) { rgbData = new Uint8Array(uncompressedData.length); } else if (uncompressedData instanceof Int16Array) { rgbData = new Int16Array(uncompressedData.length); } else if (uncompressedData instanceof Uint16Array) { rgbData = new Uint16Array(uncompressedData.length); } else { throw 'unsuported typed array: ${uncompressedData}'; } // https://github.com/chafey/cornerstoneWADOImageLoader/blob/master/src/decodeYBRFull.js var nPixels = uncompressedData.length / 3; var ybrIndex = 0; var _rgbaIndex = 0; for (var _i = 0; _i < nPixels; _i++) { var y = uncompressedData[ybrIndex++]; var cb = uncompressedData[ybrIndex++]; var cr = uncompressedData[ybrIndex++]; rgbData[_rgbaIndex++] = y + 1.40200 * (cr - 128); // red rgbData[_rgbaIndex++] = y - 0.34414 * (cb - 128) - 0.71414 * (cr - 128); // green rgbData[_rgbaIndex++] = y + 1.77200 * (cb - 128); // blue // rgbData[rgbaIndex++] = 255; //alpha } } else { throw 'photometric interpolation not supported: ${photometricInterpretation}'; } return rgbData; } /** * Swap bytes in frame. */ }, { key: '_swapFrame', value: function _swapFrame(frame) { // swap bytes ( if 8bits (1byte), nothing to swap) var bitsAllocated = this.bitsAllocated(); if (bitsAllocated === 16) { for (var i = 0; i < frame.length; i++) { frame[i] = this._swap16(frame[i]); } } else if (bitsAllocated === 32) { for (var _i2 = 0; _i2 < frame.length; _i2++) { frame[_i2] = this._swap32(frame[_i2]); } } return frame; } }]); return ParsersDicom; }(_parsers2.default); // VJS.parsers.dicom.prototype.frameOfReferenceUID = function(imageJqueryDom) { // // try to access frame of reference UID through its DICOM tag // let seriesNumber = imageJqueryDom.find('[tag="00200052"] Value').text(); // // if not available, assume we only have 1 frame // if (seriesNumber === '') { // seriesNumber = 1; // } // return seriesNumber; // }; // // ENDIAN NESS NOT TAKEN CARE OF // http://stackoverflow.com/questions/5320439/how-do-i-swap-endian-ness-byte-order-of-a-letiable-in-javascript // http://www.barre.nom.fr/medical/samples/ // // exports.default = ParsersDicom; module.exports = exports['default'];