UNPKG

dicom-microscopy-viewer-changed

Version:
1,761 lines (1,465 loc) 1.49 MB
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; function createCommonjsModule(fn, module) { return module = { exports: {} }, fn(module, module.exports), module.exports; } /* Copyright © 2018 Andrew Powell This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. The above copyright notice and this permission notice shall be included in all copies or substantial portions of this Source Code Form. */ const noop = () => {}; const levels = Symbol('log-levels'); const instance = Symbol('log-instance'); var MethodFactory_1 = class MethodFactory { constructor(logger) { this[instance] = logger; this[levels] = { TRACE: 0, DEBUG: 1, INFO: 2, WARN: 3, ERROR: 4, SILENT: 5 }; } get levels() { return this[levels]; } get logger() { return this[instance]; } set logger(logger) { this[instance] = logger; } get methods() { return Object.keys(this.levels) .map((key) => key.toLowerCase()) .filter((key) => key !== 'silent'); } // eslint-disable-next-line class-methods-use-this bindMethod(obj, methodName) { const method = obj[methodName]; if (typeof method.bind === 'function') { return method.bind(obj); } try { return Function.prototype.bind.call(method, obj); } catch (e) { // Missing bind shim or IE8 + Modernizr, fallback to wrapping return function result() { // eslint-disable-next-line prefer-rest-params return Function.prototype.apply.apply(method, [obj, arguments]); }; } } distillLevel(level) { let result = level; if (typeof result === 'string' && typeof this.levels[result.toUpperCase()] !== 'undefined') { result = this.levels[result.toUpperCase()]; } if (this.levelValid(result)) { return result; } return false; } levelValid(level) { if (typeof level === 'number' && level >= 0 && level <= this.levels.SILENT) { return true; } return false; } /** * Build the best logging method possible for this env * Wherever possible we want to bind, not wrap, to preserve stack traces. * Since we're targeting modern browsers, there's no need to wait for the * console to become available. */ // eslint-disable-next-line class-methods-use-this make(methodName) { if (methodName === 'debug') { // eslint-disable-next-line no-param-reassign methodName = 'log'; } /* eslint-disable no-console */ if (typeof console[methodName] !== 'undefined') { return this.bindMethod(console, methodName); } else if (typeof console.log !== 'undefined') { return this.bindMethod(console, 'log'); } /* eslint-enable no-console */ return noop; } replaceMethods(logLevel) { const level = this.distillLevel(logLevel); if (level == null) { throw new Error(`loglevelnext: replaceMethods() called with invalid level: ${logLevel}`); } if (!this.logger || this.logger.type !== 'LogLevel') { throw new TypeError( 'loglevelnext: Logger is undefined or invalid. Please specify a valid Logger instance.' ); } this.methods.forEach((methodName) => { const { [methodName.toUpperCase()]: methodLevel } = this.levels; this.logger[methodName] = methodLevel < level ? noop : this.make(methodName); }); // Define log.log as an alias for log.debug this.logger.log = this.logger.debug; } }; /* Copyright © 2018 Andrew Powell This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. The above copyright notice and this permission notice shall be included in all copies or substantial portions of this Source Code Form. */ const defaults = { level: (opts) => `[${opts.level}]`, name: (opts) => opts.logger.name, template: '{{time}} {{level}} ', time: () => new Date().toTimeString().split(' ')[0] }; var PrefixFactory_1 = class PrefixFactory extends MethodFactory_1 { constructor(logger, options) { super(logger); this.options = Object.assign({}, defaults, options); } interpolate(level) { return this.options.template.replace(/{{([^{}]*)}}/g, (stache, prop) => { const fn = this.options[prop]; if (fn) { return fn({ level, logger: this.logger }); } return stache; }); } make(methodName) { const og = super.make(methodName); return (...args) => { const output = this.interpolate(methodName); const [first] = args; if (typeof first === 'string') { // eslint-disable-next-line no-param-reassign args[0] = output + first; } else { args.unshift(output); } og(...args); }; } }; /* Copyright © 2018 Andrew Powell This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. The above copyright notice and this permission notice shall be included in all copies or substantial portions of this Source Code Form. */ const defaults$1 = { factory: null, level: 'warn', name: +new Date(), prefix: null }; var LogLevel_1 = class LogLevel { constructor(options) { // implement for some _very_ loose type checking. avoids getting into a // circular require between MethodFactory and LogLevel this.type = 'LogLevel'; this.options = Object.assign({}, defaults$1, options); this.methodFactory = options.factory; if (!this.methodFactory) { const factory = options.prefix ? new PrefixFactory_1(this, options.prefix) : new MethodFactory_1(this); this.methodFactory = factory; } if (!this.methodFactory.logger) { this.methodFactory.logger = this; } this.name = options.name || '<unknown>'; // this.level is a setter, do this after setting up the factory this.level = this.options.level; } get factory() { return this.methodFactory; } set factory(factory) { // eslint-disable-next-line no-param-reassign factory.logger = this; this.methodFactory = factory; this.methodFactory.replaceMethods(this.level); } disable() { this.level = this.levels.SILENT; } enable() { this.level = this.levels.TRACE; } get level() { return this.currentLevel; } set level(logLevel) { const level = this.methodFactory.distillLevel(logLevel); if (level === false || level == null) { throw new RangeError(`loglevelnext: setLevel() called with invalid level: ${logLevel}`); } this.currentLevel = level; this.methodFactory.replaceMethods(level); if (typeof console === 'undefined' && level < this.levels.SILENT) { // eslint-disable-next-line no-console console.warn('loglevelnext: console is undefined. The log will produce no output.'); } } get levels() { // eslint-disable-line class-methods-use-this return this.methodFactory.levels; } }; var lib = createCommonjsModule(function (module) { /* Copyright © 2018 Andrew Powell This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. The above copyright notice and this permission notice shall be included in all copies or substantial portions of this Source Code Form. */ const factories = Symbol('log-factories'); class DefaultLogger extends LogLevel_1 { constructor() { super({ name: 'default' }); this.cache = { default: this }; this[factories] = { MethodFactory: MethodFactory_1, PrefixFactory: PrefixFactory_1 }; } get factories() { return this[factories]; } get loggers() { return this.cache; } create(opts) { let options; if (typeof opts === 'string') { options = { name: opts }; } else { options = Object.assign({}, opts); } if (!options.id) { options.id = options.name; } const { name, id } = options; const defaults = { level: this.level }; if (typeof name !== 'string' || !name || !name.length) { throw new TypeError('You must supply a name when creating a logger.'); } let logger = this.cache[id]; if (!logger) { logger = new LogLevel_1(Object.assign({}, defaults, options)); this.cache[id] = logger; } return logger; } } module.exports = new DefaultLogger(); // TypeScript fix module.exports.default = module.exports; }); var log = lib.create("dcmjs"); /* eslint no-bitwise: 0 */ var BitArray = { getBytesForBinaryFrame: getBytesForBinaryFrame, pack: pack, unpack: unpack }; function getBytesForBinaryFrame(numPixels) { // Check whether the 1-bit pixels exactly fit into bytes var remainder = numPixels % 8; // Number of bytes that work on an exact fit var bytesRequired = Math.floor(numPixels / 8); // Add one byte if we have a remainder if (remainder > 0) { bytesRequired++; } return bytesRequired; } function pack(pixelData) { var numPixels = pixelData.length; log.log("numPixels: " + numPixels); var length = getBytesForBinaryFrame(numPixels); //log.log('getBytesForBinaryFrame: ' + length); var bitPixelData = new Uint8Array(length); var bytePos = 0; for (var i = 0; i < numPixels; i++) { // Compute byte position bytePos = Math.floor(i / 8); var pixValue = pixelData[i] !== 0; //log.log('i: ' + i); //log.log('pixValue: ' + pixValue); //log.log('bytePos: ' + bytePos); var bitPixelValue = pixValue << i % 8; //log.log('current bitPixelData: ' + bitPixelData[bytePos]); //log.log('this bitPixelValue: ' + bitPixelValue); bitPixelData[bytePos] |= bitPixelValue; //log.log('new bitPixelValue: ' + bitPixelData[bytePos]); } return bitPixelData; } // convert a packed bitwise pixel array into a byte-per-pixel // array with 255 corresponding to each set bit in the bit array function unpack(bitPixelArray) { var bitArray = new Uint8Array(bitPixelArray); var byteArray = new Uint8Array(8 * bitArray.length); for (var byteIndex = 0; byteIndex < byteArray.length; byteIndex++) { var bitIndex = byteIndex % 8; var bitByteIndex = Math.floor(byteIndex / 8); byteArray[byteIndex] = 255 * ((bitArray[bitByteIndex] & 1 << bitIndex) >> bitIndex); } return byteArray; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } function _objectSpread2(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a 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); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } function _construct(Parent, args, Class) { if (_isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); } function _isNativeFunction(fn) { return Function.toString.call(fn).indexOf("[native code]") !== -1; } function _wrapNativeSuper(Class) { var _cache = typeof Map === "function" ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (Class === null || !_isNativeFunction(Class)) return Class; if (typeof Class !== "function") { throw new TypeError("Super expression must either be null or a function"); } if (typeof _cache !== "undefined") { if (_cache.has(Class)) return _cache.get(Class); _cache.set(Class, Wrapper); } function Wrapper() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); } Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); return _setPrototypeOf(Wrapper, Class); }; return _wrapNativeSuper(Class); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; } function _get() { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get; } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(arguments.length < 3 ? target : receiver); } return desc.value; }; } return _get.apply(this, arguments); } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function () {}; return { s: F, n: function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function (e) { throw e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function () { it = it.call(o); }, n: function () { var step = it.next(); normalCompletion = step.done; return step; }, e: function (e) { didErr = true; err = e; }, f: function () { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } function toInt(val) { if (isNaN(val)) { throw new Error("Not a number: " + val); } else if (typeof val == "string") { return parseInt(val); } else return val; } function toFloat(val) { if (isNaN(val)) { throw new Error("Not a number: " + val); } else if (typeof val == "string") { return parseFloat(val); } else return val; } var BufferStream = /*#__PURE__*/function () { function BufferStream(sizeOrBuffer, littleEndian) { _classCallCheck(this, BufferStream); this.buffer = typeof sizeOrBuffer == "number" ? new ArrayBuffer(sizeOrBuffer) : sizeOrBuffer; if (!this.buffer) { this.buffer = new ArrayBuffer(0); } this.view = new DataView(this.buffer); this.offset = 0; this.isLittleEndian = littleEndian || false; this.size = 0; this.encoder = new TextEncoder("utf-8"); } _createClass(BufferStream, [{ key: "setEndian", value: function setEndian(isLittle) { this.isLittleEndian = isLittle; } }, { key: "writeUint8", value: function writeUint8(value) { this.checkSize(1); this.view.setUint8(this.offset, toInt(value)); return this.increment(1); } }, { key: "writeUint8Repeat", value: function writeUint8Repeat(value, count) { var v = toInt(value); this.checkSize(count); for (var i = 0; i < count; i++) { this.view.setUint8(this.offset + i, v); } return this.increment(count); } }, { key: "writeInt8", value: function writeInt8(value) { this.checkSize(1); this.view.setInt8(this.offset, toInt(value)); return this.increment(1); } }, { key: "writeUint16", value: function writeUint16(value) { this.checkSize(2); this.view.setUint16(this.offset, toInt(value), this.isLittleEndian); return this.increment(2); } }, { key: "writeTwoUint16s", value: function writeTwoUint16s(value) { this.checkSize(4); var first = value >> 16; var second = value & 0xffff; this.view.setUint16(this.offset, toInt(first), this.isLittleEndian); this.view.setUint16(this.offset + 2, toInt(second), this.isLittleEndian); return this.increment(4); } }, { key: "writeInt16", value: function writeInt16(value) { this.checkSize(2); this.view.setInt16(this.offset, toInt(value), this.isLittleEndian); return this.increment(2); } }, { key: "writeUint32", value: function writeUint32(value) { this.checkSize(4); this.view.setUint32(this.offset, toInt(value), this.isLittleEndian); return this.increment(4); } }, { key: "writeInt32", value: function writeInt32(value) { this.checkSize(4); this.view.setInt32(this.offset, toInt(value), this.isLittleEndian); return this.increment(4); } }, { key: "writeFloat", value: function writeFloat(value) { this.checkSize(4); this.view.setFloat32(this.offset, toFloat(value), this.isLittleEndian); return this.increment(4); } }, { key: "writeDouble", value: function writeDouble(value) { this.checkSize(8); this.view.setFloat64(this.offset, toFloat(value), this.isLittleEndian); return this.increment(8); } }, { key: "writeUTF8String", value: function writeUTF8String(value) { var encodedString = this.encoder.encode(value); this.checkSize(encodedString.byteLength); new Uint8Array(this.buffer).set(encodedString, this.offset); return this.increment(encodedString.byteLength); } }, { key: "writeAsciiString", value: function writeAsciiString(value) { value = value || ""; var len = value.length; this.checkSize(len); var startOffset = this.offset; for (var i = 0; i < len; i++) { var charcode = value.charCodeAt(i); this.view.setUint8(startOffset + i, charcode); } return this.increment(len); } }, { key: "readUint32", value: function readUint32() { var val = this.view.getUint32(this.offset, this.isLittleEndian); this.increment(4); return val; } }, { key: "readUint16", value: function readUint16() { var val = this.view.getUint16(this.offset, this.isLittleEndian); this.increment(2); return val; } }, { key: "readUint8", value: function readUint8() { var val = this.view.getUint8(this.offset); this.increment(1); return val; } }, { key: "peekUint8", value: function peekUint8(offset) { return this.view.getUint8(this.offset + offset); } }, { key: "readUint8Array", value: function readUint8Array(length) { var arr = new Uint8Array(this.buffer, this.offset, length); this.increment(length); return arr; } }, { key: "readUint16Array", value: function readUint16Array(length) { var sixlen = length / 2, arr = new Uint16Array(sixlen), i = 0; while (i++ < sixlen) { arr[i] = this.view.getUint16(this.offset, this.isLittleEndian); this.offset += 2; } return arr; } }, { key: "readInt16", value: function readInt16() { var val = this.view.getInt16(this.offset, this.isLittleEndian); this.increment(2); return val; } }, { key: "readInt32", value: function readInt32() { var val = this.view.getInt32(this.offset, this.isLittleEndian); this.increment(4); return val; } }, { key: "readFloat", value: function readFloat() { var val = this.view.getFloat32(this.offset, this.isLittleEndian); this.increment(4); return val; } }, { key: "readDouble", value: function readDouble() { var val = this.view.getFloat64(this.offset, this.isLittleEndian); this.increment(8); return val; } }, { key: "readAsciiString", value: function readAsciiString(length) { var result = ""; var start = this.offset; var end = this.offset + length; if (end >= this.buffer.byteLength) { end = this.buffer.byteLength; } for (var i = start; i < end; ++i) { result += String.fromCharCode(this.view.getUint8(i)); } this.increment(end - start); return result; } }, { key: "readVR", value: function readVR() { var vr = String.fromCharCode(this.view.getUint8(this.offset)) + String.fromCharCode(this.view.getUint8(this.offset + 1)); this.increment(2); return vr; } }, { key: "readEncodedString", value: function readEncodedString(length) { if (this.offset + length >= this.buffer.byteLength) { length = this.buffer.byteLength - this.offset; } var view = new DataView(this.buffer, this.offset, length); var result = this.decoder.decode(view); this.increment(length); return result; } }, { key: "readHex", value: function readHex(length) { var hexString = ""; for (var i = 0; i < length; i++) { hexString += this.readUint8().toString(16); } return hexString; } }, { key: "checkSize", value: function checkSize(step) { if (this.offset + step > this.buffer.byteLength) { //throw new Error("Writing exceeded the size of buffer"); // // Resize the buffer. // The idea is that when it is necessary to increase the buffer size, // there will likely be more bytes which need to be written to the // buffer in the future. Buffer allocation is costly. // So we increase the buffer size right now // by a larger amount than necessary, to reserve space for later // writes which then can be done much faster. The current size of // the buffer is the best estimate of the scale by which the size // should increase. // So approximately doubling the size of the buffer // (while ensuring it fits the new data) is a simple but effective strategy. var dstSize = this.offset + step + this.buffer.byteLength; var dst = new ArrayBuffer(dstSize); new Uint8Array(dst).set(new Uint8Array(this.buffer)); this.buffer = dst; this.view = new DataView(this.buffer); } } }, { key: "concat", value: function concat(stream) { var available = this.buffer.byteLength - this.offset; if (stream.size > available) { var newbuf = new ArrayBuffer(this.offset + stream.size); var int8 = new Uint8Array(newbuf); int8.set(new Uint8Array(this.getBuffer(0, this.offset))); int8.set(new Uint8Array(stream.getBuffer(0, stream.size)), this.offset); this.buffer = newbuf; this.view = new DataView(this.buffer); } else { var _int = new Uint8Array(this.buffer); _int.set(new Uint8Array(stream.getBuffer(0, stream.size)), this.offset); } this.offset += stream.size; this.size = this.offset; return this.buffer.byteLength; } }, { key: "increment", value: function increment(step) { this.offset += step; if (this.offset > this.size) { this.size = this.offset; } return step; } }, { key: "getBuffer", value: function getBuffer(start, end) { if (!start && !end) { start = 0; end = this.size; } return this.buffer.slice(start, end); } }, { key: "more", value: function more(length) { if (this.offset + length > this.endOffset) { throw new Error("Request more than currently allocated buffer"); } var newBuf = new ReadBufferStream(this.buffer, null, { start: this.offset, stop: this.offset + length }); this.increment(length); return newBuf; } }, { key: "reset", value: function reset() { this.offset = 0; return this; } }, { key: "end", value: function end() { return this.offset >= this.buffer.byteLength; } }, { key: "toEnd", value: function toEnd() { this.offset = this.buffer.byteLength; } }]); return BufferStream; }(); var ReadBufferStream = /*#__PURE__*/function (_BufferStream) { _inherits(ReadBufferStream, _BufferStream); var _super = _createSuper(ReadBufferStream); function ReadBufferStream(buffer, littleEndian) { var _this; var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : { start: null, stop: null, noCopy: false }; _classCallCheck(this, ReadBufferStream); _this = _super.call(this, buffer, littleEndian); _this.offset = options.start || 0; _this.size = options.stop || _this.buffer.byteLength; _this.noCopy = options.noCopy; _this.startOffset = _this.offset; _this.endOffset = _this.size; _this.decoder = new TextDecoder("latin1"); return _this; } _createClass(ReadBufferStream, [{ key: "setDecoder", value: function setDecoder(decoder) { this.decoder = decoder; } }, { key: "getBuffer", value: function getBuffer(start, end) { if (this.noCopy) { return new Uint8Array(this.buffer, start, end - start); } if (!start && !end) { start = 0; end = this.size; } return this.buffer.slice(start, end); } }, { key: "reset", value: function reset() { this.offset = this.startOffset; return this; } }, { key: "end", value: function end() { return this.offset >= this.endOffset; } }, { key: "toEnd", value: function toEnd() { this.offset = this.endOffset; } }, { key: "writeUint8", value: function writeUint8(value) { throw new Error(value, "writeUint8 not implemented"); } }, { key: "writeUint8Repeat", value: function writeUint8Repeat(value, count) { throw new Error(value, "writeUint8Repeat not implemented"); } }, { key: "writeInt8", value: function writeInt8(value) { throw new Error(value, "writeInt8 not implemented"); } }, { key: "writeUint16", value: function writeUint16(value) { throw new Error(value, "writeUint16 not implemented"); } }, { key: "writeTwoUint16s", value: function writeTwoUint16s(value) { throw new Error(value, "writeTwoUint16s not implemented"); } }, { key: "writeInt16", value: function writeInt16(value) { throw new Error(value, "writeInt16 not implemented"); } }, { key: "writeUint32", value: function writeUint32(value) { throw new Error(value, "writeUint32 not implemented"); } }, { key: "writeInt32", value: function writeInt32(value) { throw new Error(value, "writeInt32 not implemented"); } }, { key: "writeFloat", value: function writeFloat(value) { throw new Error(value, "writeFloat not implemented"); } }, { key: "writeDouble", value: function writeDouble(value) { throw new Error(value, "writeDouble not implemented"); } }, { key: "writeAsciiString", value: function writeAsciiString(value) { throw new Error(value, "writeAsciiString not implemented"); } }, { key: "writeUTF8String", value: function writeUTF8String(value) { throw new Error(value, "writeUTF8String not implemented"); } }, { key: "checkSize", value: function checkSize(step) { throw new Error(step, "checkSize not implemented"); } }, { key: "concat", value: function concat(stream) { throw new Error(stream, "concat not implemented"); } }]); return ReadBufferStream; }(BufferStream); var WriteBufferStream = /*#__PURE__*/function (_BufferStream2) { _inherits(WriteBufferStream, _BufferStream2); var _super2 = _createSuper(WriteBufferStream); function WriteBufferStream(buffer, littleEndian) { var _this2; _classCallCheck(this, WriteBufferStream); _this2 = _super2.call(this, buffer, littleEndian); _this2.size = 0; return _this2; } return _createClass(WriteBufferStream); }(BufferStream); function rtrim(str) { return str.replace(/\s*$/g, ""); } function toWindows(inputArray, size) { return Array.from({ length: inputArray.length - (size - 1) }, //get the appropriate length function (_, index) { return inputArray.slice(index, index + size); } //create the windows ); } var binaryVRs = ["FL", "FD", "SL", "SS", "UL", "US", "AT"], explicitVRs = ["OB", "OW", "OF", "SQ", "UC", "UR", "UT", "UN"], singleVRs = ["SQ", "OF", "OW", "OB", "UN"]; var ValueRepresentation = /*#__PURE__*/function () { function ValueRepresentation(type) { _classCallCheck(this, ValueRepresentation); this.type = type; this.multi = false; this._isBinary = binaryVRs.indexOf(this.type) != -1; this._allowMultiple = !this._isBinary && singleVRs.indexOf(this.type) == -1; this._isExplicit = explicitVRs.indexOf(this.type) != -1; } _createClass(ValueRepresentation, [{ key: "isBinary", value: function isBinary() { return this._isBinary; } }, { key: "allowMultiple", value: function allowMultiple() { return this._allowMultiple; } }, { key: "isExplicit", value: function isExplicit() { return this._isExplicit; } }, { key: "read", value: function read(stream, length, syntax) { if (this.fixed && this.maxLength) { if (!length) return this.defaultValue; if (this.maxLength != length) log.error("Invalid length for fixed length tag, vr " + this.type + ", length " + this.maxLength + " != " + length); } return this.readBytes(stream, length, syntax); } }, { key: "readBytes", value: function readBytes(stream, length) { return stream.readAsciiString(length); } }, { key: "readNullPaddedString", value: function readNullPaddedString(stream, length) { if (!length) return ""; if (stream.peekUint8(length - 1) !== 0) { return stream.readAsciiString(length); } else { var val = stream.readAsciiString(length - 1); stream.increment(1); return val; } } }, { key: "write", value: function write(stream, type) { var args = Array.from(arguments); if (args[2] === null || args[2] === "" || args[2] === undefined) { return [stream.writeAsciiString("")]; } else { var written = [], valueArgs = args.slice(2), func = stream["write" + type]; if (Array.isArray(valueArgs[0])) { if (valueArgs[0].length < 1) { written.push(0); } else { var self = this; valueArgs[0].forEach(function (v, k) { if (self.allowMultiple() && k > 0) { stream.writeUint8(0x5c); } var singularArgs = [v].concat(valueArgs.slice(1)); var byteCount = func.apply(stream, singularArgs); written.push(byteCount); }); } } else { written.push(func.apply(stream, valueArgs)); } return written; } } }, { key: "writeBytes", value: function writeBytes(stream, value, lengths) { var writeOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : { allowInvalidVRLength: false }; var allowInvalidVRLength = writeOptions.allowInvalidVRLength; var valid = true, valarr = Array.isArray(value) ? value : [value], total = 0; for (var i = 0; i < valarr.length; i++) { var checkValue = valarr[i], checklen = lengths[i], isString = false, displaylen = checklen; if (checkValue === null || allowInvalidVRLength) { valid = true; } else if (this.checkLength) { valid = this.checkLength(checkValue); } else if (this.maxCharLength) { var check = this.maxCharLength; //, checklen = checkValue.length; valid = checkValue.length <= check; displaylen = checkValue.length; isString = true; } else if (this.maxLength) { valid = checklen <= this.maxLength; } if (!valid) { var errmsg = "Value exceeds max length, vr: " + this.type + ", value: " + checkValue + ", length: " + displaylen; if (isString) log.log(errmsg);else throw new Error(errmsg); } total += checklen; } if (this.allowMultiple()) { total += valarr.length ? valarr.length - 1 : 0; } //check for odd var written = total; if (total & 1) { stream.writeUint8(this.padByte); written++; } return written; } }], [{ key: "createByTypeString", value: function createByTypeString(type) { var vr = VRinstances[type]; if (vr === undefined) { if (type == "ox") { // TODO: determine VR based on context (could be 1 byte pixel data) // https://github.com/dgobbi/vtk-dicom/issues/38 log.error("Invalid vr type " + type + " - using OW"); vr = VRinstances["OW"]; } else if (type == "xs") { log.error("Invalid vr type " + type + " - using US"); vr = VRinstances["US"]; } else { log.error("Invalid vr type " + type + " - using UN"); vr = VRinstances["UN"]; } } return vr; } }]); return ValueRepresentation; }(); var AsciiStringRepresentation = /*#__PURE__*/function (_ValueRepresentation) { _inherits(AsciiStringRepresentation, _ValueRepresentation); var _super = _createSuper(AsciiStringRepresentation); function AsciiStringRepresentation(type) { _classCallCheck(this, AsciiStringRepresentation); return _super.call(this, type); } _createClass(AsciiStringRepresentation, [{ key: "readBytes", value: function readBytes(stream, length) { return stream.readAsciiString(length); } }, { key: "writeBytes", value: function writeBytes(stream, value, writeOptions) { var written = _get(_getPrototypeOf(AsciiStringRepresentation.prototype), "write", this).call(this, stream, "AsciiString", value); return _get(_getPrototypeOf(AsciiStringRepresentation.prototype), "writeBytes", this).call(this, stream, value, written, writeOptions); } }]); return AsciiStringRepresentation; }(ValueRepresentation); var EncodedStringRepresentation = /*#__PURE__*/function (_ValueRepresentation2) { _inherits(EncodedStringRepresentation, _ValueRepresentation2); var _super2 = _createSuper(EncodedStringRepresentation); function EncodedStringRepresentation(type) { _classCallCheck(this, EncodedStringRepresentation); return _super2.call(this, type); } _createClass(EncodedStringRepresentation, [{ key: "readBytes", value: function readBytes(stream, length) { return stream.readEncodedString(length); } }, { key: "writeBytes", value: function writeBytes(stream, value, writeOptions) { var written = _get(_getPrototypeOf(EncodedStringRepresentation.prototype), "write", this).call(this, stream, "UTF8String", value); return _get(_getPrototypeOf(EncodedStringRepresentation.prototype), "writeBytes", this).call(this, stream, value, written, writeOptions); } }]); return EncodedStringRepresentation; }(ValueRepresentation); var BinaryRepresentation = /*#__PURE__*/function (_ValueRepresentation3) { _inherits(BinaryRepresentation, _ValueRepresentation3); var _super3 = _createSuper(BinaryRepresentation); function BinaryRepresentation(type) { _classCallCheck(this, BinaryRepresentation); return _super3.call(this, type); } _createClass(BinaryRepresentation, [{ key: "writeBytes", value: function writeBytes(stream, value, syntax, isEncapsulated) { var writeOptions = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {}; var i; var binaryStream; var _writeOptions$fragmen = writeOptions.fragmentMultiframe, fragmentMultiframe = _writeOptions$fragmen === void 0 ? true : _writeOptions$fragmen; value = value === null || value === undefined ? [] : value; if (isEncapsulated) { var fragmentSize = 1024 * 20, frames = value.length, startOffset = []; // Calculate a total length for storing binary stream var bufferLength = 0; for (i = 0; i < frames; i++) { var needsPadding = Boolean(value[i].byteLength & 1); bufferLength += value[i].byteLength + (needsPadding ? 1 : 0); var _fragmentsLength = 1; if (fragmentMultiframe) { _fragmentsLength = Math.ceil(value[i].byteLength / fragmentSize); } // 8 bytes per fragment are needed to store 0xffff (2 bytes), 0xe000 (2 bytes), and frageStream size (4 bytes) bufferLength += _fragmentsLength * 8; } binaryStream = new WriteBufferStream(bufferLength, stream.isLittleEndian); for (i = 0; i < frames; i++) { var _needsPadding = Boolean(value[i].byteLength & 1); startOffset.push(binaryStream.size); var frameBuffer = value[i], frameStream = new ReadBufferStream(frameBuffer); var fragmentsLength = 1; if (fragmentMultiframe) { fragmentsLength = Math.ceil(frameStream.size / fragmentSize); } for (var j = 0, fragmentStart = 0; j < fragmentsLength; j++) { var isFinalFragment = j === fragmentsLength - 1; var fragmentEnd = fragmentStart + frameStream.size; if (fragmentMultiframe) { fragmentEnd = fragmentStart + fragmentSize; } if (isFinalFragment) { fragmentEnd = frameStream.size; } var fragStream = new ReadBufferStream(frameStream.getBuffer(fragmentStart, fragmentEnd)); fragmentStart = fragmentEnd; binaryStream.writeUint16(0xfffe); binaryStream.writeUint16(0xe000); var addPaddingByte = isFinalFragment && _needsPadding; binaryStream.writeUint32(fragStream.size + (addPaddingByte ? 1 : 0)); binaryStream.concat(fragStream); if (addPaddingByte) { binaryStream.writeInt8(this.padByte); } } } stream.writeUint16(0xfffe); stream.writeUint16(0xe000); stream.writeUint32(startOffset.length * 4); for (i = 0; i < startOffset.length; i++) { stream.writeUint32(startOffset[i]); } stream.concat(binaryStream); stream.writeUint16(0xfffe); stream.writeUint16(0xe0dd); stream.writeUint32(0x0); return 0xffffffff; } else { var binaryData = value[0]; binaryStream = new ReadBufferStream(binaryData); stream.concat(binaryStream); return _get(_getPrototypeOf(BinaryRepresentation.prototype), "writeBytes", this).call(this, stream, binaryData, [binaryStream.size], writeOptions); } } }, { key: "readBytes", value: function readBytes(stream, length) { if (length == 0xffffffff) { var itemTagValue = Tag.readTag(stream), frames = []; if (itemTagValue.is(0xfffee000)) { var itemLength = stream.readUint32(), numOfFrames = 1, offsets = []; if (itemLength > 0x0) { //has frames numOfFrames = itemLength / 4; var i = 0; while (i++ < numOfFrames) { offsets.push(stream.readUint32()); } } else { offsets = []; } var SequenceItemTag = 0xfffee000; var SequenceDelimiterTag = 0xfffee0dd; var getNextSequenceItemData = function getNextSequenceItemData(stream) { var nextTag = Tag.readTag(stream); if (nextTag.is(SequenceItemTag)) { var _itemLength = stream.readUint32(); var buffer = stream.getBuffer(stream.offset, stream.offset + _itemLength); stream.increment(_itemLength); return buffer; } else if (nextTag.is(SequenceDelimiterTag)) { // Read SequenceDelimiterItem value for the SequenceDelimiterTag if (stream.readUint32() !== 0) { throw Error("SequenceDelimiterItem tag value was not zero"); } return null; } throw Error("Invalid tag in sequence"); }; // If there is an offset table, use that to loop through pixel data sequence if (offsets.length > 0) { // make offsets relative to the stream, not tag offsets = offsets.map(function (e) { return e + stream.offset; }); offsets.push(stream.size); // window offsets to an array of [start,stop] locations frames = toWindows(offsets, 2).map(function (range) { var fragments = []; var _range = _slicedToArray(range, 2), start = _range[0], stop = _range[1]; // create a new readable stream based on the range var rangeStream = new ReadBufferStream(stream.buffer, stream.isLittleEndian, { start: start, stop: stop, noCopy: stream.noCopy }); var frameSize = 0; while (!rangeStream.end()) { var buf = getNextSequenceItemData(rangeStream); if (buf === null) { break; } fragments.push(buf); frameSize += buf.byteLength; } // Ensure the parent stream's offset is kept up to date stream.offset = rangeStream.offset; // If there's only one buffer thne just return it directly if (fragments.length === 1) { return fragments[0]; } if (rangeStream.noCopy) { // return the fragments for downstream application to process return fragments; } else { // Allocate a final ArrayBuffer and concat all buffers into it var mergedFrame = new ArrayBuffer(frameSize); var u8Data = new Uint8Array(mergedFrame); fragments.reduce(function (offset, buffer) { u8Data.set(new Uint8Array(buffer), offset); return offset + buffer.byteLength; }, 0); return mergedFrame; } }); } // If no offset table, loop through remainder of strea