@radicalimaging/static-wado-creator 0.6.4 → 1.1.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/CHANGELOG.md +67 -0
- package/README.md +3 -1
- package/lib/DeleteStudy.js +3 -3
- package/lib/StaticWado.js +24 -2
- package/lib/index.js +1 -0
- package/lib/indexMain.js +10 -0
- package/lib/mkdicomwebConfig.js +19 -4
- package/lib/model/TagLists.js +7 -7
- package/lib/model/uids.js +9 -10
- package/lib/operation/InstanceDeduplicate.js +8 -8
- package/lib/operation/StudyData.js +24 -23
- package/lib/operation/ThumbnailService.js +1 -1
- package/lib/operation/adapter/transcodeImage.js +33 -16
- package/lib/operation/getDataSet.js +1 -1
- package/lib/operation/getVR.js +1 -1
- package/lib/util/adaptProgramOpts.js +2 -0
- package/lib/util/compressionOptionParser.js +3 -3
- package/lib/writer/CompleteStudyWriter.js +4 -6
- package/lib/writer/DeduplicateWriter.js +2 -2
- package/lib/writer/HashDataWriter.js +2 -2
- package/lib/writer/ImageFrameWriter.js +27 -8
- package/lib/writer/RawDicomWriter.js +36 -0
- package/lib/writer/VideoWriter.js +1 -1
- package/package.json +8 -7
- package/lib/dictionary/Tags.js +0 -111
- package/lib/dictionary/dataDictionary.js +0 -22268
- package/lib/operation/adapter/asyncIterableToBuffer.js +0 -112
- package/lib/writer/JSONWriter.js +0 -18
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const dicomCodec = require("@cornerstonejs/dicom-codec");
|
|
2
|
-
const Tags = require("
|
|
2
|
+
const { Tags } = require("@radicalimaging/static-wado-util");
|
|
3
3
|
const getImageInfo = require("./getImageInfo");
|
|
4
4
|
|
|
5
5
|
const transcodeOp = {
|
|
@@ -15,7 +15,7 @@ const transcodeOp = {
|
|
|
15
15
|
const transcodeDestinationMap = {
|
|
16
16
|
lei: {
|
|
17
17
|
transferSyntaxUid: "1.2.840.10008.1.2.1",
|
|
18
|
-
transcodeOp: transcodeOp.none
|
|
18
|
+
transcodeOp: transcodeOp.none,
|
|
19
19
|
},
|
|
20
20
|
jls: {
|
|
21
21
|
transferSyntaxUid: "1.2.840.10008.1.2.4.80",
|
|
@@ -33,6 +33,10 @@ const transcodeDestinationMap = {
|
|
|
33
33
|
transferSyntaxUid: "1.2.840.10008.1.2.4.91",
|
|
34
34
|
transcodeOp: transcodeOp.encode,
|
|
35
35
|
},
|
|
36
|
+
jhc: {
|
|
37
|
+
transferSyntaxUid: "3.2.840.10008.1.2.4.96",
|
|
38
|
+
transcodeOp: transcodeOp.encode,
|
|
39
|
+
},
|
|
36
40
|
};
|
|
37
41
|
|
|
38
42
|
const transcodeSourceMap = {
|
|
@@ -50,11 +54,11 @@ const transcodeSourceMap = {
|
|
|
50
54
|
},
|
|
51
55
|
"1.2.840.10008.1.2.4.57": {
|
|
52
56
|
transcodeOp: transcodeOp.decode,
|
|
53
|
-
alias: "
|
|
57
|
+
alias: "jls",
|
|
54
58
|
},
|
|
55
59
|
"1.2.840.10008.1.2.4.70": {
|
|
56
60
|
transcodeOp: transcodeOp.decode,
|
|
57
|
-
alias: "
|
|
61
|
+
alias: "jls",
|
|
58
62
|
},
|
|
59
63
|
"1.2.840.10008.1.2.4.90": {
|
|
60
64
|
transcodeOp: transcodeOp.decode,
|
|
@@ -64,6 +68,10 @@ const transcodeSourceMap = {
|
|
|
64
68
|
transcodeOp: transcodeOp.decode,
|
|
65
69
|
alias: "jp2",
|
|
66
70
|
},
|
|
71
|
+
"3.2.840.10008.1.2.4.96": {
|
|
72
|
+
transcodeOp: transcodeOp.decode,
|
|
73
|
+
alias: "jhc",
|
|
74
|
+
},
|
|
67
75
|
"1.2.840.10008.1.2.5": {
|
|
68
76
|
transcodeOp: transcodeOp.decode,
|
|
69
77
|
alias: "rle",
|
|
@@ -71,9 +79,9 @@ const transcodeSourceMap = {
|
|
|
71
79
|
};
|
|
72
80
|
|
|
73
81
|
/**
|
|
74
|
-
* Get an existing destination transcoder from destination map.
|
|
82
|
+
* Get an existing destination transcoder from destination map.
|
|
75
83
|
*
|
|
76
|
-
* @param {*} id Destination type to compress to
|
|
84
|
+
* @param {*} id Destination type to compress to
|
|
77
85
|
* @returns A partial transcoder definition. Otherwise it returns undefined.
|
|
78
86
|
*/
|
|
79
87
|
function getDestinationTranscoder(id) {
|
|
@@ -92,14 +100,14 @@ function getDestinationTranscoder(id) {
|
|
|
92
100
|
*/
|
|
93
101
|
function getTranscoder(transferSyntaxUid, { contentType, verbose }) {
|
|
94
102
|
if (verbose) {
|
|
95
|
-
console.log(
|
|
103
|
+
console.log('getTranscoder for', transferSyntaxUid, 'source to', contentType);
|
|
96
104
|
}
|
|
97
105
|
const sourceTranscoder = transcodeSourceMap[transferSyntaxUid];
|
|
98
106
|
const destinationTranscoder = getDestinationTranscoder(contentType);
|
|
99
107
|
if (!sourceTranscoder || !destinationTranscoder) {
|
|
100
108
|
return undefined;
|
|
101
109
|
}
|
|
102
|
-
|
|
110
|
+
|
|
103
111
|
return {
|
|
104
112
|
transferSyntaxUid: destinationTranscoder.transferSyntaxUid,
|
|
105
113
|
transcodeOp: sourceTranscoder.transcodeOp | destinationTranscoder.transcodeOp, // eslint-disable-line no-bitwise
|
|
@@ -107,24 +115,29 @@ function getTranscoder(transferSyntaxUid, { contentType, verbose }) {
|
|
|
107
115
|
};
|
|
108
116
|
}
|
|
109
117
|
|
|
110
|
-
|
|
111
118
|
/**
|
|
112
119
|
* Tell whether given id contain transferSyntaxUid which can be transcoded or not.
|
|
113
120
|
* @param {*} id object containing transferSyntaxUid
|
|
114
121
|
* @param {*} options runner options
|
|
115
122
|
*/
|
|
116
123
|
function shouldTranscodeImageFrame(id, options) {
|
|
117
|
-
|
|
124
|
+
const { recompress } = options;
|
|
125
|
+
if (!recompress) {
|
|
126
|
+
if( options.verbose ) console.log("Not transcoding because recompress not set");
|
|
118
127
|
return false;
|
|
119
128
|
}
|
|
120
129
|
|
|
121
130
|
function isValidTranscoder() {
|
|
122
131
|
const { transferSyntaxUid } = id;
|
|
123
132
|
const transcoder = getTranscoder(transferSyntaxUid, options);
|
|
124
|
-
return transcoder && transcoder.transferSyntaxUid &&
|
|
133
|
+
return transcoder && transcoder.transferSyntaxUid && (recompress.includes("true") || recompress.includes(transcoder.alias));
|
|
125
134
|
}
|
|
126
135
|
|
|
127
|
-
|
|
136
|
+
const ret = isValidTranscoder();
|
|
137
|
+
if( !ret && options.verbose ) {
|
|
138
|
+
console.log("Not transcoding");
|
|
139
|
+
}
|
|
140
|
+
return ret;
|
|
128
141
|
}
|
|
129
142
|
|
|
130
143
|
/**
|
|
@@ -171,6 +184,7 @@ async function transcodeImageFrame(id, targetIdSrc, imageFrame, dataSet, options
|
|
|
171
184
|
let result = {};
|
|
172
185
|
|
|
173
186
|
if (!shouldTranscodeImageFrame(id, options)) {
|
|
187
|
+
console.log("Shouldn't transcode");
|
|
174
188
|
return {
|
|
175
189
|
id,
|
|
176
190
|
imageFrame,
|
|
@@ -182,6 +196,7 @@ async function transcodeImageFrame(id, targetIdSrc, imageFrame, dataSet, options
|
|
|
182
196
|
|
|
183
197
|
// last chance to prevent transcoding
|
|
184
198
|
if (targetId.transferSyntaxUid !== transcoder.transferSyntaxUid) {
|
|
199
|
+
console.log("Image is already in", targetId.transferSyntaxUid, "not transcoding");
|
|
185
200
|
return {
|
|
186
201
|
id,
|
|
187
202
|
imageFrame,
|
|
@@ -189,9 +204,8 @@ async function transcodeImageFrame(id, targetIdSrc, imageFrame, dataSet, options
|
|
|
189
204
|
};
|
|
190
205
|
}
|
|
191
206
|
|
|
192
|
-
if
|
|
193
|
-
|
|
194
|
-
}
|
|
207
|
+
if( options.verbose ) console.log("Transcoding to", transcoder.transferSyntaxUid);
|
|
208
|
+
|
|
195
209
|
const imageInfo = getImageInfo(dataSet);
|
|
196
210
|
let done = false;
|
|
197
211
|
let processResultMsg = "";
|
|
@@ -289,7 +303,10 @@ function transcodeMetadata(metadata, id, options) {
|
|
|
289
303
|
const result = { ...metadata };
|
|
290
304
|
|
|
291
305
|
if (result[Tags.AvailableTransferSyntaxUID]) {
|
|
292
|
-
Tags.setValue(result,Tags.AvailableTransferSyntaxUID, transcodedId.transferSyntaxUid);
|
|
306
|
+
Tags.setValue(result, Tags.AvailableTransferSyntaxUID, transcodedId.transferSyntaxUid);
|
|
307
|
+
if( this.verbose ) {
|
|
308
|
+
console.log("Apply available tsuid", transcodeId.transferSyntaxUid);
|
|
309
|
+
}
|
|
293
310
|
}
|
|
294
311
|
|
|
295
312
|
return result;
|
package/lib/operation/getVR.js
CHANGED
|
@@ -29,6 +29,7 @@ module.exports = function adaptProgramOpts(programOpts, defaults) {
|
|
|
29
29
|
prependBulkDataUri,
|
|
30
30
|
expandBulkDataUri,
|
|
31
31
|
verbose,
|
|
32
|
+
scpPort,
|
|
32
33
|
} = programOpts;
|
|
33
34
|
|
|
34
35
|
return assignDefined(
|
|
@@ -50,6 +51,7 @@ module.exports = function adaptProgramOpts(programOpts, defaults) {
|
|
|
50
51
|
pathInstances,
|
|
51
52
|
removeDeduplicatedInstances,
|
|
52
53
|
storeMultipartBulkData,
|
|
54
|
+
scpPort,
|
|
53
55
|
prependBulkDataUri,
|
|
54
56
|
expandBulkDataUri,
|
|
55
57
|
verbose,
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
const { program } = require("@radicalimaging/static-wado-util");
|
|
2
2
|
const { getDestinationTranscoder } = require("../operation/adapter/transcodeImage");
|
|
3
3
|
|
|
4
|
-
module.exports = function compressionOptionParser(value) {
|
|
4
|
+
module.exports = function compressionOptionParser(value) {
|
|
5
5
|
const destination = getDestinationTranscoder(value);
|
|
6
6
|
if (destination) {
|
|
7
7
|
console.log("Found destination transferSyntax ", destination.transferSyntaxUid, "for ", value);
|
|
8
8
|
} else {
|
|
9
9
|
console.log("No transcoder destination for ", value);
|
|
10
10
|
throw new program.InvalidArgumentError(`No transcoder destination for ${value}`);
|
|
11
|
-
}
|
|
11
|
+
}
|
|
12
12
|
return destination.transferSyntaxUid;
|
|
13
|
-
}
|
|
13
|
+
};
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
const { Stats } = require("@radicalimaging/static-wado-util");
|
|
2
|
-
const {
|
|
3
|
-
const JSONWriter = require("./JSONWriter");
|
|
1
|
+
const { JSONReader, JSONWriter, Stats } = require("@radicalimaging/static-wado-util");
|
|
2
|
+
const { Tags } = require("@radicalimaging/static-wado-util");
|
|
4
3
|
const StudyData = require("../operation/StudyData");
|
|
5
|
-
const Tags = require("../dictionary/Tags");
|
|
6
4
|
|
|
7
5
|
/**
|
|
8
6
|
* CompleteStudyWriter takes the deduplicated data values, all loaded into the study parameter,
|
|
@@ -47,12 +45,12 @@ const CompleteStudyWriter = (options) => {
|
|
|
47
45
|
const studyQuery = await studyData.writeMetadata();
|
|
48
46
|
|
|
49
47
|
const allStudies = await JSONReader(options.directoryName, "studies/index.json.gz", []);
|
|
50
|
-
const studyUID = Tags.getValue(studyQuery,Tags.StudyInstanceUID);
|
|
48
|
+
const studyUID = Tags.getValue(studyQuery, Tags.StudyInstanceUID);
|
|
51
49
|
if (!studyUID) {
|
|
52
50
|
console.error("studyQuery=", studyQuery);
|
|
53
51
|
throw new Error("Study query has null studyUID");
|
|
54
52
|
}
|
|
55
|
-
const studyIndex = allStudies.findIndex((item) => Tags.getValue(item,Tags.StudyInstanceUID) == studyUID);
|
|
53
|
+
const studyIndex = allStudies.findIndex((item) => Tags.getValue(item, Tags.StudyInstanceUID) == studyUID);
|
|
56
54
|
if (studyIndex == -1) {
|
|
57
55
|
allStudies.push(studyQuery);
|
|
58
56
|
} else {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const hashFactory = require("node-object-hash");
|
|
2
2
|
|
|
3
3
|
const hasher = hashFactory();
|
|
4
|
-
const JSONWriter = require("
|
|
5
|
-
const Tags = require("
|
|
4
|
+
const { JSONWriter } = require("@radicalimaging/static-wado-util");
|
|
5
|
+
const { Tags } = require("@radicalimaging/static-wado-util");
|
|
6
6
|
const TagLists = require("../model/TagLists");
|
|
7
7
|
|
|
8
8
|
async function writeDeduplicatedFile(dir, data, hashValueSrc) {
|
|
@@ -2,7 +2,7 @@ const hashFactory = require("node-object-hash");
|
|
|
2
2
|
|
|
3
3
|
const hasher = hashFactory();
|
|
4
4
|
const path = require("path");
|
|
5
|
-
const Tags = require("
|
|
5
|
+
const { Tags } = require("@radicalimaging/static-wado-util");
|
|
6
6
|
const WriteStream = require("./WriteStream");
|
|
7
7
|
const WriteMultipart = require("./WriteMultipart");
|
|
8
8
|
const ExpandUriPath = require("./ExpandUriPath");
|
|
@@ -47,7 +47,7 @@ HashDataWriter.createHashPath = (data, options = {}) => {
|
|
|
47
47
|
const { mimeType } = options;
|
|
48
48
|
const isRaw = ArrayBuffer.isView(data);
|
|
49
49
|
const extension = isRaw ? (mimeType && extensions[mimeType]) || "" : ".json";
|
|
50
|
-
const hashValue = Tags.getValue(data,Tags.DeduppedHash) || hasher.hash(data);
|
|
50
|
+
const hashValue = Tags.getValue(data, Tags.DeduppedHash) || hasher.hash(data);
|
|
51
51
|
|
|
52
52
|
return {
|
|
53
53
|
// Use string concat as this value is used for the BulkDataURI which needs forward slashes
|
|
@@ -5,24 +5,43 @@ const ExpandUriPath = require("./ExpandUriPath");
|
|
|
5
5
|
const { MultipartHeader, MultipartAttribute } = require("./MultipartHeader");
|
|
6
6
|
|
|
7
7
|
const ImageFrameWriter = (options) => {
|
|
8
|
-
const { verbose } = options;
|
|
8
|
+
const { verbose, encapsulatedImageFrame = true } = options;
|
|
9
9
|
|
|
10
10
|
return async (id, index, imageFrame) => {
|
|
11
11
|
const { transferSyntaxUid } = id;
|
|
12
12
|
const type = uids[transferSyntaxUid] || uids.default;
|
|
13
|
-
const
|
|
14
|
-
gzip: type.gzip,
|
|
15
|
-
mkdir: true,
|
|
16
|
-
});
|
|
13
|
+
const extension = type.extension;
|
|
17
14
|
let content;
|
|
18
15
|
if (imageFrame instanceof Uint8Array) {
|
|
19
16
|
content = imageFrame;
|
|
20
17
|
} else {
|
|
21
18
|
content = Buffer.from(imageFrame.buffer);
|
|
22
19
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
|
|
21
|
+
if (encapsulatedImageFrame || !extension) {
|
|
22
|
+
const writeStream = WriteStream(id.imageFrameRootPath, `${1 + index}`, {
|
|
23
|
+
gzip: type.gzip,
|
|
24
|
+
mkdir: true,
|
|
25
|
+
});
|
|
26
|
+
await WriteMultipart(
|
|
27
|
+
writeStream,
|
|
28
|
+
[new MultipartHeader("Content-Type", type.contentType, [new MultipartAttribute("transfer-syntax", transferSyntaxUid)])],
|
|
29
|
+
content
|
|
30
|
+
);
|
|
31
|
+
writeStream.close();
|
|
32
|
+
if (verbose) {
|
|
33
|
+
console.log("Wrote encapsulated image frame", id.sopInstanceUid, index + 1, type.contentType);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (extension) {
|
|
37
|
+
const writeStreamSingle = WriteStream(id.imageFrameRootPath, `${1 + index}${extension}`, {
|
|
38
|
+
gzip: type.gzip,
|
|
39
|
+
mkdir: true,
|
|
40
|
+
});
|
|
41
|
+
await writeStreamSingle.write(content);
|
|
42
|
+
writeStreamSingle.close();
|
|
43
|
+
if (verbose) console.log("Wrote single part image frame", id.sopInstanceUid, index + 1, extension);
|
|
44
|
+
}
|
|
26
45
|
const includeSeries = true;
|
|
27
46
|
return ExpandUriPath(id, `instances/${id.sopInstanceUid}/frames`, { includeSeries, ...options });
|
|
28
47
|
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const { Tags } = require("@radicalimaging/static-wado-util");
|
|
2
|
+
const WriteStream = require("./WriteStream");
|
|
3
|
+
const WriteMultipart = require("./WriteMultipart");
|
|
4
|
+
const { MultipartHeader } = require("./MultipartHeader");
|
|
5
|
+
|
|
6
|
+
const modalitiesToRawWrite = ["SEG", "SR"];
|
|
7
|
+
|
|
8
|
+
const defaultSelector = (instance) => {
|
|
9
|
+
const modality = instance.metadata[Tags.Modality]?.Value?.[0];
|
|
10
|
+
return modalitiesToRawWrite.indexOf(modality) !== -1;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/** Writes out raw DICOM files, encapsulated in multipart and gzipped - currently just DICOM SR and SEG */
|
|
14
|
+
const RawDicomWriter =
|
|
15
|
+
() =>
|
|
16
|
+
async (id, instance, content, options = { gzip: true }) => {
|
|
17
|
+
if (!instance) {
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
const selector = options.selector || defaultSelector;
|
|
21
|
+
if (!selector(instance)) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
const contentType = options.contentType || "application/dicom";
|
|
25
|
+
const writeStream = WriteStream(id.sopInstanceRootPath, "index.mht", {
|
|
26
|
+
gzip: options.gzip,
|
|
27
|
+
mkdir: true,
|
|
28
|
+
});
|
|
29
|
+
const { length } = content;
|
|
30
|
+
const buffer = content.slice(0, length);
|
|
31
|
+
await WriteMultipart(writeStream, [new MultipartHeader("Content-Type", contentType, [])], buffer);
|
|
32
|
+
await writeStream.close();
|
|
33
|
+
};
|
|
34
|
+
RawDicomWriter.defaultSelector = defaultSelector;
|
|
35
|
+
|
|
36
|
+
module.exports = RawDicomWriter;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@radicalimaging/static-wado-creator",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Library to convert DICOMP10 to DICOMweb format. Original upstream: https://github.com/chafey/dicomp10-to-dicomweb-js",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -53,21 +53,22 @@
|
|
|
53
53
|
"build": "echo \"No build yet\" && exit 0",
|
|
54
54
|
"link:exec": "npm link",
|
|
55
55
|
"lint": "npx eslint --color \"*(bin|lib)/**/*.{js,mjs}\"",
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
"lint:fix": "npx eslint --fix --color \"*(bin|lib)/**/*.{js,mjs}\""
|
|
57
|
+
},
|
|
58
58
|
"jest": {
|
|
59
59
|
"verbose": true
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
62
|
"@cornerstonejs/dicom-codec": "^0.1.3",
|
|
63
|
-
"@radicalimaging/static-cs-lite": "^0.0.
|
|
63
|
+
"@radicalimaging/static-cs-lite": "^0.0.3",
|
|
64
64
|
"@radicalimaging/static-wado-util": "^0.6.2",
|
|
65
65
|
"canvas": "^2.9.1",
|
|
66
|
-
"config-point": "^0.5.
|
|
66
|
+
"config-point": "^0.5.1",
|
|
67
|
+
"dcmjs": "^0.28.0",
|
|
67
68
|
"dicom-parser": "^1.8.13",
|
|
68
69
|
"glob": "^7.2.0",
|
|
69
|
-
"
|
|
70
|
-
"
|
|
70
|
+
"node-object-hash": "^2.3.10",
|
|
71
|
+
"uuid": "^8.3.2"
|
|
71
72
|
},
|
|
72
73
|
"devDependencies": {
|
|
73
74
|
"must": "^0.13.4"
|
package/lib/dictionary/Tags.js
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
const dataDictionary = require("./dataDictionary");
|
|
2
|
-
const dcmjs = require("dcmjs");
|
|
3
|
-
|
|
4
|
-
const { naturalizeDataset, denaturalizeDataset} = dcmjs.data.DicomMetaDictionary
|
|
5
|
-
|
|
6
|
-
/** Find the actual tag for a private value */
|
|
7
|
-
const findPrivate = (item, tagObject, create) => {
|
|
8
|
-
if( typeof tagObject === "string" ) return tagObject;
|
|
9
|
-
if( typeof tagObject === "number" ) return `00000000${tagObject.toString(16)}`.slice(-8);
|
|
10
|
-
const {creator,tag} = tagObject;
|
|
11
|
-
if( !creator ) return tag;
|
|
12
|
-
const start = tag.substring(0,4);
|
|
13
|
-
const end = tag.substring(6,8);
|
|
14
|
-
// Should technically go all the way up, but for now only test 0x30 items
|
|
15
|
-
let assignPosition;
|
|
16
|
-
for(let offset = 0x10; offset < 0x40; offset++) {
|
|
17
|
-
const testTag = `${start}00${offset.toString(16)}`
|
|
18
|
-
const testCreator = item[testTag];
|
|
19
|
-
if( testCreator===undefined && assignPosition===undefined ) assignPosition = offset;
|
|
20
|
-
if( testCreator && testCreator.Value && testCreator.Value[0]===creator ) {
|
|
21
|
-
return `${start}${offset.toString(16)}${end}`
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
if( create ) {
|
|
25
|
-
if( !assignPosition ) throw new Error(`Couldn't find any assign positions for ${creator} ${tag} in ${item}`);
|
|
26
|
-
const creatorTag = `${start}00${assignPosition.toString(16)}`
|
|
27
|
-
item[creatorTag] = { Value: [creator], vr: 'CS' };
|
|
28
|
-
return `${start}${assignPosition.toString(16)}${end}`
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const DeduppedCreator = "dedupped";
|
|
33
|
-
|
|
34
|
-
const Tags = {
|
|
35
|
-
// Raw tags have the x before them, not parsed yet
|
|
36
|
-
RawMinTag: "x00000000",
|
|
37
|
-
RawFirstBodyTag: "x00080000",
|
|
38
|
-
RawTransferSyntaxUID: "x00020010",
|
|
39
|
-
|
|
40
|
-
// This one isn't defined in the dataDictionary
|
|
41
|
-
AvailableTransferSyntaxUID: "00083002",
|
|
42
|
-
|
|
43
|
-
DeduppedCreator,
|
|
44
|
-
|
|
45
|
-
// The references to extract data included in this object, 1..n values
|
|
46
|
-
DeduppedRef: { creator: DeduppedCreator, tag: "00091010"},
|
|
47
|
-
|
|
48
|
-
// The hash value of THIS object
|
|
49
|
-
DeduppedHash: {creator: DeduppedCreator, tag: "00091011"},
|
|
50
|
-
|
|
51
|
-
// Type of hash instance
|
|
52
|
-
DeduppedType: {creator: DeduppedCreator, tag: "00091012"},
|
|
53
|
-
InstanceType: "instance",
|
|
54
|
-
InfoType: "info",
|
|
55
|
-
|
|
56
|
-
naturalizeDataset, denaturalizeDataset,
|
|
57
|
-
|
|
58
|
-
setValue: (item, tag, value) => {
|
|
59
|
-
const actualTag = findPrivate(item,tag,true);
|
|
60
|
-
item[actualTag] = { Value: Array.isArray(value) ? value : [value] };
|
|
61
|
-
return actualTag;
|
|
62
|
-
},
|
|
63
|
-
|
|
64
|
-
setList: (item, tag, value) => {
|
|
65
|
-
const actualTag = findPrivate(item,tag,true);
|
|
66
|
-
item[actualTag] = {Value: Array.isArray(value) ? value : [value]};
|
|
67
|
-
return actualTag;
|
|
68
|
-
},
|
|
69
|
-
|
|
70
|
-
pushList: (item, tag, value) => {
|
|
71
|
-
const actualTag = findPrivate(item,tag,true);
|
|
72
|
-
if( !item[actualTag] ) item[actualTag] = { Value: [] };
|
|
73
|
-
item[actualTag].Value.push(value);
|
|
74
|
-
return actualTag;
|
|
75
|
-
},
|
|
76
|
-
|
|
77
|
-
getValue: (item, tag) => {
|
|
78
|
-
const actualTag = findPrivate(item,tag);
|
|
79
|
-
if( !actualTag ) return undefined;
|
|
80
|
-
const value = item[actualTag];
|
|
81
|
-
if( value===undefined ) return undefined;
|
|
82
|
-
if( Array.isArray(value) ) return value.length==1 ? value[0] : (value.length===0 ? "" : value);
|
|
83
|
-
if( value.Value ) return value.Value.length==1 ? value.Value[0] : (value.Value.length===0 ? "" : value.Value);
|
|
84
|
-
return value;
|
|
85
|
-
},
|
|
86
|
-
|
|
87
|
-
getList: (item, tag) => {
|
|
88
|
-
const actualTag = findPrivate(item,tag);
|
|
89
|
-
if( !actualTag ) return undefined;
|
|
90
|
-
const value = item[actualTag];
|
|
91
|
-
if( value===undefined ) return undefined;
|
|
92
|
-
if( Array.isArray(value) ) return value;
|
|
93
|
-
if( value.Value ) return value.Value;
|
|
94
|
-
return [value];
|
|
95
|
-
},
|
|
96
|
-
|
|
97
|
-
removeValue: (item,tag) => {
|
|
98
|
-
const actualTag = findPrivate(item,tag);
|
|
99
|
-
if( actualTag ) delete item[actualTag];
|
|
100
|
-
// TODO, remove creator tag if not used any longer
|
|
101
|
-
},
|
|
102
|
-
|
|
103
|
-
findPrivate,
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
Object.keys(dataDictionary).forEach((key) => {
|
|
107
|
-
const value = dataDictionary[key];
|
|
108
|
-
Tags[value.name] = key;
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
module.exports = Tags;
|