diff --git a/.eslint-full.js b/.eslint-full.js deleted file mode 100644 index 102e995fed..0000000000 --- a/.eslint-full.js +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - plugins: [ - 'jsdoc' - ], - extends: [ - '.eslintrc.js', - 'plugin:jsdoc/recommended-typescript-flavor', - ], - rules: { - // tag lines - // https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/tag-lines.md - 'jsdoc/tag-lines': ['error', 'any', {'startLines': 1}], - // require description complete sentence - // https://github.com/gajus/eslint-plugin-jsdoc/blob/HEAD/docs/rules/require-description-complete-sentence.md - 'jsdoc/require-description-complete-sentence': ['error'] - } -}; diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index f0658eebb3..0000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,135 +0,0 @@ -module.exports = { - env: { - browser: true, - node: true, - es6: true, - es2022: true - }, - extends: [ - 'eslint:recommended', - ], - parserOptions: { - sourceType: 'module' - }, - settings: { - jsdoc: { - // 1. jsdoc gives an error for index signatures as type: - // {[key: string]: {red: number[], green: number[], blue: number[]}} - // -> ERROR: Unable to parse a tag's type expression for source file ... - // Invalid type expression - // 2. in typescript mode, eslint/jsdoc 'check-types' - // gives a warning when using: Object<> - // -> Use object shorthand or index signatures instead of `Object`, - // e.g., `{[key: string]: string}` - // => adding Object to preferredTypes removes the warning - preferredTypes: { - Object: 'Object' - } - } - }, - rules: { - // require triple equal - // https://eslint.org/docs/rules/eqeqeq - eqeqeq: 'error', - // force semi colon - // https://eslint.org/docs/rules/semi - semi: ['error'], - // no var - // https://eslint.org/docs/rules/no-var - 'no-var': 'error', - // prefer const - // https://eslint.org/docs/rules/prefer-const - 'prefer-const': 'error', - // allow for some unused args - // https://eslint.org/docs/rules/no-unused-vars - 'no-unused-vars': ['error', {argsIgnorePattern: '^_'}], - - // formatting rules - - // force 2 space indent (default: 4) - // https://eslint.org/docs/rules/indent - indent: ['error', 2], - // force single quotes (default 'double') - // https://eslint.org/docs/rules/quotes - quotes: ['error', 'single'], - // no space for named functions (default 'always') - // https://eslint.org/docs/rules/space-before-function-paren - 'space-before-function-paren': ['error', {named: 'never'}], - // newline at object curly - // https://eslint.org/docs/rules/object-curly-newline - 'object-curly-newline': ['error', {consistent: true}], - // newline at object properties - // https://eslint.org/docs/rules/object-property-newline - 'object-property-newline': [ - 'error', {allowAllPropertiesOnSameLine: true} - ], - // newline at array brackets - // https://eslint.org/docs/rules/array-bracket-newline - 'array-bracket-newline': ['error', 'consistent'], - // newline at array elements (default: always) - // https://eslint.org/docs/rules/array-element-newline - 'array-element-newline': ['error', 'consistent'], - // force using curly braces - // https://eslint.org/docs/rules/curly - curly: 'error', - // force 'one true brace style' (1tbs) - // https://eslint.org/docs/rules/brace-style - 'brace-style': 'error', - // give error for long lines (default: 80) - // https://eslint.org/docs/rules/max-len - 'max-len': ['error', - {ignoreRegExpLiterals: true, ignoreUrls: true}], - // spaces in parenthesis (default: never) - // https://eslint.org/docs/rules/space-in-parens - 'space-in-parens': 'error', - // space before blocks - // https://eslint.org/docs/rules/space-before-blocks - 'space-before-blocks': 'error', - // spaces inside brackets (default: never) - // https://eslint.org/docs/rules/array-bracket-spacing - 'array-bracket-spacing': 'error', - // spaces in curly (default: never) - // https://eslint.org/docs/rules/object-curly-spacing - 'object-curly-spacing': 'error', - // no space in computed properties (default: never) - // https://eslint.org/docs/rules/computed-property-spacing - 'computed-property-spacing': 'error', - // spaces around comma (default: {"before": false, "after": true}) - // https://eslint.org/docs/rules/comma-spacing - 'comma-spacing': 'error', - // space around unary operator - // https://eslint.org/docs/rules/space-unary-ops - 'space-unary-ops': 'error', - // space around operator - // https://eslint.org/docs/rules/space-infix-ops - 'space-infix-ops': 'error', - // space around keywords (default: {'before': true, 'after': true}) - // https://eslint.org/docs/rules/keyword-spacing - 'keyword-spacing': 'error', - // no space before function call (default: never) - // https://eslint.org/docs/rules/func-call-spacing - 'func-call-spacing': 'error', - // spacing around colon - // (default: {'beforeColon': false, 'afterColon': true}) - // https://eslint.org/docs/rules/key-spacing - 'key-spacing': 'error', - // spacing around semi-colon - // https://eslint.org/docs/rules/semi-spacing - 'semi-spacing': 'error', - // no trailing spaces - // https://eslint.org/docs/rules/no-trailing-spaces - 'no-trailing-spaces': 'error', - // no multi spaces - // https://eslint.org/docs/rules/no-multi-spaces - 'no-multi-spaces': 'error', - // no space for named functions (default {'max': 2}) - // https://eslint.org/docs/rules/no-multiple-empty-lines - 'no-multiple-empty-lines': 'error', - // linebreak after operator - // https://eslint.org/docs/rules/operator-linebreak - 'operator-linebreak': 'error', - // quotes around object property names - // https://eslint.org/docs/rules/quote-props - 'quote-props': ['error', 'as-needed'] - } -}; diff --git a/.github/workflows/dependabot-automerge.yml b/.github/workflows/dependabot-automerge.yml index 703154b253..09ff135d85 100644 --- a/.github/workflows/dependabot-automerge.yml +++ b/.github/workflows/dependabot-automerge.yml @@ -15,7 +15,7 @@ jobs: steps: - name: Fetch Dependabot metadata id: metadata - uses: dependabot/fetch-metadata@v1 + uses: dependabot/fetch-metadata@v2 with: github-token: "${{ secrets.GITHUB_TOKEN }}" - name: Merge Dependabot PRs for patch update if all good diff --git a/.github/workflows/nodejs-ci.yml b/.github/workflows/nodejs-ci.yml index 2bd3fbf632..c6f1ccdc29 100644 --- a/.github/workflows/nodejs-ci.yml +++ b/.github/workflows/nodejs-ci.yml @@ -18,7 +18,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: "18.x" + node-version: "20.x" - name: Install dependencies run: yarn install --frozen-lockfile - name: Run lint diff --git a/.grenrc.js b/.grenrc.js index b7eaf62ce8..5e8eaa8d1b 100644 --- a/.grenrc.js +++ b/.grenrc.js @@ -1,15 +1,15 @@ module.exports = { - "dataSource": "milestones", - "ignore-issues-with": ["duplicate", "invalid", "question", "wontfix"], - "groupBy": { - "Breaking": ["breaking"], - "Added": ["enhancement"], - "Fixed": ["bug"], - "Dependencies": ["dependencies"] - }, - "template": { - release: "## [{{release}}](https://github.com/ivmartel/dwv/releases/tag/{{release}}) - {{date}}\n{{body}}", - group: "\n### {{heading}}\n", - issue: "- {{name}} [{{text}}]({{url}})", - } -} + dataSource: 'milestones', + 'ignore-issues-with': ['duplicate', 'invalid', 'question', 'wontfix'], + groupBy: { + Breaking: ['breaking'], + Added: ['enhancement'], + Fixed: ['bug'], + Dependencies: ['dependencies'] + }, + template: { + release: '## [{{release}}](https://github.com/ivmartel/dwv/releases/tag/{{release}}) - {{date}}\n{{body}}', + group: '\n### {{heading}}\n', + issue: '- {{name}} [{{text}}]({{url}})', + } +}; diff --git a/changelog.md b/changelog.md index c8489739bd..91a296a238 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,24 @@ # Changelog +## [v0.34.0](https://github.com/ivmartel/dwv/releases/tag/v0.34.0) - 14/11/2024 + +### Added + +- Add connector between shape and label [#1795](https://github.com/ivmartel/dwv/issues/1795) +- Default draw auto shape color to false [#1768](https://github.com/ivmartel/dwv/issues/1768) +- Export toolOptions to allow for custom tool options [#1718](https://github.com/ivmartel/dwv/issues/1718) +- Allow to move roi label independently [#1690](https://github.com/ivmartel/dwv/issues/1690) +- Add DICOM SR parsing [#1689](https://github.com/ivmartel/dwv/issues/1689) +- Add missing position to draw display details [#1521](https://github.com/ivmartel/dwv/issues/1521) +- Use DICOM to store annotations [#1020](https://github.com/ivmartel/dwv/issues/1020) + +### Fixed + +- Fixed label moves on drag out of bounds [#1770](https://github.com/ivmartel/dwv/issues/1770) +- Wrong display if adding data after zoom [#1606](https://github.com/ivmartel/dwv/issues/1606) + +--- + ## [v0.33.1](https://github.com/ivmartel/dwv/releases/tag/v0.33.1) - 13/06/2024 ### Fixed diff --git a/dist/dwv.d.ts b/dist/dwv.d.ts index 08eb13829d..4f87dc228d 100644 --- a/dist/dwv.d.ts +++ b/dist/dwv.d.ts @@ -12,6 +12,302 @@ export declare function addTagsToDictionary(group: string, tags: { [x: string]: string[]; }): void; +/** + * Image annotation. + */ +export declare class Annotation { + /** + * The ID. + * + * @type {string} + */ + id: string; + /** + * The reference image SOP UID. + * + * @type {string} + */ + referenceSopUID: string; + /** + * The mathematical shape. + * + * @type {object} + */ + mathShape: object; + /** + * Additional points used to define the annotation. + * + * @type {Point2D[]|undefined} + */ + referencePoints: Point2D[] | undefined; + /** + * The color: for example 'green', '#00ff00' or 'rgb(0,255,0)'. + * + * @type {string|undefined} + */ + colour: string | undefined; + /** + * Annotation quantification. + * + * @type {object|undefined} + */ + quantification: object | undefined; + /** + * Text expression. Can contain variables surrounded with '{}' that will + * be extracted from the quantification object. + * + * @type {string|undefined} + */ + textExpr: string | undefined; + /** + * Label position. If undefined, the default shape + * label position will be used. + * + * @type {Point2D|undefined} + */ + labelPosition: Point2D | undefined; + /** + * The plane origin, the 3D position of index [0, 0, k]. + * + * @type {Point3D|undefined} + */ + planeOrigin: Point3D | undefined; + /** + * A couple of points that help define the annotation plane. + * + * @type {Point3D[]|undefined} + */ + planePoints: Point3D[] | undefined; + /** + * Get the orientation name for this annotation. + * + * @returns {string|undefined} The orientation name, + * undefined if same as reference data. + */ + getOrientationName(): string | undefined; + /** + * Initialise the annotation. + * + * @param {ViewController} viewController The associated view controller. + */ + init(viewController: ViewController): void; + /** + * Check if an input view is compatible with the annotation. + * + * @param {PlaneHelper} planeHelper The input view to check. + * @returns {boolean} True if compatible view. + */ + isCompatibleView(planeHelper: PlaneHelper): boolean; + /** + * Set the associated view controller if it is compatible. + * + * @param {ViewController} viewController The view controller. + */ + setViewController(viewController: ViewController): void; + /** + * Get the centroid of the math shape. + * + * @returns {Point|undefined} The 3D centroid point. + */ + getCentroid(): Point | undefined; + /** + * Set the annotation text expression. + * + * @param {Object.} labelText The list of label + * texts indexed by modality. + */ + setTextExpr(labelText: { + [x: string]: string; + }): void; + /** + * Get the annotation label text by applying the + * text expression on the current quantification. + * + * @returns {string} The resulting text. + */ + getText(): string; + /** + * Update the annotation quantification. + */ + updateQuantification(): void; + /** + * Get the math shape associated draw factory. + * + * @returns {object} The factory. + */ + getFactory(): object; + #private; +} + +/** + * Annotation group. + */ +export declare class AnnotationGroup { + /** + * @param {Annotation[]} [list] Optional list, will + * create new if not provided. + */ + constructor(list?: Annotation[]); + /** + * Get the annotation group as an array. + * + * @returns {Annotation[]} The array. + */ + getList(): Annotation[]; + /** + * Get the number of annotations of this list. + * + * @returns {number} The number of annotations. + */ + getLength(): number; + /** + * Check if the annotation group is editable. + * + * @returns {boolean} True if editable. + */ + isEditable(): boolean; + /** + * Set the annotation group editability. + * + * @param {boolean} flag True to make the annotation group editable. + */ + setEditable(flag: boolean): void; + /** + * Get the group colour. + * + * @returns {string} The colour as hex string. + */ + getColour(): string; + /** + * Set the group colour. + * + * @param {string} colour The colour as hex string. + */ + setColour(colour: string): void; + /** + * Add a new annotation. + * + * @param {Annotation} annotation The annotation to add. + */ + add(annotation: Annotation): void; + /** + * Update an existing annotation. + * + * @param {Annotation} annotation The annotation to update. + * @param {string[]} [propKeys] Optional properties that got updated. + */ + update(annotation: Annotation, propKeys?: string[]): void; + /** + * Remove an annotation. + * + * @param {string} id The id of the annotation to remove. + */ + remove(id: string): void; + /** + * Set the associated view controller. + * + * @param {ViewController} viewController The associated view controller. + */ + setViewController(viewController: ViewController): void; + /** + * Find an annotation. + * + * @param {string} id The id of the annotation to find. + * @returns {Annotation|undefined} The found annotation. + */ + find(id: string): Annotation | undefined; + /** + * Get the meta data. + * + * @returns {Object} The meta data. + */ + getMeta(): { + [x: string]: any; + }; + /** + * Check if this list contains a meta data value. + * + * @param {string} key The key to check. + * @returns {boolean} True if the meta data is present. + */ + hasMeta(key: string): boolean; + /** + * Get a meta data value. + * + * @param {string} key The meta data key. + * @returns {string|object} The meta data value. + */ + getMetaValue(key: string): string | object; + /** + * Set a meta data. + * + * @param {string} key The meta data key. + * @param {string|object} value The value of the meta data. + */ + setMetaValue(key: string, value: string | object): void; + /** + * Add an event listener to this class. + * + * @param {string} type The event type. + * @param {Function} callback The function associated with the provided + * event type, will be called with the fired event. + */ + addEventListener(type: string, callback: Function): void; + /** + * Remove an event listener from this class. + * + * @param {string} type The event type. + * @param {Function} callback The function associated with the provided + * event type. + */ + removeEventListener(type: string, callback: Function): void; + #private; +} + +/** + * {@link AnnotationGroup} factory. + */ +export declare class AnnotationGroupFactory { + /** + * Get a warning string if elements are not as expected. + * Created by checkElements. + * + * @returns {string|undefined} The warning. + */ + getWarning(): string | undefined; + /** + * Check dicom elements. Throws an error if not suitable. + * + * @param {Object} dataElements The DICOM data elements. + * @returns {string|undefined} A possible warning. + */ + checkElements(dataElements: { + [x: string]: DataElement; + }): string | undefined; + /** + * Get an {@link Annotation} object from the read DICOM file. + * + * @param {Object} dataElements The DICOM tags. + * @returns {AnnotationGroup} A new annotation group. + */ + create(dataElements: { + [x: string]: DataElement; + }): AnnotationGroup; + /** + * Convert an annotation group into a DICOM SR object. + * + * @param {AnnotationGroup} annotationGroup The annotation group. + * @param {Object} [extraTags] Optional list of extra tags. + * @returns {Object} A list of dicom elements. + */ + toDicom(annotationGroup: AnnotationGroup, extraTags?: { + [x: string]: any; + }): { + [x: string]: DataElement; + }; + #private; +} + /** * List of ViewConfigs indexed by dataIds. * @@ -34,11 +330,19 @@ export declare function addTagsToDictionary(group: string, tags: { * ]); */ export declare class App { + /** + * Get a DicomData. + * + * @param {string} dataId The data id. + * @returns {DicomData|undefined} The data. + */ + getData(dataId: string): DicomData | undefined; /** * Get the image. * * @param {string} dataId The data id. * @returns {Image|undefined} The associated image. + * @deprecated Since v0.34, please use the getData method. */ getImage(dataId: string): Image_2 | undefined; /** @@ -49,15 +353,12 @@ export declare class App { */ setImage(dataId: string, img: Image_2): void; /** - * Add a new image. + * Add a new DicomData. * - * @param {Image} image The new image. - * @param {object} meta The image meta. - * @param {string} source The source of the new image, - * will be passed with load events. - * @returns {string} The new image data id. + * @param {DicomData} data The new data. + * @returns {string} The data id. */ - addNewImage(image: Image_2, meta: object, source: string): string; + addData(data: DicomData): string; /** * Get the meta data. * @@ -84,7 +385,8 @@ export declare class App { * Can the data (of the active view of the active layer) be scrolled? * * @returns {boolean} True if the data has a third dimension greater than one. - * @deprecated Please use the ViewController equivalent directly instead. + * @deprecated Since v0.33, please use the ViewController + * equivalent directly instead. */ canScroll(): boolean; /** @@ -92,7 +394,8 @@ export declare class App { * (of the active view of the active layer)? * * @returns {boolean} True if the data is monochrome. - * @deprecated Please use the ViewController equivalent directly instead. + * @deprecated Since v0.33, please use the ViewController + * equivalent directly instead. */ canWindowLevel(): boolean; /** @@ -140,6 +443,16 @@ export declare class App { * @returns {ViewLayer[]} The layers. */ getViewLayersByDataId(dataId: string): ViewLayer[]; + /** + * Get a list of view layers according to an input callback function. + * + * @param {Function} [callbackFn] A function that takes + * a ViewLayer as input and returns a boolean. If undefined, + * returns all view layers. + * @returns {ViewLayer[]} The layers that + * satisfy the callbackFn. + */ + getViewLayers(callbackFn?: Function): ViewLayer[]; /** * Get the draw layers associated to a data id. * The layer are available after the first loaded item. @@ -148,6 +461,16 @@ export declare class App { * @returns {DrawLayer[]} The layers. */ getDrawLayersByDataId(dataId: string): DrawLayer[]; + /** + * Get a list of draw layers according to an input callback function. + * + * @param {Function} [callbackFn] A function that takes + * a DrawLayer as input and returns a boolean. If undefined, + * returns all draw layers. + * @returns {DrawLayer[]} The layers that + * satisfy the callbackFn. + */ + getDrawLayers(callbackFn?: Function): DrawLayer[]; /** * Get a layer group by div id. * The layer is available after the first loaded item. @@ -176,6 +499,15 @@ export declare class App { * @function */ addToUndoStack: (cmd: object) => void; + /** + * Remove a command from the undo stack. + * + * @param {string} name The name of the command to remove. + * @returns {boolean} True if the command was found and removed. + * @fires UndoStack#undoremove + * @function + */ + removeFromUndoStack: (name: string) => boolean; /** * Initialise the application. * @@ -304,7 +636,8 @@ export declare class App { * Init the Window/Level display * (of the active layer of the active layer group). * - * @deprecated Please set the opacity of the desired view layer directly. + * @deprecated Since v0.33, please set the opacity + * of the desired view layer directly. */ initWLDisplay(): void; /** @@ -406,28 +739,28 @@ export declare class App { * Set the active view layer (of the active layer group) opacity. * * @param {number} alpha The opacity ([0:1] range). - * @deprecated Please set the opacity of the desired view layer directly. + * @deprecated Since v0.33, pplease set the opacity + * of the desired view layer directly. */ setOpacity(alpha: number): void; /** * Set the drawings of the active layer group. * + * @deprecated Since v0.34, please switch to DICOM SR annotations. * @param {Array} drawings An array of drawings. * @param {Array} drawingsDetails An array of drawings details. + * @param {string} dataId The converted data id. */ - setDrawings(drawings: any[], drawingsDetails: any[]): void; - /** - * Get the JSON state of the app. - * - * @returns {string} The state of the app as a JSON string. - */ - getJsonState(): string; + setDrawings(drawings: any[], drawingsDetails: any[], dataId: string): void; /** * Apply a JSON state to this app. * + * @deprecated Since v0.34, please switch to DICOM SR + * for annotations. * @param {string} jsonState The state of the app as a JSON string. + * @param {string} dataId The state data id. */ - applyJsonState(jsonState: string): void; + applyJsonState(jsonState: string, dataId: string): void; /** * Handle resize: fit the display to the window. * To be called once the image is loaded. @@ -473,14 +806,16 @@ export declare class App { * Set the colour map of the active view of the active layer group. * * @param {string} name The colour map name. - * @deprecated Please use the ViewController equivalent directly instead. + * @deprecated Since v0.33, please use the ViewController + * equivalent directly instead. */ setColourMap(name: string): void; /** * Set the window/level preset of the active view of the active layer group. * * @param {string} preset The window/level preset. - * @deprecated Please use the ViewController equivalent directly instead. + * @deprecated Since v0.33, please use the ViewController + * equivalent directly instead. */ setWindowLevelPreset(preset: string): void; /** @@ -532,6 +867,29 @@ export declare class App { * @param {string} dataId The data id. */ toggleOverlayListeners(dataId: string): void; + /** + * Create new annotation data based on the data of + * the active view layer. + * + * @param {string} refDataId The reference data id. + * @returns {DicomData} The new data. + */ + createAnnotationData(refDataId: string): DicomData; + /** + * Add new data and render it with a simple new data view config. + * + * @param {DicomData} data The data to add. + * @param {string} divId The div where to draw. + * @param {string} refDataId The reference data id. + */ + addAndRenderAnnotationData(data: DicomData, divId: string, refDataId: string): void; + /** + * Add a draw layer. + * + * @param {string} dataId The data id. + * @param {ViewConfig} viewConfig The data view config. + */ + addDrawLayer(dataId: string, viewConfig: ViewConfig): void; #private; } @@ -668,6 +1026,79 @@ export declare class ChangeSegmentColourCommand { #private; } +/** + * Circle shape. + */ +export declare class Circle { + /** + * @param {Point2D} centre A Point2D representing the centre + * of the circle. + * @param {number} radius The radius of the circle. + */ + constructor(centre: Point2D, radius: number); + /** + * Get the centre (point) of the circle. + * + * @returns {Point2D} The center (point) of the circle. + */ + getCenter(): Point2D; + /** + * Get the centroid of the circle. + * + * @returns {Point2D} The centroid point. + */ + getCentroid(): Point2D; + /** + * Get the radius of the circle. + * + * @returns {number} The radius of the circle. + */ + getRadius(): number; + /** + * Check for equality. + * + * @param {Circle} rhs The object to compare to. + * @returns {boolean} True if both objects are equal. + */ + equals(rhs: Circle): boolean; + /** + * Get the surface of the circle. + * + * @returns {number} The surface of the circle. + */ + getSurface(): number; + /** + * Get the surface of the circle according to a spacing. + * + * @param {Scalar2D} spacing2D The 2D spacing. + * @returns {number} The surface of the circle multiplied by the given + * spacing or null for null spacings. + */ + getWorldSurface(spacing2D: Scalar2D): number; + /** + * Get the rounded limits of the circle. + * + * See: {@link https://en.wikipedia.org/wiki/Circle#Equations}. + * + * Circle formula: `x*x + y*y = r*r`. + * + * Implies: `y = (+-) sqrt(r*r - x*x)`. + * + * @returns {number[][][]} The rounded limits: + * list of [x, y] pairs (min, max). + */ + getRound(): number[][][]; + /** + * Quantify an circle according to view information. + * + * @param {ViewController} viewController The associated view controller. + * @param {string[]} flags A list of stat values to calculate. + * @returns {object} A quantification object. + */ + quantify(viewController: ViewController, flags: string[]): object; + #private; +} + /** * Colour map: red, green and blue components * to associate with intensity values. @@ -734,10 +1165,10 @@ export declare namespace customUI { /** * Open a dialogue to edit roi data. Defaults to window.prompt. * - * @param {object} data The roi data. + * @param {Annotation} annotation The roi data. * @param {Function} callback The callback to launch on dialogue exit. */ - export function openRoiDialog(data: any, callback: Function): void; + export function openRoiDialog(annotation: Annotation, callback: Function): void; } /** @@ -887,35 +1318,69 @@ export declare class DicomCode { */ constructor(meaning: string); /** - * Code meaning (0008,0104). + * Code meaning. * * @type {string} */ meaning: string; /** - * Code value (0008,0100). + * Code value. * * @type {string|undefined} */ value: string | undefined; /** - * Long code value (0008,0119). + * Long code value. * * @type {string|undefined} */ longValue: string | undefined; /** - * URN code value (0008,0120). + * URN code value. * * @type {string|undefined} */ urnValue: string | undefined; /** - * Coding scheme designator (0008,0102). + * Coding scheme designator. * * @type {string|undefined} */ schemeDesignator: string | undefined; + /** + * Get a string representation of this object. + * + * @returns {string} The code as string. + */ + toString(): string; +} + +/** + * DICOM data: meta and possible image. + */ +export declare class DicomData { + /** + * @param {object} meta The DICOM meta data. + */ + constructor(meta: object); + /** + * DICOM meta data. + * + * @type {object} + */ + meta: object; + /** + * Image extracted from meta data. + * + * @type {Image|undefined} + */ + image: Image_2 | undefined; + /** + * Annotattion group extracted from meta data. + * + * @type {AnnotationGroup|undefined} + */ + annotationGroup: AnnotationGroup | undefined; } /** @@ -981,6 +1446,55 @@ export declare class DicomParser { #private; } +/** + * DICOM SR content: item of a SR content sequence. + * + * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.17.3.html}. + */ +export declare class DicomSRContent { + /** + * @param {string} valueType The content item value type. + */ + constructor(valueType: string); + /** + * Value type. + * + * @type {string} + */ + valueType: string; + /** + * Concept name code. + * + * @type {DicomCode|undefined} + */ + conceptNameCode: DicomCode | undefined; + /** + * Relationship Type. + * + * @type {string} + */ + relationshipType: string; + /** + * Content sequence (0040,A730). + * + * @type {DicomSRContent[]|undefined} + */ + contentSequence: DicomSRContent[] | undefined; + /** + * Value. + * + * @type {object} + */ + value: object; + /** + * Get a string representation of this object. + * + * @param {string} [prefix] An optional prefix for recursive content. + * @returns {string} The object as string. + */ + toString(prefix?: string): string; +} + /** * DICOM writer. * @@ -1070,135 +1584,101 @@ export declare class DicomWriter { */ export declare class DrawController { /** - * @param {DrawLayer} drawLayer The draw layer. + * @param {AnnotationGroup} [group] Optional annotation group. */ - constructor(drawLayer: DrawLayer); + constructor(group?: AnnotationGroup); /** - * Get the current position group. + * Get an annotation. * - * @returns {Konva.Group|undefined} The Konva.Group. + * @param {string} id The annotation id. + * @returns {Annotation|undefined} The annotation. */ - getCurrentPosGroup(): Konva.Group | undefined; + getAnnotation(id: string): Annotation | undefined; /** - * Reset: clear the layers array. + * Get the annotation group. + * + * @returns {AnnotationGroup} The list. */ - reset(): void; + getAnnotationGroup(): AnnotationGroup; /** - * Get a Konva group using its id. + * Check if the annotation group is editable. * - * @param {string} id The group id. - * @returns {object|undefined} The Konva group. + * @returns {boolean} True if editable. */ - getGroup(id: string): object | undefined; + isAnnotationGroupEditable(): boolean; /** - * Activate the current draw layer. + * Set the annotation group editability. * - * @param {Index} index The current position. - * @param {number} scrollIndex The scroll index. + * @param {boolean} flag True to make the annotation group editable. */ - activateDrawLayer(index: Index, scrollIndex: number): void; + setAnnotationGroupEditable(flag: boolean): void; /** - * Get a list of drawing display details. + * Add an annotation. * - * @returns {DrawDetails[]} A list of draw details. + * @param {Annotation} annotation The annotation to add. */ - getDrawDisplayDetails(): DrawDetails[]; + addAnnotation(annotation: Annotation): void; /** - * Get a list of drawing store details. Used in state. + * Update an anotation from the list. * - * @returns {object} A list of draw details including id, text, quant... - * TODO Unify with getDrawDisplayDetails? + * @param {Annotation} annotation The annotation to update. + * @param {string[]} [propKeys] Optional properties that got updated. */ - getDrawStoreDetails(): object; + updateAnnotation(annotation: Annotation, propKeys?: string[]): void; /** - * Set the drawings on the current stage. + * Remove an anotation for the list. * - * @param {Array} drawings An array of drawings. - * @param {DrawDetails[]} drawingsDetails An array of drawings details. - * @param {object} cmdCallback The DrawCommand callback. - * @param {object} exeCallback The callback to call once the - * DrawCommand has been executed. + * @param {string} id The id of the annotation to remove. */ - setDrawings(drawings: any[], drawingsDetails: DrawDetails[], cmdCallback: object, exeCallback: object): void; + removeAnnotation(id: string): void; /** - * Update a drawing from its details. + * Remove an annotation via a remove command (triggers draw actions). * - * @param {DrawDetails} drawDetails Details of the drawing to update. + * @param {string} id The annotation id. + * @param {Function} exeCallback The undo stack callback. */ - updateDraw(drawDetails: DrawDetails): void; + removeAnnotationWithCommand(id: string, exeCallback: Function): void; /** - * Delete a Draw from the stage. + * Update an annotation via an update command (triggers draw actions). * - * @param {Konva.Group} group The group to delete. - * @param {object} cmdCallback The DeleteCommand callback. - * @param {object} exeCallback The callback to call once the - * DeleteCommand has been executed. + * @param {string} id The annotation id. + * @param {object} originalProps The original annotation properties + * that will be updated. + * @param {object} newProps The new annotation properties + * that will replace the original ones. + * @param {Function} exeCallback The undo stack callback. */ - deleteDrawGroup(group: Konva.Group, cmdCallback: object, exeCallback: object): void; + updateAnnotationWithCommand(id: string, originalProps: object, newProps: object, exeCallback: Function): void; /** - * Delete a Draw from the stage. + * Remove all annotations via remove commands (triggers draw actions). * - * @param {string} id The id of the group to delete. - * @param {Function} cmdCallback The DeleteCommand callback. - * @param {Function} exeCallback The callback to call once the - * DeleteCommand has been executed. - * @returns {boolean} False if the group cannot be found. + * @param {Function} exeCallback The undo stack callback. */ - deleteDraw(id: string, cmdCallback: Function, exeCallback: Function): boolean; + removeAllAnnotationsWithCommand(exeCallback: Function): void; /** - * Delete all Draws from the stage. + * Check if the annotation group contains a meta data value. * - * @param {Function} cmdCallback The DeleteCommand callback. - * @param {Function} exeCallback The callback to call once the - * DeleteCommand has been executed. + * @param {string} key The key to check. + * @returns {boolean} True if the meta data is present. */ - deleteDraws(cmdCallback: Function, exeCallback: Function): void; + hasAnnotationMeta(key: string): boolean; /** - * Get the total number of draws - * (at all positions). + * Set an annotation meta data. * - * @returns {number} The total number of draws. + * @param {string} key The meta data to set. + * @param {string} value The value of the meta data. */ - getNumberOfDraws(): number; + setAnnotationMeta(key: string, value: string): void; #private; } /** - * Draw details. + * Debug function to output the layer hierarchy as text. + * + * @param {object} layer The Konva layer. + * @param {string} prefix A display prefix (used in recursion). + * @returns {string} A text representation of the hierarchy. */ -export declare class DrawDetails { - /** - * The draw ID. - * - * @type {number} - */ - id: number; - /** - * The draw position: an Index converted to string. - * - * @type {string} - */ - position: string; - /** - * The draw type. - * - * @type {string} - */ - type: string; - /** - * The draw color: for example 'green', '#00ff00' or 'rgb(0,255,0)'. - * - * @type {string} - */ - color: string; - /** - * The draw meta. - * - * @type {DrawMeta} - */ - meta: DrawMeta; -} - /** * Draw layer. */ @@ -1208,12 +1688,24 @@ export declare class DrawLayer { * as this layer id. */ constructor(containerDiv: HTMLDivElement); + /** + * Set the draw shape handler. + * + * @param {DrawShapeHandler|undefined} handler The shape handler. + */ + setShapeHandler(handler: DrawShapeHandler | undefined): void; /** * Get the associated data id. * * @returns {string} The id. */ getDataId(): string; + /** + * Get the reference data id. + * + * @returns {string} The id. + */ + getReferenceLayerId(): string; /** * Get the Konva stage. * @@ -1229,9 +1721,9 @@ export declare class DrawLayer { /** * Get the draw controller. * - * @returns {object} The controller. + * @returns {DrawController} The controller. */ - getDrawController(): object; + getDrawController(): DrawController; /** * Set the plane helper. * @@ -1293,6 +1785,14 @@ export declare class DrawLayer { * @param {Point3D} [center] The scale center. */ setScale(newScale: Scalar3D, center?: Point3D): void; + /** + * Initialise the layer scale. + * + * @param {Scalar3D} newScale The scale as {x,y,z}. + * @param {Scalar2D} absoluteZoomOffset The zoom offset as {x,y} + * without the fit scale (as provided by getAbsoluteZoomOffset). + */ + initScale(newScale: Scalar3D, absoluteZoomOffset: Scalar2D): void; /** * Set the layer offset. * @@ -1329,9 +1829,23 @@ export declare class DrawLayer { * * @param {Scalar2D} size The image size as {x,y}. * @param {Scalar2D} spacing The image spacing as {x,y}. + * @param {string} refLayerId The reference image dataId. + */ + initialise(size: Scalar2D, spacing: Scalar2D, refLayerId: string): void; + /** + * Set the annotation group. + * + * @param {AnnotationGroup} annotationGroup The annotation group. * @param {string} dataId The associated data id. + * @param {object} exeCallback The undo stack callback. + */ + setAnnotationGroup(annotationGroup: AnnotationGroup, dataId: string, exeCallback: object): void; + /** + * Activate shapes at current position. + * + * @param {boolean} flag The flag to activate or not. */ - initialise(size: Scalar2D, spacing: Scalar2D, dataId: string): void; + activateCurrentPositionShapes(flag: boolean): void; /** * Fit the layer to its parent container. * @@ -1341,34 +1855,52 @@ export declare class DrawLayer { */ fitToContainer(containerSize: Scalar2D, divToWorldSizeRatio: number, fitOffset: Scalar2D): void; /** - * Check the visibility of a given group. + * Check the visibility of an annotation. * - * @param {string} id The id of the group. - * @returns {boolean} True if the group is visible. + * @param {string} id The id of the annotation. + * @returns {boolean} True if the annotation is visible. */ - isGroupVisible(id: string): boolean; + isAnnotationVisible(id: string): boolean; /** - * Toggle the visibility of a given group. + * Set the visibility of an annotation. * - * @param {string} id The id of the group. - * @returns {boolean} False if the group cannot be found. + * @param {string} id The id of the annotation. + * @param {boolean} [visible] True to set to visible, + * will toggle visibility if not defined. + * @returns {boolean} False if the annotation shape cannot be found. */ - toggleGroupVisibility(id: string): boolean; + setAnnotationVisibility(id: string, visible?: boolean): boolean; + /** + * Set the visibility of all labels. + * + * @param {boolean} [visible] True to set to visible, + * will toggle visibility if not defined. + */ + setLabelsVisibility(visible?: boolean): void; + /** + * Set a shape group label visibility according to + * this layer setting. + * + * @param {Konva.Group} shapeGroup The shape group. + */ + setLabelVisibility(shapeGroup: Konva.Group): void; /** * Delete a Draw from the stage. * - * @param {string} id The id of the group to delete. - * @param {object} exeCallback The callback to call once the + * @deprecated Since v0.34, please switch to `annotationGroup.remove`. + * @param {string} _id The id of the group to delete. + * @param {Function} _exeCallback The callback to call once the * DeleteCommand has been executed. */ - deleteDraw(id: string, exeCallback: object): void; + deleteDraw(_id: string, _exeCallback: Function): void; /** * Delete all Draws from the stage. * - * @param {object} exeCallback The callback to call once the + * @deprecated Since v0.34, please switch to `annotationGroup.remove`. + * @param {Function} _exeCallback The callback to call once the * DeleteCommand has been executed. */ - deleteDraws(exeCallback: object): void; + deleteDraws(_exeCallback: Function): void; /** * Get the total number of draws of this layer * (at all positions). @@ -1388,10 +1920,23 @@ export declare class DrawLayer { * Set the current position. * * @param {Point} position The new position. - * @param {Index} index The new index. + * @param {Index} [index] Optional coresponding index. * @returns {boolean} True if the position was updated. */ - setCurrentPosition(position: Point, index: Index): boolean; + setCurrentPosition(position: Point, index?: Index): boolean; + /** + * Get the current position group. + * + * @returns {Konva.Group|undefined} The Konva.Group. + */ + getCurrentPosGroup(): Konva.Group | undefined; + /** + * Get a Konva group using its id. + * + * @param {string} id The group id. + * @returns {object|undefined} The Konva group. + */ + getGroup(id: string): object | undefined; /** * Add an event listener to this class. * @@ -1412,22 +1957,146 @@ export declare class DrawLayer { } /** - * Draw meta data. + * Draw shape handler: handle action on existing shapes. */ -export declare class DrawMeta { +export declare class DrawShapeHandler { + /** + * @callback eventFn@callback eventFn + * @param {object} event The event. + */ + /** + * @param {App} app The associated application. + * @param {Function} eventCallback Event callback. + */ + constructor(app: App, eventCallback: Function); /** - * Draw quantification. + * Set the draw editor shape. * - * @type {object} + * @param {Konva.Shape} shape The shape to edit. + * @param {DrawLayer} drawLayer The layer the shape belongs to. */ - quantification: object; + setEditorShape(shape: Konva.Shape, drawLayer: DrawLayer): void; /** - * Draw text expression. Can contain variables surrounded with '{}' that will - * be extracted from the quantification object. + * Get the currently edited shape group. * - * @type {string} + * @returns {Konva.Group|undefined} The edited group. */ - textExpr: string; + getEditorShapeGroup(): Konva.Group | undefined; + /** + * Get the currently edited annotation. + * + * @returns {Annotation|undefined} The edited annotation. + */ + getEditorAnnotation(): Annotation | undefined; + /** + * Disable and reset the shape editor. + */ + disableAndResetEditor(): void; + /** + * Store specific mouse over cursor. + * + * @param {string} cursor The cursor name. + */ + storeMouseOverCursor(cursor: string): void; + /** + * Handle shape group mouseout. + */ + onMouseOutShapeGroup(): void; + /** + * Add shape group listeners. + * + * @param {Konva.Group} shapeGroup The shape group to set on. + * @param {Annotation} annotation The associated annotation. + * @param {DrawLayer} drawLayer The origin draw layer. + */ + addShapeGroupListeners(shapeGroup: Konva.Group, annotation: Annotation, drawLayer: DrawLayer): void; + /** + * Remove shape group listeners. + * + * @param {Konva.Group} shapeGroup The shape group to set off. + */ + removeShapeListeners(shapeGroup: Konva.Group): void; + #private; +} + +/** + * Ellipse shape. + */ +export declare class Ellipse { + /** + * @param {Point2D} centre A Point2D representing the centre + * of the ellipse. + * @param {number} a The radius of the ellipse on the horizontal axe. + * @param {number} b The radius of the ellipse on the vertical axe. + */ + constructor(centre: Point2D, a: number, b: number); + /** + * Get the centre (point) of the ellipse. + * + * @returns {Point2D} The center (point) of the ellipse. + */ + getCenter(): Point2D; + /** + * Get the centroid of the ellipse. + * + * @returns {Point2D} The centroid point. + */ + getCentroid(): Point2D; + /** + * Get the radius of the ellipse on the horizontal axe. + * + * @returns {number} The radius of the ellipse on the horizontal axe. + */ + getA(): number; + /** + * Get the radius of the ellipse on the vertical axe. + * + * @returns {number} The radius of the ellipse on the vertical axe. + */ + getB(): number; + /** + * Check for equality. + * + * @param {Ellipse} rhs The object to compare to. + * @returns {boolean} True if both objects are equal. + */ + equals(rhs: Ellipse): boolean; + /** + * Get the surface of the ellipse. + * + * @returns {number} The surface of the ellipse. + */ + getSurface(): number; + /** + * Get the surface of the ellipse according to a spacing. + * + * @param {Scalar2D} spacing2D The 2D spacing. + * @returns {number} The surface of the ellipse multiplied by the given + * spacing or null for null spacings. + */ + getWorldSurface(spacing2D: Scalar2D): number; + /** + * Get the rounded limits of the ellipse. + * + * See: {@link https://en.wikipedia.org/wiki/Ellipse#Standard_equation}. + * + * Ellipse formula: `x*x / a*a + y*y / b*b = 1`. + * + * Implies: `y = (+-)(b/a) * sqrt(a*a - x*x)`. + * + * @returns {number[][][]} The rounded limits: + * list of [x, y] pairs (min, max). + */ + getRound(): number[][][]; + /** + * Quantify an ellipse according to view information. + * + * @param {ViewController} viewController The associated view controller. + * @param {string[]} flags A list of stat values to calculate. + * @returns {object} A quantification object. + */ + quantify(viewController: ViewController, flags: string[]): object; + #private; } /** @@ -1619,6 +2288,16 @@ export declare class Geometry { */ export declare function getDefaultDicomSegJson(): object; +/** + * Get a simple dicom element item from a content item object. + * + * @param {DicomSRContent} content The content item object. + * @returns {Object} The item as a list of (key, value) pairs. + */ +export declare function getDicomSRContentItem(content: DicomSRContent): { + [x: string]: any; +}; + /** * List of DICOM data elements indexed via a 8 character string formed from * the group and element numbers. @@ -1664,7 +2343,7 @@ export declare function getEllipseIndices(center: Index, radius: number[], dir: * @param {object} event The event to get the layer div id from. Expecting * an event origininating from a canvas inside a layer HTML div * with the 'layer' class and id generated with `getLayerDivId`. - * @returns {object} The layer details as {groupDivId, layerId}. + * @returns {object} The layer details as {groupDivId, layerIndex, layerId}. */ export declare function getLayerDetailsFromEvent(event: object): object; @@ -1679,11 +2358,12 @@ export declare function getMousePoint(event: object): Point2D; /** * Get the name of an image orientation patient. * - * @param {number[]} orientation The image orientation patient. + * @param {number[]} cosines The image orientation + * patient cosines (6 values). * @returns {string|undefined} The orientation * name: axial, coronal or sagittal. */ -export declare function getOrientationName(orientation: number[]): string | undefined; +export declare function getOrientationName(cosines: number[]): string | undefined; /** * Get the PixelData Tag. @@ -1692,6 +2372,16 @@ export declare function getOrientationName(orientation: number[]): string | unde */ export declare function getPixelDataTag(): Tag; +/** + * Get the indices that form a rectangle. + * + * @param {Index} center The rectangle center. + * @param {number[]} size The 2 rectangle sizes. + * @param {number[]} dir The 2 rectangle directions. + * @returns {Index[]} The indices of the rectangle. + */ +export declare function getRectangleIndices(center: Index, size: number[], dir: number[]): Index[]; + /** * Get patient orientation label in the reverse direction. * @@ -1700,6 +2390,16 @@ export declare function getPixelDataTag(): Tag; */ export declare function getReverseOrientation(ori: string): string; +/** + * Get a content item object from a dicom element. + * + * @param {Object} dataElements The dicom element. + * @returns {DicomSRContent} A content item object. + */ +export declare function getSRContent(dataElements: { + [x: string]: DataElement; +}): DicomSRContent; + /** * Split a group-element key used to store DICOM elements. * @@ -1817,6 +2517,20 @@ declare class Image_2 { * @returns {string} The UID. */ getImageUid(index?: Index): string; + /** + * Get the image origin for a image UID. + * + * @param {string} uid The UID. + * @returns {Point3D|undefined} The origin. + */ + getOriginForImageUid(uid: string): Point3D | undefined; + /** + * Check if the image includes an UID. + * + * @param {string} uid The UID. + * @returns {boolean} True if present. + */ + includesImageUid(uid: string): boolean; /** * Check if this image includes the input uids. * @@ -1847,7 +2561,7 @@ declare class Image_2 { * Can window and level be applied to the data? * * @returns {boolean} True if the data is monochrome. - * @deprecated Please use isMonochrome instead. + * @deprecated Since v0.33, please use isMonochrome instead. */ canWindowLevel(): boolean; /** @@ -2236,14 +2950,7 @@ export declare class Index { * @param {number} j The new 1 index. * @returns {Index} The new index. */ - getWithNew2D(i: number, j: number): Index; - /** - * Get a string id from the index values in the form of: '#0-1_#1-2'. - * - * @param {number[]} [dims] Optional list of dimensions to use. - * @returns {string} The string id. - */ - toStringId(dims?: number[]): string; + getWithNew2D(i: number, j: number): Index; #private; } @@ -2348,6 +3055,35 @@ export declare class LayerGroup { * a layer with the input id. */ includes(id: string): boolean; + /** + * Get a list of view layers according to an input callback function. + * + * @param {Function} [callbackFn] A function that takes + * a ViewLayer as input and returns a boolean. If undefined, + * returns all view layers. + * @returns {ViewLayer[]} The layers that + * satisfy the callbackFn. + */ + getViewLayers(callbackFn?: Function): ViewLayer[]; + /** + * Test if one of the view layers satisfies an input callbackFn. + * + * @param {Function} callbackFn A function that takes + * a ViewLayer as input and returns a boolean. + * @returns {boolean} True if one of the ViewLayers + * satisfies the callbackFn. + */ + someViewLayer(callbackFn: Function): boolean; + /** + * Get a list of draw layers according to an input callback function. + * + * @param {Function} [callbackFn] A function that takes + * a DrawLayer as input and returns a boolean. If undefined, + * returns all draw layers. + * @returns {DrawLayer[]} The layers that + * satisfy the callbackFn. + */ + getDrawLayers(callbackFn?: Function): DrawLayer[]; /** * Get the number of view layers handled by this class. * @@ -2414,9 +3150,10 @@ export declare class LayerGroup { /** * Set the active draw layer. * - * @param {number} index The index of the layer to set as active. + * @param {number|undefined} index The index of the layer to set as active + * or undefined to not set any. */ - setActiveDrawLayer(index: number): void; + setActiveDrawLayer(index: number | undefined): void; /** * Set the active draw layer with a data id. * @@ -2469,14 +3206,6 @@ export declare class LayerGroup { * Remove the tooltip html div. */ removeTooltipDiv(): void; - /** - * Test if one of the view layers satisfies an input callbackFn. - * - * @param {Function} callbackFn A function that takes a ViewLayer as input - * and returns a boolean. - * @returns {boolean} True if one of the ViewLayers satisfies the callbackFn. - */ - someViewLayer(callbackFn: Function): boolean; /** * Can the input position be set on one of the view layers. * @@ -2756,6 +3485,12 @@ export declare class MaskSegmentHelper { * @returns {boolean} True if the segment is included. */ hasSegment(segmentNumber: number): boolean; + /** + * Get the number of segments of the segmentation. + * + * @returns {number} The number of segments. + */ + getNumberOfSegments(): number; /** * Check if a segment is present in a mask image. * @@ -3021,11 +3756,22 @@ export declare class OverlayData { */ export declare class PlaneHelper { /** - * @param {Spacing} spacing The spacing. - * @param {Matrix33} imageOrientation The image oientation. + * @param {Geometry} imageGeometry The image geometry. * @param {Matrix33} viewOrientation The view orientation. */ - constructor(spacing: Spacing, imageOrientation: Matrix33, viewOrientation: Matrix33); + constructor(imageGeometry: Geometry, viewOrientation: Matrix33); + /** + * Get the view orientation. + * + * @returns {Matrix33} The orientation matrix. + */ + getViewOrientation(): Matrix33; + /** + * Get the target orientation. + * + * @returns {Matrix33} The orientation matrix. + */ + getTargetOrientation(): Matrix33; /** * Get a 3D offset from a plane one. * @@ -3089,6 +3835,48 @@ export declare class PlaneHelper { * @returns {Point3D} The de-orienteded point. */ getImageDeOrientedPoint3D(point: Point3D): Point3D; + /** + * Get a world position from a 2D plane position. + * + * @param {Point2D} point2D The plane point. + * @param {number} k The slice index. + * @returns {Point3D} The world position. + */ + getPositionFromPlanePoint(point2D: Point2D, k: number): Point3D; + /** + * Get a 2D plane position from a world position. + * + * @param {Point} point The world position. + * @returns {Point3D} The plane point. + */ + getPlanePointFromPosition(point: Point): Point3D; + /** + * Get the cosines of this plane. + * + * @returns {number[]} The 2 cosines vectors (3D). + */ + getCosines(): number[]; + /** + * Get a list of points that define the plane at input position, + * given this classes orientation. + * + * @param {Point} position The position. + * @returns {Point3D[]} An origin and 2 cosines vectors. + */ + getPlanePoints(position: Point): Point3D[]; + /** + * Image world to index. + * + * @param {Point} point The input point. + * @returns {Index} The corresponding index. + */ + worldToIndex(point: Point): Index; + /** + * Is this view in the same orientation as the image aquisition. + * + * @returns {boolean} True if in aquisition plane. + */ + isAquisitionOrientation(): boolean; /** * Reorder values to follow target orientation. * @@ -3114,7 +3902,7 @@ export declare class PlaneHelper { /** * Immutable point. * Warning: the input array is NOT cloned, modifying it will - * modify the index values. + * modify the point values. */ export declare class Point { /** @@ -3122,26 +3910,26 @@ export declare class Point { */ constructor(values: number[]); /** - * Get the index value at the given array index. + * Get the point value at the given array index. * * @param {number} i The index to get. * @returns {number} The value. */ get(i: number): number; /** - * Get the length of the index. + * Get the length of the point. * * @returns {number} The length. */ length(): number; /** - * Get a string representation of the Index. + * Get a string representation of the point. * - * @returns {string} The Index as a string. + * @returns {string} The point as a string. */ toString(): string; /** - * Get the values of this index. + * Get the values of this point. * * @returns {number[]} The array of values. */ @@ -3211,6 +3999,18 @@ export declare class Point2D { * @returns {number} The Y position of the point. */ getY(): number; + /** + * Get the values of this point. + * + * @returns {number[]} The array of values. + */ + getValues(): number[]; + /** + * Get the centroid of the point, ie itself. + * + * @returns {Point2D} The centroid point. + */ + getCentroid(): Point2D; /** * Check for Point2D equality. * @@ -3224,6 +4024,13 @@ export declare class Point2D { * @returns {string} The point as a string. */ toString(): string; + /** + * Get the distance to another Point2D. + * + * @param {Point2D} point2D The input point. + * @returns {number} Ths distance to the input point. + */ + getDistance(point2D: Point2D): number; #private; } @@ -3255,6 +4062,12 @@ export declare class Point3D { * @returns {number} The Z position of the point. */ getZ(): number; + /** + * Get the values of this point. + * + * @returns {number[]} The array of values. + */ + getValues(): number[]; /** * Check for Point3D equality. * @@ -3316,6 +4129,137 @@ export declare class Point3D { */ export declare function precisionRound(number: number, precision: number): number; +/** + * Protractor shape: 3 points from which to calculate an angle. + */ +export declare class Protractor { + /** + * @param {Point2D[]} points The list of Point2D that make + * the protractor. + */ + constructor(points: Point2D[]); + /** + * Get a point of the list. + * + * @param {number} index The index of the point + * to get (beware, no size check). + * @returns {Point2D|undefined} The Point2D at the given index. + */ + getPoint(index: number): Point2D | undefined; + /** + * Get the length of the path (should be 3). + * + * @returns {number} The length of the path. + */ + getLength(): number; + /** + * Get the centroid of the protractor. + * + * @returns {Point2D} THe centroid point. + */ + getCentroid(): Point2D; + /** + * Quantify a path according to view information. + * + * @param {ViewController} _viewController The associated view controller. + * @param {string[]} _flags A list of stat values to calculate. + * @returns {object} A quantification object. + */ + quantify(_viewController: ViewController, _flags: string[]): object; + #private; +} + +/** + * Rectangle shape. + */ +export declare class Rectangle { + /** + * @param {Point2D} begin A Point2D representing the beginning + * of the rectangle. + * @param {Point2D} end A Point2D representing the end + * of the rectangle. + */ + constructor(begin: Point2D, end: Point2D); + /** + * Get the begin point of the rectangle. + * + * @returns {Point2D} The begin point of the rectangle. + */ + getBegin(): Point2D; + /** + * Get the end point of the rectangle. + * + * @returns {Point2D} The end point of the rectangle. + */ + getEnd(): Point2D; + /** + * Check for equality. + * + * @param {Rectangle} rhs The object to compare to. + * @returns {boolean} True if both objects are equal. + */ + equals(rhs: Rectangle): boolean; + /** + * Get the surface of the rectangle. + * + * @returns {number} The surface of the rectangle. + */ + getSurface(): number; + /** + * Get the surface of the rectangle according to a spacing. + * + * @param {Scalar2D} spacing2D The 2D spacing. + * @returns {number} The surface of the rectangle multiplied by the given + * spacing or null for null spacings. + */ + getWorldSurface(spacing2D: Scalar2D): number; + /** + * Get the real width of the rectangle. + * + * @returns {number} The real width of the rectangle. + */ + getRealWidth(): number; + /** + * Get the real height of the rectangle. + * + * @returns {number} The real height of the rectangle. + */ + getRealHeight(): number; + /** + * Get the width of the rectangle. + * + * @returns {number} The width of the rectangle. + */ + getWidth(): number; + /** + * Get the height of the rectangle. + * + * @returns {number} The height of the rectangle. + */ + getHeight(): number; + /** + * Get the rounded limits of the rectangle. + * + * @returns {object} The rounded limits as {min, max} (Point2D). + */ + getRound(): object; + /** + * Get the centroid of the rectangle. + * + * @returns {Point2D} The centroid point. + */ + getCentroid(): Point2D; + /** + * Quantify a rectangle according to view information. + * + * @param {ViewController} viewController The associated view controller. + * @param {string[]} flags A list of stat values to calculate. + * @returns {object} A quantification object. + */ + quantify(viewController: ViewController, flags: string[]): object; + #private; +} + /** * Rescale Slope and Intercept. */ @@ -3390,6 +4334,58 @@ export declare class RGB { b: number; } +/** + * Region Of Interest shape. + * Note: should be a closed path. + */ +export declare class ROI { + /** + * @param {Point2D[]} [points] Optional initial point list. + */ + constructor(points?: Point2D[]); + /** + * Get a point of the list at a given index. + * + * @param {number} index The index of the point to get + * (beware, no size check). + * @returns {Point2D|undefined} The Point2D at the given index. + */ + getPoint(index: number): Point2D | undefined; + /** + * Get the point list. + * + * @returns {Point2D[]} The list. + */ + getPoints(): Point2D[]; + /** + * Get the length of the point list. + * + * @returns {number} The length of the point list. + */ + getLength(): number; + /** + * Add a point to the ROI. + * + * @param {Point2D} point The Point2D to add. + */ + addPoint(point: Point2D): void; + /** + * Add points to the ROI. + * + * @param {Point2D[]} rhs The array of POints2D to add. + */ + addPoints(rhs: Point2D[]): void; + /** + * Get the centroid of the roi. Only valid for + * a non-self-intersecting closed polygon. + * Ref: {@link https://en.wikipedia.org/wiki/Centroid#Of_a_polygon}. + * + * @returns {Point2D} The centroid point. + */ + getCentroid(): Point2D; + #private; +} + /** * Mutable 2D scalar ({x,y}). */ @@ -3805,12 +4801,109 @@ export declare class ToolConfig { * List of client provided tools to be added to * the default ones. * + * @example + * // custom tool + * class AlertTool { + * mousedown() {alert('AlertTool mousedown');} + * init() {} + * activate() {} + * } + * // pass it to dwv tool list + * dwv.toolList['Alert'] = AlertTool; + * // create the dwv app + * const app = new dwv.App(); + * // initialise + * const viewConfig0 = new dwv.ViewConfig('layerGroup0'); + * const viewConfigs = {'*': [viewConfig0]}; + * const options = new dwv.AppOptions(viewConfigs); + * options.tools = {Alert: {}}; + * app.init(options); + * // activate tool + * app.addEventListener('load', function () { + * app.setTool('Alert'); + * }); + * // load dicom data + * app.loadURLs([ + * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm' + * ]); + * * @type {Object} */ export declare const toolList: { [x: string]: any; }; +/** + * List of client provided tool options to be added to + * the default ones. + * + * @example + * // custom factory + * class LoveFactory { + * getName() {return 'love';} + * static supports(mathShape) {return mathShape instanceof ROI;} + * getNPoints() {return 1;} + * getTimeout() {return 0;} + * setAnnotationMathShape(annotation, points) { + * const px = points[0].getX(); + * const py = points[0].getY(); + * annotation.mathShape = new dwv.ROI([ + * new dwv.Point2D(px+15,py), new dwv.Point2D(px+10,py-10), + * new dwv.Point2D(px,py), new dwv.Point2D(px-10,py-10), + * new dwv.Point2D(px-15,py), new dwv.Point2D(px,py+20) + * ]); + * annotation.getFactory = function () {return new LoveFactory();} + * } + * createShapeGroup(annotation, style) { + * const roi = annotation.mathShape; + * // konva line + * const arr = []; + * for (let i = 0; i < roi.getLength(); ++i) { + * arr.push(roi.getPoint(i).getX()); + * arr.push(roi.getPoint(i).getY()); + * } + * const shape = new Konva.Line({ + * name: 'shape', points: arr, + * stroke: 'red', strokeWidth: 2, + * closed: true + * }); + * // konva group + * const group = new Konva.Group(); + * group.name('love-group'); + * group.visible(true); + * group.id(annotation.id); + * group.add(shape); + * return group; + * } + * } + * // pass it to dwv option list + * dwv.toolOptions['draw'] = {LoveFactory}; + * // create the dwv app + * const app = new dwv.App(); + * // initialise + * const viewConfig0 = new dwv.ViewConfig('layerGroup0'); + * const viewConfigs = {'*': [viewConfig0]}; + * const options = new dwv.AppOptions(viewConfigs); + * options.tools = {Draw: {options: ['Love']}}; + * app.init(options); + * // activate tool + * app.addEventListener('load', function () { + * app.setTool('Draw'); + * app.setToolFeatures({shapeName: 'Love'}); + * }); + * // load dicom data + * app.loadURLs([ + * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm' + * ]); + * + * @type {Object>} + */ +export declare const toolOptions: { + [x: string]: { + [x: string]: any; + }; +}; + /** * Immutable 3D vector. */ @@ -4043,6 +5136,26 @@ export declare class View { * @returns {Index} The current index. */ getCurrentIndex(): Index; + /** + * Get the SOP image UID of the current image. + * + * @returns {string} The UID. + */ + getCurrentImageUid(): string; + /** + * Get the image origin for a image UID. + * + * @param {string} uid The UID. + * @returns {Point3D|undefined} The origin. + */ + getOriginForImageUid(uid: string): Point3D | undefined; + /** + * Check if the image includes an UID. + * + * @param {string} uid The UID. + * @returns {boolean} True if present. + */ + includesImageUid(uid: string): boolean; /** * Check if the current position (default) or * the provided position is in bounds. @@ -4062,11 +5175,11 @@ export declare class View { * Set the current position. * * @param {Point} position The new position. - * @param {boolean} silent Flag to fire event or not. + * @param {boolean} [silent] Flag to fire event or not. * @returns {boolean} False if not in bounds. * @fires View#positionchange */ - setCurrentPosition(position: Point, silent: boolean): boolean; + setCurrentPosition(position: Point, silent?: boolean): boolean; /** * Set the current index. * @@ -4148,6 +5261,12 @@ export declare class View { * @returns {number} The index. */ getScrollIndex(): number; + /** + * Is this view in the same orientation as the image aquisition. + * + * @returns {boolean} True if in aquisition plane. + */ + isAquisitionOrientation(): boolean; #private; } @@ -4213,9 +5332,8 @@ export declare class ViewConfig { export declare class ViewController { /** * @param {View} view The associated view. - * @param {string} dataId The associated data id. */ - constructor(view: View, dataId: string); + constructor(view: View); /** * Get the plane helper. * @@ -4281,6 +5399,26 @@ export declare class ViewController { * @returns {Index} The current index. */ getCurrentIndex(): Index; + /** + * Get the SOP image UID of the current image. + * + * @returns {string} The UID. + */ + getCurrentImageUid(): string; + /** + * Get the image origin for a image UID. + * + * @param {string} uid The UID. + * @returns {Point3D|undefined} The origin. + */ + getOriginForImageUid(uid: string): Point3D | undefined; + /** + * Check if the image includes an UID. + * + * @param {string} uid The UID. + * @returns {boolean} True if present. + */ + includesImageUid(uid: string): boolean; /** * Get the current oriented index. * @@ -4302,16 +5440,30 @@ export declare class ViewController { /** * Get the first origin or at a given position. * - * @param {Point} [position] Opitonal position. + * @param {Point} [position] Optional position. * @returns {Point3D} The origin. */ getOrigin(position?: Point): Point3D; + /** + * Is this view in the same orientation as the image aquisition. + * + * @returns {boolean} True if in aquisition plane. + */ + isAquisitionOrientation(): boolean; + /** + * Get a list of points that define the plane at input position, + * given this classes orientation. + * + * @param {Point} position The position. + * @returns {Point3D[]} An origin and 2 cosines vectors. + */ + getPlanePoints(position: Point): Point3D[]; /** * Get the current scroll position value. * - * @returns {object} The value. + * @returns {number} The value. */ - getCurrentScrollPosition(): object; + getCurrentScrollPosition(): number; /** * Generate display image data to be given to a canvas. * @@ -4324,9 +5476,8 @@ export declare class ViewController { * Set the associated image. * * @param {Image} img The associated image. - * @param {string} dataId The data id of the image. */ - setImage(img: Image_2, dataId: string): void; + setImage(img: Image_2): void; /** * Get the current view (2D) spacing. * @@ -4372,7 +5523,7 @@ export declare class ViewController { * Can window and level be applied to the data? * * @returns {boolean} True if possible. - * @deprecated Please use isMonochrome instead. + * @deprecated Since v0.33, please use isMonochrome instead. */ canWindowLevel(): boolean; /** @@ -4442,9 +5593,11 @@ export declare class ViewController { * Get a world position from a 2D plane position. * * @param {Point2D} point2D The input point. + * @param {number} [k] Optional slice index, + * if undefined, uses the current one. * @returns {Point} The associated position. */ - getPositionFromPlanePoint(point2D: Point2D): Point; + getPositionFromPlanePoint(point2D: Point2D, k?: number): Point; /** * Get a 2D plane position from a world position. * @@ -4452,6 +5605,13 @@ export declare class ViewController { * @returns {Point2D} The 2D position. */ getPlanePositionFromPosition(point: Point): Point2D; + /** + * Get the index of a world position. + * + * @param {Point} point The 3D position. + * @returns {Index} The index. + */ + getIndexFromPosition(point: Point): Index; /** * Set the current index. * @@ -4593,22 +5753,6 @@ export declare class ViewController { * @param {ViewLayer} viewLayer The layer to bind. */ unbindImageAndLayer(viewLayer: ViewLayer): void; - /** - * Add an event listener to this class. - * - * @param {string} type The event type. - * @param {Function} callback The function associated with the provided - * event type, will be called with the fired event. - */ - addEventListener(type: string, callback: Function): void; - /** - * Remove an event listener from this class. - * - * @param {string} type The event type. - * @param {Function} callback The function associated with the provided - * event type. - */ - removeEventListener(type: string, callback: Function): void; #private; } diff --git a/dist/dwv.min.js b/dist/dwv.min.js index e20e2d3dcb..3a1bdbd26c 100644 --- a/dist/dwv.min.js +++ b/dist/dwv.min.js @@ -1,2 +1,2 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("konva"),require("jszip"),require("magic-wand-tool")):"function"==typeof define&&define.amd?define(["konva","jszip","konmagic-wand-tool"],t):"object"==typeof exports?exports.dwv=t(require("konva"),require("jszip"),require("magic-wand-tool")):e.dwv=t(e.Konva,e.JSZip,e.MagicWand)}(this,(function(e,t,n){return function(){"use strict";var i={654:function(e){e.exports=t},944:function(t){t.exports=e},324:function(e){e.exports=n}},r={};function o(e){var t=r[e];if(void 0!==t)return t.exports;var n=r[e]={exports:{}};return i[e](n,n.exports,o),n.exports}o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,{a:t}),t},o.d=function(e,t){for(var n in t)o.o(t,n)&&!o.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var a={};return function(){o.r(a),o.d(a,{App:function(){return Xi},AppOptions:function(){return Yi},BLACK:function(){return p},ChangeSegmentColourCommand:function(){return _i},ColourMap:function(){return S},DataElement:function(){return Te},DeleteSegmentCommand:function(){return Zi},DicomCode:function(){return bt},DicomParser:function(){return ke},DicomWriter:function(){return Pt},DrawController:function(){return In},DrawDetails:function(){return pn},DrawLayer:function(){return Tn},DrawMeta:function(){return mn},Geometry:function(){return it},Image:function(){return Yt},Index:function(){return e},LayerGroup:function(){return On},MaskFactory:function(){return Ht},MaskSegment:function(){return Ft},MaskSegmentHelper:function(){return ji},MaskSegmentViewHelper:function(){return Ki},Matrix33:function(){return w},NumberRange:function(){return tt},Orientation:function(){return De},OverlayData:function(){return hi},PlaneHelper:function(){return Kt},Point:function(){return R},Point2D:function(){return b},Point3D:function(){return x},RGB:function(){return m},RescaleSlopeAndIntercept:function(){return je},Scalar2D:function(){return Ji},Scalar3D:function(){return $i},ScrollWheel:function(){return gi},Size:function(){return Ze},Spacing:function(){return nt},Tag:function(){return le},TagValueExtractor:function(){return ht},ToolConfig:function(){return Wi},ToolboxController:function(){return Bn},Vector3D:function(){return T},View:function(){return _t},ViewConfig:function(){return zi},ViewController:function(){return Jt},ViewLayer:function(){return an},WindowLevel:function(){return r},WriterRule:function(){return pt},addTagsToDictionary:function(){return Y},buildMultipart:function(){return z},createImage:function(){return zt},createMaskImage:function(){return Wt},createView:function(){return Zt},customUI:function(){return en},decoderScripts:function(){return Xn},defaultPresets:function(){return s},defaults:function(){return Li},getDefaultDicomSegJson:function(){return kt},getDwvVersion:function(){return Le},getElementsFromJSONTags:function(){return At},getEllipseIndices:function(){return Ui},getLayerDetailsFromEvent:function(){return Pn},getMousePoint:function(){return rn},getOrientationName:function(){return be},getPixelDataTag:function(){return Se},getReverseOrientation:function(){return Ae},getTagFromKey:function(){return ce},getTouchPoints:function(){return nn},getTypedArray:function(){return Me},getUID:function(){return yt},hasDicomPrefix:function(){return Pe},i18n:function(){return mi},isEqualRgb:function(){return f},labToUintLab:function(){return D},logger:function(){return i},luts:function(){return g},precisionRound:function(){return B},srgbToCielab:function(){return v},toolList:function(){return Gi}});class e{#e;constructor(e){if(!e||void 0===e)throw new Error("Cannot create index with no values.");if(0===e.length)throw new Error("Cannot create index with empty values.");if(!e.every((function(e){return!isNaN(e)})))throw new Error("Cannot create index with non number values.");this.#e=e}get(e){return this.#e[e]}length(){return this.#e.length}toString(){return"("+this.#e.toString()+")"}getValues(){return this.#e.slice()}canCompare(e){return!!e&&this.length()===e.length()}equals(e){if(!this.canCompare(e))return!1;for(let t=0,n=this.length();t=this.length())throw new Error("Non valid dimension for toStringId.");let t="";for(let n=0;nr&&(r=i+1);const o=new Array(r);o.fill(0);for(let e=0;ethis.#u?this.#l:e*this.#d+this.#h}}class c{#g;#m;#r;#p=0;#f=!0;constructor(e,t,n){if(this.#g=e,t){const e=this.#g.getLength();this.#p=e/2}else this.#p=0;this.#f=n}getVoiLut(){return this.#m}getModalityLut(){return this.#g}setVoiLut(e){if(this.#m=e,this.#m.setSignedOffset(this.#g.getRSI().getSlope()*this.#p),this.#f){const e=this.#g.getLength();this.#r=new Uint8ClampedArray(e);for(let t=0;t255?255:t})),green:u((function(e){const t=256/3;let n=0;return e>=t&&(n=3*(e-t),n>255)?255:n})),blue:u((function(e){const t=256/3;let n=0;return e>=2*t&&(n=3*(e-2*t),n>255)?255:n}))},hot_iron:{red:[0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98,100,102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164,166,168,170,172,174,176,178,180,182,184,186,188,190,192,194,196,198,200,202,204,206,208,210,212,214,216,218,220,222,224,226,228,230,232,234,236,238,240,242,244,246,248,250,252,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],green:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98,100,102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164,166,168,170,172,174,176,178,180,182,184,186,188,190,192,194,196,198,200,202,204,206,208,210,212,214,216,218,220,222,224,226,228,230,232,234,236,238,240,242,244,246,248,250,252,255],blue:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152,156,160,164,168,172,176,180,184,188,192,196,200,204,208,212,216,220,224,228,232,236,240,244,248,252,255]},pet:{red:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,85,86,88,90,92,94,96,98,100,102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164,166,168,170,171,173,175,177,179,181,183,185,187,189,191,193,195,197,199,201,203,205,207,209,211,213,215,217,219,221,223,225,227,229,231,233,235,237,239,241,243,245,247,249,251,253,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],green:[0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,97,99,101,103,105,107,109,111,113,115,117,119,121,123,125,128,126,124,122,120,118,116,114,112,110,108,106,104,102,100,98,96,94,92,90,88,86,84,82,80,78,76,74,72,70,68,66,64,63,61,59,57,55,53,51,49,47,45,43,41,39,37,35,33,31,29,27,25,23,21,19,17,15,13,11,9,7,5,3,1,0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98,100,102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164,166,168,170,172,174,176,178,180,182,184,186,188,190,192,194,196,198,200,202,204,206,208,210,212,214,216,218,220,222,224,226,228,230,232,234,236,238,240,242,244,246,248,250,252,255],blue:[0,1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,97,99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,129,131,133,135,137,139,141,143,145,147,149,151,153,155,157,159,161,163,165,167,169,171,173,175,177,179,181,183,185,187,189,191,193,195,197,199,201,203,205,207,209,211,213,215,217,219,221,223,225,227,229,231,233,235,237,239,241,243,245,247,249,251,253,255,252,248,244,240,236,232,228,224,220,216,212,208,204,200,196,192,188,184,180,176,172,168,164,160,156,152,148,144,140,136,132,128,124,120,116,112,108,104,100,96,92,88,84,80,76,72,68,64,60,56,52,48,44,40,36,32,28,24,20,16,12,8,4,0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,85,89,93,97,101,105,109,113,117,121,125,129,133,137,141,145,149,153,157,161,165,170,174,178,182,186,190,194,198,202,206,210,214,218,222,226,230,234,238,242,246,250,255]},hot_metal_blue:{red:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,6,9,12,15,18,21,24,26,29,32,35,38,41,44,47,50,52,55,57,59,62,64,66,69,71,74,76,78,81,83,85,88,90,93,96,99,102,105,108,111,114,116,119,122,125,128,131,134,137,140,143,146,149,152,155,158,161,164,166,169,172,175,178,181,184,187,190,194,198,201,205,209,213,217,221,224,228,232,236,240,244,247,251,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],green:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,6,8,9,11,13,15,17,19,21,23,24,26,28,30,32,34,36,38,40,41,43,45,47,49,51,53,55,56,58,60,62,64,66,68,70,72,73,75,77,79,81,83,85,87,88,90,92,94,96,98,100,102,104,105,107,109,111,113,115,117,119,120,122,124,126,128,130,132,134,136,137,139,141,143,145,147,149,151,152,154,156,158,160,162,164,166,168,169,171,173,175,177,179,181,183,184,186,188,190,192,194,196,198,200,201,203,205,207,209,211,213,215,216,218,220,222,224,226,228,229,231,233,235,237,239,240,242,244,246,248,250,251,253,255],blue:[0,2,4,6,8,10,12,14,16,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,84,86,88,90,92,94,96,98,100,102,104,106,108,110,112,114,116,117,119,121,123,125,127,129,131,133,135,137,139,141,143,145,147,149,151,153,155,157,159,161,163,165,167,169,171,173,175,177,179,181,183,184,186,188,190,192,194,196,198,200,197,194,191,188,185,182,179,176,174,171,168,165,162,159,156,153,150,144,138,132,126,121,115,109,103,97,91,85,79,74,68,62,56,50,47,44,41,38,35,32,29,26,24,21,18,15,12,9,6,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,6,9,12,15,18,21,24,26,29,32,35,38,41,44,47,50,53,56,59,62,65,68,71,74,76,79,82,85,88,91,94,97,100,103,106,109,112,115,118,121,124,126,129,132,135,138,141,144,147,150,153,156,159,162,165,168,171,174,176,179,182,185,188,191,194,197,200,203,206,210,213,216,219,223,226,229,232,236,239,242,245,249,252,255]},pet_20step:{red:[0,0,0,0,0,0,0,0,0,0,0,0,0,96,96,96,96,96,96,96,96,96,96,96,96,96,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,80,80,80,80,80,80,80,80,80,80,80,80,80,96,96,96,96,96,96,96,96,96,96,96,96,96,112,112,112,112,112,112,112,112,112,112,112,112,112,128,128,128,128,128,128,128,128,128,128,128,128,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,80,80,80,80,80,80,80,80,80,80,80,80,80,64,64,64,64,64,64,64,64,64,64,64,64,224,224,224,224,224,224,224,224,224,224,224,224,224,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,192,192,192,192,192,192,192,192,192,192,192,192,192,176,176,176,176,176,176,176,176,176,176,176,176,176,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],green:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,80,80,80,80,80,80,80,80,80,80,80,80,80,96,96,96,96,96,96,96,96,96,96,96,96,96,112,112,112,112,112,112,112,112,112,112,112,112,112,128,128,128,128,128,128,128,128,128,128,128,128,96,96,96,96,96,96,96,96,96,96,96,96,96,144,144,144,144,144,144,144,144,144,144,144,144,144,192,192,192,192,192,192,192,192,192,192,192,192,192,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,208,208,208,208,208,208,208,208,208,208,208,208,208,176,176,176,176,176,176,176,176,176,176,176,176,176,144,144,144,144,144,144,144,144,144,144,144,144,96,96,96,96,96,96,96,96,96,96,96,96,96,48,48,48,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255],blue:[0,0,0,0,0,0,0,0,0,0,0,0,0,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,112,112,112,112,112,112,112,112,112,112,112,112,128,128,128,128,128,128,128,128,128,128,128,128,128,176,176,176,176,176,176,176,176,176,176,176,176,176,192,192,192,192,192,192,192,192,192,192,192,192,192,224,224,224,224,224,224,224,224,224,224,224,224,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,80,80,80,80,80,80,80,80,80,80,80,80,80,64,64,64,64,64,64,64,64,64,64,64,64,80,80,80,80,80,80,80,80,80,80,80,80,80,96,96,96,96,96,96,96,96,96,96,96,96,96,64,64,64,64,64,64,64,64,64,64,64,64,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255]}};class m{r;g;b;constructor(e,t,n){this.r=e,this.g=t,this.b=n}}const p={r:0,g:0,b:0};function f(e,t){return null!==e&&null!==t&&void 0!==e&&void 0!==t&&e.r===t.r&&e.g===t.g&&e.b===t.b}function y(e){return function(e){return n=e,.001172549*(t={r:parseInt(n.substring(1,3),16),g:parseInt(n.substring(3,5),16),b:parseInt(n.substring(5,7),16)}).r+.002301961*t.g+447059e-9*t.b<.5;var t,n}(e)?"#fff":"#000"}function D(e){return{l:655.35*e.l,a:257*e.a+32896,b:257*e.b+32896}}const C={x:95.0489,y:100,z:108.884};function v(e){return function(e){function t(e){let t=null;return t=e>.008856452?Math.pow(e,.333333333):7.787037037*e+.137931034,t}const n=C,i=t(e.y/n.y);return{l:116*i-16,a:500*(t(e.x/n.x)-i),b:200*(i-t(e.z/n.z))}}(function(e){function t(e){let t=null;return t=e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4),t}const n=t(e.r/255),i=t(e.g/255),r=t(e.b/255);return{x:100*(.4124*n+.3576*i+.1805*r),y:100*(.2126*n+.7152*i+.0722*r),z:100*(.0193*n+.1192*i+.9505*r)}}(e))}function I(e){const t={Yellow:"#ffff00",Red:"#ff0000",White:"#ffffff",Green:"#008000",Blue:"#0000ff",Lime:"#00ff00",Fuchsia:"#ff00ff",Black:"#000000"};let n="#ffff00";return void 0!==t[e]&&(n=t[e]),n}class T{#y;#D;#C;constructor(e,t,n){this.#y=e,this.#D=t,this.#C=n}getX(){return this.#y}getY(){return this.#D}getZ(){return this.#C}equals(e){return null!==e&&this.#y===e.getX()&&this.#D===e.getY()&&this.#C===e.getZ()}toString(){return"("+this.#y+", "+this.#D+", "+this.#C+")"}norm(){return Math.sqrt(this.#y*this.#y+this.#D*this.#D+this.#C*this.#C)}crossProduct(e){return new T(this.#D*e.getZ()-e.getY()*this.#C,this.#C*e.getX()-e.getZ()*this.#y,this.#y*e.getY()-e.getX()*this.#D)}dotProduct(e){return this.#y*e.getX()+this.#D*e.getY()+this.#C*e.getZ()}isCodirectional(e){return this.dotProduct(e)>0}}Number.EPSILON;const L=1e-4;function P(e,t,n){return void 0===n&&(n=Number.EPSILON),Math.abs(e-t)0?1:-1;for(let t=0;t<3;++t)t===n.index?e.push(1*i):e.push(0)}return new w(e)}getThirdColMajorDirection(){return this.getColAbsMax(2).index}}function O(){return new w([1,0,0,0,1,0,0,0,1])}function A(e){return e.equals(O())}class b{#y;#D;constructor(e,t){this.#y=e,this.#D=t}getX(){return this.#y}getY(){return this.#D}equals(e){return null!=e&&this.#y===e.getX()&&this.#D===e.getY()}toString(){return"("+this.#y+", "+this.#D+")"}}class x{#y;#D;#C;constructor(e,t,n){this.#y=e,this.#D=t,this.#C=n}getX(){return this.#y}getY(){return this.#D}getZ(){return this.#C}equals(e){return null!==e&&this.#y===e.getX()&&this.#D===e.getY()&&this.#C===e.getZ()}isSimilar(e,t){return null!==e&&P(this.#y,e.getX(),t)&&P(this.#D,e.getY(),t)&&P(this.#C,e.getZ(),t)}toString(){return"("+this.#y+", "+this.#D+", "+this.#C+")"}getDistance(e){return Math.sqrt(this.#I(e))}#I(e){const t=this.#y-e.getX(),n=this.#D-e.getY(),i=this.#C-e.getZ();return t*t+n*n+i*i}getClosest(e){let t=0,n=this.#I(e[t]);for(let i=0;i0?0|n:0;return e.substring(i,i+t.length)===t}function E(e,t){return null!=e&&null!=t&&e.substring(e.length-t.length)===t}function q(e){const t=[];if(null==e)return t;const n=/{(\w+)}/g;let i=n.exec(e);for(;i;)t.push(i[1]),i=n.exec(e);return t}function U(e,t){let n="";if(null==e)return n;if(n=e,null==t)return n;const i=q(e);for(let e=0;e=e.length)&&(n=0),(void 0===i||i<=n||i>e.length)&&(i=e.length);for(let r=n;ro;t--,o++)r=n[o],n[o]=n[t],n[t]=r}class fe{#w;#O=!0;#A=function(){return new Int8Array(new Int16Array([1]).buffer)[0]>0}();#b;#x;constructor(e,t){this.#w=e,void 0!==t&&(this.#O=t),this.#b=this.#O!==this.#A,this.#x=new DataView(e)}readUint16(e){return this.#x.getUint16(e,this.#O)}readInt16(e){return this.#x.getInt16(e,this.#O)}readUint32(e){return this.#x.getUint32(e,this.#O)}readBigUint64(e){return this.#x.getBigUint64(e,this.#O)}readInt32(e){return this.#x.getInt32(e,this.#O)}readBigInt64(e){return this.#x.getBigInt64(e,this.#O)}readFloat32(e){return this.#x.getFloat32(e,this.#O)}readFloat64(e){return this.#x.getFloat64(e,this.#O)}readBinaryArray(e,t){const n=new Uint8Array(this.#w,e,t),i=8*n.length,r=new Uint8Array(i);let o=0,a=0;for(let e=0;ea&&t.getX()>t.getY()&&t.getX()>t.getZ())n+=i,t=new T(0,t.getY(),t.getZ());else if(t.getY()>a&&t.getY()>t.getX()&&t.getY()>t.getZ())n+=r,t=new T(t.getX(),0,t.getZ());else{if(!(t.getZ()>a&&t.getZ()>t.getX()&&t.getZ()>t.getY()))break;n+=o,t=new T(t.getX(),t.getY(),0)}return n}function Ie(e){let t;if(void 0!==e&&6===e.length){const n=new T(e[0],e[1],e[2]),i=new T(e[3],e[4],e[5]),r=n.crossProduct(i);t=new w([n.getX(),i.getX(),r.getX(),n.getY(),i.getY(),r.getY(),n.getZ(),i.getZ(),r.getZ()])}return t}class Te{vr;value;tag;vl;undefinedLength;startOffset;endOffset;items;constructor(e){this.vr=e}}function Le(){return"0.33.1"}function Pe(e){return!(e.byteLength<132)&&"DICM"===new Uint8Array(e,128,4).reduce((function(e,t){return e+String.fromCharCode(t)}),"")}const we=String.fromCharCode("u200B");class Oe{decode(e){let t="";for(let n=0,i=e.length;n2^"+e+").")}}return r}function Qe(e,t){return t?8:Z(e)?12:8}const Be="00280008",Ne="00280100",Ve="00280103",Ge="7FE00010";class ke{#R={};#F;#E=new Oe;#q=this.#E;#U(e){return this.#E.decode(e)}#M(e){return this.#q.decode(e)}getDefaultCharacterSet(){return this.#F}setDefaultCharacterSet(e){this.#F=e}setDecoderCharacterSet(e){this.#q=new TextDecoder(e)}getDicomElements(){return this.#R}#Q(e,t){const n=e.readHex(t);t+=Uint16Array.BYTES_PER_ELEMENT;const i=e.readHex(t);return t+=Uint16Array.BYTES_PER_ELEMENT,{tag:new le(n,i),endOffset:t}}#B(e,t,n){const i={};let r=this.#N(e,t,n);if(t=r.endOffset,he(r.tag))return{data:i,endOffset:r.endOffset,isSeqDelim:!0};if(i[r.tag.getKey()]={tag:r.tag,vr:"NONE",vl:r.vl,undefinedLength:r.undefinedLength},r.undefinedLength){let o=!1;for(;!o;)r=this.#N(e,t,n),t=r.endOffset,o="FFFEE00D"===r.tag.getKey(),o||(i[r.tag.getKey()]=r)}else{const o=t;for(t-=r.vl;t8&&"OB"===s&&(i.warn("Reading DICOM pixel data with bitsAllocated>8 and OB VR, treating as OW"),e.vr="OW"),c=[],1===r)c.push(t.readBinaryArray(l,a));else if(8===r)0===n?c.push(t.readUint8Array(l,a)):c.push(t.readInt8Array(l,a));else{if(16!==r)throw new Error("Unsupported bits allocated: "+r);0===n?c.push(t.readUint16Array(l,a)):c.push(t.readInt16Array(l,a))}else if(void 0!==u)if("Uint8"===u)c=t.readUint8Array(l,a);else if("Uint16"===u)c=t.readUint16Array(l,a),"O"!==s[0]&&(c=Array.from(c));else if("Uint32"===u)c=t.readUint32Array(l,a),"O"!==s[0]&&(c=Array.from(c));else if("Uint64"===u)c=t.readUint64Array(l,a);else if("Int16"===u)c=Array.from(t.readInt16Array(l,a));else if("Int32"===u)c=Array.from(t.readInt32Array(l,a));else if("Int64"===u)c=t.readInt64Array(l,a);else if("Float32"===u)c=Array.from(t.readFloat32Array(l,a));else if("Float64"===u)c=Array.from(t.readFloat64Array(l,a));else{if("string"!==u)throw new Error("Unknown VR type: "+u);{const e=t.readUint8Array(l,a);c=K(s)?this.#M(e):this.#U(e),c=function(e){let t=e;const n=e.length-1;return e[n]===we&&(t=e.substring(0,n)),t=t.trim(),t}(c).split("\\")}}else if("xx"===s)c=Array.from(t.readUint16Array(l,a));else if("ox"===s)c=8===r?0===n?Array.from(t.readUint8Array(l,a)):Array.from(t.readInt8Array(l,a)):0===n?Array.from(t.readUint16Array(l,a)):Array.from(t.readInt16Array(l,a));else if("xs"===s)c=0===n?Array.from(t.readUint16Array(l,a)):Array.from(t.readInt16Array(l,a));else if("AT"===s){const e=t.readUint16Array(l,a);c=[];for(let t=0,n=e.length;t=65&&r<=90&&o>=65&&o<=90);let s=null;if(n===t)s=a?ee:te;else{if(a)throw new Error("Not a valid DICOM file (no magic DICM word foundand implicit VR big endian detected)");s=ne}const l=new Te("UI");return l.tag=new le("0002","0010"),l.value=[s],l.vl=l.value[0].length,l.startOffset=e.startOffset,l.endOffset=l.startOffset+l.vl,l}(r);this.#R[e.tag.getKey()]=e,n=e.value[0],t=0}if(!function(e){return e===ee||e===te||e===ne||Fe(e)||Ee(e)||qe(e)||Ue(e)}(n))throw new Error("Unsupported DICOM transfer syntax: '"+n+"' ("+function(e){let t="Unknown";return void 0!==$[e]&&(t=$[e]),t}(n)+")");let l=!1;for(xe(n)&&(l=!0),Re(n)&&(a=new fe(e,!1));t1&&t.length>e){const n=t.length/e,i=[];let o=0;for(let r=0;r{if(void 0===this.#H[e.type])return;const t=this.#H[e.type].slice();for(let n=0;n2?e:0})));let c=o.indexToOffset(l);void 0===i&&(i=!1);let u=null;u=i?function(e){return t.getRescaledValueAtOffset(e)}:function(e){return t.getValueAtOffset(e)};const d=o.get(0),h=o.get(1),S=o.get(2);let g=o.getDimSize(2);const m=t.getNumberOfComponents(),p=1===t.getPlanarConfiguration(),f=function(e,t,n,i,r,o,a,s){return 1===m?ze(e,t,n,i,r,o,a,s):3===m?function(e,t,n,i,r,o,a,s,l){const c=[];return l?(c.push(ze(e,t,n,i,r,o,a,s)),c.push(ze(e,t+n*i,n,i,r,o,a,s)),c.push(ze(e,t+2*n*i,n,i,r,o,a,s))):(i*=3,o*=3,c.push(ze(e,t,n,i,r,o,a,s)),c.push(ze(e,t+1,n,i,r,o,a,s)),c.push(ze(e,t+2,n,i,r,o,a,s))),{next:function(){const e=c[0].next(),t=c[1].next(),n=c[2].next();return e.done?{done:!0,index:n.index}:{value:[e.value,t.value,n.value],done:!1,index:[e.index,t.index,n.index]}}}}(e,3*t,n,i,r,o,a,s,p):void 0};let y=null;if(r&&void 0!==r){const e=r.getColAbsMax(0),t=r.getColAbsMax(2),n=!1,i=!1;let o=null;if(2===t.index)o=d*h,y=0===e.index?f(u,c,o,1,d,d,n,i):f(u,c,o,d,h,1,n,i);else if(0===t.index)o=S*h,y=1===e.index?f(u,c,o,d,h,g,n,i):f(u,c,o,g,S,d,n,i);else{if(1!==t.index)throw new Error("Unknown direction: "+t.index);o=S*d,y=0===e.index?f(u,c,o,1,d,g,n,i):f(u,c,o,g,S,1,n,i)}}else if(1===t.getNumberOfComponents())y=function(e,t,n,i){void 0===i&&(i=1);let r=t;return{next:function(){if(r=e[i+1].index&&++i;const t={value:e[i].colour,done:!1,index:n};return++n,t}return{done:!0,index:t}}}}class je{#d;#z;constructor(e,t){this.#d=e,this.#z=t}getSlope(){return this.#d}getIntercept(){return this.#z}apply(e){return e*this.#d+this.#z}equals(e){return null!=e&&this.getSlope()===e.getSlope()&&this.getIntercept()===e.getIntercept()}isID(){return 1===this.getSlope()&&0===this.getIntercept()}}class Ze{#e;constructor(e){if(!e||void 0===e)throw new Error("Cannot create size with no values.");if(0===e.length)throw new Error("Cannot create size with empty values.");if(!e.every((function(e){return!isNaN(e)&&0!==e})))throw new Error("Cannot create size with non number or zero values.");this.#e=e}get(e){return this.#e[e]}length(){return this.#e.length}toString(){return"("+this.#e.toString()+")"}getValues(){return this.#e.slice()}moreThanOne(e){return this.length()>=e+1&&1!==this.get(e)}canScroll3D(e){let t=2;return void 0!==e&&(t=e.getThirdColMajorDirection()),this.moreThanOne(t)}canScroll(e){let t=this.canScroll3D(e);for(let e=3;ethis.length())return null;if(void 0===t)t=0;else if(t<0||t>e)throw new Error("Invalid start value for getDimSize");let n=1;for(let i=t;in-1)throw new Error("Wrong input dir value: "+t[e]);for(let n=0;n=0&&ithis.length()-1)throw new Error("Invalid start value for indexToOffset");let n=0;for(let i=t;i0;--e)r=this.getDimSize(e),n[e]=Math.floor(i/r),i-=n[e]*r;return n[0]=i,new e(n)}get2D(){return{x:this.get(0),y:this.get(1)}}}class _e{min;max;mean;stdDev;median;p25;p75;constructor(e,t,n,i){this.min=e,this.max=t,this.mean=n,this.stdDev=i}}function Ke(e,t){return function(e){return null!=e&&(e.includes("median")||e.includes("p25")||e.includes("p75"))}(t)?function(e){const t=Je(e);return e.sort((function(e,t){return e-t})),t.median=$e(e,.5),t.p25=$e(e,.25),t.p75=$e(e,.75),t}(e):Je(e)}function Je(e){let t=e[0],n=t,i=0,r=0,o=0;const a=e.length;for(let s=0;sn&&(n=o),i+=o,r+=o*o;const s=i/a;let l=r/a-s*s;l<0&&(l=0);const c=Math.sqrt(l);return new _e(t,n,s,c)}function $e(e,t){if(0===e.length)throw new Error("Empty array provided for percentile calculation.");if(t<0||t>1)throw new Error("Invalid ratio provided for percentile calculation: "+t);if(0===t)return e[0];if(1===t)return e[e.length-1];const n=(e.length-1)*t,i=Math.floor(n),r=e[i];return r+(e[i+1]-r)*(n-i)}function et(){return Math.random().toString(36).substring(2,15)}class tt{min;max;constructor(e,t){this.min=e,this.max=t}}class nt{#e;constructor(e){if(!e||void 0===e)throw new Error("Cannot create spacing with no values.");if(0===e.length)throw new Error("Cannot create spacing with empty values.");if(!e.every((function(e){return!isNaN(e)&&0!==e})))throw new Error("Cannot create spacing with non number or zero values.");this.#e=e}get(e){return this.#e[e]}length(){return this.#e.length}toString(){return"("+this.#e.toString()+")"}getValues(){return this.#e.slice()}equals(e){if(!e)return!1;const t=this.length();if(t!==e.length())return!1;for(let n=0;nL&&i.warn("Varying slice spacing, value: "+r+" (mean: "+n.mean+", min: "+n.min+", max: "+n.max+", stdDev: "+n.stdDev+")"),r}(this.#W);if(void 0!==e&&this.#X.get(2)!==e){i.trace("Using geometric spacing "+e+" instead of tag spacing "+this.#X.get(2));const t=this.#X.getValues();t[2]=e,this.#X=new nt(t)}}getSpacing(e){this.#K&&(this.#J(),this.#K=!1);let t=this.#X;if(e&&void 0!==e){let n=rt([this.#X.get(0),this.#X.get(1),this.#X.get(2)],e);n=n.map(Math.abs),t=new nt(n)}return t}getRealSpacing(){return this.getSpacing(this.#_.getInverse().asOneAndZeros())}getOrientation(){return this.#_}getSliceIndex(e,t){let n=this.#W;void 0!==t&&(n=this.#j[t]);const i=e.getClosest(n),r=n[i],o=e.minus(r);return new T(this.#_.get(0,2),this.#_.get(1,2),this.#_.get(2,2)).isCodirectional(o)?i+1:i}appendOrigin(e,t,n){const i=function(t){return t.equals(e)};if(void 0!==n){if(void 0!==this.#j[n].find(i))throw new Error("Cannot append same time origin twice");this.#j[n].splice(t,0,e)}if(void 0===n||n===this.#Z){if(void 0!==this.#W.find(i))throw new Error("Cannot append same origin twice");this.#K=!0,this.#W.splice(t,0,e);const n=this.#Y.getValues();n[2]+=1,this.#Y=new Ze(n)}}appendFrame(e,t){this.#j[t]=[e];const n=this.#Y.getValues(),i=this.#X.getValues();4===n.length?n[3]+=1:(n.push(2),i.push(1)),this.#Y=new Ze(n),this.#X=new nt(i)}toString(){return"Origin: "+this.getOrigin()+", Size: "+this.getSize()+", Spacing: "+this.getSpacing()+", Orientation: "+this.getOrientation()}equals(e){return null!==e&&this.getOrigin().equals(e.getOrigin())&&this.getSize().equals(e.getSize())&&this.getSpacing().equals(e.getSpacing())}isInBounds(e){return this.isIndexInBounds(this.worldToIndex(e))}isIndexInBounds(e,t){return this.getSize().isInBounds(e,t)}indexToWorld(e){const t=this.getSpacing(),n=new x(e.get(0)*t.get(0),e.get(1)*t.get(1),e.get(2)*t.get(2)),i=this.getOrientation().multiplyPoint3D(n),r=e.getValues(),o=this.getOrigin();return r[0]=o.getX()+i.getX(),r[1]=o.getY()+i.getY(),r[2]=o.getZ()+i.getZ(),new R(r)}pointToWorld(e){const t=this.getSpacing(),n=new x(e.getX()*t.get(0),e.getY()*t.get(1),e.getZ()*t.get(2)),i=this.getOrientation().multiplyPoint3D(n),r=this.getOrigin();return new x(r.getX()+i.getX(),r.getY()+i.getY(),r.getZ()+i.getZ())}worldToIndex(t){const n=this.getOrigin(),i=new x(t.get(0)-n.getX(),t.get(1)-n.getY(),t.get(2)-n.getZ()),r=this.getOrientation().getInverse().multiplyPoint3D(i),o=t.getValues(),a=this.getSpacing();return o[0]=Math.round(r.getX()/a.get(0)),o[1]=Math.round(r.getY()/a.get(1)),o[2]=Math.round(r.getZ()/a.get(2)),new e(o)}worldToPoint(e){const t=this.getOrigin(),n=new x(e.get(0)-t.getX(),e.get(1)-t.getY(),e.get(2)-t.getZ()),i=this.getOrientation().getInverse().multiplyPoint3D(n),r=e.getValues(),o=this.getSpacing();return r[0]=i.getX()/o.get(0),r[1]=i.getY()/o.get(1),r[2]=i.getZ()/o.get(2),new x(r[0],r[1],r[2])}}function rt(e,t){return t.getInverse().multiplyArray3D(e)}function ot(e,t){return t.multiplyArray3D(e)}function at(e){const t=e["00280010"];if(void 0===t)throw new Error("Missing DICOM image number of rows");if(0===t.value.length)throw new Error("Empty DICOM image number of rows");const n=e["00280011"];if(void 0===n)throw new Error("Missing DICOM image number of columns");if(0===n.value.length)throw new Error("Empty DICOM image number of columns");return[n.value[0],t.value[0]]}function st(e){if(void 0===e)return;if(1!==e.value.length)return;const t=e.value[0];let n=4,i=6;return 10===t.length&&(n=5,i=8),{year:parseInt(t.substring(0,4),10),monthIndex:t.length>=n+2?parseInt(t.substring(n,n+2),10)-1:0,day:t.length===i+2?parseInt(t.substring(i,i+2),10):0}}function lt(e){if(void 0===e)return;if(1!==e.value.length)return;const t=e.value[0],n=parseInt(t.substring(0,2),10),i=t.length>=4?parseInt(t.substring(2,4),10):0,r=t.length>=6?parseInt(t.substring(4,6),10):0,o=t.length>=8?t.substring(7,10):0;return{hours:n,minutes:i,seconds:r,milliseconds:0===o?0:parseInt(o,10)*Math.pow(10,3-o.length)}}function ct(e){return("0"+e).slice(-2)}function ut(e){if(void 0===e["00280030"])return null;const t=e["00280030"],n=[parseFloat(t.value[1]),parseFloat(t.value[0])];return void 0!==e["00180088"]&&n.push(parseFloat(e["00180088"].value[0])),new nt(n)}function dt(e,t,n){let i="";if(void 0===e)i+=" "+t+" is undefined,";else if(0===e.value.length)i+=" "+t+" is empty,";else if(void 0!==n)for(let r=0;r=9?lt({value:[t.substring(8)]}):void 0}}(h);S=e.date,g=e.time}void 0===g&&(g={hours:0,minutes:0,seconds:0,milliseconds:0}),s=new Date(S.year,S.monthIndex,S.day,g.hours,g.minutes,g.seconds,g.milliseconds)}const c=lt(e["00080031"]);let u=new Date(r.year,r.monthIndex,r.day,c.hours,c.minutes,c.seconds,c.milliseconds);const d=e["00080022"],h=e["00080032"];if(void 0!==d&&void 0!==h){const t=st(d),r=lt(h),o=new Date(t.year,t.monthIndex,t.day,r.hours,r.minutes,r.seconds,r.milliseconds);if(u>o){const s="Series date/time is after Aquisition date/time (diff="+(u.getTime()-o.getTime()).toString()+"ms) ";i.debug(s);let l=0;const c="FrameReferenceTime (00541300)",d=e["00541300"];n+=dt(d,c),void 0!==d&&(l=d.value[0]);let h=0;const S="ActualFrameDuration (0018,1242)",g=e["00181242"];if(n+=dt(g,S),void 0!==g&&(h=g.value[0]),l>0&&h>0){h/=1e3,l/=1e3;const e=Math.log(2)/a,n=e*h,i=1/e*Math.log(n/(1-Math.exp(-n)))-l;u=new Date(t.year,t.monthIndex,t.day,r.hours,r.minutes,r.seconds+i,r.milliseconds)}}}let S;if(void 0!==u&&void 0!==s&&void 0!==o&&void 0!==a){const e=(u.getTime()-s.getTime())/1e3;S=o*Math.pow(2,-e/a)}return{value:S,warning:n}}(e);n+=a.warning;const s={};return 0!==n.length?s.warning="Cannot calculate PET SUV:"+n:s.value=1e3*t/a.value,s}(e);this.#ee=t.value,this.#$=t.warning}return this.#$}create(e,t,n){const o=at(e),a=[o[0],o[1],1],s=e["00280008"];if(void 0!==s){const e=parseInt(s.value[0],10);e>1&&a.push(e)}const l=new Ze(a),c=function(e){let t=1,n=1;const r=["00280030","00181164","00182010","00280034"];for(let i=0;iparseFloat(e))))),n}(e),y=new x(p[0],p[1],p[2]),D=(new ht).getTime(e),C=new it(y,l,c,f,D);let v;const I=e["00080018"];void 0!==I&&(v=I.value[0]);let T=1;const L=e["00280002"];void 0!==L&&(T=L.value[0]);const P=l.getTotalSize()*T;if(P!==t.length){if(i.warn("Badly sized pixel buffer: "+t.length+" != "+P),!(P>8};o=t.value.map(e),a=n.value.map(e),s=r.value.map(e)}}else if(8===l.value[2]){i.info("Scaling 16bits color lut since the lut descriptor is 8.");let e=t.value.slice(0);o=Array.from(new Uint8Array(e.buffer)),e=n.value.slice(0),a=Array.from(new Uint8Array(e.buffer)),e=r.value.slice(0),s=Array.from(new Uint8Array(e.buffer))}g.palette={red:o,green:a,blue:s}}const z=e["00082144"];return void 0!==z&&(q.RecommendedDisplayFrameRate=parseInt(z.value[0],10)),w.setMeta(q),w}}class gt{#O=!0;#x;constructor(e,t){void 0!==t&&(this.#O=t),this.#x=new DataView(e)}writeUint8(e,t){return this.#x.setUint8(e,t),e+Uint8Array.BYTES_PER_ELEMENT}writeInt8(e,t){return this.#x.setInt8(e,t),e+Int8Array.BYTES_PER_ELEMENT}writeUint16(e,t){return this.#x.setUint16(e,t,this.#O),e+Uint16Array.BYTES_PER_ELEMENT}writeInt16(e,t){return this.#x.setInt16(e,t,this.#O),e+Int16Array.BYTES_PER_ELEMENT}writeUint32(e,t){return this.#x.setUint32(e,t,this.#O),e+Uint32Array.BYTES_PER_ELEMENT}writeUint64(e,t){return this.#x.setBigUint64(e,t,this.#O),e+BigUint64Array.BYTES_PER_ELEMENT}writeInt32(e,t){return this.#x.setInt32(e,t,this.#O),e+Int32Array.BYTES_PER_ELEMENT}writeInt64(e,t){return this.#x.setBigInt64(e,t,this.#O),e+BigInt64Array.BYTES_PER_ELEMENT}writeFloat32(e,t){return this.#x.setFloat32(e,t,this.#O),e+Float32Array.BYTES_PER_ELEMENT}writeFloat64(e,t){return this.#x.setFloat64(e,t,this.#O),e+Float64Array.BYTES_PER_ELEMENT}writeHex(e,t){const n=parseInt(t,16);return this.#x.setUint16(e,n,this.#O),e+Uint16Array.BYTES_PER_ELEMENT}writeBinaryArray(e,t){if(t.length%8!=0)throw new Error("Cannot write boolean array as binary.");let n=null,i=null;for(let r=0,o=t.length;r1){let t="";for(let n=0;n1&&(o=function(e){const t=e.length,n=e[0].length;if(void 0===n)return e;const i=t*n,r=new e[0].constructor(i);for(let i=0;i.206896552?Math.pow(e,3):.128418549*e-.017712903,t}const n=C,i=(e.l+16)/116;return{x:n.x*t(i+e.a/500),y:n.y*t(i),z:n.z*t(i-e.b/200)}}(e))}({l:.001525902*(n={l:i[0],a:i[1],b:i[2]}).l,a:.003891051*n.a-128,b:.003891051*n.b-128});t.displayRGBValue=r}var n;if(void 0===e["00620003"])throw new Error("Missing Segmented Property Category Code Sequence.");if(t.propertyCategoryCode=xt(e["00620003"].value[0]),void 0===e["0062000F"])throw new Error("Missing Segmented Property Type Code Sequence.");return t.propertyTypeCode=xt(e["0062000F"].value[0]),void 0!==e["00620020"]&&(t.trackingId=e["00620020"].value[0],t.trackingUid=e["00620021"].value[0]),t}function qt(e){let t=e.algorithmType;void 0===t&&(t="MANUAL");const n={SegmentNumber:e.number,SegmentLabel:e.label,SegmentAlgorithmType:t};if("MANUAL"!==t&&void 0!==e.algorithmName&&(n.SegmentAlgorithmName=e.algorithmName),e.displayRGBValue){const t=D(v(e.displayRGBValue));n.RecommendedDisplayCIELabValue=[Math.round(t.l),Math.round(t.a),Math.round(t.b)]}else n.RecommendedDisplayGrayscaleValue=e.displayValue;return e.propertyCategoryCode&&(n.SegmentedPropertyCategoryCodeSequence={value:[Rt(e.propertyCategoryCode)]}),e.propertyTypeCode&&(n.SegmentedPropertyTypeCodeSequence={value:[Rt(e.propertyTypeCode)]}),e.trackingId&&(n.TrackingID=e.trackingId,n.TrackingUID=e.trackingUid),n}class Ut{dimIndex;imagePosPat;derivationImages;refSegmentNumber;imageOrientationPatient;spacing;constructor(e,t,n,i){this.dimIndex=e,this.imagePosPat=t,this.derivationImages=n,this.refSegmentNumber=i}}function Mt(e){const t=[];if(void 0!==e["00089124"]){const n=e["00089124"].value;for(let e=0;eL;return t&&(t=e>.001,t?(t=e>.01,t||i.warn("Using larger+ real world epsilon in SEG pos pat adding")):i.warn("Using larger real world epsilon in SEG pos pat adding")),t},E=[];E.push(C[0]);let q=0;for(let t=1;ts)throw new Error("Test distance is increasing when adding intermediate pos pats");E.push(C[t])}const U=E.length,M=new it(b[0],o,h,O),Q=["0"];for(let e=1;e=0;--i){const a=Number.parseInt(o[i],10);m.push(S[r][a]);const s=e.getGeometry().getOrigins()[a],l=[s.getX(),s.getY(),s.getZ()],c={dimIndex:[t,o.length-i],imagePosPat:l,refSegmentNumber:t};if(void 0!==n){const e=n.getGeometry().worldToIndex(new R([s.getX(),s.getY(),s.getZ()]));c.derivationImages=[{sourceImages:[{referencedSOPInstanceUID:n.getImageUid(e),referencedSOPClassUID:n.getMeta().SOPClassUID}]}],p.push({ReferencedSOPInstanceUID:n.getImageUid(e),ReferencedSOPClassUID:n.getMeta().SOPClassUID})}g.push(c)}}o.NumberOfFrames=m.length.toString();const f=[];for(const e of g)f.push(Qt(e));if(o.PerFrameFunctionalGroupsSequence={value:f},void 0!==n){const e=[];e.push({ReferencedInstanceSequence:{value:p},SeriesInstanceUID:n.getMeta().SeriesInstanceUID}),o.ReferencedSeriesSequence={value:e}}void 0!==r&&function(e,t){const n=Object.keys(t);for(const r of n)void 0!==e[r]&&i.trace("Overwritting tag: "+r),e[r]=t[r]}(o,r);const y=At(o),D=s.getDimSize(2),C=m.length*D/8,v=new Te("OB");return v.tag=new le("7FE0","0010"),v.vl=C,v.value=m,y["7FE00010"]=v,y}}function zt(e){return(new St).create(e,e["7FE00010"].value[0],1)}function Wt(e){return(new Ht).create(e,e["7FE00010"].value[0])}class Yt{#me;#w;#pe;#t=new je(1,0);#fe=null;#ye=!0;#De=!0;#Ce="MONOCHROME2";#ve=0;#Ie;#Te={};#Le=null;#Pe=null;#we=null;#Oe=new He;constructor(e,t,n){this.#me=e,this.#w=t,this.#pe=n,this.#Ie=this.#w.length/this.#me.getSize().getTotalSize()}getImageUid(e){let t=this.#pe[0];return 1!==this.#pe.length&&void 0!==e&&(t=this.#pe[this.getSecondaryOffset(e)]),t}containsImageUids(e){return function(e,t){if(null===e||null===t||void 0===e||void 0===t)return!1;if(0===e.length||0===t.length||t.length>e.length)return!1;for(const n of t)if(!e.includes(n))return!1;return!0}(this.#pe,e)}getGeometry(){return this.#me}getBuffer(){return this.#w}canQuantify(){return 1===this.getNumberOfComponents()}canWindowLevel(){return this.isMonochrome()}isMonochrome(){return null!==this.getPhotometricInterpretation().match(/MONOCHROME/)}canScroll(e){const t=this.getGeometry().getSize();let n=1;return void 0!==this.#Te.numberOfFiles&&(n=this.#Te.numberOfFiles),t.canScroll(e)||1!==n}#Ae(){return this.#me.getSize().getTotalSize(2)}getSecondaryOffset(e){return this.#me.getSize().indexToOffset(e,2)}getRescaleSlopeAndIntercept(e){let t=this.#t;if(!this.isConstantRSI()){if(void 0===e)throw new Error("Cannot get non constant RSI with empty slice index.");const n=this.getSecondaryOffset(e);void 0!==this.#fe[n]?t=this.#fe[n]:i.warn("undefined non constant rsi at "+n)}return t}#be(e){return this.#fe[e]}setRescaleSlopeAndIntercept(e,t){if(this.#ye=this.#ye&&e.isID(),this.#De){if(!this.#t.equals(e))if(void 0===t)this.#t=e;else{this.#De=!1,this.#fe=[];for(let e=0,t=this.#Ae();e=this.#Te.numberOfFiles?i.warn("Ignoring frame at index "+t+" (size: "+this.#Te.numberOfFiles+")"):(this.#w.set(e,r*t),this.appendFrame(t,new x(0,0,0)))}appendFrame(e,t){this.#me.appendFrame(t,e),this.#Re({type:"appendframe"})}getDataRange(){return this.#Le||(this.#Le=this.calculateDataRange()),this.#Le}getRescaledDataRange(){return this.#Pe||(this.#Pe=this.calculateRescaledDataRange()),this.#Pe}getHistogram(){if(!this.#we){const e=this.calculateHistogram();this.#Le=e.dataRange,this.#Pe=e.rescaledDataRange,this.#we=e.histogram}return this.#we}addEventListener(e,t){this.#Oe.add(e,t)}removeEventListener(e,t){this.#Oe.remove(e,t)}#Re=e=>{this.#Oe.fireEvent(e)};setAtOffsets(e,t){let n,i;if("number"==typeof t){if(1!==this.#Ie)throw new Error("Number of components is not 1 for setting single value.");n=[t]}else if(void 0!==t.r&&void 0!==t.g&&void 0!==t.b){if(3!==this.#Ie)throw new Error("Number of components is not 3 for setting RGB value.");n=[t.r,t.g,t.b]}for(let t=0,r=e.length;t=3&&(r=i.getDimSize(3));for(let i=0;it&&(t=n),nn?t:n}}{let e=this.getRescaledValueAtOffset(0),t=e,n=0;const i=this.getGeometry().getSize();let r=i.getTotalSize();3===i.length()&&(r=i.getDimSize(3));for(let i=0;it&&(t=n),ni&&(i=r),ra&&(a=s),s{const t=this.getCurrentIndex();if(3===t.length()){const n=t.getValues();n.push(0),this.setCurrentIndex(new e(n))}}))}getImage(){return this.#Fe}setImage(e){this.#Fe=e}getOrientation(){return this.#_}setOrientation(e){this.#_=e}init(){this.setInitialIndex()}setInitialIndex(){const t=this.#Fe.getGeometry().getSize(),n=new Array(t.length());n.fill(0),n[0]=Math.floor(t.get(0)/2),n[1]=Math.floor(t.get(1)/2),n[2]=Math.floor(t.get(2)/2),this.setCurrentIndex(new e(n),!0)}getPlaybackMilliseconds(e){return e||(e=10),Math.round(1e3/e)}#Ne=function(e,t){return 255};getAlphaFunction(){return this.#Ne}setAlphaFunction(e){this.#Ne=e,this.#Re({type:"alphafuncchange"})}#Ve(){if(this.#Ue&&void 0!==this.#qe[this.#Ue]&&void 0!==this.#qe[this.#Ue].perslice&&!0===this.#qe[this.#Ue].perslice){this.getCurrentIndex()||this.setInitialIndex();const e=this.getCurrentIndex(),t=this.#Fe.getSecondaryOffset(e),n=this.#qe[this.#Ue].wl[t];this.setWindowLevel(n,this.#Ue,!0)}if(void 0===this.#Me&&this.setWindowLevelPresetById(0,!0),void 0===this.#De||this.#Fe.isConstantRSI()!==this.#De){let e,t;this.#De=this.#Fe.isConstantRSI(),this.#De?(e=this.#Fe.getRescaleSlopeAndIntercept(),t=!0):(e=new je(1,0),t=!1);const i=new n(e,this.#Fe.getMeta().BitsStored);this.#Ee=new c(i,this.#Fe.getMeta().IsSigned,t)}const e=this.#Ee.getVoiLut();let t;if(void 0!==e&&(t=e.getWindowLevel()),void 0===e||!this.#Me.equals(t)){const e=new l(this.#Me);this.#Ee.setVoiLut(e)}return this.#Ee}getWindowPresets(){return this.#qe}getWindowPresetsNames(){return Object.keys(this.#qe)}setWindowPresets(e){this.#qe=e}addWindowPresets(e){const t=Object.keys(e);let n=null;for(let i=0;i{this.#Oe.fireEvent(e)};getWindowLevelMinMax(){const e=this.getImage().getRescaledDataRange(),t=e.min;let n=e.max-t;return n<1&&(i.warn("Zero or negative window width, defaulting to one."),n=1),new r(t+n/2,n)}setWindowLevelMinMax(){const e=this.getWindowLevelMinMax();this.setWindowLevel(e,"minmax")}generateImageData(e,t){void 0===t&&(this.getCurrentIndex()||this.setInitialIndex(),t=this.getCurrentIndex());const n=this.getImage(),r=!n.isConstantRSI(),o=Ye(n,t,r,this.getOrientation()),a=n.getPhotometricInterpretation();switch(a){case"MONOCHROME1":case"MONOCHROME2":!function(e,t,n,i,r){let o=0,a=0,s=t.next();for(;!s.done;)a=i.getValue(s.value),e.data[o]=r.red[a],e.data[o+1]=r.green[a],e.data[o+2]=r.blue[a],e.data[o+3]=n(s.value,s.index),o+=4,s=t.next()}(e,o,this.getAlphaFunction(),this.#Ve(),this.#Ge());break;case"PALETTE COLOR":!function(e,t,n,r,o){const a=function(e){return e>>8};o&&i.info("Scaling 16bits data to 8bits.");let s=0,l=0,c=t.next();for(;!c.done;)l=c.value,o?(e.data[s]=a(r.red[l]),e.data[s+1]=a(r.green[l]),e.data[s+2]=a(r.blue[l])):(e.data[s]=r.red[l],e.data[s+1]=r.green[l],e.data[s+2]=r.blue[l]),e.data[s+3]=n(l,c.index),s+=4,c=t.next()}(e,o,this.getAlphaFunction(),this.#Ge(),16===n.getMeta().BitsStored);break;case"RGB":!function(e,t,n){let i=0,r=t.next();for(;!r.done;)e.data[i]=r.value[0],e.data[i+1]=r.value[1],e.data[i+2]=r.value[2],e.data[i+3]=n(r.value,r.index),i+=4,r=t.next()}(e,o,this.getAlphaFunction());break;case"YBR_FULL":!function(e,t,n){let i=0,r=null,o=t.next();for(;!o.done;)a=o.value[0],s=o.value[1],r={r:a+1.402*((l=o.value[2])-128),g:a-.34414*(s-128)-.71414*(l-128),b:a+1.772*(s-128)},e.data[i]=r.r,e.data[i+1]=r.g,e.data[i+2]=r.b,e.data[i+3]=n(o.value,o.index),i+=4,o=t.next();var a,s,l}(e,o,this.getAlphaFunction());break;default:throw new Error("Unsupported photometric interpretation: "+a)}}getScrollIndex(){let e=null;const t=this.getOrientation();return e=void 0!==t?t.getThirdColMajorDirection():2,e}}class Kt{#X;#ke;#He;#ze;constructor(e,t,n){this.#X=e,this.#ke=t,this.#He=n,this.#ze=function(e,t){let n=e.asOneAndZeros().multiply(t);return e.asOneAndZeros().getAbs().equals(ye().getAbs())&&(n=n.getAbs()),n}(t,n)}getOffset3DFromPlaneOffset(e){const t=new T(e.x,e.y,0),n=this.getTargetDeOrientedVector3D(t);return new T(n.getX()*this.#X.get(0),n.getY()*this.#X.get(1),n.getZ()*this.#X.get(2))}getPlaneOffsetFromOffset3D(e){const t=new T(e.x/this.#X.get(0),e.y/this.#X.get(1),e.z/this.#X.get(2)),n=this.getTargetOrientedVector3D(t);return{x:n.getX(),y:n.getY()}}getTargetOrientedVector3D(e){let t=e;return void 0!==this.#ze&&(t=this.#ze.getInverse().multiplyVector3D(e)),t}getTargetDeOrientedVector3D(e){let t=e;return void 0!==this.#ze&&(t=this.#ze.multiplyVector3D(e)),t}getTargetDeOrientedPoint3D(e){let t=e;return void 0!==this.#ze&&(t=this.#ze.multiplyPoint3D(e)),t}getImageOrientedVector3D(e){let t=e;if(void 0!==this.#He){const n=ot([e.getX(),e.getY(),e.getZ()],this.#He);t=new T(n[0],n[1],n[2])}return t}getImageOrientedPoint3D(e){let t=e;if(void 0!==this.#He){const n=ot([e.getX(),e.getY(),e.getZ()],this.#He);t=new x(n[0],n[1],n[2])}return t}getImageDeOrientedVector3D(e){let t=e;if(void 0!==this.#He){const n=rt([e.getX(),e.getY(),e.getZ()],this.#He);t=new T(n[0],n[1],n[2])}return t}getImageDeOrientedPoint3D(e){let t=e;if(void 0!==this.#He){const n=rt([e.getX(),e.getY(),e.getZ()],this.#He);t=new x(n[0],n[1],n[2])}return t}getTargetOrientedPositiveXYZ(e){const t=rt([e.x,e.y,e.z],this.#ze);return{x:t[0],y:t[1],z:t[2]}}getScrollIndex(){let e=null;return e=void 0!==this.#He?this.#He.getThirdColMajorDirection():2,e}getNativeScrollIndex(){let e=null;return e=void 0!==this.#ke?this.#ke.getThirdColMajorDirection():2,e}}class Jt{#x;#We;#Ye;#Qe="plain";#Xe;#je=!1;constructor(e,t){if(void 0===e.getImage())throw new Error("View does not have an image, cannot setup controller");this.#x=e,this.#We=t,this.#Ye=new Kt(e.getImage().getGeometry().getRealSpacing(),e.getImage().getGeometry().getOrientation(),e.getOrientation()),"SEG"===e.getImage().getMeta().Modality&&(this.#je=!0)}#Oe=new He;getPlaneHelper(){return this.#Ye}isMask(){return this.#je}initialise(){this.setWindowLevelPresetById(0),this.setCurrentPosition(this.getPositionFromPlanePoint(new b(0,0)))}getModality(){return this.#x.getImage().getMeta().Modality}getWindowLevelPresetsNames(){return this.#x.getWindowPresetsNames()}addWindowLevelPresets(e){return this.#x.addWindowPresets(e)}setWindowLevelPreset(e){this.#x.setWindowLevelPreset(e)}setWindowLevelPresetById(e){this.#x.setWindowLevelPresetById(e)}isPlaying(){return void 0!==this.#Xe}getCurrentPosition(){return this.#x.getCurrentPosition()}getCurrentIndex(){return this.#x.getCurrentIndex()}getCurrentOrientedIndex(){let t=this.#x.getCurrentIndex();if(void 0!==this.#x.getOrientation()){const n=this.#Ye.getImageDeOrientedVector3D(new T(t.get(0),t.get(1),t.get(2)));t=new e([n.getX(),n.getY(),n.getZ()])}return t}getScrollIndex(){return this.#x.getScrollIndex()}getCurrentScrollIndexValue(){return this.#x.getCurrentIndex().get(this.#x.getScrollIndex())}getOrigin(e){return this.#x.getOrigin(e)}getCurrentScrollPosition(){const e=this.#x.getScrollIndex();return this.#x.getCurrentPosition().get(e)}generateImageData(e,t){this.#x.generateImageData(e,t)}setImage(e,t){this.#x.setImage(e),this.#We=t}get2DSpacing(){return this.#x.getImage().getGeometry().getSpacing(this.#x.getOrientation()).get2D()}getRescaledImageValue(e){const t=this.#x.getImage();if(!t.canQuantify())return;const n=t.getGeometry(),i=n.worldToIndex(e);let r;return n.isIndexInBounds(i)&&(r=t.getRescaledValueAtIndex(i)),r}getPixelUnit(){return this.#x.getImage().getMeta().pixelUnit}#Ze(e,t,n,i){const r=We(Ye(e,t,n,i)),o=e.getGeometry().getSize(i).getValues();o[2]=1;const a=new Ze(o),s=e.getGeometry().getSpacing(i).getValues();s[2]=1;const l=new nt(s),c=new x(0,0,0),u=new it(c,a,l);return new Yt(u,r)}getImageRegionValues(t,n){let i=this.#x.getImage();const r=this.#x.getOrientation();let o=this.getCurrentIndex(),a=!0;A(r)||(i=this.#Ze(i,o,a,r),o=new e([0,0,0]),a=!1);const s=function(e,t,n,i,r){if(1!==e.getNumberOfComponents())throw new Error("Unsupported number of components for region iterator: "+e.getNumberOfComponents());void 0===n&&(n=!1);let o=null;o=n?function(t){return e.getRescaledValueAtOffset(t)}:function(t){return e.getValueAtOffset(t)};const a=e.getGeometry().getSize();void 0===i&&(i=new b(0,0)),void 0===r&&(r=new b(a.get(0)-1,a.get(1)));const s=a.indexToOffset(t.getWithNew2D(i.getX(),i.getY())),l=a.indexToOffset(t.getWithNew2D(r.getX(),r.getY()-1)),c=Math.max(1,r.getX()-i.getX());return function(e,t,n,i,r,o){let a=t,s=0;return{next:function(){if(a{let t=!1;if(t=r?this.incrementScrollIndex():this.incrementIndex(3),!t){const t=this.getCurrentIndex().getValues(),n=this.#x.getOrientation();r?t[n.getThirdColMajorDirection()]=0:t[3]=0;const i=new e(t),o=this.#x.getImage().getGeometry();this.setCurrentPosition(o.indexToWorld(i))}}),i)}else this.stop()}stop(){void 0!==this.#Xe&&(clearInterval(this.#Xe),this.#Xe=void 0)}getWindowLevel(){return this.#x.getWindowLevel()}getCurrentWindowPresetName(){return this.#x.getCurrentWindowPresetName()}setWindowLevel(e){this.#x.setWindowLevel(e)}getColourMap(){return this.#x.getColourMap()}setColourMap(e){this.#x.setColourMap(e)}setViewAlphaFunction(e){this.#x.setAlphaFunction(e)}bindImageAndLayer(e){const t=this.#x.getImage();t.addEventListener("imagecontentchange",e.onimagecontentchange),t.addEventListener("imagegeometrychange",e.onimagegeometrychange)}unbindImageAndLayer(e){const t=this.#x.getImage();t.removeEventListener("imagecontentchange",e.onimagecontentchange),t.removeEventListener("imagegeometrychange",e.onimagegeometrychange)}addEventListener(e,t){this.#Oe.add(e,t)}removeEventListener(e,t){this.#Oe.remove(e,t)}#Re=e=>{e.dataid=this.#We,this.#Oe.fireEvent(e)}}const $t=["mousedown","mousemove","mouseup","mouseout","wheel","dblclick","touchstart","touchmove","touchend"],en={openRoiDialog(e,t){const n=prompt("Label",e.textExpr);null!==n&&(e.textExpr=n,t(e))}};function tn(e){let t=0,n=0;if(0!==e.length&&void 0!==e[0].target){let i=e[0].target.offsetParent;for(;i;)isNaN(i.offsetLeft)||(t+=i.offsetLeft),isNaN(i.offsetTop)||(n+=i.offsetTop),i=i.offsetParent}else i.debug("No touch target offset parent.");const r=[];for(let i=0;i{this.#We===e.dataid&&(this.#tt.setImage(e.value[0],this.#We),this.#wt(this.#tt.getImageSize().get2D()),this.#yt=!0)};bindImage(){this.#tt&&this.#tt.bindImageAndLayer(this)}unbindImage(){this.#tt&&this.#tt.unbindImageAndLayer(this)}onimagecontentchange=e=>{this.#We===e.dataid&&(this.#ot=this.#tt.isPositionInBounds(),this.#yt=!0,this.draw())};onimagegeometrychange=e=>{if(this.#We===e.dataid){const e=this.#tt.getImageSize().get2D();if(this.#st.x!==e.x||this.#st.y!==e.y){if(void 0!==this.#Ct&&void 0!==this.#vt){const e=this.#tt.getOrigin(),t=this.#vt.minus(e),n=this.#tt.getOrigin(this.#tt.getCurrentPosition()),i=this.#Ct.minus(n);this.setBaseOffset(t,i)}this.#wt(e),this.#yt=!0,this.draw()}}};getId(){return this.#et.id}removeFromDOM(){this.#et.remove()}getBaseSize(){return this.#st}getImageWorldSize(){return this.#tt.getImageWorldSize()}getOpacity(){return this.#ct}setOpacity(e){if(e===this.#ct)return;this.#ct=Math.min(Math.max(e,0),1);const t={type:"opacitychange",value:[this.#ct]};this.#Re(t)}addFlipOffsetX(){this.#ft.x+=this.#nt.width/this.#ut.x,this.#St.x+=this.#ft.x}addFlipOffsetY(){this.#ft.y+=this.#nt.height/this.#ut.y,this.#St.y+=this.#ft.y}flipScaleX(){this.#ht.x*=-1}flipScaleY(){this.#ht.y*=-1}flipScaleZ(){this.#ht.z*=-1}setScale(e,t){const n=this.#tt.getPlaneHelper(),i=n.getTargetOrientedPositiveXYZ({x:e.x*this.#ht.x,y:e.y*this.#ht.y,z:e.z*this.#ht.z}),r={x:this.#dt.x*i.x,y:this.#dt.y*i.y};if(1===Math.abs(e.x)&&1===Math.abs(e.y)&&1===Math.abs(e.z)){const e={x:this.#St.x-this.#pt.x,y:this.#St.y-this.#pt.y};this.#pt={x:0,y:0},this.#St=e}else if(void 0!==t){let e=n.getPlaneOffsetFromOffset3D({x:t.getX(),y:t.getY(),z:t.getZ()});e={x:e.x+this.#gt.x,y:e.y+this.#gt.y};const i=wn(this.#St,this.#ut,r,e),o={x:this.#pt.x+i.x-this.#St.x,y:this.#pt.y+i.y-this.#St.y};this.#pt=o,this.#St=i}this.#ut=r}initScale(e,t){const n=this.#tt.getPlaneHelper().getTargetOrientedPositiveXYZ({x:e.x*this.#ht.x,y:e.y*this.#ht.y,z:e.z*this.#ht.z}),i={x:this.#dt.x*n.x,y:this.#dt.y*n.y};this.#ut=i,this.#pt={x:t.x/this.#dt.x,y:t.y/this.#dt.y},this.#St={x:this.#St.x+this.#pt.x,y:this.#St.y+this.#pt.y}}setBaseOffset(e,t,n,i){const r=this.#tt.getPlaneHelper(),o=r.getNativeScrollIndex(),a=r.getPlaneOffsetFromOffset3D({x:0===o?e.getX():t.getX(),y:1===o?e.getY():t.getY(),z:2===o?e.getZ():t.getZ()}),s=this.#gt.x!==a.x||this.#gt.y!==a.y;return void 0!==n&&void 0!==i&&(this.#Ct=n,this.#vt=i),s&&(this.#St={x:this.#St.x-this.#gt.x+a.x,y:this.#St.y-this.#gt.y+a.y},this.#gt=a),s}setOffset(e){const t=this.#tt.getPlaneHelper().getPlaneOffsetFromOffset3D(e);this.#St={x:t.x+this.#mt.x+this.#gt.x+this.#pt.x+this.#ft.x,y:t.y+this.#mt.y+this.#gt.y+this.#pt.y+this.#ft.y}}displayToPlaneIndex(t){const n=this.displayToPlanePos(t);return new e([Math.floor(n.getX()),Math.floor(n.getY())])}displayToPlaneScale(e){return new b(e.getX()/this.#ut.x,e.getY()/this.#ut.y)}displayToPlanePos(e){const t=this.displayToPlaneScale(e);return new b(t.getX()+this.#St.x,t.getY()+this.#St.y)}planePosToDisplay(e){let t=(e.getX()-this.#St.x+this.#gt.x)*this.#ut.x,n=(e.getY()-this.#St.y+this.#gt.y)*this.#ut.y;return(t<0||t>=this.#nt.width)&&(t=void 0),(n<0||n>=this.#nt.height)&&(n=void 0),new b(t,n)}displayToMainPlanePos(e){const t=this.displayToPlanePos(e);return new b(t.getX()-this.#gt.x,t.getY()-this.#gt.y)}display(e){this.#et.style.display=e?"":"none"}isVisible(){return""===this.#et.style.display}draw(){if(!this.#ot)return;let e={type:"renderstart",layerid:this.getId(),dataid:this.getDataId()};this.#Re(e),this.#yt&&this.#Ot(),this.#rt.globalAlpha=this.#ct,this.clear(),this.#rt.setTransform(this.#ut.x,0,0,this.#ut.y,-1*this.#St.x*this.#ut.x,-1*this.#St.y*this.#ut.y),this.#rt.imageSmoothingEnabled=this.#Dt,this.#rt.drawImage(this.#it,0,0),e={type:"renderend",layerid:this.getId(),dataid:this.getDataId()},this.#Re(e)}initialise(e,t,n){this.#lt=t,this.#ct=Math.min(Math.max(n,0),1),this.#nt=document.createElement("canvas"),this.#et.appendChild(this.#nt),this.#nt.getContext?(this.#rt=this.#nt.getContext("2d"),this.#rt?(this.#it=document.createElement("canvas"),this.#wt(e),this.#yt=!0):alert("Error: failed to get the 2D context.")):alert("Error: no canvas.getContext method.")}#wt(e){if(!on(e.x,e.y))throw new Error("Cannot create canvas with size "+e.x+", "+e.y);this.#st=e,this.#it.width=this.#st.x,this.#it.height=this.#st.y,this.#rt.clearRect(0,0,this.#st.x,this.#st.y),this.#at=this.#rt.createImageData(this.#st.x,this.#st.y)}fitToContainer(e,t,n){let i=!1;if(this.#nt.width!==e.x||this.#nt.height!==e.y){if(!on(e.x,e.y))throw new Error("Cannot resize canvas "+e.x+", "+e.y);this.#nt.width=e.x,this.#nt.height=e.y,i=!0}const r={x:t*this.#lt.x,y:t*this.#lt.y},o={x:this.#ut.x*r.x/this.#dt.x,y:this.#ut.y*r.y/this.#dt.y};this.#ut.x===o.x&&this.#ut.y===o.y||(this.#dt=r,this.#ut=o,i=!0);const a={x:n.x/r.x,y:n.y/r.y},s={x:e.x/r.x,y:e.y/r.y},l={x:0!==this.#ft.x?s.x:0,y:0!==this.#ft.y?s.y:0};this.#mt.x===a.x&&this.#mt.y===a.y&&this.#ft.x===l.x&&this.#ft.y===l.y||(this.#St={x:this.#St.x+a.x-this.#mt.x+l.x-this.#ft.x,y:this.#St.y+a.y-this.#mt.y+l.y-this.#ft.y},this.#ft=l,this.#mt=a,i=!0),i&&this.draw()}bindInteraction(){this.#et.style.pointerEvents="auto";const e=$t;for(let t=0;t{e.srclayerid=this.getId(),e.dataid=this.#We,this.#Oe.fireEvent(e)};#Ot(){this.#tt.generateImageData(this.#at),this.#it.getContext("2d").putImageData(this.#at,0,0),this.#yt=!1}#It=e=>{void 0!==e.skipGenerate&&!0===e.skipGenerate||(this.#yt=!0,this.draw())};#Tt=e=>{void 0!==e.skipGenerate&&!0===e.skipGenerate||(this.#yt=!0,this.draw())};#Lt=e=>{if(void 0===e.skipGenerate||!0!==e.skipGenerate){let t=!0;if(void 0!==e.valid&&(t=e.valid),t){const t=[0,1,2],n=t.indexOf(this.#tt.getScrollIndex());t.splice(n,1),0===e.diffDims.filter((function(e){return-1===t.indexOf(e)})).length&&this.#ot||(this.#ot=!0,this.#yt=!0,this.draw())}else this.#ot&&(this.#ot=!1,this.clear())}};#Pt=e=>{void 0!==e.skipGenerate&&!0===e.skipGenerate||(this.#yt=!0,this.draw())};setCurrentPosition(e,t){return this.#tt.setCurrentPosition(e)}clear(){this.#rt.save(),this.#rt.setTransform(1,0,0,1,0,0),this.#rt.clearRect(0,0,this.#nt.width,this.#nt.height),this.#rt.restore()}}var sn=o(944),ln=o.n(sn);class cn{#At=10;#bt="Verdana";#xt="#fff";#Rt="#ffff80";#Ft={x:1,y:1};#Et={x:1,y:1};#qt=2;#Ut={x:.25,y:.25};#Mt=.2;#Qt=3;getFontFamily(){return this.#bt}getFontSize(){return this.#At}getStrokeWidth(){return this.#qt}getTextColour(){return this.#xt}getLineColour(){return this.#Rt}setLineColour(e){this.#Rt=e}setBaseScale(e){this.#Ft=e}setZoomScale(e){this.#Et=e}getBaseScale(){return this.#Ft}getZoomScale(){return this.#Et}scale(e){return e/this.#Ft.x}applyZoomScale(e){return{x:2*e/this.#Et.x,y:2*e/this.#Et.y}}getShadowOffset(){return this.#Ut}getTagOpacity(){return this.#Mt}getTextPadding(){return this.#Qt}getFontStr(){return"normal "+this.getFontSize()+"px sans-serif"}getLineHeight(){return this.getFontSize()+this.getFontSize()/5}getScaledFontSize(){return this.scale(this.getFontSize())}getScaledStrokeWidth(){return this.scale(this.getStrokeWidth())}getShadowLineColour(){return y(this.getLineColour())}}function un(e){let t="shape";return e instanceof ln().Line?t=4===e.points().length?"line":6===e.points().length?"protractor":"roi":e instanceof ln().Rect?t="rectangle":e instanceof ln().Ellipse&&(t="ellipse"),t}class dn{#T;#Bt;#Nt;#Vt;#Gt;constructor(e,t,n,i){this.#T=e,this.#Bt=t,this.#Nt=n,this.#Vt=void 0!==i&&i,this.#Gt=e.getParent()}getName(){return"Draw-"+this.#Bt}execute(){this.#Gt.add(this.#T),this.#Nt.getKonvaLayer().draw(),this.#Vt||this.onExecute({type:"drawcreate",id:this.#T.id(),srclayerid:this.#Nt.getId(),dataid:this.#Nt.getDataId()})}undo(){this.#T.remove(),this.#Nt.getKonvaLayer().draw(),this.onUndo({type:"drawdelete",id:this.#T.id(),srclayerid:this.#Nt.getId(),dataid:this.#Nt.getDataId()})}onExecute(e){}onUndo(e){}}class hn{#T;#Bt;#kt;#Nt;constructor(e,t,n,i){this.#T=e,this.#Bt=t,this.#kt=n,this.#Nt=i}getName(){return"Move-"+this.#Bt}execute(){this.#T.move(this.#kt),this.#Nt.getKonvaLayer().draw(),this.onExecute({type:"drawmove",id:this.#T.id(),srclayerid:this.#Nt.getId(),dataid:this.#Nt.getDataId()})}undo(){const e={x:-this.#kt.x,y:-this.#kt.y};this.#T.move(e),this.#Nt.getKonvaLayer().draw(),this.onUndo({type:"drawmove",id:this.#T.id(),srclayerid:this.#Nt.getId(),dataid:this.#Nt.getDataId()})}onExecute(e){}onUndo(e){}}class Sn{#Bt;#Ht;#zt;#Wt;#Nt;#tt;#Yt;constructor(e,t,n,i,r,o,a){this.#Bt=e,this.#Ht=t,this.#zt=n,this.#Wt=i,this.#Nt=r,this.#tt=o,this.#Yt=a}getName(){return"Change-"+this.#Bt}execute(){this.#Ht.update(this.#Wt,this.#Yt,this.#tt),this.#Nt.getKonvaLayer().draw(),this.onExecute({type:"drawchange",id:this.#Wt.getParent().id(),srclayerid:this.#Nt.getId(),dataid:this.#Nt.getDataId()})}undo(){this.#Ht.update(this.#zt,this.#Yt,this.#tt),this.#Nt.getKonvaLayer().draw(),this.onUndo({type:"drawchange",id:this.#zt.getParent().id(),srclayerid:this.#Nt.getId(),dataid:this.#Nt.getDataId()})}onExecute(e){}onUndo(e){}}class gn{#T;#Bt;#Nt;#Gt;constructor(e,t,n){this.#T=e,this.#Bt=t,this.#Nt=n,this.#Gt=e.getParent()}getName(){return"Delete-"+this.#Bt}execute(){this.#T.remove(),this.#Nt.getKonvaLayer().draw(),this.onExecute({type:"drawdelete",id:this.#T.id(),srclayerid:this.#Nt.getId(),dataid:this.#Nt.getDataId()})}undo(){this.#Gt.add(this.#T),this.#Nt.getKonvaLayer().draw(),this.onUndo({type:"drawcreate",id:this.#T.id(),srclayerid:this.#Nt.getId(),dataid:this.#Nt.getDataId()})}onExecute(e){}onUndo(e){}}class mn{quantification;textExpr}class pn{id;position;type;color;meta}function fn(e){return"shape"===e.name()}function yn(e){return e.name().startsWith("shape-")}function Dn(e){return"label"===e.name()}function Cn(e){return"position-group"===e.name()}function vn(e){return function(t){return t.id()===e}}class In{#Xt;#jt;#Zt=null;constructor(e){this.#Xt=e,this.#jt=e.getKonvaLayer()}getCurrentPosGroup(){const e=this.#jt.getChildren((e=>e.id()===this.#Zt));let t;return 1===e.length?e[0]instanceof ln().Group&&(t=e[0]):0===e.length?(t=new(ln().Group),t.name("position-group"),t.id(this.#Zt),t.visible(!0),this.#jt.add(t)):i.warn("Unexpected number of draw position groups."),t}reset(){this.#jt=null}getGroup(e){const t=this.#jt.findOne("#"+e);return void 0===t&&i.warn("Cannot find node with id: "+e),t}activateDrawLayer(e,t){const n=[t];for(let t=3;t{e.srclayerid=this.getId(),e.dataid=this.#We,this.#Oe.fireEvent(e)};#Jt(e){const t=2/e.x,n=2/e.y,i=this.#_t.find("Label");for(let e=0;e{this.#an()};getDivId(){return this.#et.id}getScale(){return this.#ut}getBaseScale(){return this.#Ft}getAddedScale(){return{x:this.#ut.x/this.#Ft.x,y:this.#ut.y/this.#Ft.y,z:this.#ut.z/this.#Ft.z}}getOffset(){return this.#St}getNumberOfLayers(){let e=0;return this.#$t.forEach((t=>{void 0!==t&&e++})),e}includes(e){if(void 0===e)return!1;for(const t of this.#$t)if(void 0!==t&&t.getId()===e)return!0;return!1}getNumberOfViewLayers(){let e=0;return this.#$t.forEach((t=>{void 0!==t&&t instanceof an&&e++})),e}getActiveViewLayer(){let e;if(void 0!==this.#en){const t=this.#$t[this.#en];t instanceof an&&(e=t)}else i.info("No active view layer to return");return e}getBaseViewLayer(){let e;return this.#$t[0]instanceof an&&(e=this.#$t[0]),e}getViewLayersByDataId(e){const t=[];for(const n of this.#$t)n instanceof an&&n.getDataId()===e&&t.push(n);return t}searchViewLayers(e){const t=[];for(const n of this.#$t)n instanceof an&&n.getViewController().equalImageMeta(e)&&t.push(n);return t}getViewDataIndices(){const e=[];for(const t of this.#$t)t instanceof an&&e.push(t.getDataId());return e}getActiveDrawLayer(){let e;if(void 0!==this.#tn){const t=this.#$t[this.#tn];t instanceof Tn&&(e=t)}else i.info("No active draw layer to return");return e}getDrawLayersByDataId(e){const t=[];for(const n of this.#$t)n instanceof Tn&&n.getDataId()===e&&t.push(n);return t}setActiveViewLayer(e){this.#$t[e]instanceof an?(this.#en=e,this.#Re({type:"activelayerchange",value:[this.#$t[e]]})):i.warn("No view layer to set as active with index: "+e)}setActiveViewLayerByDataId(e){let t;for(let n=0;n0;)e[0].remove()}removeLayersByDataId(e){for(const t of this.#$t)void 0!==t&&t.getDataId()===e&&this.removeLayer(t)}removeLayer(e){const t=this.#$t.findIndex((t=>t===e));if(-1===t)throw new Error("Cannot find layer to remove");if(e instanceof an)this.#dn(e),this.#en===t&&(t-2>=0?this.setActiveViewLayer(t-2):this.#en=void 0);else{const n=e.getNumberOfDraws();if(void 0!==n){let t=0;e.addEventListener("drawdelete",(i=>{++t,t===n&&this.#hn(e)}))}e.deleteDraws(),void 0===n&&this.#hn(e),this.#tn===t&&(t-2>=0?this.setActiveDrawLayer(t-2):this.#tn=void 0)}this.#$t[t]=void 0,e.removeFromDOM()}#an(e){let t;void 0===e&&(e=this.#Be),this.#sn();for(const e of this.#$t)if(e instanceof an){t=e;break}if(void 0===t)return void i.warn("No layer to show crosshair");const n=t.getViewController().getPlanePositionFromPosition(e),r=t.planePosToDisplay(n);if(void 0!==r.getY()){const e=document.createElement("hr");e.id=this.getDivId()+"-scroll-crosshair-horizontal",e.className="horizontal",e.style.width=this.#et.offsetWidth+"px",e.style.left="0px",e.style.top=r.getY()+"px",this.#in.push(e),this.#et.appendChild(e)}if(void 0!==r.getX()){const e=document.createElement("hr");e.id=this.getDivId()+"-scroll-crosshair-vertical",e.className="vertical",e.style.width=this.#et.offsetHeight+"px",e.style.left=r.getX()+"px",e.style.top="0px",this.#in.push(e),this.#et.appendChild(e)}}#sn(){for(const e of this.#in)e.remove();this.#in=[]}showTooltip(e){this.removeTooltipDiv();const t=this.getActiveViewLayer(),n=t.getViewController(),i=t.displayToPlanePos(e),r=n.getPositionFromPlanePoint(i),o=n.getRescaledImageValue(r);if(void 0!==o){const t=document.createElement("span");t.id="scroll-tooltip",t.style.left=e.getX()+10+"px",t.style.top=e.getY()+10+"px";let i=B(o,3).toString();void 0!==n.getPixelUnit()&&(i+=" "+n.getPixelUnit()),t.appendChild(document.createTextNode(i)),this.#rn=t,this.#et.appendChild(t)}}removeTooltipDiv(){void 0!==this.#rn&&(this.#rn.remove(),this.#rn=void 0)}someViewLayer(e){let t=!1;for(const n of this.#$t)if(n instanceof an&&e(n)){t=!0;break}return t}isPositionInBounds(e){return this.someViewLayer((function(t){return t.getViewController().isPositionInBounds(e)}))}canScroll(){return this.someViewLayer((function(e){return e.getViewController().canScroll()}))}moreThanOne(e){return this.someViewLayer((function(t){return t.getViewController().moreThanOne(e)}))}updateLayersToPositionChange=t=>{for(const e of this.#$t)e instanceof an&&(e.removeEventListener("positionchange",this.updateLayersToPositionChange),e.removeEventListener("positionchange",this.#Re));const n=new e(t.value[0]),i=new R(t.value[1]);let r,o,a,s;this.#Be=i,this.#nn&&this.#an(i);for(const e of this.#$t){if(void 0===e)continue;let l=!1;if(e instanceof an){const t=e.getViewController(),n=t.getOrigin(),l=t.getOrigin(i);if(void 0===o)r=n,o=l,a=new T(0,0,0),s=new T(0,0,0);else if(t.isPositionInBounds(i)&&void 0!==l){const e=r.minus(n);a=new T(e.getX(),e.getY(),e.getZ());const t=o.minus(l);s=new T(t.getX(),t.getY(),t.getZ())}}void 0!==a&&void 0!==s&&(l=e.setBaseOffset(a,s,o,r)),e instanceof Tn&&(a=void 0,s=void 0);let c=!1;e.getId()!==t.srclayerid&&(c=e.setCurrentPosition(i,n)),!c&&l&&e.draw()}for(const e of this.#$t)e instanceof an&&(e.addEventListener("positionchange",this.updateLayersToPositionChange),e.addEventListener("positionchange",this.#Re))};getDivToWorldSizeRatio(){if(0===this.#et.offsetWidth&&0===this.#et.offsetHeight)throw new Error("Cannot fit to zero sized container.");const e=this.getMaxWorldSize();if(void 0!==e){if(0===this.#et.offsetHeight){const t=this.#et.offsetWidth/e.x,n=e.y*t;this.#et.style.height=n+"px"}return Math.min(this.#et.offsetWidth/e.x,this.#et.offsetHeight/e.y)}}fitToContainer(e){const t=this.getMaxWorldSize();if(void 0===t)return;const n={x:this.#et.offsetWidth,y:this.#et.offsetHeight},i={x:-.5*(n.x-Math.floor(t.x*e)),y:-.5*(n.y-Math.floor(t.y*e))};for(const t of this.#$t)void 0!==t&&t.fitToContainer(n,e,i);this.#nn&&this.#an()}getMaxWorldSize(){let e={x:0,y:0};for(const t of this.#$t)if(t instanceof an){const n=t.getImageWorldSize();n.x>e.x&&(e.x=n.x),n.y>e.y&&(e.y=n.y)}return 0===e.x&&0===e.y&&(e=void 0),e}flipScaleZ(){this.#Ft.z*=-1,this.setScale(this.#Ft)}addScale(e,t){const n={x:this.#ut.x*(1+e),y:this.#ut.y*(1+e),z:this.#ut.z*(1+e)};this.setScale(n,t)}setScale(e,t){this.#ut=e;for(const e of this.#$t)void 0!==e&&e.setScale(this.#ut,t);const n=[e.x,e.y,e.z];void 0!==t&&(n.push(t.getX()),n.push(t.getY()),n.push(t.getZ())),this.#Re({type:"zoomchange",value:n})}addTranslation(e){this.setOffset({x:this.#St.x-e.x,y:this.#St.y-e.y,z:this.#St.z-e.z})}setOffset(e){this.#St=e;for(const e of this.#$t)void 0!==e&&e.setOffset(this.#St);this.#Re({type:"offsetchange",value:[this.#St.x,this.#St.y,this.#St.z]})}reset(){this.setScale(this.#Ft),this.setOffset({x:0,y:0,z:0})}draw(){for(const e of this.#$t)void 0!==e&&e.draw()}display(e){for(const t of this.#$t)void 0!==t&&t.display(e)}addEventListener(e,t){this.#Oe.add(e,t)}removeEventListener(e,t){this.#Oe.remove(e,t)}#Re=e=>{this.#Oe.fireEvent(e)}}const An={WindowLevelBinder:class{getEventType=function(){return"wlchange"};getCallback=function(e){return function(t){const n=e.getViewLayersByDataId(t.dataid);if(0!==n.length){const e=n[0].getViewController();if(2===t.value.length){const n=new r(t.value[0],t.value[1]);e.setWindowLevel(n)}3===t.value.length&&e.setWindowLevelPreset(t.value[2])}}}},PositionBinder:class{getEventType=function(){return"positionchange"};getCallback=function(e){return function(t){const n=t.value[1],i=e.getActiveViewLayer().getViewController(),r=i.getCurrentPosition(),o=r.length(),a=n.length;a!==o&&(a===o-1?n.push(r.get(o-1)):a===o+1&&n.pop()),i.setCurrentPosition(new R(n))}}},ZoomBinder:class{getEventType=function(){return"zoomchange"};getCallback=function(e){return function(t){const n={x:t.value[0],y:t.value[1],z:t.value[2]};let i;6===t.value.length&&(i=new x(t.value[3],t.value[4],t.value[5])),e.setScale(n,i),e.draw()}}},OffsetBinder:class{getEventType=function(){return"offsetchange"};getCallback=function(e){return function(t){e.setOffset({x:t.value[0],y:t.value[1],z:t.value[2]}),e.draw()}}},OpacityBinder:class{getEventType=function(){return"opacitychange"};getCallback=function(e){return function(t){if(void 0===t.dataid)return;const n=e.getViewLayersByDataId(t.dataid);0!==n.length&&(n[0].setOpacity(t.value),n[0].draw())}}},ColourMapBinder:class{getEventType=function(){return"colourmapchange"};getCallback=function(e){return function(t){const n=e.getViewLayersByDataId(t.dataid);0!==n.length&&n[0].getViewController().setColourMap(t.value[0])}}}};class bn{#Sn=[];#gn;#Dt=!1;#mn=[];#pn=null;getLayerGroup(e){return this.#Sn[e]}getNumberOfLayerGroups(){return this.#Sn.length}getActiveLayerGroup(){return this.getLayerGroup(this.#gn)}setActiveLayerGroup(e){void 0!==this.getLayerGroup(e)?this.#gn=e:i.warn("No layer group to set as active with index: "+e)}getViewLayersByDataId(e){let t=[];for(let n=0;nt===e));if(-1===t)throw new Error("Cannot find layerGroup to remove");this.unbindLayerGroups(),e.empty(),this.#Sn.splice(t,1),this.#gn===t&&(this.#gn=void 0),this.bindLayerGroups()}reset(){for(let e=0;e{this.#yn(t,e),e.getCallback(this.#Sn[t])(n),this.#fn(t,e)}},this.#pn[t].push(n)),n.callback}#fn(e,t){for(let n=0;n0&&(--this.#wn,this.#Pn[this.#wn].undo(),this.#Re({type:"undo",command:this.#Pn[this.#wn].getName()}))}redo(){this.#wn{this.#Oe.fireEvent(e)}}class Bn{#On;#An=null;#pn=[];#bn={};constructor(e){this.#On=e}init(){for(const e in this.#On)this.#On[e].init();this.enableShortcuts(!0)}enableShortcuts(e){e?window.addEventListener("keydown",this.#xn("window","keydown"),!0):window.removeEventListener("keydown",this.#xn("window","keydown"),!0)}getToolList(){return this.#On}hasTool(e){return void 0!==this.getToolList()[e]}getSelectedTool(){return this.#An}getSelectedToolEventHandler(e){return this.getSelectedTool()[e]}setSelectedTool(e){if(!this.hasTool(e))throw new Error("Unknown tool: '"+e+"'");this.#An&&this.#An.activate(!1),this.#An=this.#On[e],this.#An.activate(!0)}setToolFeatures(e){this.getSelectedTool()&&this.getSelectedTool().setFeatures(e)}bindLayerGroup(e,t){const n=e.getDivId();e.addEventListener("activelayerchange",this.#Rn(n)),this.#Fn(n,t)}#Fn(e,t){void 0!==this.#bn[e]&&this.#En(this.#bn[e]),this.#bn[e]=t,this.#qn(t)}#Rn(e){return t=>{const n=t.value[0];this.#Fn(e,n)}}#qn(e){e.bindInteraction();const t=$t;for(let n=0;n{if(this.#An){const t=this.#An[e.type];t&&t(e)}};this.#pn[e][t]=n}return this.#pn[e][t]}}class Nn{#Un=[];#Mn=2;#Qn;constructor(e){this.#Qn=e}setNumberOfDimensions(e){this.#Mn=e}setNToLoad(e){for(let t=0;t{if(!e.lengthComputable)return;if(void 0===e.subindex)return;if(void 0===e.index)return;const t=100*e.loaded/e.total;this.#Un[e.index][e.subindex]=t;let n=null;n=void 0!==e.item?e.item:{loaded:this.#Bn(e.index),total:100,source:e.source},this.#Qn({lengthComputable:!0,loaded:this.#Nn(),total:100,item:n})};#Bn(e){let t=0;for(let n=0;n{n.index=e,n.subindex=t,this.onprogress(n)}}getUndefinedMonoProgressHandler(e){return t=>{t.subindex=e,this.onprogress(t)}}}class Vn{#Vn=null;#Gn=[];#kn=null;#Hn=0;#zn=0;#Wn;#F;getDefaultCharacterSet(){return this.#F}setDefaultCharacterSet(e){this.#F=e}#Yn(e){this.#Vn=e,this.#Hn=0,this.#zn=0,this.#Wn=!1,this.#Xn(),this.#jn()}#Zn(e){this.#Gn.push(e)}#Xn(){this.#Gn=[]}#_n(e){this.#kn=e}#jn(){this.#kn=null}#Kn=e=>{this.#Hn++,this.#Hn===this.#Vn.length&&this.onload({source:this.#Vn})};#Jn=e=>{this.#zn++,this.#zn===this.#Vn.length&&this.onloadend({source:this.#Vn})};#$n(e,t){return n=>{n.source=t,e(n)}}load(e,t){this.onloadstart({source:e}),1===e.length&&(E(e[0],"DICOMDIR")||E(e[0],".dcmdir"))?this.#ei(e[0],t):this.#ti(e,t)}#ni(e,t,n){return i=>{const r=i.target.status;200!==r&&0!==r?(this.onerror({source:t,error:"GET "+i.target.responseURL+" "+i.target.status+" ("+i.target.statusText+")",target:i.target}),this.#Jn()):e.load(i.target.response,t,n)}}#ti(e,t){if(void 0===e||0===e.length)return;this.#Yn(e);const n=new Nn(this.onprogress);n.setNToLoad(e.length);const i=[];for(let e=0;e{s{this.#Jn(),s(e)};const c=this.#$n(this.onabort,r);a.onabort=e=>{this.#Jn(),c(e)},1===o.loadUrlAs()&&(a.responseType="arraybuffer"),this.#Zn(a)}let c=this.#Gn.length;void 0!==t&&void 0!==t.batchSize&&0!==c&&(c=Math.min(t.batchSize,this.#Gn.length));for(let e=0;e{const r=n.target.status;if(200!==r&&0!==r)this.onerror({source:e,error:"GET "+n.target.responseURL+" "+n.target.status+" ("+n.target.statusText+")",target:n.target}),this.onloadend({});else{const r=function(e){const t=new ke;t.parse(e);const n=t.getDicomElements();if(void 0===n["00041220"]||void 0===n["00041220"].value)return void i.warn("No Directory Record Sequence found in DICOMDIR.");const r=n["00041220"].value;if(0===r.length)return void i.warn("The Directory Record Sequence of the DICOMDIR is empty.");const o=[];let a=null,s=null;for(let e=0;e{this.#$n(this.onerror,e)(t),this.onloadend({})},n.onabort=t=>{this.#$n(this.onabort,e)(t),this.onloadend({})},n.send(null)}abort(){this.#Wn=!0;for(let e=0;e0){const t=this.freeThreads.shift();this.runningThreads.push(t),t.run(e)}else this.taskQueue.push(e)}abort(){this.#ii(),this.onabort({type:"work-abort"}),this.onworkend({type:"work-end"})}onTaskEnd(e){if(this.taskQueue.length>0){const t=this.taskQueue.shift();e.run(t)}else{e.stop(),this.freeThreads.push(e);for(let t=0;t{this.#ii(),this.onerror({error:e}),this.onworkend({type:"work-end"})};#ii(){this.taskQueue=[];for(let e=0;e{e.itemNumber=this.runningTask.info.itemNumber,e.numberOfItems=this.runningTask.info.numberOfItems,e.index=this.runningTask.info.index,this.parentPool.onworkitem(e),this.parentPool.onTaskEnd(this)};onerror=e=>{e.itemNumber=this.runningTask.info.itemNumber,e.numberOfItems=this.runningTask.info.numberOfItems,e.index=this.runningTask.info.index,this.parentPool.handleWorkerError(e),this.stop()}}class Hn{constructor(e,t,n){this.script=e,this.startMessage=t,this.info=n}}const zn="undefined"!=typeof JpegImage,Wn="undefined"!=typeof jpeg&&void 0!==jpeg.lossless,Yn="undefined"!=typeof JpxImage,Xn={jpeg2000:"","jpeg-lossless":"","jpeg-baseline":"",rle:""};class jn{#ri;#oi=new Gn(10);#ai=!1;constructor(e,t){this.#ri=e}decode(e,t,n){this.#ai||(this.#ai=!0,this.#oi.onworkstart=this.ondecodestart,this.#oi.onworkitem=this.ondecodeditem,this.#oi.onwork=this.ondecoded,this.#oi.onworkend=this.ondecodeend,this.#oi.onerror=this.onerror,this.#oi.onabort=this.onabort);const i=new Hn(this.#ri,{buffer:e,meta:t},n);this.#oi.addWorkerTask(i)}abort(){this.#oi.abort()}ondecodestart(e){}ondecodeditem(e){}ondecoded(e){}ondecodeend(e){}onerror(e){}onabort(e){}}class Zn{#si;#li;constructor(e,t){this.#si=e,this.#li=t}#ci=0;decode(e,t,n){++this.#ci;let i=null,r=null;if("jpeg-lossless"===this.#si){if(!Wn)throw new Error("No JPEG Lossless decoder provided");const n=t.bitsAllocated/8,o=new Uint8Array(e);i=new jpeg.lossless.Decoder;const a=i.decode(o.buffer,0,o.buffer.byteLength,n);8===t.bitsAllocated?r=t.isSigned?new Int8Array(a.buffer):new Uint8Array(a.buffer):16===t.bitsAllocated&&(r=t.isSigned?new Int16Array(a.buffer):new Uint16Array(a.buffer))}else if("jpeg-baseline"===this.#si){if(!zn)throw new Error("No JPEG Baseline decoder provided");i=new JpegImage,i.parse(e),r=i.getData(i.width,i.height)}else if("jpeg2000"===this.#si){if(!Yn)throw new Error("No JPEG 2000 decoder provided");i=new JpxImage,i.parse(e),r=i.tiles[0].items}else"rle"===this.#si&&(i=new dwvdecoder.RleDecoder,r=i.decode(e,t.bitsAllocated,t.isSigned,t.sliceSize,t.samplesPerPixel,t.planarConfiguration));this.ondecodeditem({data:[r],index:n.index,numberOfItems:n.numberOfItems,itemNumber:n.itemNumber}),this.#ci===this.#li&&(this.ondecoded({}),this.ondecodeend({}))}abort(){this.onabort({}),this.ondecodeend({})}ondecodestart(e){}ondecodeditem(e){}ondecoded(e){}ondecodeend(e){}onerror(e){}onabort(e){}}class _n{#ai=!1;#ui=null;constructor(e,t){void 0!==Xn&&void 0!==Xn[e]?this.#ui=new jn(Xn[e],t):this.#ui=new Zn(e,t)}decode(e,t,n){this.#ai||(this.#ai=!0,this.#ui.ondecodestart=this.ondecodestart,this.#ui.ondecodeditem=this.ondecodeditem,this.#ui.ondecoded=this.ondecoded,this.#ui.ondecodeend=this.ondecodeend,this.#ui.onerror=this.onerror,this.#ui.onabort=this.onabort),this.#ui.decode(e,t,n)}abort(){this.#ui.abort()}ondecodestart(e){}ondecodeditem(e){}ondecoded(e){}ondecodeend(e){}onerror(e){}onabort(e){}}class Kn{#di;setOptions(e){this.#di=e}#ui=null;#hi=[];#Si=[];#gi=[];#mi=[];#pi(e){let t;const n=e["00080060"];return void 0!==n&&"SEG"===n.value[0]&&(t=new Ht),void 0===t&&(t=new St),t}#fi(e,t){const n=this.#hi[e].getDicomElements(),i=this.#mi[e];try{const r=i.create(n,this.#Si[e],this.#di.numberOfFiles);this.onloaditem({data:{image:r,info:n},source:t,warn:i.getWarning()})}catch(e){this.onerror({error:e,source:t}),this.onloadend({source:t})}}#yi(e){this.onprogress({lengthComputable:!0,loaded:e.itemNumber+1,total:e.numberOfItems,index:e.index,source:origin});const t=e.index,n=e.data[0];if(1!==e.numberOfItems){if(void 0===this.#gi[t]){this.#gi[t]=n.length;const r=e.numberOfItems*this.#gi[t];try{this.#Si[t]=new n.constructor(r)}catch(e){if(e instanceof RangeError){const e=Math.floor(Math.log(r)/Math.log(2));i.error("Cannot allocate "+n.constructor.name+" of size: "+r+" (>2^"+e+") for decompressed data.")}return this.#ui.abort(),this.onerror({error:e,source:origin}),void this.onloadend({source:origin})}}n.length!==this.#gi[t]&&i.warn("Unsupported varying decompressed data size: "+n.length+" != "+this.#gi[t]),this.#Si[t].set(n,this.#gi[t]*e.itemNumber)}else this.#Si[t]=n;0===e.itemNumber&&this.#fi(t,origin)}convert(e,t,n){this.onloadstart({source:t,index:n});const i=new ke;let r;void 0!==this.#di.defaultCharacterSet&&i.setDefaultCharacterSet(this.#di.defaultCharacterSet);try{i.parse(e),r=this.#pi(i.getDicomElements()),r.checkElements(i.getDicomElements())}catch(e){return this.onerror({error:e,source:t}),void this.onloadend({source:t})}const o=i.getDicomElements()["7FE00010"].value;i.getDicomElements()["7FE00010"].value=[];const a=function(e){let t=null;return qe(e)?t="jpeg2000":Fe(e)?t="jpeg-baseline":Ee(e)?t="jpeg-lossless":Ue(e)&&(t="rle"),t}(i.getDicomElements()["00020010"].value[0]),s=null!==a;if(this.#hi[n]=i,this.#Si[n]=o[0],this.#mi[n]=r,s){const e={bitsAllocated:i.getDicomElements()["00280100"].value[0],isSigned:1===i.getDicomElements()["00280103"].value[0]},t=i.getDicomElements()["00280011"],r=i.getDicomElements()["00280010"];void 0!==t&&void 0!==r&&(e.sliceSize=t.value[0]*r.value[0]);const s=i.getDicomElements()["00280002"];void 0!==s&&(e.samplesPerPixel=s.value[0]);const l=i.getDicomElements()["00280006"];void 0!==l&&(e.planarConfiguration=l.value[0]);const c=o.length;null===this.#ui&&(this.#ui=new _n(a,c),this.#ui.ondecodeditem=e=>{this.#yi(e),e.itemNumber+1===e.numberOfItems&&(this.onload(e),this.onloadend(e))},this.#ui.onerror=this.onerror,this.#ui.onabort=this.onabort);for(let t=0;t{this.#Hn++,this.#Hn===this.#Vn.length&&this.onload({source:this.#Vn})};#Jn=e=>{this.#zn++,this.#zn===this.#Vn.length&&this.onloadend({source:this.#Vn})};load(e){if(void 0===e||0===e.length)return;this.#Yn(e),this.onloadstart({source:e});const t=new Nn(this.onprogress);t.setNToLoad(e.length),t.setNumberOfDimensions(1);const n=[];for(let e=0;e{this.#Di=!1,this.onloadend(e)},this.#Ci.onerror=e=>{e.source=t,this.onerror(e)},this.#Ci.onabort=this.onabort),this.#Di=!0,this.#Ci.convert(e,t,n)}abort(){this.#Di=!1,this.#Ci.abort()}canLoadFile(e){const t=M(e.name);return null===t||"dcm"===t}canLoadUrl(e,t){if(void 0!==t){if(void 0!==t.forceLoader&&"dicom"===t.forceLoader)return!0;if(void 0!==t.requestHeaders){const e=function(e){return"Accept"===e.name},n=t.requestHeaders.find(e);if(void 0!==n){const e="application/dicom";return F(n.value,e)&&"+"!==n.value[e.length]}}}const n=Un(e),i=M(n.pathname),r=null===i,o="dcm"===i,a=n.searchParams.get("contentType");return null!=a?"application/dicom"===a:r||o}canLoadMemory(e){const t=e["Content-Type"];if(void 0!==t&&t.startsWith("application/dicom"))return!0;if(void 0!==e.filename){const t=new File(["from memory"],e.filename);return this.canLoadFile(t)}return!1}loadFileAs(){return ri.ArrayBuffer}loadUrlAs(){return 1}onloadstart(e){}onprogress(e){}onloaditem(e){}onload(e){}onloadend(e){}onerror(e){}onabort(e){}},class{#Di=!1;setOptions(e){}isLoading(){return this.#Di}load(e,t,n){this.#Di=!0,this.onloadstart({source:t});try{this.onprogress({lengthComputable:!0,loaded:100,total:100,index:n,source:t});const i={data:e,source:t};this.onloaditem(i),this.onload(i)}catch(e){this.onerror({error:e,source:t})}finally{this.#Di=!1,this.onloadend({source:t})}}abort(){this.#Di=!1,this.onabort({}),this.onloadend({})}canLoadFile(e){return"json"===M(e.name)}canLoadUrl(e,t){if(void 0!==t){if(void 0!==t.forceLoader&&"json"===t.forceLoader)return!0;if(void 0!==t.requestHeaders){const e=function(e){return"Accept"===e.name},n=t.requestHeaders.find(e);if(void 0!==n)return F(n.value,"application/json")||F(n.value,"application/dicom+json")}}return"json"===M(Un(e).pathname)}canLoadMemory(e){const t=e["Content-Type"];if(void 0!==t&&t.startsWith("application/json"))return!0;if(void 0!==e.filename){const t=new File(["from memory"],e.filename);return this.canLoadFile(t)}return!1}loadFileAs(){return ri.Text}loadUrlAs(){return 0}onloadstart(e){}onprogress(e){}onloaditem(e){}onload(e){}onloadend(e){}onerror(e){}onabort(e){}},class{#Di=!1;setOptions(e){}isLoading(){return this.#Di}load(e,t,n){this.onloadstart({source:t}),this.#Di=!0;const i=new Jn;i.onprogress=e=>{e.loaded=50+e.loaded/2,e.index=n,this.onprogress(e)},i.onloaditem=this.onloaditem,i.onload=this.onload,i.onloadend=e=>{this.#Di=!1,this.onloadend(e)},i.onerror=this.onerror,i.onabort=this.onabort,i.load(function(e){const t=new Uint8Array(e),n=[];if(0===t.length)return n;const i=H(new Uint8Array([13,10,13,10]));let r=k(t,i,0);if(void 0===r)throw new Error("Can't find the end of the first multipart header");const o=G(t.slice(0,r)).split("\r\n");let a;for(let e=0;e{try{if(!this.#vi){this.onprogress({lengthComputable:!0,loaded:100,total:100,index:n,source:t});const e=function(e,t,n){const i=e.width,r=e.height,o=document.createElement("canvas");o.width=i,o.height=r;const a=o.getContext("2d");a.drawImage(e,0,0);const s=a.getImageData(0,0,i,r),l={};"string"==typeof t?l.origin={value:t}:(l.fileName={value:t.name},l.fileType={value:t.type},l.fileLastModifiedDate={value:t.lastModified}),l.imageWidth={value:i},l.imageHeight={value:r};const c=n||0;return l.imageUid={value:c},{data:{image:ei(i,r,c,$n(s),1,c.toString()),info:l},source:t}}(i,t,n);this.onloaditem(e),this.onload(e)}}catch(e){this.onerror({error:e,source:t})}finally{this.onloadend({source:t})}},"string"==typeof e)i.src=e;else if("string"==typeof t){const n=t.split(".").pop().toLowerCase();i.src=this.#Ii(e,n)}}abort(){this.#vi=!0,this.onabort({}),this.onloadend({})}canLoadFile(e){return void 0!==e.type&&null!==e.type.match("image.*")}canLoadUrl(e,t){if(void 0!==t){if(void 0!==t.forceLoader&&"rawimage"===t.forceLoader)return!0;if(void 0!==t.requestHeaders){const e=function(e){return"Accept"===e.name},n=t.requestHeaders.find(e);if(void 0!==n)return F(n.value,"image/")}}const n=Un(e),i=M(n.pathname),r="jpeg"===i||"jpg"===i||"png"===i||"gif"===i,o=n.searchParams.get("contentType");return null!=o?"image/jpeg"===o||"image/png"===o||"image/gif"===o:r}canLoadMemory(e){if(void 0!==e.filename){const t=new File(["from memory"],e.filename);return this.canLoadFile(t)}return!1}loadFileAs(){return ri.DataURL}loadUrlAs(){return 1}onloadstart(e){}onprogress(e){}onloaditem(e){}onload(e){}onloadend(e){}onerror(e){}onabort(e){}},class{setOptions(e){}isLoading(){return!0}#Ii(e,t){const n=new Uint8Array(e);let i="";for(let e=0;e{try{!function(e,t,n,i,r,o,a){const s=e.videoWidth,l=e.videoHeight,c=Math.ceil(30*e.duration),u={};"string"==typeof o?u.origin={value:o}:(u.fileName={value:o.name},u.fileType={value:o.type},u.fileLastModifiedDate={value:o.lastModified}),u.imageWidth={value:s},u.imageHeight={value:l},u.numberOfFrames={value:c},u.imageUid={value:0};const d=document.createElement("canvas");d.width=s,d.height=l;const h=d.getContext("2d");e.addEventListener("seeked",(function d(p){(function(){i({lengthComputable:!0,loaded:S,total:c,index:a,source:o}),h.drawImage(e,0,0);const n=$n(h.getImageData(0,0,s,l));0===S?(g=ei(s,l,1,n,c,a.toString()),t({data:{image:g,info:u},source:o})):g.appendFrameBuffer(n,S),++S})(),m+=1/30,m<=p.target.duration?this.currentTime=m:(n({source:o}),r({source:o}),e.removeEventListener("seeked",d))}),!1);let S=0,g=null,m=0;e.currentTime=m}(e.target,this.onloaditem,this.onload,this.onprogress,this.onloadend,t,n)}catch(e){this.onerror({error:e,source:t}),this.onloadend({source:t})}}}abort(){this.onabort({}),this.onloadend({})}canLoadFile(e){return void 0!==e.type&&null!==e.type.match("video.*")}canLoadUrl(e,t){if(void 0!==t){if(void 0!==t.forceLoader&&"rawvideo"===t.forceLoader)return!0;if(void 0!==t.requestHeaders){const e=function(e){return"Accept"===e.name},n=t.requestHeaders.find(e);if(void 0!==n)return F(n.value,"video/")}}const n=M(Un(e).pathname);return"mp4"===n||"ogg"===n||"webm"===n}canLoadMemory(e){if(void 0!==e.filename){const t=new File(["from memory"],e.filename);return this.canLoadFile(t)}return!1}loadFileAs(){return ri.DataURL}loadUrlAs(){return 1}onloadstart(e){}onprogress(e){}onloaditem(e){}onload(e){}onloadend(e){}onerror(e){}onabort(e){}},class{#Di=!1;setOptions(e){}isLoading(){return this.#Di}#Ti="";#Li=[];#Pi=null;#wi(e,t,n){this.#Li.push({filename:this.#Ti,data:e});const i=100*this.#Li.length/this.#Pi.length;if(this.onprogress({lengthComputable:!0,loaded:i/2,total:100,index:n,item:{loaded:i,total:100,source:t}}),this.#Li.length{this.#wi(e,t,n)}))}else{const e=new Jn;e.onprogress=e=>{e.loaded=50+e.loaded/2,e.index=n,this.onprogress(e)},e.onloaditem=this.onloaditem,e.onload=this.onload,e.onloadend=e=>{this.#Di=!1,this.onloadend(e)},e.onerror=this.onerror,e.onabort=this.onabort,e.load(this.#Li)}}load(e,t,n){this.onloadstart({source:t}),this.#Di=!0,ni().loadAsync(e).then((e=>{this.#Li=[],this.#Pi=e.file(/.*\.dcm/);const i=this.#Li.length;this.#Ti=this.#Pi[i].name,this.#Pi[i].async("arrayBuffer").then((e=>{this.#wi(e,t,n)}))}))}abort(){this.#Di=!1,this.onabort({}),this.onloadend({})}canLoadFile(e){return"zip"===M(e.name)}canLoadUrl(e,t){if(void 0!==t){if(void 0!==t.forceLoader&&"zip"===t.forceLoader)return!0;if(void 0!==t.requestHeaders){const e=function(e){return"Accept"===e.name},n=t.requestHeaders.find(e);if(void 0!==n)return F(n.value,"application/zip")}}return"zip"===M(Un(e).pathname)}canLoadMemory(e){const t=e["Content-Type"];if(void 0!==t&&t.startsWith("application/zip"))return!0;if(void 0!==e.filename){const t=new File(["from memory"],e.filename);return this.canLoadFile(t)}return!1}loadFileAs(){return ri.ArrayBuffer}loadUrlAs(){return 1}onloadstart(e){}onprogress(e){}onloaditem(e){}onload(e){}onloadend(e){}onerror(e){}onabort(e){}}],ri={Text:0,ArrayBuffer:1,DataURL:2};class oi{#Vn=null;#Oi=[];#kn=null;#Hn=0;#zn=0;#F;getDefaultCharacterSet(){return this.#F}setDefaultCharacterSet(e){this.#F=e}#Yn(e){this.#Vn=e,this.#Hn=0,this.#zn=0,this.#Ai(),this.#jn()}#bi(e){this.#Oi.push(e)}#Ai(){this.#Oi=[]}#_n(e){this.#kn=e}#jn(){this.#kn=null}#Kn=e=>{this.#Hn++,this.#Hn===this.#Vn.length&&this.onload({source:this.#Vn})};#Jn=e=>{this.#zn++,this.#zn===this.#Vn.length&&this.onloadend({source:this.#Vn})};#$n(e,t){return n=>{n.source=t,e(n)}}#ni(e,t,n){return i=>{e.load(i.target.result,t,n)}}load(e){if(void 0===e||0===e.length)return;this.#Yn(e),this.onloadstart({source:e});const t=new Nn(this.onprogress);t.setNToLoad(e.length);const n=[];for(let e=0;e{this.#Jn(),a(e)};const s=this.#$n(this.onabort,i);o.onabort=e=>{this.#Jn(),s(e)},r.loadFileAs()===ri.Text?o.readAsText(i):r.loadFileAs()===ri.DataURL?o.readAsDataURL(i):r.loadFileAs()===ri.ArrayBuffer&&o.readAsArrayBuffer(i)}}abort(){for(let e=0;e{this.#xi[i]={loader:t,isFirstItem:!0},this.#$n(this.onloadstart,o)(e)},t.onprogress=this.#$n(this.onprogress,o),t.onloaditem=e=>{const t={loadtype:n,dataid:i};void 0!==this.#xi[i]&&(t.isfirstitem=this.#xi[i].isFirstItem),this.#$n(this.onloaditem,t)(e),void 0!==this.#xi[i]&&this.#xi[i].isFirstItem&&(this.#xi[i].isFirstItem=!1)},t.onload=this.#$n(this.onload,o),t.onloadend=e=>{delete this.#xi[i],this.#$n(this.onloadend,o)(e)},t.onerror=this.#$n(this.onerror,o),t.onabort=this.#$n(this.onabort,o);try{t.load(e,r)}catch(e){return this.onerror({error:e,dataid:i}),void this.onloadend({dataid:i})}}#$n(e,t){return function(n){const i=Object.keys(t);for(let e=0;e{this.#Oe.fireEvent(e)};#Bi(e){return t=>{t.dataid=e,this.#Re(t)}}}function ci(e){return function(t){return Number(t).toPrecision(e)}}function ui(e){let t="";for(let n=0;n{e.dataid===this.#We&&void 0!==e.data&&void 0!==e.data.imageUid&&this.#zi!==e.data.imageUid&&(this.#zi=e.data.imageUid,this.#Yi(e))};#Yi=e=>{if(e.dataid!==this.#We)return;const t=this.#Hi[this.#zi];if(void 0!==t){for(let n=0;nt?1:e.wheelDeltaY<-t?-1:-e.deltaY/60}}(e)}clear(){this.#Xi=0}isTick(){return Math.abs(this.#Xi)>=1}}class gi{#Ni;#ji=new Si;constructor(e){this.#Ni=e}wheel(e){this.#ji.add(e);const t=this.#ji.getSum()>=0;if(!this.#ji.isTick())return;this.#ji.clear(),e.preventDefault();const n=Pn(e),i=this.#Ni.getLayerGroupByDivId(n.groupDivId),r=i.getActiveViewLayer().getViewController();let o;i.canScroll()?o=t?r.getIncrementScrollPosition():r.getDecrementScrollPosition():i.moreThanOne(3)&&(o=t?r.getIncrementPosition(3):r.getDecrementPosition(3)),void 0!==o&&i.isPositionInBounds(o)&&r.setCurrentPosition(o)}}const mi={t(e){const t=e.split(".");if(2!==t.length)throw new Error("Unexpected translation key length.");if("unit"!==t[0])throw new Error("Unexpected translation key prefix.");return{mm:"mm",cm2:"cm²",degree:"°"}[t[1]]}};class pi{#Zi;#_i;constructor(e,t){this.#Zi=e,this.#_i=t}getBegin(){return this.#Zi}getEnd(){return this.#_i}equals(e){return null!==e&&this.getBegin().equals(e.getBegin())&&this.getEnd().equals(e.getEnd())}getDeltaX(){return this.getEnd().getX()-this.getBegin().getX()}getDeltaY(){return this.getEnd().getY()-this.getBegin().getY()}getLength(){return Math.sqrt(this.getDeltaX()*this.getDeltaX()+this.getDeltaY()*this.getDeltaY())}getWorldLength(e){let t=null;if(null!==e){const n=this.getDeltaX()*e.x,i=this.getDeltaY()*e.y;t=Math.sqrt(n*n+i*i)}return t}getMidpoint(){return new b((this.getBegin().getX()+this.getEnd().getX())/2,(this.getBegin().getY()+this.getEnd().getY())/2)}getSlope(){return this.getDeltaY()/this.getDeltaX()}getIntercept(){return(this.getEnd().getX()*this.getBegin().getY()-this.getBegin().getX()*this.getEnd().getY())/this.getDeltaX()}getInclination(){return 180-180*Math.atan2(this.getDeltaY(),this.getDeltaX())/Math.PI}quantify(e){const t={},n=e.get2DSpacing(),i=this.getWorldLength(n);return null!==i&&(t.length={value:i,unit:mi.t("unit.mm")}),t}}function fi(e,t){const n=e.getDeltaX(),i=e.getDeltaY(),r=t.getDeltaX(),o=t.getDeltaY(),a=n*r+i*o,s=n*o-i*r;return 360-(180-180*Math.atan2(s,a)/Math.PI)}function yi(e,t,n){let i=0,r=0,o=0,a=0;if(0!==e.getSlope()){const s=-1/e.getSlope(),l=t.getY()-s*t.getX(),c=n/(2*Math.sqrt(1+s*s));i=t.getX()-c,r=s*i+l,o=t.getX()+c,a=s*o+l}else i=t.getX(),r=t.getY()-n/2,o=t.getX(),a=t.getY()+n/2;return new pi(new b(i,r),new b(o,a))}function Di(e,t,n,i){const r=i.applyZoomScale(3),o={x:Math.abs(r.x),y:Math.abs(r.y)};return new(ln().Ellipse)({x:e,y:t,stroke:"#999",fill:"rgba(100,100,100,0.7",strokeWidth:i.getStrokeWidth(),strokeScaleEnabled:!1,radius:o,radiusX:o.x,radiusY:o.y,name:"anchor",id:n.toString(),dragOnTop:!1,draggable:!0,visible:!1})}class Ci{#Ni;constructor(e){this.#Ni=e}#Ki=null;#Ji=null;#$i=null;#Xt;#tt=null;#er=!1;#tr=null;setFactoryList(e){this.#Ki=e}setShape(e,t,n){if(this.#$i=e,this.#Xt=t,this.#tt=n,this.#$i){this.#nr();const e=this.#$i.getParent(),t=Object.keys(this.#Ki);this.#Ji=null;for(let n=0;n{this.#ar(e)}:e=>{this.#sr(e)},this.#or(t)}#nr(){this.#or((function(e){e.remove()}))}#ir(){if(!this.#$i||!this.#$i.getLayer())return;const e=this.#$i.getParent(),t=this.#Ji.getAnchors(this.#$i,this.#Ni.getStyle());for(let n=0;n{const n=e.target;n instanceof ln().Shape&&(t=this.#lr(n),e.cancelBubble=!0)})),e.on("dragmove.edit",(e=>{const t=e.target;t instanceof ln().Shape&&(function(e,t){const n=t.getParent();Ii(t,new b(-n.x(),-n.y()),new b(e.x-n.x(),e.y-n.y()))}(this.#Xt.getBaseSize(),t),this.#Ji.update(t,this.#Ni.getStyle(),this.#tt),t.getLayer()?t.getLayer().draw():i.warn("No layer to draw the anchor!"),e.cancelBubble=!0)})),e.on("dragend.edit",(e=>{const i=e.target;if(!(i instanceof ln().Shape))return;const r=this.#lr(i),o=new Sn(n,this.#Ji,t,r,this.#Xt,this.#tt,this.#Ni.getStyle());o.onExecute=this.#tr,o.onUndo=this.#tr,o.execute(),this.#Ni.addToUndoStack(o),t=r,e.cancelBubble=!0})),e.on("mousedown touchstart",(e=>{e.target.moveToTop()})),e.on("mouseover.edit",(e=>{const t=e.target;t instanceof ln().Shape&&(t.stroke("#ddd"),t.getLayer()?t.getLayer().draw():i.warn("No layer to draw the anchor!"))})),e.on("mouseout.edit",(e=>{const t=e.target;t instanceof ln().Shape&&(t.stroke("#999"),t.getLayer()?t.getLayer().draw():i.warn("No layer to draw the anchor!"))}))}#sr(e){e.off("dragstart.edit"),e.off("dragmove.edit"),e.off("dragend.edit"),e.off("mousedown touchstart"),e.off("mouseover.edit"),e.off("mouseout.edit")}}class vi{#cr;constructor(){this.createTrashIcon()}createTrashIcon(){this.#cr=new(ln().Group);const e=new(ln().Line)({points:[-10,-10,10,10],stroke:"red"}),t=new(ln().Line)({points:[10,-10,-10,10],stroke:"red"});this.#cr.width(20),this.#cr.height(20),this.#cr.add(e),this.#cr.add(t)}activate(e){const t=e.getKonvaStage(),n=t.scale(),i=e.getKonvaLayer(),r={x:1/n.x,y:1/n.y};this.#cr.x(t.offset().x+t.width()/(2*n.x)),this.#cr.y(t.offset().y+t.height()/(15*n.y)),this.#cr.scale(r),i.add(this.#cr),i.draw()}changeChildrenColourOnTrashHover(e,t,n){if(this.isOverTrash(e))return this.changeGroupChildrenColour(this.#cr,"orange"),void this.changeGroupChildrenColour(t,"red");this.changeGroupChildrenColour(this.#cr,"red"),this.changeGroupChildrenColour(t,n)}changeGroupChildrenColour(e,t){e.getChildren().forEach((function(e){e instanceof ln().Shape&&void 0!==e.stroke&&e.stroke(t)}))}remove(){this.#cr.remove()}isOverTrash(e){const t=this.#cr.width()*Math.abs(this.#cr.scaleX())/2,n=this.#cr.height()*Math.abs(this.#cr.scaleY())/2;return Math.abs(e.x-this.#cr.x())n.getX()&&(e.x(n.getX()),i=!0),e.y()n.getY()&&(e.y(n.getY()),i=!0),i}class Ti{#ur=[];getPoint(e){return this.#ur[e]}getLength(){return this.#ur.length}addPoint(e){this.#ur.push(e)}addPoints(e){this.#ur=this.#ur.concat(e)}}const Li={labelText:{arrow:{"*":""},circle:{"*":"{surface}"},ellipse:{"*":"{surface}"},freeHand:{"*":""},protractor:{"*":"{angle}"},rectangle:{"*":"{surface}"},roi:{"*":""},ruler:{"*":"{length}"}}};class Pi{getGroupName(){return"roi-group"}getNPoints(){}getTimeout(){return 100}isFactoryGroup(e){return this.getGroupName()===e.name()}create(e,t,n){const i=new Ti;i.addPoints(e);const r=[];for(let e=0;e.33?0:1;t[n][e.data[n].length-2]=1,t[n][e.data[n].length-1]=1}t[e.data.length-2]=[],t[e.data.length-1]=[];for(let n=1;nMath.round(this.searchGran*this.cost[e.y][e.x]);setPoint(e){this.setWorking(!0),this.curPoint=e;let t=0,n=0;for(this.visited=[],n=0;nethis.getMax()?t:e))}}class Bi{getName(){return"Sharpen"}#yr=null;setOriginalImage(e){this.#yr=e}getOriginalImage(){return this.#yr}update(){return this.getOriginalImage().convolute2D([0,-1,0,-1,5,-1,0,-1,0])}}class Ni{getName(){return"Sobel"}#yr=null;setOriginalImage(e){this.#yr=e}getOriginalImage(){return this.#yr}update(){const e=this.getOriginalImage(),t=e.convolute2D([1,0,-1,2,0,-2,1,0,-1]),n=e.convolute2D([1,2,1,0,0,0,-1,-2,-1]);return t.compose(n,(function(e,t){return Math.sqrt(e*e+t*t)}))}}class Vi{#Dr;#We;#Ni;constructor(e,t,n){this.#Dr=e,this.#We=t,this.#Ni=n}getName(){return"Filter-"+this.#Dr.getName()}execute(){this.#Ni.setImage(this.#We,this.#Dr.update()),this.#Ni.render(this.#We);const e={type:"filterrun",id:this.getName(),dataId:this.#We};this.onExecute(e)}undo(){this.#Ni.setImage(this.#We,this.#Dr.getOriginalImage()),this.#Ni.render(this.#We);const e={type:"filterundo",id:this.getName(),dataid:this.#We};this.onUndo(e)}onExecute(e){}onUndo(e){}}const Gi={},ki={WindowLevel:class{#Ni;#Cr=!1;#vr;#Ir;constructor(e){this.#Ni=e,this.#Ir=new gi(e)}#Tr(e){this.#Cr=!0,this.#vr=e}#Lr(e,t){if(!this.#Cr)return;const n=this.#Ni.getLayerGroupByDivId(t).getActiveViewLayer().getViewController(),i=e.getX()-this.#vr.getX(),o=this.#vr.getY()-e.getY(),a=n.getImageRescaledDataRange(),s=.01*(a.max-a.min),l=n.getWindowLevel().center,c=n.getWindowLevel().width,u=l+Math.round(o*s);let d=c+Math.round(i*s);var h;d=(h=d)<1?1:h;const S=new r(u,d);n.setWindowLevel(S),this.#vr=e}#Pr(){this.#Cr&&(this.#Cr=!1)}mousedown=e=>{const t=rn(e);this.#Tr(t)};mousemove=e=>{const t=rn(e),n=Pn(e);this.#Lr(t,n.groupDivId)};mouseup=e=>{this.#Pr()};mouseout=e=>{this.#Pr()};touchstart=e=>{const t=nn(e);this.#Tr(t[0])};touchmove=e=>{const t=nn(e),n=Pn(e);this.#Lr(t[0],n.groupDivId)};touchend=e=>{this.#Pr()};dblclick=e=>{const t=Pn(e),n=rn(e),i=this.#Ni.getLayerGroupByDivId(t.groupDivId).getActiveViewLayer(),o=i.displayToPlaneIndex(n),a=i.getViewController(),s=this.#Ni.getImage(i.getDataId()),l=new r(s.getRescaledValueAtIndex(a.getCurrentIndex().getWithNew2D(o.get(0),o.get(1))),a.getWindowLevel().width);a.setWindowLevel(l)};wheel=e=>{this.#Ir.wheel(e)};keydown=e=>{e.context="WindowLevel",this.#Ni.onKeydown(e)};activate(e){}init(){}setFeatures(e){}},Scroll:class{#Ni;#Cr=!1;#vr;#Ir;#wr;#Or=!1;#Ar;constructor(e){this.#Ni=e,this.#Ir=new gi(e)}#Tr(e,t){this.#br();const n=this.#Ni.getLayerGroupByDivId(t).getActiveViewLayer(),i=n.getViewController();i.isPlaying()&&i.stop(),this.#Cr=!0,this.#vr=e;const r=n.displayToPlanePos(e),o=i.getPositionFromPlanePoint(r);i.setCurrentPosition(o)}#Lr(e,t){if(!this.#Cr)return void(this.#Or&&this.#xr(e,t));const n=this.#Ni.getLayerGroupByDivId(t),i=n.getActiveViewLayer().getViewController();let r;const o=e.getY()-this.#vr.getY(),a=Math.abs(o)>15;a&&n.canScroll()&&(r=o>0?i.getDecrementScrollPosition():i.getIncrementScrollPosition());const s=e.getX()-this.#vr.getX(),l=Math.abs(s)>15;l&&n.moreThanOne(3)&&(r=s>0?i.getIncrementPosition(3):i.getDecrementPosition(3)),void 0!==r&&n.isPositionInBounds(r)&&i.setCurrentPosition(r),(l||a)&&(this.#vr=e)}#Pr(){this.#Cr&&(this.#Cr=!1)}mousedown=e=>{const t=rn(e),n=Pn(e);this.#Tr(t,n.groupDivId)};mousemove=e=>{const t=rn(e),n=Pn(e);this.#Lr(t,n.groupDivId)};mouseup=e=>{this.#Pr()};mouseout=e=>{this.#Pr(),this.#br()};touchstart=e=>{this.#wr=setTimeout((()=>{this.dblclick(e)}),500);const t=nn(e),n=Pn(e);this.#Tr(t[0],n.groupDivId)};touchmove=e=>{null!==this.#wr&&(clearTimeout(this.#wr),this.#wr=null);const t=nn(e),n=Pn(e);this.#Lr(t[0],n.groupDivId)};touchend=e=>{null!==this.#wr&&(clearTimeout(this.#wr),this.#wr=null),this.#Pr()};wheel=e=>{this.#Ir.wheel(e)};keydown=e=>{e.context="Scroll",this.#Ni.onKeydown(e)};dblclick=e=>{const t=Pn(e);this.#Ni.getLayerGroupByDivId(t.groupDivId).getActiveViewLayer().getViewController().play()};#xr(e,t){const n=this.#Ni.getLayerGroupByDivId(t);this.#Ar=t,n.showTooltip(e)}#br(){void 0!==this.#Ar&&(this.#Ni.getLayerGroupByDivId(this.#Ar).removeTooltipDiv(),this.#Ar=void 0)}activate(e){e||this.#br()}setFeatures(e){void 0!==e.displayTooltip&&(this.#Or=e.displayTooltip)}init(){}},ZoomAndPan:class{#Ni;#Cr=!1;#vr;#Rr;#Fr;#Er;constructor(e){this.#Ni=e}#Tr(e){this.#Cr=!0,this.#vr=e,this.#Rr=!1}#qr=e=>{this.#Cr=!0,this.#vr=e[0],this.#Rr=!1,this.#Fr=new pi(e[0],e[1]),this.#Er=this.#Fr.getMidpoint()};#Lr(e,t){if(!this.#Cr)return;this.#Rr=!0;const n=e.getX()-this.#vr.getX(),i=e.getY()-this.#vr.getY(),r=this.#Ni.getLayerGroupByDivId(t),o=r.getActiveViewLayer(),a=o.getViewController(),s=o.displayToPlaneScale(new b(n,i)),l=a.getOffset3DFromPlaneOffset({x:s.getX(),y:s.getY()});r.addTranslation({x:l.getX(),y:l.getY(),z:l.getZ()}),r.draw(),this.#vr=e}#Ur=(e,t)=>{if(!this.#Cr)return;this.#Rr=!0;const n=new pi(e[0],e[1]).getLength()/this.#Fr.getLength(),i=this.#Ni.getLayerGroupByDivId(t),r=i.getActiveViewLayer(),o=r.getViewController();if(1===n){const t=e[0].getY()-this.#vr.getY();if(Math.abs(t)<15)return;if(i.canScroll()){let e;e=t>0?o.getIncrementScrollPosition():o.getDecrementScrollPosition(),void 0!==e&&i.isPositionInBounds(e)&&o.setCurrentPosition(e)}}else{const e=(n-1)/10;if(Math.abs(e)%.1<=.05&&void 0!==this.#Er){const t=r.displayToMainPlanePos(this.#Er),n=o.getPlanePositionFromPlanePoint(t);i.addScale(e,n),i.draw()}}};#Mr(e,t){const n=this.#Ni.getLayerGroupByDivId(t).getActiveViewLayer(),i=n.getViewController(),r=n.displayToPlanePos(e),o=i.getPositionFromPlanePoint(r);i.setCurrentPosition(o)}#Pr(){this.#Cr&&(this.#Cr=!1)}mousedown=e=>{const t=rn(e);this.#Tr(t)};mousemove=e=>{const t=rn(e),n=Pn(e);this.#Lr(t,n.groupDivId)};mouseup=e=>{if(!this.#Rr){const t=rn(e),n=Pn(e);this.#Mr(t,n.groupDivId)}this.#Pr()};mouseout=e=>{this.#Pr()};touchstart=e=>{const t=nn(e);1===t.length?this.#Tr(t[0]):2===t.length&&this.#qr(t)};touchmove=e=>{const t=nn(e),n=Pn(e);1===t.length?this.#Lr(t[0],n.groupDivId):2===t.length&&this.#Ur(t,n.groupDivId)};touchend=e=>{if(!this.#Rr){const t=rn(e),n=Pn(e);this.#Mr(t,n.groupDivId)}this.#Pr()};wheel=e=>{e.preventDefault();const t=-e.deltaY/500,n=Pn(e),i=rn(e),r=this.#Ni.getLayerGroupByDivId(n.groupDivId),o=r.getActiveViewLayer(),a=o.getViewController(),s=o.displayToMainPlanePos(i),l=a.getPlanePositionFromPlanePoint(s);r.addScale(t,l),r.draw()};keydown=e=>{e.context="ZoomAndPan",this.#Ni.onKeydown(e)};activate(e){}init(){}setFeatures(e){}},Opacity:class{#Ni;#Cr=!1;#vr;#Ir;constructor(e){this.#Ni=e,this.#Ir=new gi(e)}#Tr(e){this.#Cr=!0,this.#vr=e}#Lr(e,t){if(!this.#Cr)return;const n=e.getX()-this.#vr.getX();if(Math.abs(n)>15){const i=this.#Ni.getLayerGroupByDivId(t).getActiveViewLayer(),r=i.getOpacity();i.setOpacity(r+n/200),i.draw(),this.#vr=e}}#Pr(){this.#Cr&&(this.#Cr=!1)}mousedown=e=>{const t=rn(e);this.#Tr(t)};mousemove=e=>{const t=rn(e),n=Pn(e);this.#Lr(t,n.groupDivId)};mouseup=e=>{this.#Pr()};mouseout=e=>{this.#Pr()};touchstart=e=>{const t=nn(e);this.#Tr(t[0])};touchmove=e=>{const t=nn(e),n=Pn(e);this.#Lr(t[0],n.groupDivId)};touchend=e=>{this.#Pr()};wheel=e=>{this.#Ir.wheel(e)};keydown=e=>{e.context="Opacity",this.#Ni.onKeydown(e)};activate(e){}init(){}setFeatures(e){}},Draw:class{#Ni;#Ir;#Qr;#cr;#Yt;#pn=[];constructor(e){this.#Ni=e,this.#Ir=new gi(e),this.#Qr=new Ci(e),this.#Qr.setDrawEventCallback(this.#Re),this.#Yt=e.getStyle(),this.#cr=new vi}#Br=!1;#Ki=null;#Ji=null;#Nr=null;#Vr;#ur=[];#Gr=null;#kr;#Hr;#zr="pointer";#Wr=!0;#Yr=!0;#H={};#Xr=!1;#jr(e,t){const n=this.#Ni.getLayerGroupByDivId(t),i=n.getActiveDrawLayer(),r=i.getKonvaStage(),o=r.getIntersection({x:e.getX(),y:e.getY()});this.#Yt.setZoomScale(r.scale()),o?this.#Zr(n,i,o):this.#_r(n,e)}#_r(e,t){this.#Qr.disable(),this.#Qr.reset(),this.#Kr();const n=e.getActiveViewLayer();this.#Gr=n.displayToPlanePos(t),this.#ur.push(this.#Gr)}#Kr(){this.#Br=!0,this.#Ji=new this.#Ki[this.#Vr],this.#ur=[]}#Jr(){this.#Br=!1,this.#ur=[]}#Zr(e,t,n){const i=n.getParent().find(".shape")[0];if(i&&i instanceof ln().Shape&&i!==this.#Qr.getShape()){this.#Qr.disable();const n=e.getActiveViewLayer().getViewController();this.#Qr.setShape(i,t,n),this.#Qr.enable()}}#$r(e,t){const n=this.#Ni.getLayerGroupByDivId(t),i=n.getActiveViewLayer().displayToPlanePos(e);(Math.abs(i.getX()-this.#Gr.getX())>0||Math.abs(i.getY()-this.#Gr.getY())>0)&&(this.#Xr&&this.#ur.pop(),this.#Gr=i,this.#Xr=!0,this.#ur.push(this.#Gr),this.#eo(this.#ur,n))}#to(e){if(0!==this.#ur.length){if(this.#ur.length===this.#Ji.getNPoints()){const t=this.#Ni.getLayerGroupByDivId(e);this.#no(this.#ur,t),this.#Jr()}this.#Xr=!1}else i.warn("Draw mouseup but no points...")}mousedown=e=>{if(this.#Br)return;const t=rn(e),n=Pn(e);this.#jr(t,n.groupDivId)};mousemove=e=>{if(!this.#Br)return;const t=rn(e),n=Pn(e);this.#$r(t,n.groupDivId)};mouseup=e=>{if(!this.#Br)return;const t=Pn(e);this.#to(t.groupDivId)};dblclick=e=>{if(void 0!==this.#Ji.getNPoints())return;if(!this.#Br)return;if(0===this.#ur.length)return void i.warn("Draw dblclick but no points...");const t=Pn(e),n=this.#Ni.getLayerGroupByDivId(t.groupDivId);this.#no(this.#ur,n),this.#Jr()};mouseout=e=>{if(!this.#Br)return;const t=Pn(e);this.#to(t.groupDivId)};touchstart=e=>{if(this.#Br)return;const t=nn(e),n=Pn(e);this.#jr(t[0],n.groupDivId)};touchmove=e=>{if(!this.#Br)return;const t=Pn(e),n=nn(e),i=this.#Ni.getLayerGroupByDivId(t.groupDivId),r=i.getActiveViewLayer().displayToPlanePos(n[0]);(Math.abs(r.getX()-this.#Gr.getX())>0||Math.abs(r.getY()-this.#Gr.getY())>0)&&(1!==this.#ur.length&&this.#ur.pop(),this.#Gr=r,this.#ur.push(this.#Gr),this.#ur.length{this.#ur.push(this.#Gr)}),this.#Ji.getTimeout())),this.#eo(this.#ur,i))};touchend=e=>{this.dblclick(e)};wheel=e=>{this.#Wr&&this.#Ir.wheel(e)};keydown=e=>{if(this.#Br||(e.context="Draw",this.#Ni.onKeydown(e)),("Delete"===e.key||"Backspace"===e.key)&&this.#Qr.isActive()){const e=this.#Qr.getShape().getParent();if(!(e instanceof ln().Group))return;const t=e.getChildren(fn)[0];if(!(t instanceof ln().Shape))return;const n=this.#Ni.getActiveLayerGroup().getActiveDrawLayer();this.#io(n,e,t)}if("Escape"===e.key&&null!==this.#Nr){const e=this.#Nr.getLayer();this.#Nr.destroy(),this.#Nr=null,this.#Jr(),e.draw()}};#eo(e,t){this.#Nr&&(this.#Nr.destroy(),this.#Nr=null);const n=t.getActiveDrawLayer().getKonvaLayer(),i=t.getActiveViewLayer();if(this.#Yr){const e=["#ffff80","#ff80ff","#80ffff","#80ff80","8080ff","ff8080"],t=i.getId(),n=t.substring(t.length-1),r=e[parseInt(n,10)/2];void 0!==r&&this.#Yt.setLineColour(r)}const r=i.getViewController();this.#Nr=this.#Ji.create(e,this.#Yt,r),this.#Nr.getChildren(fn)[0].listening(!1),n.listening(!1),n.add(this.#Nr),n.draw()}#no(e,t){this.#Nr&&(this.#Nr.destroy(),this.#Nr=null);const n=t.getActiveDrawLayer(),i=n.getKonvaLayer(),r=n.getDrawController(),o=t.getActiveViewLayer().getViewController(),a=this.#Ji.create(e,this.#Yt,o);a.id(et()),r.getCurrentPosGroup().add(a),i.listening(!0),this.#ro(n,a),this.#oo(t,a)}#ro(e,t){const n=new dn(t,this.#Vr,e);n.onExecute=this.#Re,n.onUndo=this.#Re,n.execute(),this.#Ni.addToUndoStack(n)}#io(e,t,n){const i=un(n),r=new gn(t,i,e);r.onExecute=this.#Re,r.onUndo=this.#Re,r.execute(),this.#Ni.addToUndoStack(r)}#ao(e,t,n,i){const r=un(n),o=new hn(t,r,i,e);o.onExecute=this.#Re,o.onUndo=this.#Re,this.#Ni.addToUndoStack(o)}#so(e){const t=e.getDivId();return void 0===this.#pn[t]&&(this.#pn[t]=()=>{this.#lo(e)}),this.#pn[t]}activate(e){this.#Qr.disable(),this.#Qr.reset();const t=this.#Ni.getActiveLayerGroup();if(void 0===t)throw new Error("No active layerGroup to activate draw on");this.#co(e,t),e?(this.#Hr=document.body.style.cursor,this.#Ni.addEventListener("positionchange",this.#so(t))):(this.#uo(),this.#Hr=void 0,this.#Ni.removeEventListener("positionchange",this.#so(t)))}#lo(e){this.#co(!0,e)}#co(e,t){const n=t.getActiveDrawLayer();if(void 0===n)return;const i=n.getDrawController().getCurrentPosGroup().getChildren();e?i.forEach((e=>{this.#oo(t,e)})):i.forEach((e=>{this.#do(e)}));const r=n.getKonvaLayer();0!==i.length&&r.listening(!0),r.draw()}#do(e){this.#ho(e),e.draggable(!1),e.off("dragstart.draw"),e.off("dragmove.draw"),e.off("dragend.draw"),e.off("dblclick")}#So(e,t){const n=t.getActiveDrawLayer().getKonvaStage();return{x:n.offset().x+e.x/n.scale().x,y:n.offset().y+e.y/n.scale().y}}#uo(){void 0!==this.#Hr&&(document.body.style.cursor=this.#Hr),void 0!==this.#kr&&this.#kr.opacity(1)}#go(e){e.on("mouseover",(()=>{this.#kr=e,document.body.style.cursor=this.#zr,e.opacity(.75)})),e.on("mouseout",(()=>{this.#uo(),this.#kr=void 0}))}#ho(e){e.off("mouseover"),e.off("mouseout")}#mo(e){let t;const n=Object.keys(this.#Ki);for(let i=0;i{const e=t.getChildren(fn)[0];e instanceof ln().Shape&&(a=e.stroke(),this.#cr.activate(n),this.#Qr.setAnchorsActive(!1),i.draw())})),t.on("dragmove.draw",(r=>{const o=r.target;if(!(o instanceof ln().Group))return;!function(e,t){const n=t.getChildren(fn)[0],i=function(e){const t=e.find(".anchor");if(0===t.length)return;let n=t[0].x(),i=t[0].y();for(let e=0;e{const l=s.target;if(!(l instanceof ln().Group))return;if(this.#cr.remove(),void 0===s||void 0===s.evt)return;const c=l.x(),u=l.y(),d=rn(s.evt),h={x:d.getX(),y:d.getY()},S=this.#So(h,e);if(this.#cr.isOverTrash(S))l.x(r.x),l.y(r.y),this.#Qr.disable(),this.#Qr.reset(),this.#cr.changeGroupChildrenColour(t,a),this.#io(n,t,o),document.body.style.cursor=this.#Hr;else{const e={x:c-r.x,y:u-r.y};0===e.x&&0===e.y||(this.#ao(n,l,o,e),this.#Re({type:"drawmove",id:l.id(),srclayerid:n.getId(),dataid:n.getDataId()})),this.#Qr.setAnchorsActive(!0),this.#Qr.resetAnchors()}i.draw(),r={x:l.x(),y:l.y()}})),t.on("dblclick",(e=>{const t=e.currentTarget;if(!(t instanceof ln().Group))return;const r=t.findOne("Label");if(!(r instanceof ln().Label))return;if(void 0===r)throw new Error("Could not find the shape label.");const o=r.getText(),a=t.id();en.openRoiDialog(o.meta,(e=>{o.meta=e,o.setText(U(e.textExpr,e.quantification)),r.visible(0!==e.textExpr.length),this.#Re({type:"drawchange",id:a,srclayerid:n.getId(),dataid:n.getDataId()}),i.draw()}))}))}setOptions(e){this.#Ki=e,this.#Qr.setFactoryList(e)}getOptionsType(){return"factory"}setFeatures(e){if(void 0!==e.autoShapeColour&&(this.#Yr=e.autoShapeColour),void 0!==e.shapeColour&&(this.#Yt.setLineColour(e.shapeColour),this.#Yr=!1),void 0!==e.shapeName){if(!this.hasShape(e.shapeName))throw new Error("Unknown shape: '"+e.shapeName+"'");this.#Vr=e.shapeName}void 0!==e.mouseOverCursor&&(this.#zr=e.mouseOverCursor),void 0!==e.withScroll&&(this.#Wr=e.withScroll)}init(){}getEventNames(){return["drawcreate","drawchange","drawmove","drawdelete"]}addEventListener(e,t){void 0===this.#H[e]&&(this.#H[e]=[]),this.#H[e].push(t)}removeEventListener(e,t){if(void 0!==this.#H[e])for(let n=0;n{if(void 0!==this.#H[e.type])for(let t=0;t{e.context="Filter",this.#Ni.onKeydown(e)};getEventNames(){return["filterrun","filterundo"]}addEventListener(e,t){this.#Oe.add(e,t)}removeEventListener(e,t){this.#Oe.remove(e,t)}#Re=e=>{this.#Oe.fireEvent(e)};getSelectedFilter(){return this.#fo}setFeatures(e){if(void 0!==e.filterName){if(!this.hasFilter(e.filterName))throw new Error("Unknown filter: '"+e.filterName+"'");this.#fo&&this.#fo.activate(!1),this.#fo=this.#po[e.filterName],this.#fo.activate(!0)}if(void 0!==e.run&&e.run){let t={};void 0!==e.runArgs&&(t=e.runArgs),this.getSelectedFilter().run(t)}}getFilterList(){return this.#po}hasFilter(e){return this.#po[e]}},Floodfill:class{#Ni;constructor(e){this.#Ni=e}#yo=5;#Do=0;#Co=2e3;#vo=null;#Io=null;#To=10;#Lo=null;#Cr=!1;#Po=null;#wo=null;#Oo;#Ao=null;#bo=[];#xo=!1;#Ro;#Yt=new cn;#Oe=new He;setExtend(e){this.#xo=e}getExtend(){return this.#xo}#Fo=(e,t)=>{const n=this.#Ni.getLayerGroupByDivId(t).getActiveViewLayer().displayToPlaneIndex(e);return{x:n.get(0),y:n.get(1)}};#Eo(e,t,n){this.#bo=[];const i={data:this.#vo.data,width:this.#vo.width,height:this.#vo.height,bytes:4};this.#Io=Oi().floodFill(i,e.x,e.y,t),this.#Io=Oi().gaussBlurOnlyBorder(this.#Io,this.#yo);let r=Oi().traceContours(this.#Io);if(r=Oi().simplifyContours(r,this.#Do,this.#Co),r.length>0&&r[0].points[0].x){if(n)return r[0].points;for(let e=0,t=r[0].points.length;eo&&this.#qo(this.#Oo,a,n);t--)i.decrementIndex(2);i.setCurrentPosition(r)}modifyThreshold(e,t){if(t||!this.#wo)throw"No shape found";t=this.#wo.getChildren((function(e){return"shape"===e.name()}))[0],clearTimeout(this.#Ro),this.#Ro=setTimeout((()=>{if(this.#Ao=this.#Eo(this.#Oo,e,!0),!this.#Ao)return!1;const n=[];for(let e=0,t=this.#Ao.length;e{const t=rn(e),n=Pn(e);this.#Tr(t,n.groupDivId)};mousemove=e=>{const t=rn(e),n=Pn(e);this.#Lr(t,n.groupDivId)};mouseup=e=>{this.#Pr()};mouseout=e=>{this.#Pr()};touchstart=e=>{const t=nn(e),n=Pn(e);this.#Tr(t[0],n.groupDivId)};touchmove=e=>{const t=nn(e),n=Pn(e);this.#Lr(t[0],n.groupDivId)};touchend=e=>{this.#Pr()};keydown=e=>{e.context="Floodfill",this.#Ni.onKeydown(e)};activate(e){e&&(this.#Yt.setBaseScale(this.#Ni.getBaseScale()),this.setFeatures({shapeColour:this.#Yt.getLineColour()}))}init(){}getEventNames(){return["drawcreate","drawchange","drawmove","drawdelete"]}addEventListener(e,t){this.#Oe.add(e,t)}removeEventListener(e,t){this.#Oe.remove(e,t)}#Re=e=>{this.#Oe.fireEvent(e)};setFeatures(e){void 0!==e.shapeColour&&this.#Yt.setLineColour(e.shapeColour)}},Livewire:class{#Ni;constructor(e){this.#Ni=e}#Cr=!1;#vr;#Po=null;#wo=null;#Yt=new cn;#Uo=new Ai;#Mo=new Ai;#bo=[];#Qo=5;#Oe=new He;#Bo(e){const t=e.get(1);for(let e=0;e{const t=rn(e),n=Pn(e);this.#Tr(t,n.groupDivId)};mousemove=e=>{const t=rn(e),n=Pn(e);this.#Lr(t,n.groupDivId)};mouseup(e){}mouseout=e=>{};dblclick=e=>{this.#Go()};touchstart=e=>{const t=nn(e),n=Pn(e);this.#Tr(t[0],n.groupDivId)};touchmove=e=>{const t=nn(e),n=Pn(e);this.#Lr(t[0],n.groupDivId)};touchend=e=>{};keydown=e=>{e.context="Livewire",this.#Ni.onKeydown(e)};activate(e){if(e){const e=this.#Ni.getActiveLayerGroup().getActiveViewLayer(),t=e.getViewController().getImageSize();this.#Vo.setDimensions(t.get(0),t.get(1)),this.#Vo.setData(e.getImageData().data),this.#Yt.setBaseScale(this.#Ni.getBaseScale()),this.setFeatures({shapeColour:this.#Yt.getLineColour()})}}init(){}getEventNames(){return["drawcreate","drawchange","drawmove","drawdelete"]}addEventListener(e,t){this.#Oe.add(e,t)}removeEventListener(e,t){this.#Oe.remove(e,t)}#Re=e=>{this.#Oe.fireEvent(e)};setFeatures(e){void 0!==e.shapeColour&&this.#Yt.setLineColour(e.shapeColour)}}},Hi={draw:{ArrowFactory:class{getGroupName(){return"line-group"}getNPoints(){return 2}getTimeout(){return 0}isFactoryGroup(e){return this.getGroupName()===e.name()}create(e,t,n){const i=new pi(e[0],e[1]),r=new(ln().Line)({points:[i.getBegin().getX(),i.getBegin().getY(),i.getEnd().getX(),i.getEnd().getY()],stroke:t.getLineColour(),strokeWidth:t.getStrokeWidth(),strokeScaleEnabled:!1,name:"shape"}),o=t.applyZoomScale(10).x,a=yi(i,e[0],o),s=yi(i,e[1],o);r.hitFunc((function(e){e.beginPath(),e.moveTo(a.getBegin().getX(),a.getBegin().getY()),e.lineTo(a.getEnd().getX(),a.getEnd().getY()),e.lineTo(s.getEnd().getX(),s.getEnd().getY()),e.lineTo(s.getBegin().getX(),s.getBegin().getY()),e.closePath(),e.fillStrokeShape(r)}));const l=new b(i.getBegin().getX(),i.getBegin().getY()-10),c=new pi(i.getBegin(),l),u=fi(i,c),d=u*Math.PI/180,h=Math.abs(t.applyZoomScale(8).x),S=new(ln().RegularPolygon)({x:i.getBegin().getX()+h*Math.sin(d),y:i.getBegin().getY()+h*Math.cos(d),sides:3,radius:h,rotation:-u,fill:t.getLineColour(),strokeWidth:t.getStrokeWidth(),strokeScaleEnabled:!1,name:"shape-triangle"}),g=new(ln().Text)({fontSize:t.getFontSize(),fontFamily:t.getFontFamily(),fill:t.getLineColour(),padding:t.getTextPadding(),shadowColor:t.getShadowLineColour(),shadowOffset:t.getShadowOffset(),name:"text"});let m="";const p=n.getModality();m=void 0!==Li.labelText.arrow[p]?Li.labelText.arrow[p]:Li.labelText.arrow["*"],g.setText(m),g.meta={textExpr:m,quantification:{}};const f=i.getBegin().getX()>i.getEnd().getX()?0:-1,y=i.getBegin().getY()>i.getEnd().getY()?-1:0,D=new(ln().Label)({x:i.getEnd().getX()+f*g.width(),y:i.getEnd().getY()+y*t.applyZoomScale(15).y,scale:t.applyZoomScale(1),visible:0!==m.length,name:"label"});D.add(g),D.add(new(ln().Tag)({fill:t.getLineColour(),opacity:t.getTagOpacity()}));const C=new(ln().Group);return C.name(this.getGroupName()),C.add(D),C.add(S),C.add(r),C.visible(!0),C}getAnchors(e,t){const n=e.points(),i=[];return i.push(Di(n[0]+e.x(),n[1]+e.y(),"begin",t)),i.push(Di(n[2]+e.x(),n[3]+e.y(),"end",t)),i}update(e,t,n){const i=e.getParent(),r=i.getChildren((function(e){return"shape"===e.name()}))[0];if(!(r instanceof ln().Line))return;const o=i.getChildren((function(e){return"shape-triangle"===e.name()}))[0];if(!(o instanceof ln().RegularPolygon))return;const a=i.getChildren((function(e){return"label"===e.name()}))[0];if(!(a instanceof ln().Label))return;const s=i.getChildren((function(e){return"begin"===e.id()}))[0],l=i.getChildren((function(e){return"end"===e.id()}))[0];switch(e.id()){case"begin":s.x(e.x()),s.y(e.y());break;case"end":l.x(e.x()),l.y(e.y())}const c=s.x()-r.x(),u=s.y()-r.y(),d=l.x()-r.x(),h=l.y()-r.y();r.points([c,u,d,h]);const S=new b(s.x(),s.y()),g=new b(l.x(),l.y()),m=new pi(S,g),p=new b(c,u),f=new b(d,h),y=t.applyZoomScale(10).x,D=yi(m,p,y),C=yi(m,f,y);r.hitFunc((function(e){e.beginPath(),e.moveTo(D.getBegin().getX(),D.getBegin().getY()),e.lineTo(D.getEnd().getX(),D.getEnd().getY()),e.lineTo(C.getEnd().getX(),C.getEnd().getY()),e.lineTo(C.getBegin().getX(),C.getBegin().getY()),e.closePath(),e.fillStrokeShape(r)}));const v=new b(m.getBegin().getX(),m.getBegin().getY()-10),I=new pi(m.getBegin(),v),T=fi(m,I),L=T*Math.PI/180;o.x(m.getBegin().getX()+o.radius()*Math.sin(L)),o.y(m.getBegin().getY()+o.radius()*Math.cos(L)),o.rotation(-T);const P=a.getText();P.setText(P.meta.textExpr);const w=m.getBegin().getX()>m.getEnd().getX()?0:-1,O=m.getBegin().getY()>m.getEnd().getY()?-1:0,A={x:m.getEnd().getX()+w*P.width(),y:m.getEnd().getY()+O*t.applyZoomScale(15).y};a.position(A)}},CircleFactory:class{getGroupName(){return"circle-group"}getNPoints(){return 2}getTimeout(){return 0}isFactoryGroup(e){return this.getGroupName()===e.name()}#ko(e){const t=Math.abs(e[0].getX()-e[1].getX()),n=Math.abs(e[0].getY()-e[1].getY()),i=Math.round(Math.sqrt(t*t+n*n));return new Ei(e[0],i)}#Ho(e,t){return new(ln().Circle)({x:e.getCenter().getX(),y:e.getCenter().getY(),radius:e.getRadius(),stroke:t.getLineColour(),strokeWidth:t.getStrokeWidth(),strokeScaleEnabled:!1,name:"shape"})}#zo(e,t,n){const i=new(ln().Text)({fontSize:t.getFontSize(),fontFamily:t.getFontFamily(),fill:t.getLineColour(),padding:t.getTextPadding(),shadowColor:t.getShadowLineColour(),shadowOffset:t.getShadowOffset(),name:"text"});let r="";const o=n.getModality();r=void 0!==Li.labelText.circle[o]?Li.labelText.circle[o]:Li.labelText.circle["*"];const a=e.quantify(n,q(r));i.setText(U(r,a)),i.meta={textExpr:r,quantification:a};const s=new(ln().Label)({x:e.getCenter().getX()-e.getRadius(),y:e.getCenter().getY()+e.getRadius(),scale:t.applyZoomScale(1),visible:0!==r.length,name:"label"});return s.add(i),s.add(new(ln().Tag)({fill:t.getLineColour(),opacity:t.getTagOpacity()})),s}create(e,t,n){const i=new(ln().Group);i.name(this.getGroupName()),i.visible(!0);const r=this.#ko(e),o=this.#Ho(r,t);i.add(o);const a=this.#zo(r,t,n);return i.add(a),i}getAnchors(e,t){const n=e.x(),i=e.y(),r=e.radius(),o=[];return o.push(Di(n-r,i,"left",t)),o.push(Di(n+r,i,"right",t)),o.push(Di(n,i+r,"bottom",t)),o.push(Di(n,i-r,"top",t)),o}update(e,t,n){const r=e.getParent();if(!(r instanceof ln().Group))return;const o=r.getChildren((function(e){return"shape"===e.name()}))[0];if(!(o instanceof ln().Circle))return;const a=r.getChildren((function(e){return"label"===e.name()}))[0],s=r.getChildren((function(e){return"left"===e.id()}))[0],l=r.getChildren((function(e){return"right"===e.id()}))[0],c=r.getChildren((function(e){return"bottom"===e.id()}))[0],u=r.getChildren((function(e){return"top"===e.id()}))[0];const d=o.x(),h=o.y();let S;switch(e.id()){case"left":S=d-e.x(),s.x(e.x()),s.y(l.y()),l.x(d+S),c.y(h+S),u.y(h-S);break;case"right":S=e.x()-d,l.x(e.x()),l.y(s.y()),s.x(d-S),c.y(h+S),u.y(h-S);break;case"bottom":S=e.y()-h,c.x(u.x()),c.y(e.y()),s.x(d-S),l.x(d+S),u.y(h-S);break;case"top":S=h-e.y(),u.x(c.x()),u.y(e.y()),s.x(d-S),l.x(d+S),c.y(h+S);break;default:i.error("Unhandled anchor id: "+e.id())}o.radius(Math.abs(S));const g=new b(r.x()+d,r.y()+h),m=(new Ei(g,S),{x:d-Math.abs(S),y:h+Math.abs(S)});a.position(m),this.#Wo(r,n)}updateQuantification(e,t){this.#Wo(e,t)}#Wo(e,t){const n=e.getChildren((function(e){return"shape"===e.name()}))[0];if(!(n instanceof ln().Circle))return;const i=e.getChildren((function(e){return"label"===e.name()}))[0];if(!(i instanceof ln().Label))return;const r=new b(e.x()+n.x(),e.y()+n.y()),o=new Ei(r,n.radius()),a=i.getText(),s=a.meta,l=o.quantify(t,q(s.textExpr));a.setText(U(s.textExpr,l)),s.quantification=l}#Yo(e,t){let n=0,i=0;void 0!==t&&(n=t.x(),i=t.y());const r=new(ln().Group);r.name("shadow");const o=e.getRound();for(let e=0;e180&&(s=360-s,l+=s);const c=new(ln().Text)({fontSize:t.getFontSize(),fontFamily:t.getFontFamily(),fill:t.getLineColour(),padding:t.getTextPadding(),shadowColor:t.getShadowLineColour(),shadowOffset:t.getShadowOffset(),name:"text"});let u="";const d=n.getModality();u=void 0!==Li.labelText.protractor[d]?Li.labelText.protractor[d]:Li.labelText.protractor["*"];const h={angle:{value:s,unit:mi.t("unit.degree")}};c.setText(U(u,h)),c.meta={textExpr:u,quantification:h};const S=(i.getMidpoint().getX()+r.getMidpoint().getX())/2,g=(i.getMidpoint().getY()+r.getMidpoint().getY())/2,m=new(ln().Label)({x:S,y:g-t.applyZoomScale(15).y,scale:t.applyZoomScale(1),visible:0!==u.length,name:"label"});m.add(c),m.add(new(ln().Tag)({fill:t.getLineColour(),opacity:t.getTagOpacity()}));const p=33*Math.min(i.getLength(),r.getLength())/100,f=new(ln().Arc)({innerRadius:p,outerRadius:p,stroke:t.getLineColour(),strokeWidth:t.getStrokeWidth(),strokeScaleEnabled:!1,angle:s,rotation:-l,x:e[1].getX(),y:e[1].getY(),name:"shape-arc"});a.add(m),a.add(f)}return a.add(o),a.visible(!0),a}getAnchors(e,t){const n=e.points(),i=[];return i.push(Di(n[0]+e.x(),n[1]+e.y(),"begin",t)),i.push(Di(n[2]+e.x(),n[3]+e.y(),"mid",t)),i.push(Di(n[4]+e.x(),n[5]+e.y(),"end",t)),i}update(e,t,n){const i=e.getParent(),r=i.getChildren((function(e){return"shape"===e.name()}))[0];if(!(r instanceof ln().Line))return;const o=i.getChildren((function(e){return"label"===e.name()}))[0];if(!(o instanceof ln().Label))return;const a=i.getChildren((function(e){return"shape-arc"===e.name()}))[0];if(!(a instanceof ln().Arc))return;const s=i.getChildren((function(e){return"begin"===e.id()}))[0],l=i.getChildren((function(e){return"mid"===e.id()}))[0],c=i.getChildren((function(e){return"end"===e.id()}))[0];switch(e.id()){case"begin":s.x(e.x()),s.y(e.y());break;case"mid":l.x(e.x()),l.y(e.y());break;case"end":c.x(e.x()),c.y(e.y())}const u=s.x()-r.x(),d=s.y()-r.y(),h=l.x()-r.x(),S=l.y()-r.y(),g=c.x()-r.x(),m=c.y()-r.y();r.points([u,d,h,S,g,m]),r.hitFunc((function(e){e.beginPath(),e.moveTo(u,d),e.lineTo(h,S),e.lineTo(g,m),e.closePath(),e.fillStrokeShape(r)}));const p=new b(s.x(),s.y()),f=new b(l.x(),l.y()),y=new b(c.x(),c.y()),D=new pi(p,f),C=new pi(f,y);let v=fi(D,C),I=D.getInclination();v>180&&(v=360-v,I+=v);const T=o.getText(),L=T.meta,P={angle:{value:v,unit:mi.t("unit.degree")}};T.setText(U(L.textExpr,P)),L.quantification=P;const w={x:(D.getMidpoint().getX()+C.getMidpoint().getX())/2,y:(D.getMidpoint().getY()+C.getMidpoint().getY())/2-t.applyZoomScale(15).y};o.position(w);const O=33*Math.min(D.getLength(),C.getLength())/100;a.innerRadius(O),a.outerRadius(O),a.angle(v),a.rotation(-I);const A={x:l.x(),y:l.y()};a.position(A)}},RectangleFactory:class{getGroupName(){return"rectangle-group"}getNPoints(){return 2}getTimeout(){return 0}isFactoryGroup(e){return this.getGroupName()===e.name()}create(e,t,n){const i=new Mi(e[0],e[1]),r=new(ln().Rect)({x:i.getBegin().getX(),y:i.getBegin().getY(),width:i.getWidth(),height:i.getHeight(),stroke:t.getLineColour(),strokeWidth:t.getStrokeWidth(),strokeScaleEnabled:!1,name:"shape"}),o=new(ln().Text)({fontSize:t.getFontSize(),fontFamily:t.getFontFamily(),fill:t.getLineColour(),padding:t.getTextPadding(),shadowColor:t.getShadowLineColour(),shadowOffset:t.getShadowOffset(),name:"text"});let a="";const s=n.getModality();a=void 0!==Li.labelText.rectangle[s]?Li.labelText.rectangle[s]:Li.labelText.rectangle["*"];const l=i.quantify(n,q(a));o.setText(U(a,l)),o.meta={textExpr:a,quantification:l};const c=new(ln().Label)({x:i.getBegin().getX(),y:i.getEnd().getY(),scale:t.applyZoomScale(1),visible:0!==a.length,name:"label"});c.add(o),c.add(new(ln().Tag)({fill:t.getLineColour(),opacity:t.getTagOpacity()}));const u=new(ln().Group);return u.name(this.getGroupName()),u.add(c),u.add(r),u.visible(!0),u}getAnchors(e,t){const n=e.x(),i=e.y(),r=e.width(),o=e.height(),a=[];return a.push(Di(n,i,"topLeft",t)),a.push(Di(n+r,i,"topRight",t)),a.push(Di(n+r,i+o,"bottomRight",t)),a.push(Di(n,i+o,"bottomLeft",t)),a}update(e,t,n){const r=e.getParent();if(!(r instanceof ln().Group))return;const o=r.getChildren((function(e){return"shape"===e.name()}))[0],a=r.getChildren((function(e){return"label"===e.name()}))[0],s=r.getChildren((function(e){return"topLeft"===e.id()}))[0],l=r.getChildren((function(e){return"topRight"===e.id()}))[0],c=r.getChildren((function(e){return"bottomRight"===e.id()}))[0],u=r.getChildren((function(e){return"bottomLeft"===e.id()}))[0];let d;switch(e.id()){case"topLeft":s.x(e.x()),s.y(e.y()),l.y(e.y()),u.x(e.x());break;case"topRight":l.x(e.x()),l.y(e.y()),s.y(e.y()),c.x(e.x());break;case"bottomRight":c.x(e.x()),c.y(e.y()),u.y(e.y()),l.x(e.x());break;case"bottomLeft":u.x(e.x()),u.y(e.y()),c.y(e.y()),s.x(e.x());break;default:i.error("Unhandled anchor id: "+e.id())}o.position(s.position());const h=l.x()-s.x(),S=u.y()-s.y();h&&S&&o.size({width:h,height:S});const g=new b(r.x()+s.x(),r.y()+s.y()),m=new b(r.x()+c.x(),r.y()+c.y()),p=new Mi(g,m);const f={x:p.getBegin().getX()-r.x(),y:p.getEnd().getY()-r.y()};a.position(f),this.#Zo(r,n)}updateQuantification(e,t){this.#Zo(e,t)}#Zo(e,t){const n=e.getChildren((function(e){return"shape"===e.name()}))[0],i=e.getChildren((function(e){return"label"===e.name()}))[0];if(!(i instanceof ln().Label))return;const r=new b(e.x()+n.x(),e.y()+n.y()),o=new b(r.getX()+n.width(),r.getY()+n.height()),a=new Mi(r,o),s=i.getText(),l=s.meta,c=a.quantify(t,q(l.textExpr));s.setText(U(l.textExpr,c)),l.quantification=c}#_o(e){const t=e.getRound(),n=t.max.getX()-t.min.getX(),i=t.max.getY()-t.min.getY();return new(ln().Rect)({x:t.min.getX(),y:t.min.getY(),width:n,height:i,fill:"grey",strokeWidth:0,strokeScaleEnabled:!1,opacity:.3,name:"shadow"})}},RoiFactory:Pi,RulerFactory:class{getGroupName(){return"ruler-group"}getNPoints(){return 2}getTimeout(){return 0}isFactoryGroup(e){return this.getGroupName()===e.name()}create(e,t,n){const i=new pi(e[0],e[1]),r=new(ln().Line)({points:[i.getBegin().getX(),i.getBegin().getY(),i.getEnd().getX(),i.getEnd().getY()],stroke:t.getLineColour(),strokeWidth:t.getStrokeWidth(),strokeScaleEnabled:!1,name:"shape"}),o=t.applyZoomScale(10).x,a=yi(i,e[0],o),s=new(ln().Line)({points:[a.getBegin().getX(),a.getBegin().getY(),a.getEnd().getX(),a.getEnd().getY()],stroke:t.getLineColour(),strokeWidth:t.getStrokeWidth(),strokeScaleEnabled:!1,name:"shape-tick0"}),l=yi(i,e[1],o),c=new(ln().Line)({points:[l.getBegin().getX(),l.getBegin().getY(),l.getEnd().getX(),l.getEnd().getY()],stroke:t.getLineColour(),strokeWidth:t.getStrokeWidth(),strokeScaleEnabled:!1,name:"shape-tick1"});r.hitFunc((function(e){e.beginPath(),e.moveTo(a.getBegin().getX(),a.getBegin().getY()),e.lineTo(a.getEnd().getX(),a.getEnd().getY()),e.lineTo(l.getEnd().getX(),l.getEnd().getY()),e.lineTo(l.getBegin().getX(),l.getBegin().getY()),e.closePath(),e.fillStrokeShape(r)}));const u=new(ln().Text)({fontSize:t.getFontSize(),fontFamily:t.getFontFamily(),fill:t.getLineColour(),padding:t.getTextPadding(),shadowColor:t.getShadowLineColour(),shadowOffset:t.getShadowOffset(),name:"text"});let d="";const h=n.getModality();d=void 0!==Li.labelText.ruler[h]?Li.labelText.ruler[h]:Li.labelText.ruler["*"];const S=i.quantify(n);u.setText(U(d,S)),u.meta={textExpr:d,quantification:S};const g=i.getBegin().getX()>i.getEnd().getX()?0:-1,m=i.getBegin().getY()>i.getEnd().getY()?-1:0,p=new(ln().Label)({x:i.getEnd().getX()+g*t.applyZoomScale(u.width()).x,y:i.getEnd().getY()+m*t.applyZoomScale(15).y,scale:t.applyZoomScale(1),visible:0!==d.length,name:"label"});p.add(u),p.add(new(ln().Tag)({fill:t.getLineColour(),opacity:t.getTagOpacity()}));const f=new(ln().Group);return f.name(this.getGroupName()),f.add(p),f.add(s),f.add(c),f.add(r),f.visible(!0),f}getAnchors(e,t){const n=e.points(),i=[];return i.push(Di(n[0]+e.x(),n[1]+e.y(),"begin",t)),i.push(Di(n[2]+e.x(),n[3]+e.y(),"end",t)),i}update(e,t,n){const i=e.getParent(),r=i.getChildren((function(e){return"shape"===e.name()}))[0];if(!(r instanceof ln().Line))return;const o=i.getChildren((function(e){return"shape-tick0"===e.name()}))[0];if(!(o instanceof ln().Line))return;const a=i.getChildren((function(e){return"shape-tick1"===e.name()}))[0];if(!(a instanceof ln().Line))return;const s=i.getChildren((function(e){return"label"===e.name()}))[0];if(!(s instanceof ln().Label))return;const l=i.getChildren((function(e){return"begin"===e.id()}))[0],c=i.getChildren((function(e){return"end"===e.id()}))[0];switch(e.id()){case"begin":l.x(e.x()),l.y(e.y());break;case"end":c.x(e.x()),c.y(e.y())}const u=l.x()-r.x(),d=l.y()-r.y(),h=c.x()-r.x(),S=c.y()-r.y();r.points([u,d,h,S]);const g=new b(l.x(),l.y()),m=new b(c.x(),c.y()),p=new pi(g,m),f=t.applyZoomScale(10).x,y=new b(u,d),D=new b(h,S),C=yi(p,y,f);o.points([C.getBegin().getX(),C.getBegin().getY(),C.getEnd().getX(),C.getEnd().getY()]);const v=yi(p,D,f);a.points([v.getBegin().getX(),v.getBegin().getY(),v.getEnd().getX(),v.getEnd().getY()]),r.hitFunc((function(e){e.beginPath(),e.moveTo(C.getBegin().getX(),C.getBegin().getY()),e.lineTo(C.getEnd().getX(),C.getEnd().getY()),e.lineTo(v.getEnd().getX(),v.getEnd().getY()),e.lineTo(v.getBegin().getX(),v.getBegin().getY()),e.closePath(),e.fillStrokeShape(r)}));const I=s.getText(),T=I.meta,L=p.quantify(n);I.setText(U(T.textExpr,L)),T.quantification=L;const P=p.getBegin().getX()>p.getEnd().getX()?0:-1,w=p.getBegin().getY()>p.getEnd().getY()?-1:0,O={x:p.getEnd().getX()+P*t.applyZoomScale(I.width()).x,y:p.getEnd().getY()+w*t.applyZoomScale(15).y};s.position(O)}}},filter:{Threshold:class{#Ni;constructor(e){this.#Ni=e}#Dr=new Qi;#Ko=!0;#Oe=new He;activate(e){e&&(this.#Ko=!0)}init(){}run(e){if(void 0===e.dataId)throw new Error("No dataId to run threshod filter on.");this.#Dr.setMin(e.min),this.#Dr.setMax(e.max),this.#Ko&&(this.#Dr.setOriginalImage(this.#Ni.getImage(e.dataId)),this.#Ko=!1);const t=new Vi(this.#Dr,e.dataId,this.#Ni);t.onExecute=this.#Re,t.onUndo=this.#Re,t.execute(),this.#Ni.addToUndoStack(t)}addEventListener(e,t){this.#Oe.add(e,t)}removeEventListener(e,t){this.#Oe.remove(e,t)}#Re=e=>{this.#Oe.fireEvent(e)}},Sobel:class{#Ni;constructor(e){this.#Ni=e}#Oe=new He;activate(e){}init(){}run(e){if(void 0===e.dataId)throw new Error("No dataId to run sobel filter on.");const t=new Ni;t.setOriginalImage(this.#Ni.getImage(e.dataId));const n=new Vi(t,e.dataId,this.#Ni);n.onExecute=this.#Re,n.onUndo=this.#Re,n.execute(),this.#Ni.addToUndoStack(n)}addEventListener(e,t){this.#Oe.add(e,t)}removeEventListener(e,t){this.#Oe.remove(e,t)}#Re=e=>{this.#Oe.fireEvent(e)}},Sharpen:class{#Ni;constructor(e){this.#Ni=e}#Oe=new He;activate(e){}init(){}run(e){if(void 0===e.dataId)throw new Error("No dataId to run sharpen filter on.");const t=new Bi;t.setOriginalImage(this.#Ni.getImage(e.dataId));const n=new Vi(t,e.dataId,this.#Ni);n.onExecute=this.#Re,n.onUndo=this.#Re,n.execute(),this.#Ni.addToUndoStack(n)}addEventListener(e,t){this.#Oe.add(e,t)}removeEventListener(e,t){this.#Oe.remove(e,t)}#Re=e=>{this.#Oe.fireEvent(e)}}}};class zi{divId;orientation;colourMap;opacity;wlPresetName;windowCenter;windowWidth;constructor(e){this.divId=e}}class Wi{options;constructor(e){this.options=e}}class Yi{dataViewConfigs;tools;binders;viewOnFirstLoadItem;defaultCharacterSet;overlayConfig;rootDocument;constructor(e){this.dataViewConfigs=e}}class Xi{#di=null;#Jo=null;#$o=null;#ea=null;#ta=null;#na=null;#Yt=new cn;#ia={};#Oe=new He;getImage(e){let t;return void 0!==this.#Jo.get(e)&&(t=this.#Jo.get(e).image),t}setImage(e,t){this.#Jo.setImage(e,t)}addNewImage(e,t,n){const i=this.#Jo.getNextDataId();return this.#Re({type:"loadstart",loadtype:"image",source:n,dataid:i}),this.#Jo.addNew(i,e,t),this.#Re({type:"loaditem",loadtype:"image",data:t,source:n,dataid:i,isfirstitem:!0}),this.#di.viewOnFirstLoadItem&&this.render(i),this.#Re({type:"load",loadtype:"image",source:n,dataid:i}),this.#Re({type:"loadend",loadtype:"image",source:n,dataid:i}),i}getMetaData(e){let t;return void 0!==this.#Jo.get(e)&&(t=this.#Jo.get(e).meta),t}getDataIds(){return this.#Jo.getDataIds()}getDataIdsFromSopUids(e){return this.#Jo.getDataIdsFromSopUids(e)}canScroll(){return this.#ta.getActiveLayerGroup().getActiveViewLayer().getViewController().canScroll()}canWindowLevel(){return this.#ta.getActiveLayerGroup().getActiveViewLayer().getViewController().canWindowLevel()}getAddedScale(){return this.#ta.getActiveLayerGroup().getAddedScale()}getBaseScale(){return this.#ta.getActiveLayerGroup().getBaseScale()}getOffset(){return this.#ta.getActiveLayerGroup().getOffset()}getToolboxController(){return this.#$o}getActiveLayerGroup(){return this.#ta.getActiveLayerGroup()}setActiveLayerGroup(e){this.#ta.setActiveLayerGroup(e)}getViewLayersByDataId(e){return this.#ta.getViewLayersByDataId(e)}getDrawLayersByDataId(e){return this.#ta.getDrawLayersByDataId(e)}getLayerGroupByDivId(e){return this.#ta.getLayerGroupByDivId(e)}getNumberOfLayerGroups(){return this.#ta.getNumberOfLayerGroups()}getStyle(){return this.#Yt}addToUndoStack=e=>{null!==this.#na&&this.#na.add(e)};init(e){if(this.#di=e,void 0===this.#di.viewOnFirstLoadItem&&(this.#di.viewOnFirstLoadItem=!0),void 0===this.#di.dataViewConfigs&&(this.#di.dataViewConfigs={}),void 0===this.#di.rootDocument&&(this.#di.rootDocument=document),this.#na=new Qn,this.#na.addEventListener("undoadd",this.#Re),this.#na.addEventListener("undo",this.#Re),this.#na.addEventListener("redo",this.#Re),void 0!==this.#di.tools){const e={},t=Object.keys(this.#di.tools);for(let n=0;n{const t=this.#Jo.getNextDataId();0!==e.length?this.#ea.loadFiles(e,t):i.warn("Ignoring empty input file list.")};loadURLs=(e,t)=>{const n=this.#Jo.getNextDataId();0!==e.length?this.#ea.loadURLs(e,n,t):i.warn("Ignoring empty input url list.")};loadFromUri=(e,t)=>{const n=function(e){const t=Mn(e);return 0===Object.keys(t).length?null:t.query}(e),r=()=>{this.removeEventListener("loadend",r),this.loadURLs([n.state])};n&&void 0!==n.input&&(void 0!==n.state&&this.addEventListener("loadend",r),function(e,t,n){e.type&&"manifest"===e.type?function(e,t){let n="";"/"===e.input[0]&&(n=window.location.protocol+"//"+window.location.host),n+=e.input;const r=new XMLHttpRequest;r.open("GET",decodeURIComponent(n),!0),r.responseType="document",r.onload=function(n){t(function(e,t){const n=[],r=e.getElementsByTagName("wado_query")[0].getAttribute("wadoURL")+"?requestType=WADO&contentType=application/dicom&",o=e.getElementsByTagName("Patient");o.length>1&&i.warn("More than one patient, loading first one.");const a=o[0].getElementsByTagName("Study");a.length>1&&i.warn("More than one study, loading first one.");const s=a[0].getAttribute("StudyInstanceUID"),l=a[0].getElementsByTagName("Series");l.length>1&&i.warn("More than one series, loading first one.");const c=l[0].getAttribute("SeriesInstanceUID"),u=l[0].getElementsByTagName("Instance");let d=u.length;t{const t=this.#Jo.getNextDataId();this.#ea.loadImageObject(e,t)};abortAllLoads(){const e=this.#ea.getLoadingDataIds();for(const t of e)this.abortLoad(t)}abortLoad(e){this.#ea.abort(e),this.#Jo.remove(e),this.#ta.removeLayersByDataId(e)}fitToContainer(){this.#ta.fitToContainer()}initWLDisplay(){this.#ta.getActiveLayerGroup().getActiveViewLayer().getViewController().initialise()}setImageSmoothing(e){this.#ta.setImageSmoothing(e),this.#ta.draw()}getViewConfigs(e,t){if(null===this.#di.dataViewConfigs||void 0===this.#di.dataViewConfigs)throw new Error("No available data view configuration");let n=[];return void 0!==this.#di.dataViewConfigs[e]?n=this.#di.dataViewConfigs[e]:t||void 0===this.#di.dataViewConfigs["*"]||(n=this.#di.dataViewConfigs["*"]),n}getViewConfig(e,t,n){return this.getViewConfigs(e,n).find((function(e){return e.divId===t}))}getDataViewConfigs(){return this.#di.dataViewConfigs}setDataViewConfigs(e){this.#ta.empty(),this.#di.dataViewConfigs=e,this.#da(e)}addDataViewConfig(e,t){const n=this.#di.dataViewConfigs;if(void 0===n[e]&&(n[e]=[]),-1!==n[e].findIndex((function(e){return e.divId===t.divId})))throw new Error("Duplicate view config for data "+e+" and div "+t.divId);this.#di.dataViewConfigs[e].push(t),void 0===this.#ta.getLayerGroupByDivId(t.divId)&&this.#ha(t),this.render(e,[t])}removeDataViewConfig(e,t){const n=this.#di.dataViewConfigs;if(void 0===n[e])return;const i=n[e].findIndex((function(e){return e.divId===t}));if(-1!==i&&(n[e].splice(i,1),0===n[e].length&&delete n[e],void 0!==this.#Jo.get(e))){const n=this.#ta.getLayerGroupByDivId(t);if(void 0!==n){const t=n.getViewLayersByDataId(e);if(1!==t.length)throw new Error("Expected one view layer, got "+t.length);n.removeLayer(t[0]);const i=n.getDrawLayersByDataId(e);if(1!==i.length)throw new Error("Expected one draw layer, got "+i.length);n.removeLayer(i[0]),0===n.getNumberOfLayers()&&this.#ta.removeLayerGroup(n)}}}updateDataViewConfig(e,t,n){const i=this.#di.dataViewConfigs;if(void 0===i[e])throw new Error("No config for dataId: "+e);const r=i[e].findIndex((function(e){return e.divId===t}));if(-1===r)throw new Error("No config for dataId: "+e+" and divId: "+t);const o=i[e][r];for(const e in n)o[e]=n[e];const a=this.#ta.getLayerGroupByDivId(o.divId);if(void 0!==a){const t=a.getViewLayersByDataId(e);if(1!==t.length)throw new Error("Expected one view layer, got "+t.length);a.removeLayer(t[0]);const n=a.getDrawLayersByDataId(e);if(1!==n.length)throw new Error("Expected one draw layer, got "+n.length);a.removeLayer(n[0])}this.render(e,[o])}#da(e){const t=Object.keys(e),n=[];for(let i=0;i{this.fitToContainer()};onKeydown=e=>{this.#Re(e)};defaultOnKeydown=e=>{if(e.ctrlKey)if(e.shiftKey){const t=this.#ta.getActiveLayerGroup(),n=t.getActiveViewLayer().getViewController();"ArrowLeft"===e.key?n.moreThanOne(3)&&n.decrementIndex(3):"ArrowUp"===e.key?t.canScroll()&&n.incrementScrollIndex():"ArrowRight"===e.key?t.moreThanOne(3)&&n.incrementIndex(3):"ArrowDown"===e.key&&t.canScroll()&&n.decrementScrollIndex()}else if("y"===e.key)this.#na.redo();else if("z"===e.key)this.#na.undo();else if(" "===e.key)for(let e=0;e{this.#Oe.fireEvent(e)};#ra=e=>{void 0!==this.#di.overlayConfig&&(this.#ia[e.dataid]=new hi(this,e.dataid,this.#di.overlayConfig)),e.type="loadstart",this.#Re(e)};#oa=e=>{e.type="loadprogress",this.#Re(e)};#aa=e=>{void 0===e.data&&i.error("Missing loaditem event data."),void 0===e.loadtype&&i.error("Missing loaditem event load type.");const t=e.isfirstitem;let n=null;"image"===e.loadtype?(t?this.#Jo.addNew(e.dataid,e.data.image,e.data.info):this.#Jo.update(e.dataid,e.data.image,e.data.info),n=e.data.info):"state"===e.loadtype&&(this.applyJsonState(e.data),n="state"),this.#Re({type:"loaditem",data:n,source:e.source,loadtype:e.loadtype,dataid:e.dataid,isfirstitem:e.isfirstitem,warn:e.warn}),void 0!==this.#ia&&void 0!==this.#ia[e.dataid]&&this.#ia[e.dataid].addItemMeta(n),"image"===e.loadtype&&0!==this.getViewConfigs(e.dataid).length&&t&&this.#di.viewOnFirstLoadItem&&this.render(e.dataid)};#sa=e=>{e.type="load",this.#Re(e)};#la=e=>{e.type="loadend",this.#Re(e)};#ca=e=>{void 0===e.type&&(e.type="error"),this.#Re(e)};#ua=e=>{void 0===e.type&&(e.type="abort"),this.#Re(e)};#Sa(e){e.addEventListener("zoomchange",this.#Re),e.addEventListener("offsetchange",this.#Re),e.addEventListener("renderstart",this.#Re),e.addEventListener("renderend",this.#Re);for(let t=0;t{const t=Ln(e.srclayerid).groupDivId,n=this.getViewConfig(e.dataid,t,!0);void 0!==n&&(n.windowCenter=void 0,n.windowWidth=void 0,n.wlPresetName=void 0,2===e.value.length&&(n.windowCenter=e.value[0],n.windowWidth=e.value[1]),3===e.value.length&&(n.wlPresetName=e.value[2]))})),e.addEventListener("opacitychange",(e=>{const t=Ln(e.srclayerid).groupDivId,n=this.getViewConfig(e.dataid,t,!0);void 0!==n&&(n.opacity=e.value[0])})),e.addEventListener("colourmapchange",(e=>{const t=Ln(e.srclayerid).groupDivId,n=this.getViewConfig(e.dataid,t,!0);void 0!==n&&(n.colourMap=e.value[0])}))}#ga(e,t){const n=this.#Jo.get(e);if(!n)throw new Error("Cannot initialise layer with missing data, id: "+e);const i=this.#ta.getLayerGroupByDivId(t.divId);if(!i)throw new Error("Cannot initialise layer with missing group, id: "+t.divId);const o=n.image.getGeometry();this.#ta.unbindLayerGroups();const a=(new Xt).create(n.meta,n.image),s=function(e,t){let n=O();return void 0!==t&&(n=e.asOneAndZeros().getInverse().multiply(t)),n.getAbs()}(o.getOrientation(),function(e){let t;return e===De.Axial?t=O():e===De.Coronal?t=ye():e===De.Sagittal&&(t=new w([0,0,-1,1,0,0,0,-1,0])),t}(t.orientation));a.setOrientation(s),"SEG"===n.image.getMeta().Modality&&a.setAlphaFunction((function(e){return 0===e[0]&&0===e[1]&&0===e[2]?0:255}));const l=0===i.getNumberOfLayers();let c=1;void 0!==t.opacity?c=t.opacity:l||(c=.5);const u=i.addViewLayer();u.setView(a,e);const d=o.getSize(s).get2D(),h=o.getSpacing(s).get2D();u.initialise(d,h,c);const S=u.getViewController();if(void 0!==t.wlPresetName)S.setWindowLevelPreset(t.wlPresetName);else if(void 0!==t.windowCenter&&void 0!==t.windowWidth){const e=new r(t.windowCenter,t.windowWidth);S.setWindowLevel(e)}let g;void 0!==t.colourMap?S.setColourMap(t.colourMap):l||("PT"===n.image.getMeta().Modality?S.setColourMap("hot"):S.setColourMap("rainbow")),this.#Jo.addEventListener("imageset",u.onimageset),this.#$o&&this.#$o.hasTool("Draw")&&(g=i.addDrawLayer(),g.initialise(d,h,e),g.setPlaneHelper(u.getViewController().getPlaneHelper()));const m=[S.getCurrentIndex().getValues(),S.getCurrentPosition().getValues()];i.updateLayersToPositionChange({value:m,srclayerid:u.getId()}),this.#ta.fitToContainer(),u.setOffset(i.getOffset());const p=this.#ma(o.getOrientation(),t.orientation);if(p.offset.x&&(u.addFlipOffsetX(),void 0!==g&&g.addFlipOffsetX()),p.offset.y&&(u.addFlipOffsetY(),void 0!==g&&g.addFlipOffsetY()),p.scale.x&&(u.flipScaleX(),void 0!==g&&g.flipScaleX()),p.scale.y&&(u.flipScaleY(),void 0!==g&&g.flipScaleY()),p.scale.z&&(u.flipScaleZ(),void 0!==g&&g.flipScaleZ()),l)u.setScale(i.getScale());else{const e=i.getBaseViewLayer();u.initScale(i.getScale(),e.getAbsoluteZoomOffset())}void 0!==g&&g.setScale(i.getScale()),this.#ta.bindLayerGroups(),this.#$o&&this.#$o.bindLayerGroup(i,u),l&&this.#$o&&this.#$o.init()}#ma(e,t){const n=Ce(e.asOneAndZeros());if(void 0===n)throw new Error("Unsupported undefined orientation code");const r=void 0===t,o=!r&&t===De.Axial,a=!r&&t===De.Coronal,s=!r&&t===De.Sagittal,l={x:!1,y:!1},c={x:!1,y:!1,z:!1};return"LPS"===n?(a||s)&&(c.z=!0,l.y=!0):"LAI"===n?r||o?l.y=!0:a?c.z=!0:s&&(c.z=!0,l.x=!0):"RPI"===n?r||o?l.x=!0:a?(c.z=!0,l.x=!0):s&&(c.z=!0):"RAS"===n?(l.x=!0,l.y=!0,(a||s)&&(c.z=!0)):"LSA"===n?(l.y=!0,r||a?c.z=!0:o?c.y=!0:s&&(l.x=!0,c.y=!0,c.z=!0)):"RSP"===n?r||a?(l.x=!0,l.y=!0,c.x=!0,c.z=!0):o?(l.x=!0,c.x=!0):s&&(l.y=!0,c.z=!0):"RIA"===n?(l.x=!0,r||a?c.x=!0:o?(l.y=!0,c.x=!0,c.y=!0):s&&(c.y=!0)):"PSL"===n?(c.z=!0,(r||s||a)&&(l.y=!0)):"PIR"===n?(c.z=!0,(o||a)&&(l.x=!0)):"ASR"===n?(l.x=!0,l.y=!0,(r||s||a)&&(c.z=!0)):"AIL"===n?r||s?(l.x=!0,c.z=!0):o?l.y=!0:a&&(c.z=!0):i.warn("Unsupported orientation code: "+n+", display could be incorrect"),{scale:c,offset:l}}}class ji{#Io;#pa;constructor(e){this.#Io=e;const t=e.getMeta();void 0===t.custom&&(t.custom={}),void 0===t.custom.segments&&(t.custom.segments=[]),this.#pa=t.custom.segments}#fa(e){return this.#pa.findIndex((function(t){return t.number===e}))}hasSegment(e){return-1!==this.#fa(e)}maskHasSegments(e){const t=[],n=[];for(let r=0;r