@radicalimaging/static-wado-creator 1.6.10 → 1.6.12
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/dist/index.js +84817 -54902
- package/lib/DeleteStudy.js +9 -14
- package/lib/RejectInstance.js +4 -15
- package/lib/StaticWado.js +92 -147
- package/lib/createMain.js +3 -3
- package/lib/createPart10.js +19 -23
- package/lib/createThumbnail.js +27 -45
- package/lib/deleteMain.js +2 -2
- package/lib/groupMain.js +2 -2
- package/lib/index.js +6 -6
- package/lib/indexMain.js +2 -2
- package/lib/instanceMain.js +2 -2
- package/lib/metadataMain.js +2 -2
- package/lib/mkdicomwebConfig.js +157 -165
- package/lib/model/TagLists.js +5 -17
- package/lib/model/uids.js +29 -29
- package/lib/operation/InstanceDeduplicate.js +14 -19
- package/lib/operation/ScanStudy.js +11 -18
- package/lib/operation/StudyData.js +87 -156
- package/lib/operation/ThumbnailService.js +29 -54
- package/lib/operation/adapter/decodeImage.js +2 -2
- package/lib/operation/adapter/getImageInfo.js +7 -8
- package/lib/operation/adapter/transcodeImage.js +95 -146
- package/lib/operation/extractImageFrames.js +13 -17
- package/lib/operation/getDataSet.js +9 -43
- package/lib/operation/getEncapsulatedImageFrame.js +7 -19
- package/lib/operation/getNumberOfFrames.js +2 -2
- package/lib/operation/getUncompressedImageFrame.js +2 -10
- package/lib/operation/getVR.js +5 -5
- package/lib/operation/getValue.js +42 -65
- package/lib/operation/validateMetadata.js +4 -4
- package/lib/program/index.js +2 -5
- package/lib/rejectMain.js +2 -2
- package/lib/serverMain.js +8 -14
- package/lib/util/IdCreator.js +8 -17
- package/lib/util/adaptProgramOpts.js +2 -2
- package/lib/util/compressionOptionParser.js +5 -14
- package/lib/util/resultsReport.ts +67 -68
- package/lib/writer/CompleteStudyWriter.js +24 -37
- package/lib/writer/DeduplicateWriter.js +7 -8
- package/lib/writer/ExpandUriPath.js +3 -5
- package/lib/writer/HashDataWriter.js +18 -18
- package/lib/writer/ImageFrameWriter.js +20 -33
- package/lib/writer/MultipartHeader.js +1 -1
- package/lib/writer/RawDicomWriter.js +12 -13
- package/lib/writer/ThumbnailWriter.js +2 -2
- package/lib/writer/VideoWriter.js +23 -34
- package/lib/writer/WriteMultipart.js +4 -6
- package/lib/writer/WriteStream.js +14 -20
- package/package.json +1 -1
- package/lib/writer/static-dicomweb.code-workspace +0 -8
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const dicomCodec = require(
|
|
2
|
-
const { Tags, replicate } = require(
|
|
3
|
-
const getImageInfo = require(
|
|
1
|
+
const dicomCodec = require('@cornerstonejs/dicom-codec');
|
|
2
|
+
const { Tags, replicate } = require('@radicalimaging/static-wado-util');
|
|
3
|
+
const getImageInfo = require('./getImageInfo');
|
|
4
4
|
|
|
5
|
-
dicomCodec.setConfig(
|
|
5
|
+
dicomCodec.setConfig('verbose: false');
|
|
6
6
|
|
|
7
7
|
const transcodeOp = {
|
|
8
8
|
none: 0,
|
|
@@ -14,21 +14,21 @@ const transcodeOp = {
|
|
|
14
14
|
const jpegBeforeEncode = (options, encoder) => {
|
|
15
15
|
const quality = options.quality ?? 99;
|
|
16
16
|
// First value is to encode as reversible lossless colour
|
|
17
|
-
return
|
|
18
|
-
console.log(
|
|
17
|
+
return encoder => {
|
|
18
|
+
console.log('Calling setQuality', quality, !!encoder.setQuality);
|
|
19
19
|
encoder.setQuality(quality);
|
|
20
20
|
};
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
-
const jlsBeforeEncode =
|
|
23
|
+
const jlsBeforeEncode = options => {
|
|
24
24
|
const delta = (options.delta ?? lossy) ? 3 : 0;
|
|
25
|
-
return
|
|
25
|
+
return encoder => encoder.setNearLossless(delta);
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
const htj2kBeforeEncode =
|
|
28
|
+
const htj2kBeforeEncode = options => {
|
|
29
29
|
const { lossy } = options;
|
|
30
30
|
const quality = lossy === true ? 0.002 : -1;
|
|
31
|
-
return
|
|
31
|
+
return encoder => encoder.setQuality(!lossy, quality);
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
/**
|
|
@@ -36,92 +36,92 @@ const htj2kBeforeEncode = (options) => {
|
|
|
36
36
|
*/
|
|
37
37
|
const transcodeDestinationMap = {
|
|
38
38
|
lei: {
|
|
39
|
-
transferSyntaxUid:
|
|
39
|
+
transferSyntaxUid: '1.2.840.10008.1.2.1',
|
|
40
40
|
transcodeOp: transcodeOp.none,
|
|
41
41
|
},
|
|
42
42
|
jls: {
|
|
43
|
-
transferSyntaxUid:
|
|
43
|
+
transferSyntaxUid: '1.2.840.10008.1.2.4.80',
|
|
44
44
|
transcodeOp: transcodeOp.encode,
|
|
45
45
|
beforeEncode: jlsBeforeEncode.bind(null, { lossy: false }),
|
|
46
46
|
},
|
|
47
|
-
|
|
48
|
-
transferSyntaxUid:
|
|
47
|
+
'jls-lossy': {
|
|
48
|
+
transferSyntaxUid: '1.2.840.10008.1.2.4.81',
|
|
49
49
|
transcodeOp: transcodeOp.encode,
|
|
50
50
|
beforeEncode: jlsBeforeEncode.bind(null, { lossy: true, delta: 3 }),
|
|
51
51
|
},
|
|
52
52
|
jp2: {
|
|
53
|
-
transferSyntaxUid:
|
|
53
|
+
transferSyntaxUid: '1.2.840.10008.1.2.4.90',
|
|
54
54
|
transcodeOp: transcodeOp.encode,
|
|
55
55
|
},
|
|
56
|
-
|
|
57
|
-
transferSyntaxUid:
|
|
56
|
+
'jp2-lossy': {
|
|
57
|
+
transferSyntaxUid: '1.2.840.10008.1.2.4.91',
|
|
58
58
|
transcodeOp: transcodeOp.encode,
|
|
59
59
|
},
|
|
60
60
|
jhc: {
|
|
61
|
-
transferSyntaxUid:
|
|
61
|
+
transferSyntaxUid: '1.2.840.10008.1.2.4.201',
|
|
62
62
|
transcodeOp: transcodeOp.encode,
|
|
63
63
|
beforeEncode: htj2kBeforeEncode({}),
|
|
64
64
|
},
|
|
65
|
-
|
|
66
|
-
transferSyntaxUid:
|
|
65
|
+
'jhc-lossy': {
|
|
66
|
+
transferSyntaxUid: '1.2.840.10008.1.2.4.202',
|
|
67
67
|
transcodeOp: transcodeOp.encode,
|
|
68
68
|
beforeEncode: htj2kBeforeEncode({ lossy: true }),
|
|
69
69
|
},
|
|
70
70
|
jpeg: {
|
|
71
|
-
transferSyntaxUid:
|
|
71
|
+
transferSyntaxUid: '1.2.840.10008.1.2.4.50',
|
|
72
72
|
transcodeOp: transcodeOp.encode,
|
|
73
73
|
// beforeEncode: jpegBeforeEncode({}),
|
|
74
74
|
},
|
|
75
75
|
};
|
|
76
76
|
|
|
77
77
|
const transcodeSourceMap = {
|
|
78
|
-
|
|
78
|
+
'1.2.840.10008.1.2': {
|
|
79
79
|
transcodeOp: transcodeOp.decode,
|
|
80
|
-
alias:
|
|
80
|
+
alias: 'uncompressed',
|
|
81
81
|
},
|
|
82
|
-
|
|
82
|
+
'1.2.840.10008.1.2.1': {
|
|
83
83
|
transcodeOp: transcodeOp.none,
|
|
84
|
-
alias:
|
|
84
|
+
alias: 'uncompressed',
|
|
85
85
|
},
|
|
86
|
-
|
|
86
|
+
'1.2.840.10008.1.2.2': {
|
|
87
87
|
transcodeOp: transcodeOp.decode,
|
|
88
|
-
alias:
|
|
88
|
+
alias: 'uncompressed',
|
|
89
89
|
},
|
|
90
|
-
|
|
90
|
+
'1.2.840.10008.1.2.4.50': {
|
|
91
91
|
transcodeOp: transcodeOp.decode,
|
|
92
|
-
alias:
|
|
92
|
+
alias: 'jpeg',
|
|
93
93
|
},
|
|
94
|
-
|
|
94
|
+
'1.2.840.10008.1.2.4.57': {
|
|
95
95
|
transcodeOp: transcodeOp.decode,
|
|
96
|
-
alias:
|
|
96
|
+
alias: 'jls',
|
|
97
97
|
},
|
|
98
|
-
|
|
98
|
+
'1.2.840.10008.1.2.4.70': {
|
|
99
99
|
transcodeOp: transcodeOp.decode,
|
|
100
|
-
alias:
|
|
100
|
+
alias: 'jpll',
|
|
101
101
|
},
|
|
102
|
-
|
|
102
|
+
'1.2.840.10008.1.2.4.80': {
|
|
103
103
|
transcodeOp: transcodeOp.decode,
|
|
104
|
-
alias:
|
|
104
|
+
alias: 'jls',
|
|
105
105
|
},
|
|
106
|
-
|
|
106
|
+
'1.2.840.10008.1.2.4.90': {
|
|
107
107
|
transcodeOp: transcodeOp.decode,
|
|
108
|
-
alias:
|
|
108
|
+
alias: 'jp2',
|
|
109
109
|
},
|
|
110
|
-
|
|
110
|
+
'1.2.840.10008.1.2.4.91': {
|
|
111
111
|
transcodeOp: transcodeOp.decode,
|
|
112
|
-
alias:
|
|
112
|
+
alias: 'jp2',
|
|
113
113
|
},
|
|
114
|
-
|
|
114
|
+
'3.2.840.10008.1.2.4.96': {
|
|
115
115
|
transcodeOp: transcodeOp.decode,
|
|
116
|
-
alias:
|
|
116
|
+
alias: 'jhc',
|
|
117
117
|
},
|
|
118
|
-
|
|
118
|
+
'1.2.840.10008.1.2.4.202': {
|
|
119
119
|
transcodeOp: transcodeOp.decode,
|
|
120
|
-
alias:
|
|
120
|
+
alias: 'jhc',
|
|
121
121
|
},
|
|
122
|
-
|
|
122
|
+
'1.2.840.10008.1.2.5': {
|
|
123
123
|
transcodeOp: transcodeOp.decode,
|
|
124
|
-
alias:
|
|
124
|
+
alias: 'rle',
|
|
125
125
|
},
|
|
126
126
|
};
|
|
127
127
|
|
|
@@ -134,9 +134,7 @@ const transcodeSourceMap = {
|
|
|
134
134
|
function getDestinationTranscoder(id) {
|
|
135
135
|
const destinationTranscoderEntry =
|
|
136
136
|
transcodeDestinationMap[id] ||
|
|
137
|
-
Object.values(transcodeDestinationMap).find(
|
|
138
|
-
(value) => value.transferSyntaxUid === id,
|
|
139
|
-
);
|
|
137
|
+
Object.values(transcodeDestinationMap).find(value => value.transferSyntaxUid === id);
|
|
140
138
|
return destinationTranscoderEntry;
|
|
141
139
|
}
|
|
142
140
|
|
|
@@ -149,10 +147,9 @@ function getDestinationTranscoder(id) {
|
|
|
149
147
|
function getTranscoder(
|
|
150
148
|
transferSyntaxUid,
|
|
151
149
|
{ contentType: greyContentType, colorContentType },
|
|
152
|
-
samplesPerPixel
|
|
150
|
+
samplesPerPixel
|
|
153
151
|
) {
|
|
154
|
-
const contentType =
|
|
155
|
-
samplesPerPixel === 3 ? colorContentType : greyContentType;
|
|
152
|
+
const contentType = samplesPerPixel === 3 ? colorContentType : greyContentType;
|
|
156
153
|
const sourceTranscoder = transcodeSourceMap[transferSyntaxUid];
|
|
157
154
|
const destinationTranscoder = getDestinationTranscoder(contentType);
|
|
158
155
|
if (!sourceTranscoder || !destinationTranscoder) {
|
|
@@ -161,8 +158,7 @@ function getTranscoder(
|
|
|
161
158
|
|
|
162
159
|
return {
|
|
163
160
|
transferSyntaxUid: destinationTranscoder.transferSyntaxUid,
|
|
164
|
-
transcodeOp:
|
|
165
|
-
sourceTranscoder.transcodeOp | destinationTranscoder.transcodeOp,
|
|
161
|
+
transcodeOp: sourceTranscoder.transcodeOp | destinationTranscoder.transcodeOp,
|
|
166
162
|
alias: sourceTranscoder.alias,
|
|
167
163
|
beforeEncode: destinationTranscoder.beforeEncode,
|
|
168
164
|
};
|
|
@@ -177,7 +173,7 @@ function shouldTranscodeImageFrame(id, options, samplesPerPixel) {
|
|
|
177
173
|
const { recompress: recompressGrey, recompressColor } = options;
|
|
178
174
|
const recompress = samplesPerPixel === 3 ? recompressColor : recompressGrey;
|
|
179
175
|
if (!recompress) {
|
|
180
|
-
console.verbose(
|
|
176
|
+
console.verbose('Not transcoding because recompress not set');
|
|
181
177
|
return false;
|
|
182
178
|
}
|
|
183
179
|
|
|
@@ -186,20 +182,19 @@ function shouldTranscodeImageFrame(id, options, samplesPerPixel) {
|
|
|
186
182
|
const validTranscoder = transcoder && transcoder.transferSyntaxUid;
|
|
187
183
|
if (!validTranscoder) {
|
|
188
184
|
console.verbose(
|
|
189
|
-
|
|
185
|
+
'Not transcoding because no decoder found for',
|
|
190
186
|
transferSyntaxUid,
|
|
191
|
-
samplesPerPixel
|
|
187
|
+
samplesPerPixel
|
|
192
188
|
);
|
|
193
189
|
return false;
|
|
194
190
|
}
|
|
195
|
-
const validRecompress =
|
|
196
|
-
recompress.includes("true") || recompress.includes(transcoder.alias);
|
|
191
|
+
const validRecompress = recompress.includes('true') || recompress.includes(transcoder.alias);
|
|
197
192
|
if (!validRecompress) {
|
|
198
193
|
console.verbose(
|
|
199
|
-
|
|
194
|
+
'Not transcoding because recompress',
|
|
200
195
|
recompress,
|
|
201
|
-
|
|
202
|
-
transcoder.alias
|
|
196
|
+
'does not include',
|
|
197
|
+
transcoder.alias
|
|
203
198
|
);
|
|
204
199
|
return false;
|
|
205
200
|
}
|
|
@@ -222,7 +217,7 @@ function shouldThumbUseTranscoded(id, options) {
|
|
|
222
217
|
function isValidTranscoder() {
|
|
223
218
|
const { transferSyntaxUid } = id;
|
|
224
219
|
// Ignore the samples per pixel for thumbnails
|
|
225
|
-
const transcoder = getTranscoder(transferSyntaxUid, options,
|
|
220
|
+
const transcoder = getTranscoder(transferSyntaxUid, options, 'thumbnail');
|
|
226
221
|
const result =
|
|
227
222
|
transcoder &&
|
|
228
223
|
transcoder.transferSyntaxUid &&
|
|
@@ -235,15 +230,14 @@ function shouldThumbUseTranscoded(id, options) {
|
|
|
235
230
|
return isValidTranscoder();
|
|
236
231
|
}
|
|
237
232
|
|
|
238
|
-
function transcodeLog(options, msg, error =
|
|
233
|
+
function transcodeLog(options, msg, error = '') {
|
|
239
234
|
if (options.verbose) {
|
|
240
235
|
console.log(`\x1b[34m${msg}\x1b[0m`, error);
|
|
241
236
|
}
|
|
242
237
|
}
|
|
243
238
|
|
|
244
239
|
function scale(imageFrame, imageInfo) {
|
|
245
|
-
const { rows, columns, bitsPerPixel, pixelRepresentation, samplesPerPixel } =
|
|
246
|
-
imageInfo;
|
|
240
|
+
const { rows, columns, bitsPerPixel, pixelRepresentation, samplesPerPixel } = imageInfo;
|
|
247
241
|
let ArrayConstructor = Float32Array;
|
|
248
242
|
if (bitsPerPixel === 8) {
|
|
249
243
|
ArrayConstructor = pixelRepresentation ? Int8Array : Uint8Array;
|
|
@@ -261,9 +255,7 @@ function scale(imageFrame, imageInfo) {
|
|
|
261
255
|
columns: Math.round(columns / 4),
|
|
262
256
|
samplesPerPixel,
|
|
263
257
|
};
|
|
264
|
-
dest.pixelData = new ArrayConstructor(
|
|
265
|
-
dest.rows * dest.columns * samplesPerPixel,
|
|
266
|
-
);
|
|
258
|
+
dest.pixelData = new ArrayConstructor(dest.rows * dest.columns * samplesPerPixel);
|
|
267
259
|
replicate(src, dest);
|
|
268
260
|
|
|
269
261
|
return {
|
|
@@ -288,16 +280,13 @@ function scale(imageFrame, imageInfo) {
|
|
|
288
280
|
async function generateLossyImage(id, decoded, options) {
|
|
289
281
|
if (!options.alternate) return;
|
|
290
282
|
if (!decoded?.imageFrame) return;
|
|
291
|
-
console.verbose(
|
|
283
|
+
console.verbose('Writing alternate thumbnail');
|
|
292
284
|
|
|
293
285
|
try {
|
|
294
286
|
let { imageFrame, imageInfo } = decoded;
|
|
295
287
|
const lossyId = {
|
|
296
288
|
...id,
|
|
297
|
-
imageFrameRootPath: id.imageFrameRootPath.replace(
|
|
298
|
-
"frames",
|
|
299
|
-
options.alternateName,
|
|
300
|
-
),
|
|
289
|
+
imageFrameRootPath: id.imageFrameRootPath.replace('frames', options.alternateName),
|
|
301
290
|
transferSyntaxUid: transcodeDestinationMap.jhc.transferSyntaxUid,
|
|
302
291
|
};
|
|
303
292
|
|
|
@@ -312,13 +301,12 @@ async function generateLossyImage(id, decoded, options) {
|
|
|
312
301
|
imageInfo = scaled.imageInfo;
|
|
313
302
|
}
|
|
314
303
|
|
|
315
|
-
if (options.alternate ===
|
|
316
|
-
lossyId.transferSyntaxUid =
|
|
317
|
-
|
|
318
|
-
} else if (options.alternate === "jlsLossless") {
|
|
304
|
+
if (options.alternate === 'jls') {
|
|
305
|
+
lossyId.transferSyntaxUid = transcodeDestinationMap['jls-lossy'].transferSyntaxUid;
|
|
306
|
+
} else if (options.alternate === 'jlsLossless') {
|
|
319
307
|
lossyId.transferSyntaxUid = transcodeDestinationMap.jls.transferSyntaxUid;
|
|
320
308
|
lossy = false;
|
|
321
|
-
} else if (options.alternate ===
|
|
309
|
+
} else if (options.alternate === 'jhcLossless') {
|
|
322
310
|
lossy = false;
|
|
323
311
|
}
|
|
324
312
|
|
|
@@ -330,23 +318,23 @@ async function generateLossyImage(id, decoded, options) {
|
|
|
330
318
|
imageFrame,
|
|
331
319
|
imageInfo,
|
|
332
320
|
lossyId.transferSyntaxUid,
|
|
333
|
-
encodeOptions
|
|
321
|
+
encodeOptions
|
|
334
322
|
);
|
|
335
323
|
console.verbose(
|
|
336
|
-
|
|
324
|
+
'Encoded alternate',
|
|
337
325
|
lossyId.transferSyntaxUid,
|
|
338
|
-
|
|
339
|
-
lossyEncoding.imageFrame.length
|
|
326
|
+
'of size',
|
|
327
|
+
lossyEncoding.imageFrame.length
|
|
340
328
|
);
|
|
341
329
|
|
|
342
330
|
return { id: lossyId, imageFrame: lossyEncoding.imageFrame };
|
|
343
331
|
} catch (e) {
|
|
344
|
-
console.warn(
|
|
332
|
+
console.warn('Unable to create alternate:', e);
|
|
345
333
|
}
|
|
346
334
|
}
|
|
347
335
|
|
|
348
336
|
function isPalette(dataSet) {
|
|
349
|
-
return dataSet.string(Tags.RawPhotometricInterpretation) ===
|
|
337
|
+
return dataSet.string(Tags.RawPhotometricInterpretation) === 'PALETTE COLOR';
|
|
350
338
|
}
|
|
351
339
|
|
|
352
340
|
/**
|
|
@@ -359,18 +347,12 @@ function isPalette(dataSet) {
|
|
|
359
347
|
* @param {*} options runner options
|
|
360
348
|
* @returns object result for transcoding operation with id and image frame.
|
|
361
349
|
*/
|
|
362
|
-
async function transcodeImageFrame(
|
|
363
|
-
id,
|
|
364
|
-
targetIdSrc,
|
|
365
|
-
imageFrame,
|
|
366
|
-
dataSet,
|
|
367
|
-
options = {},
|
|
368
|
-
) {
|
|
350
|
+
async function transcodeImageFrame(id, targetIdSrc, imageFrame, dataSet, options = {}) {
|
|
369
351
|
let targetId = targetIdSrc;
|
|
370
352
|
let result = {};
|
|
371
353
|
|
|
372
354
|
const samplesPerPixel = dataSet.uint16(Tags.RawSamplesPerPixel);
|
|
373
|
-
const planarConfiguration = dataSet.uint16(
|
|
355
|
+
const planarConfiguration = dataSet.uint16('x00280006');
|
|
374
356
|
if (
|
|
375
357
|
!shouldTranscodeImageFrame(id, options, samplesPerPixel) ||
|
|
376
358
|
planarConfiguration === 1 ||
|
|
@@ -384,22 +366,11 @@ async function transcodeImageFrame(
|
|
|
384
366
|
};
|
|
385
367
|
}
|
|
386
368
|
|
|
387
|
-
const transcoder = getTranscoder(
|
|
388
|
-
id.transferSyntaxUid,
|
|
389
|
-
options,
|
|
390
|
-
samplesPerPixel,
|
|
391
|
-
);
|
|
369
|
+
const transcoder = getTranscoder(id.transferSyntaxUid, options, samplesPerPixel);
|
|
392
370
|
|
|
393
371
|
// Don't transcode if not required
|
|
394
|
-
if (
|
|
395
|
-
|
|
396
|
-
!options.forceTranscode
|
|
397
|
-
) {
|
|
398
|
-
console.verbose(
|
|
399
|
-
"Image is already in",
|
|
400
|
-
targetId.transferSyntaxUid,
|
|
401
|
-
"not transcoding",
|
|
402
|
-
);
|
|
372
|
+
if (targetId.transferSyntaxUid !== transcoder.transferSyntaxUid && !options.forceTranscode) {
|
|
373
|
+
console.verbose('Image is already in', targetId.transferSyntaxUid, 'not transcoding');
|
|
403
374
|
return {
|
|
404
375
|
id,
|
|
405
376
|
imageFrame,
|
|
@@ -407,11 +378,11 @@ async function transcodeImageFrame(
|
|
|
407
378
|
};
|
|
408
379
|
}
|
|
409
380
|
|
|
410
|
-
console.verbose(
|
|
381
|
+
console.verbose('Transcoding to', transcoder.transferSyntaxUid);
|
|
411
382
|
|
|
412
383
|
const imageInfo = getImageInfo(dataSet);
|
|
413
384
|
let done = false;
|
|
414
|
-
let processResultMsg =
|
|
385
|
+
let processResultMsg = '';
|
|
415
386
|
const encodeOptions = {
|
|
416
387
|
beforeEncode: transcoder.beforeEncode,
|
|
417
388
|
};
|
|
@@ -422,64 +393,50 @@ async function transcodeImageFrame(
|
|
|
422
393
|
case transcodeOp.transcode:
|
|
423
394
|
transcodeLog(
|
|
424
395
|
options,
|
|
425
|
-
`Full transcoding image from \x1b[43m${id.transferSyntaxUid}\x1b[0m to \x1b[43m${targetId.transferSyntaxUid}\x1b[0m
|
|
396
|
+
`Full transcoding image from \x1b[43m${id.transferSyntaxUid}\x1b[0m to \x1b[43m${targetId.transferSyntaxUid}\x1b[0m`
|
|
426
397
|
);
|
|
427
398
|
|
|
428
|
-
decoded = await dicomCodec.decode(
|
|
429
|
-
imageFrame,
|
|
430
|
-
imageInfo,
|
|
431
|
-
id.transferSyntaxUid,
|
|
432
|
-
);
|
|
399
|
+
decoded = await dicomCodec.decode(imageFrame, imageInfo, id.transferSyntaxUid);
|
|
433
400
|
result = await dicomCodec.encode(
|
|
434
401
|
decoded.imageFrame,
|
|
435
402
|
decoded.imageInfo,
|
|
436
403
|
targetId.transferSyntaxUid,
|
|
437
|
-
encodeOptions
|
|
404
|
+
encodeOptions
|
|
438
405
|
);
|
|
439
406
|
|
|
440
407
|
console.verbose(
|
|
441
|
-
|
|
408
|
+
'transcoded image to',
|
|
442
409
|
targetId.transferSyntaxUid,
|
|
443
|
-
|
|
444
|
-
result.imageFrame.length
|
|
410
|
+
'of size',
|
|
411
|
+
result.imageFrame.length
|
|
445
412
|
);
|
|
446
413
|
processResultMsg = `Transcoding finished`;
|
|
447
414
|
break;
|
|
448
415
|
case transcodeOp.encode:
|
|
449
|
-
transcodeLog(
|
|
450
|
-
options,
|
|
451
|
-
`Encoding image to \x1b[43m${targetId.transferSyntaxUid}\x1b[0m`,
|
|
452
|
-
);
|
|
416
|
+
transcodeLog(options, `Encoding image to \x1b[43m${targetId.transferSyntaxUid}\x1b[0m`);
|
|
453
417
|
|
|
454
418
|
result = await dicomCodec.encode(
|
|
455
419
|
imageFrame,
|
|
456
420
|
imageInfo,
|
|
457
421
|
targetId.transferSyntaxUid,
|
|
458
|
-
encodeOptions
|
|
422
|
+
encodeOptions
|
|
459
423
|
);
|
|
460
424
|
|
|
461
425
|
processResultMsg = `Encoding finished`;
|
|
462
426
|
break;
|
|
463
427
|
case transcodeOp.decode:
|
|
464
|
-
transcodeLog(
|
|
465
|
-
|
|
466
|
-
`Decoding image from \x1b[43m${id.transferSyntaxUid}\x1b[0m`,
|
|
467
|
-
);
|
|
468
|
-
result = await dicomCodec.decode(
|
|
469
|
-
imageFrame,
|
|
470
|
-
imageInfo,
|
|
471
|
-
id.transferSyntaxUid,
|
|
472
|
-
);
|
|
428
|
+
transcodeLog(options, `Decoding image from \x1b[43m${id.transferSyntaxUid}\x1b[0m`);
|
|
429
|
+
result = await dicomCodec.decode(imageFrame, imageInfo, id.transferSyntaxUid);
|
|
473
430
|
|
|
474
431
|
processResultMsg = `Decoding finished`;
|
|
475
432
|
break;
|
|
476
433
|
default:
|
|
477
|
-
processResultMsg =
|
|
434
|
+
processResultMsg = '';
|
|
478
435
|
}
|
|
479
436
|
|
|
480
437
|
done = !!result.imageFrame;
|
|
481
438
|
} catch (e) {
|
|
482
|
-
transcodeLog(options,
|
|
439
|
+
transcodeLog(options, 'Failed to transcode image', e);
|
|
483
440
|
}
|
|
484
441
|
|
|
485
442
|
// recover transfer syntax
|
|
@@ -489,7 +446,7 @@ async function transcodeImageFrame(
|
|
|
489
446
|
|
|
490
447
|
// log final message only if resultMsg is present
|
|
491
448
|
if (processResultMsg) {
|
|
492
|
-
processResultMsg += done ?
|
|
449
|
+
processResultMsg += done ? ' successfully' : ' unsuccessfully';
|
|
493
450
|
transcodeLog(options, processResultMsg);
|
|
494
451
|
}
|
|
495
452
|
|
|
@@ -517,11 +474,7 @@ function transcodeId(id, options, samplesPerPixel) {
|
|
|
517
474
|
}
|
|
518
475
|
|
|
519
476
|
const targetId = { ...id };
|
|
520
|
-
const { transferSyntaxUid } = getTranscoder(
|
|
521
|
-
id.transferSyntaxUid,
|
|
522
|
-
options,
|
|
523
|
-
samplesPerPixel,
|
|
524
|
-
);
|
|
477
|
+
const { transferSyntaxUid } = getTranscoder(id.transferSyntaxUid, options, samplesPerPixel);
|
|
525
478
|
|
|
526
479
|
targetId.transferSyntaxUid = transferSyntaxUid;
|
|
527
480
|
|
|
@@ -550,12 +503,8 @@ function transcodeMetadata(metadata, id, options) {
|
|
|
550
503
|
const result = { ...metadata };
|
|
551
504
|
|
|
552
505
|
if (result[Tags.AvailableTransferSyntaxUID]) {
|
|
553
|
-
Tags.setValue(
|
|
554
|
-
|
|
555
|
-
Tags.AvailableTransferSyntaxUID,
|
|
556
|
-
transcodedId.transferSyntaxUid,
|
|
557
|
-
);
|
|
558
|
-
console.verbose("Apply available tsuid", transcodeId.transferSyntaxUid);
|
|
506
|
+
Tags.setValue(result, Tags.AvailableTransferSyntaxUID, transcodedId.transferSyntaxUid);
|
|
507
|
+
console.verbose('Apply available tsuid', transcodeId.transferSyntaxUid);
|
|
559
508
|
}
|
|
560
509
|
|
|
561
510
|
return result;
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
const { Stats } = require(
|
|
1
|
+
const { Stats } = require('@radicalimaging/static-wado-util');
|
|
2
2
|
|
|
3
|
-
const getNumberOfFrames = require(
|
|
4
|
-
const getUncompressedImageFrame = require(
|
|
5
|
-
const getEncapsulatedImageFrame = require(
|
|
6
|
-
const { isVideo } = require(
|
|
3
|
+
const getNumberOfFrames = require('./getNumberOfFrames');
|
|
4
|
+
const getUncompressedImageFrame = require('./getUncompressedImageFrame');
|
|
5
|
+
const getEncapsulatedImageFrame = require('./getEncapsulatedImageFrame');
|
|
6
|
+
const { isVideo } = require('../writer/VideoWriter');
|
|
7
7
|
|
|
8
8
|
const areFramesAreFragmented = (attr, numberOfFrames) =>
|
|
9
9
|
attr.encapsulatedPixelData && numberOfFrames != attr.fragments.length;
|
|
10
10
|
|
|
11
|
-
const getFrameSize =
|
|
12
|
-
const rows = dataSet.uint16(
|
|
13
|
-
const columns = dataSet.uint16(
|
|
14
|
-
const samplesPerPixel = dataSet.uint16(
|
|
15
|
-
const bitsAllocated = dataSet.uint16(
|
|
11
|
+
const getFrameSize = dataSet => {
|
|
12
|
+
const rows = dataSet.uint16('x00280010');
|
|
13
|
+
const columns = dataSet.uint16('x00280011');
|
|
14
|
+
const samplesPerPixel = dataSet.uint16('x00280002');
|
|
15
|
+
const bitsAllocated = dataSet.uint16('x00280100');
|
|
16
16
|
return (rows * columns * samplesPerPixel * bitsAllocated) / 8;
|
|
17
17
|
};
|
|
18
18
|
|
|
@@ -35,20 +35,16 @@ const extractImageFrames = async (dataSet, attr, vr, callback) => {
|
|
|
35
35
|
dataSet,
|
|
36
36
|
attr,
|
|
37
37
|
frameIndex,
|
|
38
|
-
framesAreFragmented
|
|
38
|
+
framesAreFragmented
|
|
39
39
|
);
|
|
40
40
|
BulkDataURI = await callback.imageFrame(compressedFrame, { dataSet });
|
|
41
|
-
Stats.OverallStats.add(
|
|
42
|
-
"Image Write",
|
|
43
|
-
`Write image frame ${frameIndex + 1}`,
|
|
44
|
-
5000,
|
|
45
|
-
);
|
|
41
|
+
Stats.OverallStats.add('Image Write', `Write image frame ${frameIndex + 1}`, 5000);
|
|
46
42
|
} else {
|
|
47
43
|
const uncompressedFrame = getUncompressedImageFrame(
|
|
48
44
|
dataSet,
|
|
49
45
|
attr,
|
|
50
46
|
frameIndex,
|
|
51
|
-
uncompressedFrameSize
|
|
47
|
+
uncompressedFrameSize
|
|
52
48
|
);
|
|
53
49
|
BulkDataURI = await callback.imageFrame(uncompressedFrame, { dataSet });
|
|
54
50
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const { Tags } = require(
|
|
2
|
-
const getVR = require(
|
|
3
|
-
const getValue = require(
|
|
1
|
+
const { Tags } = require('@radicalimaging/static-wado-util');
|
|
2
|
+
const getVR = require('./getVR');
|
|
3
|
+
const getValue = require('./getValue');
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Get dataset.
|
|
@@ -13,23 +13,14 @@ const getValue = require("./getValue");
|
|
|
13
13
|
* @param {*} parentAttr Parent reference for sequence element tags.
|
|
14
14
|
* @returns
|
|
15
15
|
*/
|
|
16
|
-
async function getDataSet(
|
|
17
|
-
dataSet,
|
|
18
|
-
callback,
|
|
19
|
-
optionsOrig,
|
|
20
|
-
parentAttr = undefined,
|
|
21
|
-
) {
|
|
16
|
+
async function getDataSet(dataSet, callback, optionsOrig, parentAttr = undefined) {
|
|
22
17
|
const metadata = {};
|
|
23
18
|
let options = optionsOrig;
|
|
24
19
|
|
|
25
20
|
// iterate over dataSet attributes in order
|
|
26
21
|
for (const tag in dataSet.elements) {
|
|
27
22
|
// Raw versions have the x in front of them
|
|
28
|
-
if (
|
|
29
|
-
tag != Tags.RawTransferSyntaxUID &&
|
|
30
|
-
tag >= Tags.RawMinTag &&
|
|
31
|
-
tag < Tags.RawFirstBodyTag
|
|
32
|
-
) {
|
|
23
|
+
if (tag != Tags.RawTransferSyntaxUID && tag >= Tags.RawMinTag && tag < Tags.RawFirstBodyTag) {
|
|
33
24
|
continue;
|
|
34
25
|
}
|
|
35
26
|
if (tag === Tags.RawSpecificCharacterSet) {
|
|
@@ -38,45 +29,20 @@ async function getDataSet(
|
|
|
38
29
|
}
|
|
39
30
|
const attr = dataSet.elements[tag];
|
|
40
31
|
|
|
41
|
-
await attributeToJS(
|
|
42
|
-
metadata,
|
|
43
|
-
tag,
|
|
44
|
-
dataSet,
|
|
45
|
-
attr,
|
|
46
|
-
callback,
|
|
47
|
-
options,
|
|
48
|
-
parentAttr,
|
|
49
|
-
);
|
|
32
|
+
await attributeToJS(metadata, tag, dataSet, attr, callback, options, parentAttr);
|
|
50
33
|
}
|
|
51
34
|
if (metadata[Tags.TransferSyntaxUID]) {
|
|
52
35
|
// console.log(`Found tsuid ${JSON.stringify(metadata[Tags.TransferSyntaxUID])} assigning to ${Tags.AvailableTransferSyntaxUID}`)
|
|
53
|
-
metadata[Tags.AvailableTransferSyntaxUID] =
|
|
54
|
-
metadata[Tags.TransferSyntaxUID];
|
|
36
|
+
metadata[Tags.AvailableTransferSyntaxUID] = metadata[Tags.TransferSyntaxUID];
|
|
55
37
|
delete metadata[Tags.TransferSyntaxUID];
|
|
56
38
|
}
|
|
57
39
|
return { metadata };
|
|
58
40
|
}
|
|
59
41
|
|
|
60
|
-
async function attributeToJS(
|
|
61
|
-
metadataSrc,
|
|
62
|
-
tag,
|
|
63
|
-
dataSet,
|
|
64
|
-
attr,
|
|
65
|
-
callback,
|
|
66
|
-
options,
|
|
67
|
-
parentAttr,
|
|
68
|
-
) {
|
|
42
|
+
async function attributeToJS(metadataSrc, tag, dataSet, attr, callback, options, parentAttr) {
|
|
69
43
|
const metadata = metadataSrc;
|
|
70
44
|
const vr = getVR(attr);
|
|
71
|
-
const value = await getValue(
|
|
72
|
-
dataSet,
|
|
73
|
-
attr,
|
|
74
|
-
vr,
|
|
75
|
-
getDataSet,
|
|
76
|
-
callback,
|
|
77
|
-
options,
|
|
78
|
-
parentAttr,
|
|
79
|
-
);
|
|
45
|
+
const value = await getValue(dataSet, attr, vr, getDataSet, callback, options, parentAttr);
|
|
80
46
|
const key = tag.substring(1).toUpperCase();
|
|
81
47
|
if (value === undefined || value === null || value.length === 0) {
|
|
82
48
|
if (!vr) return;
|