@cornerstonejs/metadata 5.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.
- package/LICENSE +21 -0
- package/dist/esm/enums/CalibrationTypes.d.ts +12 -0
- package/dist/esm/enums/CalibrationTypes.js +13 -0
- package/dist/esm/enums/MetadataModules.d.ts +54 -0
- package/dist/esm/enums/MetadataModules.js +57 -0
- package/dist/esm/enums/index.d.ts +4 -0
- package/dist/esm/enums/index.js +4 -0
- package/dist/esm/index.d.ts +10 -0
- package/dist/esm/index.js +9 -0
- package/dist/esm/metaData.d.ts +33 -0
- package/dist/esm/metaData.js +181 -0
- package/dist/esm/registerDefaultProviders.d.ts +1 -0
- package/dist/esm/registerDefaultProviders.js +38 -0
- package/dist/esm/types/DicomStreamTypes.d.ts +13 -0
- package/dist/esm/types/DicomStreamTypes.js +0 -0
- package/dist/esm/types/IImageCalibration.d.ts +11 -0
- package/dist/esm/types/IImageCalibration.js +0 -0
- package/dist/esm/types/MetadataModuleTypes.d.ts +100 -0
- package/dist/esm/types/MetadataModuleTypes.js +0 -0
- package/dist/esm/types/index.d.ts +3 -0
- package/dist/esm/types/index.js +0 -0
- package/dist/esm/utilities/Tags.d.ts +25 -0
- package/dist/esm/utilities/Tags.js +112 -0
- package/dist/esm/utilities/bulkDataFromArray.d.ts +1 -0
- package/dist/esm/utilities/bulkDataFromArray.js +38 -0
- package/dist/esm/utilities/calibratedPixelSpacingMetadataProvider.d.ts +7 -0
- package/dist/esm/utilities/calibratedPixelSpacingMetadataProvider.js +21 -0
- package/dist/esm/utilities/dicomStream/MetaDataIterator.d.ts +11 -0
- package/dist/esm/utilities/dicomStream/MetaDataIterator.js +58 -0
- package/dist/esm/utilities/dicomStream/NaturalTagListener.d.ts +22 -0
- package/dist/esm/utilities/dicomStream/NaturalTagListener.js +106 -0
- package/dist/esm/utilities/dicomStream/index.d.ts +3 -0
- package/dist/esm/utilities/dicomStream/index.js +2 -0
- package/dist/esm/utilities/getNaturalizedField.d.ts +3 -0
- package/dist/esm/utilities/getNaturalizedField.js +34 -0
- package/dist/esm/utilities/getPixelSpacingInformation.d.ts +13 -0
- package/dist/esm/utilities/getPixelSpacingInformation.js +93 -0
- package/dist/esm/utilities/imageIdToURI.d.ts +1 -0
- package/dist/esm/utilities/imageIdToURI.js +15 -0
- package/dist/esm/utilities/index.d.ts +15 -0
- package/dist/esm/utilities/index.js +15 -0
- package/dist/esm/utilities/isEqual.d.ts +2 -0
- package/dist/esm/utilities/isEqual.js +2 -0
- package/dist/esm/utilities/isVideoTransferSyntax.d.ts +2 -0
- package/dist/esm/utilities/isVideoTransferSyntax.js +25 -0
- package/dist/esm/utilities/logging.d.ts +3 -0
- package/dist/esm/utilities/logging.js +2 -0
- package/dist/esm/utilities/metadataProvider/addDicomPart10Instance.d.ts +2 -0
- package/dist/esm/utilities/metadataProvider/addDicomPart10Instance.js +12 -0
- package/dist/esm/utilities/metadataProvider/cacheData.d.ts +39 -0
- package/dist/esm/utilities/metadataProvider/cacheData.js +235 -0
- package/dist/esm/utilities/metadataProvider/calibrationModule.d.ts +2 -0
- package/dist/esm/utilities/metadataProvider/calibrationModule.js +25 -0
- package/dist/esm/utilities/metadataProvider/combineFrameInstance.d.ts +5 -0
- package/dist/esm/utilities/metadataProvider/combineFrameInstance.js +158 -0
- package/dist/esm/utilities/metadataProvider/compressedFrameData.d.ts +1 -0
- package/dist/esm/utilities/metadataProvider/compressedFrameData.js +133 -0
- package/dist/esm/utilities/metadataProvider/dataLookup.d.ts +7 -0
- package/dist/esm/utilities/metadataProvider/dataLookup.js +18 -0
- package/dist/esm/utilities/metadataProvider/dicomSplit.d.ts +1 -0
- package/dist/esm/utilities/metadataProvider/dicomSplit.js +5 -0
- package/dist/esm/utilities/metadataProvider/ecgFromInstance.d.ts +18 -0
- package/dist/esm/utilities/metadataProvider/ecgFromInstance.js +228 -0
- package/dist/esm/utilities/metadataProvider/ecgModule.d.ts +1 -0
- package/dist/esm/utilities/metadataProvider/ecgModule.js +0 -0
- package/dist/esm/utilities/metadataProvider/imageIdsProviders.d.ts +11 -0
- package/dist/esm/utilities/metadataProvider/imageIdsProviders.js +117 -0
- package/dist/esm/utilities/metadataProvider/imagePlaneCalibrated.d.ts +4 -0
- package/dist/esm/utilities/metadataProvider/imagePlaneCalibrated.js +89 -0
- package/dist/esm/utilities/metadataProvider/index.d.ts +18 -0
- package/dist/esm/utilities/metadataProvider/index.js +17 -0
- package/dist/esm/utilities/metadataProvider/instanceFromListener.d.ts +2 -0
- package/dist/esm/utilities/metadataProvider/instanceFromListener.js +9 -0
- package/dist/esm/utilities/metadataProvider/makeArrayLike.d.ts +1 -0
- package/dist/esm/utilities/metadataProvider/makeArrayLike.js +25 -0
- package/dist/esm/utilities/metadataProvider/naturalizedHandlers.d.ts +5 -0
- package/dist/esm/utilities/metadataProvider/naturalizedHandlers.js +67 -0
- package/dist/esm/utilities/metadataProvider/pixelDataUpdate.d.ts +2 -0
- package/dist/esm/utilities/metadataProvider/pixelDataUpdate.js +133 -0
- package/dist/esm/utilities/metadataProvider/scalingFromInstance.d.ts +1 -0
- package/dist/esm/utilities/metadataProvider/scalingFromInstance.js +148 -0
- package/dist/esm/utilities/metadataProvider/tagModules.d.ts +7 -0
- package/dist/esm/utilities/metadataProvider/tagModules.js +62 -0
- package/dist/esm/utilities/metadataProvider/transferSyntaxProvider.d.ts +2 -0
- package/dist/esm/utilities/metadataProvider/transferSyntaxProvider.js +20 -0
- package/dist/esm/utilities/metadataProvider/uriModule.d.ts +19 -0
- package/dist/esm/utilities/metadataProvider/uriModule.js +26 -0
- package/dist/esm/utilities/modules/cine.d.ts +2 -0
- package/dist/esm/utilities/modules/cine.js +4 -0
- package/dist/esm/utilities/modules/clinicalTrial.d.ts +2 -0
- package/dist/esm/utilities/modules/clinicalTrial.js +6 -0
- package/dist/esm/utilities/modules/ecg.d.ts +2 -0
- package/dist/esm/utilities/modules/ecg.js +11 -0
- package/dist/esm/utilities/modules/generalImage.d.ts +2 -0
- package/dist/esm/utilities/modules/generalImage.js +14 -0
- package/dist/esm/utilities/modules/generalSeries.d.ts +2 -0
- package/dist/esm/utilities/modules/generalSeries.js +11 -0
- package/dist/esm/utilities/modules/generalStudy.d.ts +2 -0
- package/dist/esm/utilities/modules/generalStudy.js +7 -0
- package/dist/esm/utilities/modules/imagePixel.d.ts +2 -0
- package/dist/esm/utilities/modules/imagePixel.js +31 -0
- package/dist/esm/utilities/modules/imagePlane.d.ts +2 -0
- package/dist/esm/utilities/modules/imagePlane.js +8 -0
- package/dist/esm/utilities/modules/index.d.ts +5 -0
- package/dist/esm/utilities/modules/index.js +48 -0
- package/dist/esm/utilities/modules/modalityLut.d.ts +2 -0
- package/dist/esm/utilities/modules/modalityLut.js +5 -0
- package/dist/esm/utilities/modules/patient.d.ts +2 -0
- package/dist/esm/utilities/modules/patient.js +6 -0
- package/dist/esm/utilities/modules/patientStudy.d.ts +2 -0
- package/dist/esm/utilities/modules/patientStudy.js +6 -0
- package/dist/esm/utilities/modules/ptImage.d.ts +2 -0
- package/dist/esm/utilities/modules/ptImage.js +4 -0
- package/dist/esm/utilities/modules/ptIsotope.d.ts +2 -0
- package/dist/esm/utilities/modules/ptIsotope.js +1 -0
- package/dist/esm/utilities/modules/ptSeries.d.ts +2 -0
- package/dist/esm/utilities/modules/ptSeries.js +5 -0
- package/dist/esm/utilities/modules/radiopharmaceuticalInfo.d.ts +2 -0
- package/dist/esm/utilities/modules/radiopharmaceuticalInfo.js +6 -0
- package/dist/esm/utilities/modules/sopCommon.d.ts +2 -0
- package/dist/esm/utilities/modules/sopCommon.js +1 -0
- package/dist/esm/utilities/modules/transferSyntax.d.ts +2 -0
- package/dist/esm/utilities/modules/transferSyntax.js +4 -0
- package/dist/esm/utilities/modules/ultrasoundEnhancedRegion.d.ts +2 -0
- package/dist/esm/utilities/modules/ultrasoundEnhancedRegion.js +1 -0
- package/dist/esm/utilities/modules/unassigned.d.ts +2 -0
- package/dist/esm/utilities/modules/unassigned.js +15 -0
- package/dist/esm/utilities/modules/usRegionChild.d.ts +2 -0
- package/dist/esm/utilities/modules/usRegionChild.js +18 -0
- package/dist/esm/utilities/modules/voiLut.d.ts +2 -0
- package/dist/esm/utilities/modules/voiLut.js +6 -0
- package/dist/esm/utilities/splitImageIdsBy4DTags.d.ts +12 -0
- package/dist/esm/utilities/splitImageIdsBy4DTags.js +314 -0
- package/dist/esm/utilities/toNumber.d.ts +2 -0
- package/dist/esm/utilities/toNumber.js +2 -0
- package/dist/esm/version.d.ts +1 -0
- package/dist/esm/version.js +1 -0
- package/package.json +99 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import * as metaData from '../metaData';
|
|
2
|
+
import dcmjs from 'dcmjs';
|
|
3
|
+
import { moduleDefinitions, USRegionChild, CLINICAL_TRIAL, RadiopharmaceuticalInfoModule, } from './modules';
|
|
4
|
+
const dicomDictionary = dcmjs.data.DicomMetaDictionary.dictionary;
|
|
5
|
+
const nameMap = dcmjs.data.DicomMetaDictionary.nameMap;
|
|
6
|
+
export { USRegionChild, CLINICAL_TRIAL, RadiopharmaceuticalInfoModule };
|
|
7
|
+
export function createTagEntry(hexTag, ...groups) {
|
|
8
|
+
return {
|
|
9
|
+
tag: hexTag,
|
|
10
|
+
groups,
|
|
11
|
+
xTag: null,
|
|
12
|
+
primaryGroup: null,
|
|
13
|
+
name: null,
|
|
14
|
+
lowerName: null,
|
|
15
|
+
vr: null,
|
|
16
|
+
vm: null,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export function parseVm(vm) {
|
|
20
|
+
if (vm === undefined || vm === null) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
if (typeof vm === 'number') {
|
|
24
|
+
return vm;
|
|
25
|
+
}
|
|
26
|
+
const n = parseInt(vm, 10);
|
|
27
|
+
if (String(n) === vm) {
|
|
28
|
+
return n;
|
|
29
|
+
}
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
export function dictionaryLookup(hexTag) {
|
|
33
|
+
return dicomDictionary[hexTag.toUpperCase()];
|
|
34
|
+
}
|
|
35
|
+
export function getTagCodeByName(name) {
|
|
36
|
+
return mapTagInfo.get(name)?.tag;
|
|
37
|
+
}
|
|
38
|
+
export const mapModuleTags = new Map();
|
|
39
|
+
export const mapTagInfo = new Map();
|
|
40
|
+
export function addTag(name, value) {
|
|
41
|
+
if (name && value.name && name !== value.name) {
|
|
42
|
+
throw new Error(`Tag name provided and value don't match: ${name} !== ${value.name}`);
|
|
43
|
+
}
|
|
44
|
+
value.name ||= name;
|
|
45
|
+
value.lowerName ||= metaData.toLowerCamelTag(name);
|
|
46
|
+
Tags[name] = value;
|
|
47
|
+
const { tag: hexTag } = value;
|
|
48
|
+
value.primaryGroup ||= value.groups?.[0];
|
|
49
|
+
const { groups } = value;
|
|
50
|
+
mapTagInfo.set(name, value);
|
|
51
|
+
if (hexTag) {
|
|
52
|
+
value.xTag = `x${hexTag.toLowerCase()}`;
|
|
53
|
+
value.tag = hexTag.toUpperCase();
|
|
54
|
+
mapTagInfo.set(value.xTag, value);
|
|
55
|
+
mapTagInfo.set(value.tag, value);
|
|
56
|
+
if (!value.vr) {
|
|
57
|
+
const dictEntry = dicomDictionary[value.tag];
|
|
58
|
+
if (dictEntry) {
|
|
59
|
+
value.vr = dictEntry.vr;
|
|
60
|
+
value.vm = parseVm(dictEntry.vm);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (groups?.length) {
|
|
65
|
+
for (const group of groups) {
|
|
66
|
+
let moduleEntries = mapModuleTags.get(group);
|
|
67
|
+
if (!moduleEntries) {
|
|
68
|
+
moduleEntries = [value];
|
|
69
|
+
mapModuleTags.set(group, moduleEntries);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const foundIndex = moduleEntries.findIndex((it) => it.name === name);
|
|
73
|
+
if (foundIndex === -1) {
|
|
74
|
+
moduleEntries.push(value);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
moduleEntries[foundIndex] = value;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export function resolveHexFromKeyword(keyword) {
|
|
83
|
+
const entry = nameMap[keyword];
|
|
84
|
+
if (!entry) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
return entry.tag.substring(1, 5) + entry.tag.substring(6, 10);
|
|
88
|
+
}
|
|
89
|
+
export const Tags = {};
|
|
90
|
+
const tagGroups = new Map();
|
|
91
|
+
for (const [moduleName, keywords] of moduleDefinitions) {
|
|
92
|
+
for (const entry of keywords) {
|
|
93
|
+
const keyword = typeof entry === 'string' ? entry : entry[0];
|
|
94
|
+
const hexOverride = typeof entry === 'string' ? undefined : entry[1];
|
|
95
|
+
let data = tagGroups.get(keyword);
|
|
96
|
+
if (!data) {
|
|
97
|
+
const hex = hexOverride ?? resolveHexFromKeyword(keyword);
|
|
98
|
+
data = { hex, groups: [] };
|
|
99
|
+
tagGroups.set(keyword, data);
|
|
100
|
+
}
|
|
101
|
+
if (moduleName !== null) {
|
|
102
|
+
data.groups.push(moduleName);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
for (const [keyword, { hex, groups }] of tagGroups) {
|
|
107
|
+
if (!hex) {
|
|
108
|
+
console.warn(`Tags: keyword "${keyword}" not found in dcmjs nameMap`);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
addTag(keyword, createTagEntry(hex, ...groups));
|
|
112
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getSingleBufferFromArray(raw: unknown): ArrayBufferView | undefined;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
function asView(buf) {
|
|
2
|
+
if (buf instanceof ArrayBuffer) {
|
|
3
|
+
return new Uint8Array(buf);
|
|
4
|
+
}
|
|
5
|
+
return buf;
|
|
6
|
+
}
|
|
7
|
+
export function getSingleBufferFromArray(raw) {
|
|
8
|
+
if (raw instanceof ArrayBuffer || ArrayBuffer.isView(raw)) {
|
|
9
|
+
return asView(raw);
|
|
10
|
+
}
|
|
11
|
+
if (!Array.isArray(raw) || raw.length === 0) {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
const first = raw[0];
|
|
15
|
+
if (first === undefined ||
|
|
16
|
+
first === null ||
|
|
17
|
+
(!(first instanceof ArrayBuffer) && !ArrayBuffer.isView(first))) {
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
if (raw.length === 1) {
|
|
21
|
+
return asView(first);
|
|
22
|
+
}
|
|
23
|
+
const views = raw.filter((item) => item != null && (item instanceof ArrayBuffer || ArrayBuffer.isView(item)));
|
|
24
|
+
if (views.length === 0)
|
|
25
|
+
return undefined;
|
|
26
|
+
const totalLength = views.reduce((sum, v) => sum +
|
|
27
|
+
(v instanceof ArrayBuffer
|
|
28
|
+
? v.byteLength
|
|
29
|
+
: v.byteLength), 0);
|
|
30
|
+
const out = new Uint8Array(totalLength);
|
|
31
|
+
let offset = 0;
|
|
32
|
+
for (const v of views) {
|
|
33
|
+
const view = asView(v);
|
|
34
|
+
out.set(new Uint8Array(view.buffer, view.byteOffset, view.byteLength), offset);
|
|
35
|
+
offset += view.byteLength;
|
|
36
|
+
}
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { IImageCalibration } from '../types/IImageCalibration';
|
|
2
|
+
declare const metadataProvider: {
|
|
3
|
+
add: (imageId: string, payload: IImageCalibration) => void;
|
|
4
|
+
get: (type: string, imageId: string) => IImageCalibration;
|
|
5
|
+
clear: () => void;
|
|
6
|
+
};
|
|
7
|
+
export default metadataProvider;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import imageIdToURI from './imageIdToURI';
|
|
2
|
+
import { MetadataModules } from '../enums';
|
|
3
|
+
import { clearQuery } from '../metaData';
|
|
4
|
+
const state = new Map();
|
|
5
|
+
const metadataProvider = {
|
|
6
|
+
add: (imageId, payload) => {
|
|
7
|
+
const imageURI = imageIdToURI(imageId);
|
|
8
|
+
state.set(imageURI, payload);
|
|
9
|
+
clearQuery(MetadataModules.IMAGE_PLANE, imageId);
|
|
10
|
+
},
|
|
11
|
+
get: (type, imageId) => {
|
|
12
|
+
if (type === 'calibratedPixelSpacing') {
|
|
13
|
+
const imageURI = imageIdToURI(imageId);
|
|
14
|
+
return state.get(imageURI);
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
clear: () => {
|
|
18
|
+
state.clear();
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
export default metadataProvider;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare class MetaDataIterator {
|
|
2
|
+
metadata: any;
|
|
3
|
+
constructor(metadata: any);
|
|
4
|
+
syncIterator(listener: any, object?: any): void;
|
|
5
|
+
}
|
|
6
|
+
export type MetadataValue = {
|
|
7
|
+
Value?: unknown[];
|
|
8
|
+
vr: string;
|
|
9
|
+
BulkDataURI?: string;
|
|
10
|
+
InlineBinary?: string;
|
|
11
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { dictionaryLookup, mapTagInfo } from '../Tags';
|
|
2
|
+
export class MetaDataIterator {
|
|
3
|
+
constructor(metadata) {
|
|
4
|
+
this.metadata = metadata;
|
|
5
|
+
}
|
|
6
|
+
syncIterator(listener, object = this.metadata) {
|
|
7
|
+
for (const [key, value] of Object.entries(object)) {
|
|
8
|
+
if (key === '_vrMap' || value === undefined) {
|
|
9
|
+
continue;
|
|
10
|
+
}
|
|
11
|
+
if (value === null) {
|
|
12
|
+
listener.addTag(key, { length: 0 });
|
|
13
|
+
listener.pop();
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
const vr = value.vr;
|
|
17
|
+
const tagData = mapTagInfo.get(key);
|
|
18
|
+
const dictEntry = !tagData ? dictionaryLookup(key) : undefined;
|
|
19
|
+
const hasBulk = !value.Value &&
|
|
20
|
+
(value.BulkDataURI ??
|
|
21
|
+
value.InlineBinary);
|
|
22
|
+
if (!value.Value && !hasBulk) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
listener.addTag(key, {
|
|
26
|
+
vr,
|
|
27
|
+
name: tagData?.name || dictEntry?.name,
|
|
28
|
+
vm: tagData?.vm ?? dictEntry?.vm,
|
|
29
|
+
});
|
|
30
|
+
if (vr === 'SQ') {
|
|
31
|
+
for (const v of value.Value) {
|
|
32
|
+
listener.startObject();
|
|
33
|
+
this.syncIterator(listener, v);
|
|
34
|
+
listener.pop();
|
|
35
|
+
}
|
|
36
|
+
listener.pop();
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (hasBulk) {
|
|
40
|
+
listener.value({
|
|
41
|
+
BulkDataURI: value.BulkDataURI,
|
|
42
|
+
InlineBinary: value.InlineBinary,
|
|
43
|
+
});
|
|
44
|
+
listener.pop();
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (value.vr === 'CS' &&
|
|
48
|
+
value.Value.length === 1 &&
|
|
49
|
+
String(value.Value[0]).indexOf('\\') !== -1) {
|
|
50
|
+
value.Value = String(value.Value[0]).split('\\');
|
|
51
|
+
}
|
|
52
|
+
for (const v of value.Value) {
|
|
53
|
+
listener.value(v);
|
|
54
|
+
}
|
|
55
|
+
listener.pop();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { IListenerInfo } from '../../types';
|
|
2
|
+
export type ListenerContext = {
|
|
3
|
+
natural?: {
|
|
4
|
+
name: string;
|
|
5
|
+
singleVm: boolean | null;
|
|
6
|
+
tag: string;
|
|
7
|
+
};
|
|
8
|
+
parent?: {
|
|
9
|
+
dest: Record<string, unknown>;
|
|
10
|
+
};
|
|
11
|
+
dest?: Record<string, unknown>;
|
|
12
|
+
};
|
|
13
|
+
export declare class NaturalTagListener {
|
|
14
|
+
constructor(_options?: {
|
|
15
|
+
nameKey?: string;
|
|
16
|
+
});
|
|
17
|
+
static createMetadataListener(options?: {
|
|
18
|
+
nameKey?: string;
|
|
19
|
+
}): any;
|
|
20
|
+
addTag(next: (tag: string, tagInfo?: IListenerInfo) => void, tag: string, tagInfo?: IListenerInfo): void;
|
|
21
|
+
pop(next: () => unknown): unknown;
|
|
22
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import dcmjs from 'dcmjs';
|
|
2
|
+
import { makeArrayLike } from '../metadataProvider/makeArrayLike';
|
|
3
|
+
import { dictionaryLookup, mapTagInfo, parseVm } from '../Tags';
|
|
4
|
+
const { DicomMetadataListener } = dcmjs.utilities;
|
|
5
|
+
function resolveSingleVm(tagData, dictEntry, tagInfo) {
|
|
6
|
+
if (tagData && tagData.vm !== undefined && tagData.vm !== null) {
|
|
7
|
+
return tagData.vm === 1;
|
|
8
|
+
}
|
|
9
|
+
const vm = tagInfo?.vm ?? dictEntry?.vm;
|
|
10
|
+
if (vm !== undefined && vm !== null) {
|
|
11
|
+
const parsed = parseVm(vm);
|
|
12
|
+
if (parsed !== null) {
|
|
13
|
+
return parsed === 1;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
function isBulkDataValue(val) {
|
|
19
|
+
if (!Array.isArray(val) || val.length === 0) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
const first = val[0];
|
|
23
|
+
if (first instanceof ArrayBuffer || ArrayBuffer.isView(first)) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
if (Array.isArray(first)) {
|
|
27
|
+
return val.every((item) => Array.isArray(item) &&
|
|
28
|
+
item.every((f) => f instanceof ArrayBuffer || ArrayBuffer.isView(f)));
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
const DEFAULT_NAME_KEY = 'name';
|
|
33
|
+
export class NaturalTagListener {
|
|
34
|
+
constructor(_options) {
|
|
35
|
+
}
|
|
36
|
+
static createMetadataListener(options) {
|
|
37
|
+
return new DicomMetadataListener({}, new NaturalTagListener(options));
|
|
38
|
+
}
|
|
39
|
+
addTag(next, tag, tagInfo) {
|
|
40
|
+
const tagData = mapTagInfo.get(tag);
|
|
41
|
+
const dictEntry = !tagData ? dictionaryLookup(tag) : undefined;
|
|
42
|
+
const name = tagInfo?.name || tagData?.[DEFAULT_NAME_KEY] || dictEntry?.name || tag;
|
|
43
|
+
const singleVm = resolveSingleVm(tagData, dictEntry, tagInfo);
|
|
44
|
+
next(tag, tagInfo);
|
|
45
|
+
this.current.natural = {
|
|
46
|
+
name,
|
|
47
|
+
singleVm,
|
|
48
|
+
tag,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
pop(next) {
|
|
52
|
+
const listener = this;
|
|
53
|
+
const nat = listener.current?.natural;
|
|
54
|
+
const parentContext = listener.current?.parent;
|
|
55
|
+
if (!nat || !parentContext?.dest) {
|
|
56
|
+
return next();
|
|
57
|
+
}
|
|
58
|
+
const result = next();
|
|
59
|
+
const parent = parentContext;
|
|
60
|
+
const raw = parent.dest[nat.tag];
|
|
61
|
+
if (raw === undefined) {
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
let val = raw.Value ?? raw;
|
|
65
|
+
if (Array.isArray(val) && val.length === 1 && val[0] === undefined) {
|
|
66
|
+
val = [];
|
|
67
|
+
}
|
|
68
|
+
if (isBulkDataValue(val)) {
|
|
69
|
+
parent.dest[nat.name] = val;
|
|
70
|
+
if (nat.name !== nat.tag)
|
|
71
|
+
delete parent.dest[nat.tag];
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
if (nat.singleVm === true && Array.isArray(val) && val.length === 1) {
|
|
75
|
+
const one = val[0];
|
|
76
|
+
if (typeof one === 'object' &&
|
|
77
|
+
one !== null &&
|
|
78
|
+
!(one instanceof ArrayBuffer) &&
|
|
79
|
+
!ArrayBuffer.isView(one)) {
|
|
80
|
+
parent.dest[nat.name] = makeArrayLike(one);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
parent.dest[nat.name] = one;
|
|
84
|
+
}
|
|
85
|
+
if (nat.name !== nat.tag)
|
|
86
|
+
delete parent.dest[nat.tag];
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
if (nat.singleVm === null &&
|
|
90
|
+
Array.isArray(val) &&
|
|
91
|
+
val.length === 1 &&
|
|
92
|
+
typeof val[0] === 'object' &&
|
|
93
|
+
val[0] !== null &&
|
|
94
|
+
!(val[0] instanceof ArrayBuffer) &&
|
|
95
|
+
!ArrayBuffer.isView(val[0])) {
|
|
96
|
+
parent.dest[nat.name] = makeArrayLike(val[0]);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
parent.dest[nat.name] = val;
|
|
100
|
+
}
|
|
101
|
+
if (nat.name !== nat.tag) {
|
|
102
|
+
delete parent.dest[nat.tag];
|
|
103
|
+
}
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare function getNaturalizedField<T = unknown>(naturalized: Record<string, unknown> | null | undefined, fieldName: string, defaultValue?: T | undefined, index?: number): unknown | T | undefined;
|
|
2
|
+
export declare function getNaturalizedString(naturalized: Record<string, unknown> | null | undefined, fieldName: string, defaultValue?: string | undefined, index?: number): string | undefined;
|
|
3
|
+
export declare function getNaturalizedNumber(naturalized: Record<string, unknown> | null | undefined, fieldName: string, defaultValue?: number | undefined, index?: number): number | undefined;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export function getNaturalizedField(naturalized, fieldName, defaultValue = undefined, index = 0) {
|
|
2
|
+
if (!naturalized) {
|
|
3
|
+
return defaultValue;
|
|
4
|
+
}
|
|
5
|
+
const value = naturalized[fieldName];
|
|
6
|
+
if (value === undefined || value === null) {
|
|
7
|
+
return defaultValue;
|
|
8
|
+
}
|
|
9
|
+
if (Array.isArray(value)) {
|
|
10
|
+
const indexedValue = value[index];
|
|
11
|
+
return indexedValue === undefined || indexedValue === null
|
|
12
|
+
? defaultValue
|
|
13
|
+
: indexedValue;
|
|
14
|
+
}
|
|
15
|
+
if (index !== 0) {
|
|
16
|
+
return defaultValue;
|
|
17
|
+
}
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
export function getNaturalizedString(naturalized, fieldName, defaultValue = undefined, index = 0) {
|
|
21
|
+
const value = getNaturalizedField(naturalized, fieldName, defaultValue, index);
|
|
22
|
+
if (value === null || value === undefined) {
|
|
23
|
+
return defaultValue;
|
|
24
|
+
}
|
|
25
|
+
return String(value);
|
|
26
|
+
}
|
|
27
|
+
export function getNaturalizedNumber(naturalized, fieldName, defaultValue = undefined, index = 0) {
|
|
28
|
+
const value = getNaturalizedField(naturalized, fieldName, defaultValue, index);
|
|
29
|
+
if (value === null || value === undefined) {
|
|
30
|
+
return defaultValue;
|
|
31
|
+
}
|
|
32
|
+
const parsedValue = Number(value);
|
|
33
|
+
return Number.isFinite(parsedValue) ? parsedValue : defaultValue;
|
|
34
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { CalibrationTypes } from '../enums';
|
|
2
|
+
export declare function getERMF(instance: any): any;
|
|
3
|
+
export declare function calculateRadiographicPixelSpacing(instance: any): {
|
|
4
|
+
PixelSpacing: any;
|
|
5
|
+
type: CalibrationTypes;
|
|
6
|
+
isProjection: boolean;
|
|
7
|
+
};
|
|
8
|
+
export declare function getPixelSpacingInformation(instance: any): {
|
|
9
|
+
PixelSpacing: any;
|
|
10
|
+
type: CalibrationTypes;
|
|
11
|
+
isProjection: boolean;
|
|
12
|
+
};
|
|
13
|
+
export default getPixelSpacingInformation;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { isEqual } from './isEqual';
|
|
2
|
+
import { CalibrationTypes } from '../enums';
|
|
3
|
+
const projectionRadiographSOPClassUIDs = new Set([
|
|
4
|
+
'1.2.840.10008.5.1.4.1.1.1',
|
|
5
|
+
'1.2.840.10008.5.1.4.1.1.1.1',
|
|
6
|
+
'1.2.840.10008.5.1.4.1.1.1.1.1',
|
|
7
|
+
'1.2.840.10008.5.1.4.1.1.1.2',
|
|
8
|
+
'1.2.840.10008.5.1.4.1.1.1.2.1',
|
|
9
|
+
'1.2.840.10008.5.1.4.1.1.1.3',
|
|
10
|
+
'1.2.840.10008.5.1.4.1.1.1.3.1',
|
|
11
|
+
'1.2.840.10008.5.1.4.1.1.12.1',
|
|
12
|
+
'1.2.840.10008.5.1.4.1.1.12.1.1',
|
|
13
|
+
'1.2.840.10008.5.1.4.1.1.12.2',
|
|
14
|
+
'1.2.840.10008.5.1.4.1.1.12.2.1',
|
|
15
|
+
'1.2.840.10008.5.1.4.1.1.12.3',
|
|
16
|
+
]);
|
|
17
|
+
export function getERMF(instance) {
|
|
18
|
+
const { PixelSpacing, ImagerPixelSpacing, EstimatedRadiographicMagnificationFactor: ermf, DistanceSourceToDetector: sid, DistanceSourceToEntrance: soe, DistanceSourceToPatient: sod = soe, } = instance;
|
|
19
|
+
if (ermf > 1) {
|
|
20
|
+
return ermf;
|
|
21
|
+
}
|
|
22
|
+
if (sod < sid) {
|
|
23
|
+
return sid / sod;
|
|
24
|
+
}
|
|
25
|
+
if (ImagerPixelSpacing?.[0] > PixelSpacing?.[0]) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export function calculateRadiographicPixelSpacing(instance) {
|
|
30
|
+
const { PixelSpacing, ImagerPixelSpacing, PixelSpacingCalibrationType } = instance;
|
|
31
|
+
const isProjection = true;
|
|
32
|
+
if (PixelSpacing && PixelSpacingCalibrationType === 'GEOMETRY') {
|
|
33
|
+
if (isEqual(PixelSpacing, ImagerPixelSpacing)) {
|
|
34
|
+
console.warn('Calibration type is geometry, but pixel spacing and imager pixel spacing identical', PixelSpacing, ImagerPixelSpacing);
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
PixelSpacing,
|
|
38
|
+
type: CalibrationTypes.ERMF,
|
|
39
|
+
isProjection,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
if (PixelSpacing && PixelSpacingCalibrationType === 'FIDUCIAL') {
|
|
43
|
+
return {
|
|
44
|
+
PixelSpacing,
|
|
45
|
+
type: CalibrationTypes.CALIBRATED,
|
|
46
|
+
isProjection,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
if (ImagerPixelSpacing) {
|
|
50
|
+
const ermf = getERMF(instance);
|
|
51
|
+
if (ermf > 1) {
|
|
52
|
+
const correctedPixelSpacing = ImagerPixelSpacing.map((pixelSpacing) => pixelSpacing / ermf);
|
|
53
|
+
return {
|
|
54
|
+
PixelSpacing: correctedPixelSpacing,
|
|
55
|
+
type: CalibrationTypes.ERMF,
|
|
56
|
+
isProjection,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (ermf === true) {
|
|
60
|
+
return {
|
|
61
|
+
PixelSpacing,
|
|
62
|
+
type: CalibrationTypes.ERMF,
|
|
63
|
+
isProjection,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if (ermf) {
|
|
67
|
+
console.error('Illegal ERMF value:', ermf);
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
PixelSpacing: PixelSpacing || ImagerPixelSpacing,
|
|
71
|
+
type: CalibrationTypes.PROJECTION,
|
|
72
|
+
isProjection,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
PixelSpacing,
|
|
77
|
+
type: CalibrationTypes.UNKNOWN,
|
|
78
|
+
isProjection,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export function getPixelSpacingInformation(instance) {
|
|
82
|
+
const { PixelSpacing, SOPClassUID } = instance;
|
|
83
|
+
const isProjection = projectionRadiographSOPClassUIDs.has(SOPClassUID);
|
|
84
|
+
if (isProjection) {
|
|
85
|
+
return calculateRadiographicPixelSpacing(instance);
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
PixelSpacing,
|
|
89
|
+
type: CalibrationTypes.NOT_APPLICABLE,
|
|
90
|
+
isProjection: false,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export default getPixelSpacingInformation;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function imageIdToURI(imageId: string): string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const schemePrefixPattern = /^[a-zA-Z]+:/;
|
|
2
|
+
export default function imageIdToURI(imageId) {
|
|
3
|
+
if (!imageId) {
|
|
4
|
+
return '';
|
|
5
|
+
}
|
|
6
|
+
const firstPrefixMatch = imageId.match(schemePrefixPattern);
|
|
7
|
+
if (!firstPrefixMatch) {
|
|
8
|
+
return imageId;
|
|
9
|
+
}
|
|
10
|
+
const remainder = imageId.substring(firstPrefixMatch[0].length);
|
|
11
|
+
if (!schemePrefixPattern.test(remainder)) {
|
|
12
|
+
return imageId;
|
|
13
|
+
}
|
|
14
|
+
return remainder;
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { getSingleBufferFromArray } from './bulkDataFromArray';
|
|
2
|
+
export { toNumber, toFiniteNumber } from './toNumber';
|
|
3
|
+
export { default as toNumberDefault } from './toNumber';
|
|
4
|
+
export { default as isVideoTransferSyntax, videoUIDs, } from './isVideoTransferSyntax';
|
|
5
|
+
export { default as imageIdToURI } from './imageIdToURI';
|
|
6
|
+
export { isEqual, isEqualNegative, isEqualAbs, isNumber } from './isEqual';
|
|
7
|
+
export { getPixelSpacingInformation, calculateRadiographicPixelSpacing, getERMF, } from './getPixelSpacingInformation';
|
|
8
|
+
export { default as calibratedPixelSpacingMetadataProvider } from './calibratedPixelSpacingMetadataProvider';
|
|
9
|
+
export * from './getNaturalizedField';
|
|
10
|
+
export { default as splitImageIdsBy4DTags, handleMultiframe4D, generateFrameImageId, } from './splitImageIdsBy4DTags';
|
|
11
|
+
export * as Tags from './Tags';
|
|
12
|
+
export * as DicomStream from './dicomStream';
|
|
13
|
+
export * from './logging';
|
|
14
|
+
export * from './metadataProvider';
|
|
15
|
+
export * as typedMetadataProviders from './metadataProvider';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { getSingleBufferFromArray } from './bulkDataFromArray';
|
|
2
|
+
export { toNumber, toFiniteNumber } from './toNumber';
|
|
3
|
+
export { default as toNumberDefault } from './toNumber';
|
|
4
|
+
export { default as isVideoTransferSyntax, videoUIDs, } from './isVideoTransferSyntax';
|
|
5
|
+
export { default as imageIdToURI } from './imageIdToURI';
|
|
6
|
+
export { isEqual, isEqualNegative, isEqualAbs, isNumber } from './isEqual';
|
|
7
|
+
export { getPixelSpacingInformation, calculateRadiographicPixelSpacing, getERMF, } from './getPixelSpacingInformation';
|
|
8
|
+
export { default as calibratedPixelSpacingMetadataProvider } from './calibratedPixelSpacingMetadataProvider';
|
|
9
|
+
export * from './getNaturalizedField';
|
|
10
|
+
export { default as splitImageIdsBy4DTags, handleMultiframe4D, generateFrameImageId, } from './splitImageIdsBy4DTags';
|
|
11
|
+
export * as Tags from './Tags';
|
|
12
|
+
export * as DicomStream from './dicomStream';
|
|
13
|
+
export * from './logging';
|
|
14
|
+
export * from './metadataProvider';
|
|
15
|
+
export * as typedMetadataProviders from './metadataProvider';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const videoUIDs = new Set([
|
|
2
|
+
'1.2.840.10008.1.2.4.100',
|
|
3
|
+
'1.2.840.10008.1.2.4.100.1',
|
|
4
|
+
'1.2.840.10008.1.2.4.101',
|
|
5
|
+
'1.2.840.10008.1.2.4.101.1',
|
|
6
|
+
'1.2.840.10008.1.2.4.102',
|
|
7
|
+
'1.2.840.10008.1.2.4.102.1',
|
|
8
|
+
'1.2.840.10008.1.2.4.103',
|
|
9
|
+
'1.2.840.10008.1.2.4.103.1',
|
|
10
|
+
'1.2.840.10008.1.2.4.104',
|
|
11
|
+
'1.2.840.10008.1.2.4.104.1',
|
|
12
|
+
'1.2.840.10008.1.2.4.105',
|
|
13
|
+
'1.2.840.10008.1.2.4.105.1',
|
|
14
|
+
'1.2.840.10008.1.2.4.106',
|
|
15
|
+
'1.2.840.10008.1.2.4.106.1',
|
|
16
|
+
'1.2.840.10008.1.2.4.107',
|
|
17
|
+
'1.2.840.10008.1.2.4.108',
|
|
18
|
+
]);
|
|
19
|
+
export default function isVideoTransferSyntax(uidOrUids) {
|
|
20
|
+
if (!uidOrUids) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
const uids = Array.isArray(uidOrUids) ? uidOrUids : [uidOrUids];
|
|
24
|
+
return uids.find((uid) => videoUIDs.has(uid));
|
|
25
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { logging } from '@cornerstonejs/utils';
|
|
2
|
+
export declare const getRootLogger: typeof logging.getRootLogger, getLogger: typeof logging.getLogger, cs3dLog: logging.Logger, metadataLog: logging.Logger, coreLog: logging.Logger, toolsLog: logging.Logger, loaderLog: logging.Logger, aiLog: logging.Logger, examplesLog: logging.Logger, workerLog: logging.Logger, dicomConsistencyLog: logging.Logger, imageConsistencyLog: logging.Logger, log: any;
|
|
3
|
+
export type Logger = logging.Logger;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare function addDicomWebInstance(imageId: string, metadata: Record<string, unknown>): Promise<never>;
|
|
2
|
+
export declare function addDicomPart10Instance(imageId: string, part10: ArrayBuffer | Uint8Array | (() => ArrayBuffer | Uint8Array | Promise<ArrayBuffer | Uint8Array>)): Promise<never>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { addTyped } from '../../metaData';
|
|
2
|
+
import { MetadataModules } from '../../enums';
|
|
3
|
+
export function addDicomWebInstance(imageId, metadata) {
|
|
4
|
+
return addTyped(MetadataModules.NATURALIZED, imageId, {
|
|
5
|
+
dicomwebJson: metadata,
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
export async function addDicomPart10Instance(imageId, part10) {
|
|
9
|
+
return addTyped(MetadataModules.NATURALIZED, imageId, {
|
|
10
|
+
part10Buffer: part10,
|
|
11
|
+
});
|
|
12
|
+
}
|