@file-viewer/renderer-dicom 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,95 @@
1
+ import * as dicomParser from 'dicom-parser';
2
+ const MEBIBYTE = 1024 * 1024;
3
+ export const DEFAULT_DICOM_LIMITS = Object.freeze({
4
+ maxSourceBytes: 64 * MEBIBYTE,
5
+ maxFrames: 256,
6
+ maxFramePixels: 16000000,
7
+ maxTotalPixels: 48000000,
8
+ });
9
+ /** Transfer syntaxes accepted by this tested MVP (intentionally narrower than the loader). */
10
+ export const SUPPORTED_DICOM_TRANSFER_SYNTAXES = new Set([
11
+ '1.2.840.10008.1.2',
12
+ '1.2.840.10008.1.2.1',
13
+ '1.2.840.10008.1.2.4.70',
14
+ '1.2.840.10008.1.2.4.80',
15
+ '1.2.840.10008.1.2.4.90',
16
+ ]);
17
+ const finitePositiveInteger = (value, label) => {
18
+ const number = typeof value === 'number' ? value : Number.parseInt(String(value || ''), 10);
19
+ if (!Number.isSafeInteger(number) || number < 1) {
20
+ throw new Error(`DICOM ${label} must be a positive integer.`);
21
+ }
22
+ return number;
23
+ };
24
+ const finiteNumber = (value, fallback) => {
25
+ const number = typeof value === 'number' ? value : Number.parseFloat(String(value || ''));
26
+ return Number.isFinite(number) ? number : fallback;
27
+ };
28
+ const resolveLimits = (limits) => {
29
+ const resolved = { ...DEFAULT_DICOM_LIMITS };
30
+ for (const key of Object.keys(DEFAULT_DICOM_LIMITS)) {
31
+ if ((limits === null || limits === void 0 ? void 0 : limits[key]) === undefined)
32
+ continue;
33
+ resolved[key] = finitePositiveInteger(limits[key], key);
34
+ }
35
+ return resolved;
36
+ };
37
+ const hasPart10Signature = (buffer) => {
38
+ if (buffer.byteLength < 132)
39
+ return false;
40
+ const bytes = new Uint8Array(buffer, 128, 4);
41
+ return bytes[0] === 0x44 && bytes[1] === 0x49 && bytes[2] === 0x43 && bytes[3] === 0x4d;
42
+ };
43
+ export const inspectDicomPart10 = (buffer, limitsInput) => {
44
+ const limits = resolveLimits(limitsInput);
45
+ if (buffer.byteLength < 132 || buffer.byteLength > limits.maxSourceBytes) {
46
+ throw new Error(`DICOM source size must be between 132 bytes and ${limits.maxSourceBytes} bytes.`);
47
+ }
48
+ if (!hasPart10Signature(buffer)) {
49
+ throw new Error('The selected file is not a DICOM Part 10 file (missing DICM signature).');
50
+ }
51
+ let dataSet;
52
+ try {
53
+ dataSet = dicomParser.parseDicom(new Uint8Array(buffer), { untilTag: 'x7fe00010' });
54
+ }
55
+ catch {
56
+ throw new Error('Unable to parse the DICOM Part 10 header.');
57
+ }
58
+ const transferSyntax = String(dataSet.string('x00020010') || '').trim();
59
+ if (!SUPPORTED_DICOM_TRANSFER_SYNTAXES.has(transferSyntax)) {
60
+ throw new Error(`DICOM transfer syntax ${transferSyntax || '(missing)'} is not supported by this preview renderer.`);
61
+ }
62
+ if (!dataSet.elements.x7fe00010) {
63
+ throw new Error('The DICOM file has no pixel data element.');
64
+ }
65
+ const rows = finitePositiveInteger(dataSet.uint16('x00280010'), 'rows');
66
+ const columns = finitePositiveInteger(dataSet.uint16('x00280011'), 'columns');
67
+ const samplesPerPixel = finitePositiveInteger(dataSet.uint16('x00280002') || 1, 'samples per pixel');
68
+ const frameCount = finitePositiveInteger(dataSet.intString('x00280008') || 1, 'frame count');
69
+ if (frameCount > limits.maxFrames) {
70
+ throw new Error(`DICOM frame count ${frameCount} exceeds the configured limit ${limits.maxFrames}.`);
71
+ }
72
+ if (rows > limits.maxFramePixels / columns / samplesPerPixel) {
73
+ throw new Error(`DICOM frame dimensions exceed the configured ${limits.maxFramePixels}-pixel limit.`);
74
+ }
75
+ const framePixels = rows * columns * samplesPerPixel;
76
+ if (framePixels > limits.maxTotalPixels / frameCount) {
77
+ throw new Error(`DICOM decoded pixels exceed the configured ${limits.maxTotalPixels}-pixel total limit.`);
78
+ }
79
+ const bitsAllocated = finitePositiveInteger(dataSet.uint16('x00280100'), 'bits allocated');
80
+ if (![1, 8, 16, 32].includes(bitsAllocated)) {
81
+ throw new Error(`DICOM Bits Allocated value ${bitsAllocated} is not supported.`);
82
+ }
83
+ return {
84
+ bitsAllocated,
85
+ columns,
86
+ frameCount,
87
+ modality: String(dataSet.string('x00080060') || 'OT').trim().slice(0, 16),
88
+ photometricInterpretation: String(dataSet.string('x00280004') || '').trim().slice(0, 32),
89
+ rows,
90
+ samplesPerPixel,
91
+ transferSyntax,
92
+ windowCenter: finiteNumber(dataSet.floatString('x00281050', 0), (2 ** bitsAllocated) / 2),
93
+ windowWidth: Math.max(1, finiteNumber(dataSet.floatString('x00281051', 0), 2 ** bitsAllocated)),
94
+ };
95
+ };
@@ -0,0 +1,94 @@
1
+ {
2
+ "$schema": "../../../ecosystem/capability-manifest.schema.json",
3
+ "schemaVersion": 1,
4
+ "id": "dicom",
5
+ "packageName": "@file-viewer/renderer-dicom",
6
+ "activation": {
7
+ "kind": "renderer-export",
8
+ "import": "@file-viewer/renderer-dicom",
9
+ "export": "dicomRenderer"
10
+ },
11
+ "rendererIds": [
12
+ "dicom"
13
+ ],
14
+ "formats": [
15
+ "dcm",
16
+ "dicom"
17
+ ],
18
+ "assets": {
19
+ "rendererIds": []
20
+ },
21
+ "license": {
22
+ "spdx": "Apache-2.0",
23
+ "policy": "permissive",
24
+ "notices": [
25
+ {
26
+ "packageName": "@cornerstonejs/core",
27
+ "spdx": "MIT",
28
+ "notice": "Pinned at 5.8.2; full closure and packaged license filenames are recorded in THIRD_PARTY_LICENSES.json."
29
+ },
30
+ {
31
+ "packageName": "@cornerstonejs/dicom-image-loader",
32
+ "spdx": "MIT",
33
+ "notice": "Pinned at 5.8.2. JavaScript codec wrapper terms and the separately tracked native libraries statically linked into their WebAssembly are recorded in THIRD_PARTY_LICENSES.json."
34
+ },
35
+ {
36
+ "packageName": "CharLS native codec",
37
+ "spdx": "BSD-3-Clause",
38
+ "notice": "Source 38d95d00671f4cddfa61f3f51eaf81b8bac34543; linked target charls; exact license is packaged under third-party/native-codecs/charls."
39
+ },
40
+ {
41
+ "packageName": "libjpeg-turbo native codec",
42
+ "spdx": "IJG AND BSD-3-Clause AND Zlib",
43
+ "notice": "Source dc4a93fab38b42d29b89a533409e012570180e28; linked target turbojpeg-static. This software is based in part on the work of the Independent JPEG Group. LICENSE.md and README.ijg are packaged unmodified."
44
+ },
45
+ {
46
+ "packageName": "OpenJPEG native codec",
47
+ "spdx": "BSD-2-Clause",
48
+ "notice": "Source 2d606701e8b7aa83f657d113c3367508e99bd12b; linked target openjp2; exact license is packaged under third-party/native-codecs/openjpeg."
49
+ },
50
+ {
51
+ "packageName": "OpenJPH native codec",
52
+ "spdx": "BSD-2-Clause",
53
+ "notice": "Source e01c7b7f9e7ecbb15cf13bb45661c9a41ab7fec6; linked target openjphsimd; exact license is packaged under third-party/native-codecs/openjph."
54
+ },
55
+ {
56
+ "packageName": "@cornerstonejs/metadata",
57
+ "spdx": "MIT",
58
+ "notice": "Pinned at 5.8.2; used for owner-specific DICOM metadata cleanup."
59
+ },
60
+ {
61
+ "packageName": "dicom-parser",
62
+ "spdx": "MIT",
63
+ "notice": "Pinned at 1.8.21; used for bounded Part 10 header inspection before runtime initialization."
64
+ },
65
+ {
66
+ "packageName": "@kitware/vtk.js",
67
+ "spdx": "BSD-3-Clause",
68
+ "notice": "Transitive Cornerstone runtime dependency pinned at 36.4.1."
69
+ },
70
+ {
71
+ "packageName": "caniuse-lite",
72
+ "spdx": "CC-BY-4.0",
73
+ "notice": "Version 1.0.30001810 data by Ben Briggs and contributors; source https://github.com/browserslist/caniuse-lite; unmodified by this renderer."
74
+ },
75
+ {
76
+ "packageName": "pako",
77
+ "spdx": "(MIT AND Zlib)",
78
+ "notice": "Versions 1.0.11 and 2.1.0 contain zlib-derived code by Jean-loup Gailly and Mark Adler."
79
+ },
80
+ {
81
+ "packageName": "argparse",
82
+ "spdx": "Python-2.0",
83
+ "notice": "Version 2.0.1 retains the Python Software Foundation license in its installed LICENSE file."
84
+ },
85
+ {
86
+ "packageName": "spark-md5",
87
+ "spdx": "(WTFPL OR MIT)",
88
+ "notice": "Version 3.0.2 retains its upstream license file."
89
+ }
90
+ ]
91
+ },
92
+ "weight": "heavy",
93
+ "profiles": []
94
+ }
package/package.json ADDED
@@ -0,0 +1,83 @@
1
+ {
2
+ "name": "@file-viewer/renderer-dicom",
3
+ "version": "3.0.0",
4
+ "private": false,
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "description": "Opt-in local DICOM Part 10 renderer plugin for File Viewer, powered by modular Cornerstone3D packages.",
8
+ "keywords": [
9
+ "file-viewer",
10
+ "renderer",
11
+ "dicom",
12
+ "medical-imaging",
13
+ "cornerstone",
14
+ "document-preview",
15
+ "self-hosted"
16
+ ],
17
+ "publishConfig": {
18
+ "access": "public",
19
+ "registry": "https://registry.npmjs.org/"
20
+ },
21
+ "author": {
22
+ "name": "Yu Wang",
23
+ "email": "admin@flyfish.dev"
24
+ },
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/flyfish-dev/file-viewer.git",
28
+ "directory": "packages/renderers/dicom"
29
+ },
30
+ "homepage": "https://doc.file-viewer.app/guide/on-demand-renderers",
31
+ "bugs": {
32
+ "url": "https://github.com/flyfish-dev/file-viewer/issues"
33
+ },
34
+ "funding": {
35
+ "type": "individual",
36
+ "url": "https://dev.flyfish.group/donate?source=npm"
37
+ },
38
+ "fileViewer": {
39
+ "capabilityManifest": "file-viewer.capability.json"
40
+ },
41
+ "main": "./dist/index.js",
42
+ "module": "./dist/index.js",
43
+ "types": "./dist/index.d.ts",
44
+ "exports": {
45
+ ".": {
46
+ "types": "./dist/index.d.ts",
47
+ "import": "./dist/index.js",
48
+ "default": "./dist/index.js"
49
+ },
50
+ "./inspect": {
51
+ "types": "./dist/inspect.d.ts",
52
+ "import": "./dist/inspect.js",
53
+ "default": "./dist/inspect.js"
54
+ },
55
+ "./capability": "./file-viewer.capability.json",
56
+ "./package.json": "./package.json"
57
+ },
58
+ "files": [
59
+ "dist",
60
+ "README.md",
61
+ "README.en.md",
62
+ "file-viewer.capability.json",
63
+ "THIRD_PARTY_NOTICES.md",
64
+ "THIRD_PARTY_LICENSES.json",
65
+ "third-party/native-codecs",
66
+ "LICENSE"
67
+ ],
68
+ "dependencies": {
69
+ "@cornerstonejs/core": "5.8.2",
70
+ "@cornerstonejs/dicom-image-loader": "5.8.2",
71
+ "@cornerstonejs/metadata": "5.8.2",
72
+ "@file-viewer/core": "3.0.0",
73
+ "dicom-parser": "1.8.21"
74
+ },
75
+ "devDependencies": {
76
+ "typescript": "^6.0.3"
77
+ },
78
+ "license": "Apache-2.0",
79
+ "scripts": {
80
+ "build": "tsc -b tsconfig.json",
81
+ "type-check": "tsc -b tsconfig.json"
82
+ }
83
+ }
@@ -0,0 +1,29 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2007, Jan de Vaan and Victor Derks
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ 3. Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,132 @@
1
+ libjpeg-turbo Licenses
2
+ ======================
3
+
4
+ libjpeg-turbo is covered by three compatible BSD-style open source licenses:
5
+
6
+ - The IJG (Independent JPEG Group) License, which is listed in
7
+ [README.ijg](README.ijg)
8
+
9
+ This license applies to the libjpeg API library and associated programs
10
+ (any code inherited from libjpeg, and any modifications to that code.)
11
+
12
+ - The Modified (3-clause) BSD License, which is listed below
13
+
14
+ This license covers the TurboJPEG API library and associated programs, as
15
+ well as the build system.
16
+
17
+ - The [zlib License](https://opensource.org/licenses/Zlib)
18
+
19
+ This license is a subset of the other two, and it covers the libjpeg-turbo
20
+ SIMD extensions.
21
+
22
+
23
+ Complying with the libjpeg-turbo Licenses
24
+ =========================================
25
+
26
+ This section provides a roll-up of the libjpeg-turbo licensing terms, to the
27
+ best of our understanding.
28
+
29
+ 1. If you are distributing a modified version of the libjpeg-turbo source,
30
+ then:
31
+
32
+ 1. You cannot alter or remove any existing copyright or license notices
33
+ from the source.
34
+
35
+ **Origin**
36
+ - Clause 1 of the IJG License
37
+ - Clause 1 of the Modified BSD License
38
+ - Clauses 1 and 3 of the zlib License
39
+
40
+ 2. You must add your own copyright notice to the header of each source
41
+ file you modified, so others can tell that you modified that file (if
42
+ there is not an existing copyright header in that file, then you can
43
+ simply add a notice stating that you modified the file.)
44
+
45
+ **Origin**
46
+ - Clause 1 of the IJG License
47
+ - Clause 2 of the zlib License
48
+
49
+ 3. You must include the IJG README file, and you must not alter any of the
50
+ copyright or license text in that file.
51
+
52
+ **Origin**
53
+ - Clause 1 of the IJG License
54
+
55
+ 2. If you are distributing only libjpeg-turbo binaries without the source, or
56
+ if you are distributing an application that statically links with
57
+ libjpeg-turbo, then:
58
+
59
+ 1. Your product documentation must include a message stating:
60
+
61
+ This software is based in part on the work of the Independent JPEG
62
+ Group.
63
+
64
+ **Origin**
65
+ - Clause 2 of the IJG license
66
+
67
+ 2. If your binary distribution includes or uses the TurboJPEG API, then
68
+ your product documentation must include the text of the Modified BSD
69
+ License (see below.)
70
+
71
+ **Origin**
72
+ - Clause 2 of the Modified BSD License
73
+
74
+ 3. You cannot use the name of the IJG or The libjpeg-turbo Project or the
75
+ contributors thereof in advertising, publicity, etc.
76
+
77
+ **Origin**
78
+ - IJG License
79
+ - Clause 3 of the Modified BSD License
80
+
81
+ 4. The IJG and The libjpeg-turbo Project do not warrant libjpeg-turbo to be
82
+ free of defects, nor do we accept any liability for undesirable
83
+ consequences resulting from your use of the software.
84
+
85
+ **Origin**
86
+ - IJG License
87
+ - Modified BSD License
88
+ - zlib License
89
+
90
+
91
+ The Modified (3-clause) BSD License
92
+ ===================================
93
+
94
+ Copyright (C)2009-2022 D. R. Commander. All Rights Reserved.<br>
95
+ Copyright (C)2015 Viktor Szathmáry. All Rights Reserved.
96
+
97
+ Redistribution and use in source and binary forms, with or without
98
+ modification, are permitted provided that the following conditions are met:
99
+
100
+ - Redistributions of source code must retain the above copyright notice,
101
+ this list of conditions and the following disclaimer.
102
+ - Redistributions in binary form must reproduce the above copyright notice,
103
+ this list of conditions and the following disclaimer in the documentation
104
+ and/or other materials provided with the distribution.
105
+ - Neither the name of the libjpeg-turbo Project nor the names of its
106
+ contributors may be used to endorse or promote products derived from this
107
+ software without specific prior written permission.
108
+
109
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
110
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
111
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
112
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
113
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
114
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
115
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
116
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
117
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
118
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
119
+ POSSIBILITY OF SUCH DAMAGE.
120
+
121
+
122
+ Why Three Licenses?
123
+ ===================
124
+
125
+ The zlib License could have been used instead of the Modified (3-clause) BSD
126
+ License, and since the IJG License effectively subsumes the distribution
127
+ conditions of the zlib License, this would have effectively placed
128
+ libjpeg-turbo binary distributions under the IJG License. However, the IJG
129
+ License specifically refers to the Independent JPEG Group and does not extend
130
+ attribution and endorsement protections to other entities. Thus, it was
131
+ desirable to choose a license that granted us the same protections for new code
132
+ that were granted to the IJG for code derived from their software.