@radicalimaging/static-wado-creator 1.5.0 → 1.6.11

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.
Files changed (54) hide show
  1. package/CHANGELOG.md +234 -0
  2. package/README.md +1 -1
  3. package/bin/mkdicomweb.mjs +8 -0
  4. package/dist/canvas-xaqc8v6y.node +0 -0
  5. package/dist/index.js +511433 -0
  6. package/lib/DeleteStudy.js +11 -9
  7. package/lib/RejectInstance.js +6 -5
  8. package/lib/StaticWado.js +222 -73
  9. package/lib/createMain.js +3 -3
  10. package/lib/createPart10.js +19 -19
  11. package/lib/createThumbnail.js +163 -0
  12. package/lib/deleteMain.js +2 -2
  13. package/lib/groupMain.js +2 -2
  14. package/lib/index.js +7 -5
  15. package/lib/indexMain.js +2 -2
  16. package/lib/instanceMain.js +3 -2
  17. package/lib/metadataMain.js +2 -2
  18. package/lib/mkdicomwebConfig.js +210 -115
  19. package/lib/model/TagLists.js +13 -4
  20. package/lib/model/uids.js +32 -28
  21. package/lib/operation/InstanceDeduplicate.js +18 -13
  22. package/lib/operation/ScanStudy.js +33 -7
  23. package/lib/operation/StudyData.js +122 -71
  24. package/lib/operation/ThumbnailService.js +44 -36
  25. package/lib/operation/adapter/decodeImage.js +7 -4
  26. package/lib/operation/adapter/getImageInfo.js +23 -6
  27. package/lib/operation/adapter/transcodeImage.js +157 -90
  28. package/lib/operation/extractImageFrames.js +25 -14
  29. package/lib/operation/getDataSet.js +4 -4
  30. package/lib/operation/getEncapsulatedImageFrame.js +16 -4
  31. package/lib/operation/getNumberOfFrames.js +2 -2
  32. package/lib/operation/getVR.js +12 -4
  33. package/lib/operation/getValue.js +42 -65
  34. package/lib/operation/validateMetadata.js +40 -0
  35. package/lib/program/index.js +2 -3
  36. package/lib/rejectMain.js +2 -2
  37. package/lib/serverMain.js +21 -0
  38. package/lib/util/IdCreator.js +25 -8
  39. package/lib/util/adaptProgramOpts.js +1 -1
  40. package/lib/util/compressionOptionParser.js +4 -4
  41. package/lib/util/resultsReport.ts +87 -0
  42. package/lib/writer/CompleteStudyWriter.js +42 -19
  43. package/lib/writer/DeduplicateWriter.js +7 -7
  44. package/lib/writer/ExpandUriPath.js +4 -3
  45. package/lib/writer/HashDataWriter.js +21 -17
  46. package/lib/writer/ImageFrameWriter.js +22 -10
  47. package/lib/writer/MultipartHeader.js +1 -1
  48. package/lib/writer/RawDicomWriter.js +18 -10
  49. package/lib/writer/ThumbnailWriter.js +2 -2
  50. package/lib/writer/VideoWriter.js +23 -34
  51. package/lib/writer/WriteMultipart.js +3 -3
  52. package/lib/writer/WriteStream.js +14 -12
  53. package/package.json +22 -18
  54. package/bin/mkdicomweb.js +0 -9
@@ -1,14 +1,16 @@
1
- const ConfigPoint = require("config-point");
2
- const { staticWadoConfig } = require("@radicalimaging/static-wado-util");
3
- const createMain = require("./createMain");
4
- const createPart10 = require("./createPart10");
5
- const deleteMain = require("./deleteMain");
6
- const rejectMain = require("./rejectMain");
7
- const instanceMain = require("./instanceMain");
8
- const indexMain = require("./indexMain");
9
- const groupMain = require("./groupMain");
10
- const metadataMain = require("./metadataMain");
11
- const compressionOptionParser = require("./util/compressionOptionParser");
1
+ const ConfigPoint = require('config-point');
2
+ const { staticWadoConfig } = require('@radicalimaging/static-wado-util');
3
+ const createMain = require('./createMain');
4
+ const createPart10 = require('./createPart10');
5
+ const createThumbnail = require('./createThumbnail');
6
+ const deleteMain = require('./deleteMain');
7
+ const rejectMain = require('./rejectMain');
8
+ const serverMain = require('./serverMain');
9
+ const instanceMain = require('./instanceMain');
10
+ const indexMain = require('./indexMain');
11
+ const groupMain = require('./groupMain');
12
+ const metadataMain = require('./metadataMain');
13
+ const compressionOptionParser = require('./util/compressionOptionParser');
12
14
 
13
15
  /**
14
16
  * Defines the basic configuration values for the dicomwebserver component. See the README for more details.
@@ -22,217 +24,310 @@ const { mkdicomwebConfig } = ConfigPoint.register({
22
24
  isGroup: true,
23
25
  options: [
24
26
  {
25
- key: "-c <configFile.json5>",
26
- description: "Use an alternate configuration file",
27
- defaultValue: "~/static-wado.json5",
27
+ key: '-c <configFile.json5>',
28
+ description: 'Use an alternate configuration file',
29
+ defaultValue: '~/static-wado.json5',
28
30
  },
29
31
  {
30
- key: "--clean",
31
- description: "Clean the outputs before generating/starting to write new values.",
32
+ key: '--clean',
33
+ description: 'Clean the outputs before generating/starting to write new values.',
32
34
  defaultValue: false,
33
35
  },
34
36
  {
35
- key: "-d, --deployments <listvalue...>",
36
- description: "List of deployments from configuration to deploy to. Separated by space.",
37
+ key: '-d, --deployments <listvalue...>',
38
+ description: 'List of deployments from configuration to deploy to. Separated by space.',
37
39
  defaultValue: undefined,
38
40
  },
39
41
  {
40
- key: "--no-notifications",
41
- description: "Turns off notifications",
42
+ key: '--no-notifications',
43
+ description: 'Turns off notifications',
42
44
  },
43
45
  {
44
- key: "--delete",
45
- description: "Delete the imported instances",
46
+ key: '--delete',
47
+ description: 'Delete the imported instances',
46
48
  defaultValue: false,
47
49
  },
48
50
  {
49
- key: "--lossy",
50
- description: "Generate lossy instances instead of lossless",
51
+ key: '--lossy',
52
+ description: 'Generate lossy instances instead of lossless',
51
53
  defaultValue: false,
52
54
  },
53
55
  {
54
- key: "--alternate <type>",
55
- description: "Generates an alternate representaton of the image generally in the /lossy sub-directory",
56
- choices: ["jhc", "jls", "jhcLossless", "jlsLossless"],
56
+ key: '--alternate <type>',
57
+ description:
58
+ 'Generates an alternate representaton of the image generally in the /lossy sub-directory',
59
+ choices: ['jhc', 'jls', 'jhcLossless', 'jlsLossless'],
57
60
  },
58
61
  {
59
- key: "--alternate-thumbnail",
60
- description: "Generates a thumbnail for the alternate representation",
62
+ key: '--alternate-thumbnail',
63
+ description: 'Generates a thumbnail for the alternate representation',
61
64
  },
62
65
  {
63
- key: "--alternate-name <dir>",
64
- description: "Uses a given sub directory name",
65
- defaultValue: "lossy",
66
+ key: '--alternate-name <dir>',
67
+ description: 'Uses a given sub directory name',
68
+ defaultValue: 'lossy',
66
69
  },
67
70
  {
68
- key: "-v, --verbose",
69
- description: "Write verbose output",
71
+ key: '-v, --verbose',
72
+ description: 'Write verbose output',
70
73
  defaultValue: false,
71
74
  },
72
75
  {
73
- key: "-t, --content-type <type>",
74
- description: 'Destination type to compress to (choices: "jpeg", "jls", "lei", "jls-lossy", "jhc", "jxl" or DICOM Transfer Syntax UID - default: "jls")',
75
- defaultValue: "jls",
76
+ key: '--show-progress',
77
+ description: 'Show progress during DICOM file processing',
78
+ },
79
+ {
80
+ key: '-t, --content-type <type>',
81
+ description:
82
+ 'Destination type to compress to (choices: "jpeg", "jls", "lei", "jls-lossy", "jhc", "jxl" or DICOM Transfer Syntax UID - default: "jls")',
83
+ defaultValue: 'jls',
76
84
  customParser: compressionOptionParser,
77
85
  },
78
86
  {
79
- key: "--encapsulated-image",
80
- description: "Avoid encapsulating the image frame. Writes with the extension and without multipart",
87
+ key: '--encapsulated-image',
88
+ description:
89
+ 'Avoid encapsulating the image frame. Writes with the extension and without multipart',
81
90
  },
82
91
  {
83
- key: "-e, --no-encapsulated-image",
84
- description: "Avoid encapsulating the image frame. Writes with the extension and without multipart",
92
+ key: '-e, --no-encapsulated-image',
93
+ description:
94
+ 'Avoid encapsulating the image frame. Writes with the extension and without multipart',
85
95
  },
86
96
  {
87
- key: "--single-part-image",
88
- description: "Writes single part image data",
97
+ key: '--single-part-image',
98
+ description: 'Writes single part image data',
89
99
  },
90
100
  {
91
- key: "--no-single-part-image",
92
- description: "Writes single part image data",
101
+ key: '--no-single-part-image',
102
+ description: 'Writes single part image data',
93
103
  },
94
104
  {
95
- key: "-m, --maximum-inline-public-length <value>",
96
- description: "Maximum length of public binary data",
105
+ key: '-m, --maximum-inline-public-length <value>',
106
+ description: 'Maximum length of public binary data',
97
107
  defaultValue: 128 * 1024 + 2,
98
108
  },
99
109
  {
100
- key: "-M, --maximum-inline-private-length <value>",
101
- description: "Maximum length of private binary data",
110
+ key: '-M, --maximum-inline-private-length <value>',
111
+ description: 'Maximum length of private binary data',
102
112
  defaultValue: 64,
103
113
  },
104
114
  {
105
- key: "-r, --recompress <listvalue...>",
106
- description: "List of types to recompress separated by space",
107
- defaultValue: ["uncompressed", "jp2", "jls", "jll"],
108
- choices: ["uncompressed", "jp2", "jpeg", "jpeglossless", "rle", "jph", "jls", "true", "none"],
115
+ key: '-r, --recompress <listvalue...>',
116
+ description: 'List of types to recompress separated by space',
117
+ defaultValue: ['uncompressed', 'jp2', 'jls', 'jll'],
118
+ choices: [
119
+ 'uncompressed',
120
+ 'jp2',
121
+ 'jpeg',
122
+ 'jpeglossless',
123
+ 'rle',
124
+ 'jph',
125
+ 'jls',
126
+ 'true',
127
+ 'none',
128
+ ],
129
+ },
130
+ {
131
+ key: '--recompress-color <listvalue...>',
132
+ description: 'List of types to recompress for color images, separated by space',
133
+ defaultValue: ['uncompressed'],
134
+ choices: [
135
+ 'uncompressed',
136
+ 'jpeg',
137
+ 'jp2',
138
+ 'jpeglossless',
139
+ 'rle',
140
+ 'jph',
141
+ 'jls',
142
+ 'true',
143
+ 'none',
144
+ ],
145
+ },
146
+ {
147
+ key: '-f, --force',
148
+ description: 'Force the update even if the SOP exists',
149
+ defaultValue: false,
109
150
  },
110
151
  {
111
- key: "--recompress-color <listvalue...>",
112
- description: "List of types to recompress for color images, separated by space",
113
- defaultValue: ["uncompressed"],
114
- choices: ["uncompressed", "jpeg", "jp2", "jpeglossless", "rle", "jph", "jls", "true", "none"],
152
+ key: '--delete-input',
153
+ description: 'Deletes successful input files',
154
+ defaultValue: false,
115
155
  },
116
156
  {
117
- key: "-f, --force",
118
- description: "Force the update even if the SOP exists",
157
+ key: '--delete-failed',
158
+ description: 'Deletes unsuccessful input files',
119
159
  defaultValue: false,
120
160
  },
121
161
  {
122
- key: "--recompress-thumb <listvalue...>",
123
- description: "List of types to recompress thumb separated by space",
124
- defaultValue: ["uncompressed", "jp2"],
125
- choices: ["uncompressed", "jp2", "jpeglossless", "rle", "none"],
162
+ key: '--recompress-thumb <listvalue...>',
163
+ description: 'List of types to recompress thumb separated by space',
164
+ defaultValue: ['uncompressed', 'jp2'],
165
+ choices: ['uncompressed', 'jp2', 'jpeglossless', 'rle', 'none'],
126
166
  },
127
167
  {
128
- key: "--no-recompress",
129
- description: "Force no recompression",
168
+ key: '--no-recompress',
169
+ description: 'Force no recompression',
130
170
  defaultValue: false,
131
171
  },
132
172
  {
133
- key: "--no-recompress-thumb",
134
- description: "Force no recompression thumbnail",
173
+ key: '--no-recompress-thumb',
174
+ description: 'Force no recompression thumbnail',
135
175
  defaultValue: false,
136
176
  },
137
177
  {
138
- key: "--thumb",
139
- description: "Generate thumbnails",
178
+ key: '--no-thumb',
179
+ description: 'Skip generating thumbnails using CS3D internal render',
180
+ defaultValue: true,
140
181
  },
141
182
  {
142
- key: "--dcm2jpg",
143
- description: "Use dcm2jpg for thumbnail image generation",
183
+ key: '--dcm2jpg',
184
+ description: 'Use dcm2jpg for thumbnail image generation',
144
185
  defaultValue: false,
145
186
  },
146
187
  {
147
- key: "--rendered",
148
- description: "Use dcm2jpg to generate a rendered PNG image",
188
+ key: '--rendered',
189
+ description: 'Use dcm2jpg to generate a rendered PNG image',
149
190
  defaultValue: false,
150
191
  },
151
192
  {
152
- key: "-T, --color-content-type <value>",
153
- description: "Colour content type",
154
- defaultValue: "jpeg",
193
+ key: '-T, --color-content-type <value>',
194
+ description: 'Colour content type',
195
+ defaultValue: 'jpeg',
196
+ },
197
+ {
198
+ key: '--path-deduplicated <path>',
199
+ description: 'Set the deduplicate data directory path (relative to dir)',
200
+ defaultValue: 'deduplicated',
201
+ },
202
+ {
203
+ key: '--path-instances <path>',
204
+ description: 'Set the instances directory path (relative to dir)',
205
+ defaultValue: 'instances',
155
206
  },
156
207
  {
157
- key: "--path-deduplicated <path>",
158
- description: "Set the deduplicate data directory path (relative to dir)",
159
- defaultValue: "deduplicated",
208
+ key: '--store-multipart-bulk-data',
209
+ description: 'Use multipart encoding for non image frame bulkdata',
210
+ defaultValue: false,
160
211
  },
161
212
  {
162
- key: "--path-instances <path>",
163
- description: "Set the instances directory path (relative to dir)",
164
- defaultValue: "instances",
213
+ key: '--prepend-bulk-data-uri <value>',
214
+ description:
215
+ 'Prepend bulkdata uri (ex. to use absolute Uri like http://host:3000/dicomweb)',
216
+ defaultValue: '',
165
217
  },
166
218
  {
167
- key: "--store-multipart-bulk-data",
168
- description: "Use multipart encoding for non image frame bulkdata",
219
+ key: '--expand-bulk-data-uri',
220
+ description:
221
+ 'expand bulkdata relative uri to use full relative path (should also be set when using --prepend-bulk-data-uri)',
169
222
  defaultValue: false,
170
223
  },
171
224
  {
172
- key: "--prepend-bulk-data-uri <value>",
173
- description: "Prepend bulkdata uri (ex. to use absolute Uri like http://host:3000/dicomweb)",
174
- defaultValue: "",
225
+ key: '--quiet',
226
+ description: 'Run quietly, minimizing extraneous output',
227
+ defaultValue: false,
175
228
  },
176
229
  {
177
- key: "--expand-bulk-data-uri",
178
- description: "expand bulkdata relative uri to use full relative path (should also be set when using --prepend-bulk-data-uri)",
230
+ key: '--multipart',
231
+ description: 'Add a multipart result output',
179
232
  defaultValue: false,
180
233
  },
181
234
  {
182
- key: "-o, --dir <value>",
183
- description: "Set output directory",
184
- defaultValue: { configOperation: "reference", source: "staticWadoConfig", reference: "rootDir" },
235
+ key: '--no-verify',
236
+ description: 'Verify',
237
+ defaultValue: true,
238
+ },
239
+ {
240
+ key: '-o, --dir <value>',
241
+ description: 'Set output directory',
242
+ defaultValue: {
243
+ configOperation: 'reference',
244
+ source: 'staticWadoConfig',
245
+ reference: 'rootDir',
246
+ },
247
+ },
248
+ {
249
+ key: '--sop-instance-uid <value>',
250
+ description: 'Choose sop instances to run against (only for instance runs)',
251
+ },
252
+ {
253
+ key: '--series-instance-uid <value>',
254
+ description: 'Choose series instances to run against (only for instance runs)',
255
+ },
256
+
257
+ {
258
+ key: '--hash-study-uid-path',
259
+ description: 'Enable hashing of studyUID folder structure',
260
+ defaultValue: false,
185
261
  },
186
262
  ],
187
263
  programs: [
188
264
  {
189
- command: "create",
265
+ command: 'create',
190
266
  isDefault: true,
191
- arguments: ["input"],
267
+ arguments: ['input'],
192
268
  main: createMain,
193
269
  helpDescription:
194
- "Make DICOMweb query and metadata from binary Part 10 DICOM files. Does a full read\n" +
195
- "of deduplicated files each time a study instance UID is found, and only updates\n" +
196
- "those studies having at least one ",
270
+ 'Make DICOMweb query and metadata from binary Part 10 DICOM files. Does a full read\n' +
271
+ 'of deduplicated files each time a study instance UID is found, and only updates\n' +
272
+ 'those studies having at least one ',
197
273
  },
198
274
  {
199
- command: "part10",
200
- arguments: ["studyUID"],
275
+ command: 'server',
276
+ main: serverMain,
277
+ helpDescription: 'Run server deploy instances single threaded/separated exec process',
278
+ },
279
+ {
280
+ command: 'part10',
281
+ arguments: ['studyUID'],
201
282
  main: createPart10,
202
- helpDescription: "Store the specified study as part 10 data",
283
+ helpDescription: 'Store the specified study as part 10 data',
203
284
  },
204
285
  {
205
- command: "index",
286
+ command: 'index',
206
287
  main: indexMain,
207
- helpDescription: "Recreate the index for the DICOMweb data.",
288
+ helpDescription: 'Recreate the index for the DICOMweb data.',
289
+ },
290
+ {
291
+ command: 'thumbnail',
292
+ main: createThumbnail,
293
+ helpDescription: 'Create a thumbnail for the specified image',
294
+ options: [
295
+ {
296
+ key: '--series-thumbnail',
297
+ description: 'Generate a series thumbnail instead of instance',
298
+ },
299
+ ],
208
300
  },
209
301
  {
210
- command: "instance",
211
- arguments: ["input"],
302
+ command: 'instance',
303
+ arguments: ['input'],
212
304
  main: instanceMain,
213
- helpDescription: "Make instance level DICOMweb metadata and bulkdata, but don't group or write series metadata",
305
+ helpDescription:
306
+ "Make instance level DICOMweb metadata and bulkdata, but don't group or write series metadata",
214
307
  },
215
308
  {
216
- command: "group",
217
- arguments: ["input"],
309
+ command: 'group',
310
+ arguments: ['input'],
218
311
  main: groupMain,
219
- helpDescription: "Group instance level metadata into deduplicated data.\nDeletes instance level deduplicated information once it is confirmed written.",
312
+ helpDescription:
313
+ 'Group instance level metadata into deduplicated data.\nDeletes instance level deduplicated information once it is confirmed written.',
220
314
  },
221
315
  {
222
- command: "metadata",
223
- arguments: ["input"],
316
+ command: 'metadata',
317
+ arguments: ['input'],
224
318
  main: metadataMain,
225
- helpDescription: "Write the metadata object (series and study details) from the grouped deduplicated data.",
319
+ helpDescription:
320
+ 'Write the metadata object (series and study details) from the grouped deduplicated data.',
226
321
  },
227
322
  {
228
- command: "delete",
323
+ command: 'delete',
229
324
  main: deleteMain,
230
- helpDescription: "Delete the given study, series or instance (not yet implemented)",
325
+ helpDescription: 'Delete the given study, series or instance (not yet implemented)',
231
326
  },
232
327
  {
233
- command: "reject <studyUID...>",
328
+ command: 'reject <studyUID...>',
234
329
  main: rejectMain,
235
- helpDescription: "Reject the specified series",
330
+ helpDescription: 'Reject the specified series',
236
331
  },
237
332
  ],
238
333
  },
@@ -1,5 +1,5 @@
1
- const hashFactory = require("node-object-hash");
2
- const { Tags } = require("@radicalimaging/static-wado-util");
1
+ const hashFactory = require('node-object-hash');
2
+ const { Tags } = require('@radicalimaging/static-wado-util');
3
3
 
4
4
  /* eslint "no-param-reassign": "off" */
5
5
 
@@ -24,7 +24,16 @@ const PatientQuery = [
24
24
  Tags.PatientIdentityRemoved,
25
25
  Tags.DeidentificationMethodCodeSequence,
26
26
  ];
27
- const StudyQuery = [StudyDescription, AccessionNumber, StudyInstanceUID, StudyDate, StudyTime, Tags.StudyStatusID, Tags.StudyPriorityID, Tags.StudyID];
27
+ const StudyQuery = [
28
+ StudyDescription,
29
+ AccessionNumber,
30
+ StudyInstanceUID,
31
+ StudyDate,
32
+ StudyTime,
33
+ Tags.StudyStatusID,
34
+ Tags.StudyPriorityID,
35
+ Tags.StudyID,
36
+ ];
28
37
 
29
38
  const PatientStudyQuery = [...PatientQuery, ...StudyQuery];
30
39
 
@@ -132,7 +141,7 @@ const TagSets = {
132
141
  extract: (data, type, tagSet, options) => {
133
142
  const ret = {};
134
143
  const { remove, hashRef } = options || {};
135
- tagSet.forEach((tag) => {
144
+ tagSet.forEach(tag => {
136
145
  const value = data[tag];
137
146
  if (value) {
138
147
  ret[tag] = value;
package/lib/model/uids.js CHANGED
@@ -1,4 +1,4 @@
1
- const octetStream = "application/octet-stream";
1
+ const octetStream = 'application/octet-stream';
2
2
  const uncompressed = {
3
3
  uncompressed: true,
4
4
  gzip: true,
@@ -8,37 +8,41 @@ const uncompressed = {
8
8
  /**
9
9
  * @see {@link https://dicom.nema.org/medical/dicom/current/output/chtml/part18/sect_8.7.3.3.2.html}
10
10
  */
11
- const jpeg = "image/jpeg";
12
- const jls = "image/jls";
13
- const jll = "image/jll";
14
- const jxl = "image/x-jxl";
15
- const htj2k = "image/jphc";
16
- const jp2 = "image/jp2";
17
- const rle = "image/dicom-rle";
11
+ const jpeg = 'image/jpeg';
12
+ const jls = 'image/jls';
13
+ const jll = 'image/jll';
14
+ const jxl = 'image/x-jxl';
15
+ const htj2k = 'image/jphc';
16
+ const jp2 = 'image/jp2';
17
+ const rle = 'image/dicom-rle';
18
18
 
19
19
  const uids = {
20
- "1.2.840.10008.1.2": uncompressed,
21
- "1.2.840.10008.1.2.1": uncompressed,
22
- "1.2.840.10008.1.2.1.99": uncompressed,
23
- "1.2.840.10008.1.2.2": uncompressed,
24
- "1.2.840.10008.1.2.4.50": { contentType: jpeg, lossy: true, extension: ".jpeg" },
25
- "1.2.840.10008.1.2.4.51": { contentType: jpeg, lossy: true },
26
- "1.2.840.10008.1.2.4.57": { contentType: jpeg },
27
- "1.2.840.10008.1.2.4.70": { contentType: jll, extension: ".jll" },
28
- "1.2.840.10008.1.2.4.140": { contentType: jxl, extension: ".jxl" },
20
+ '1.2.840.10008.1.2': uncompressed,
21
+ '1.2.840.10008.1.2.1': uncompressed,
22
+ '1.2.840.10008.1.2.1.99': uncompressed,
23
+ '1.2.840.10008.1.2.2': uncompressed,
24
+ '1.2.840.10008.1.2.4.50': {
25
+ contentType: jpeg,
26
+ lossy: true,
27
+ extension: '.jpeg',
28
+ },
29
+ '1.2.840.10008.1.2.4.51': { contentType: jpeg, lossy: true },
30
+ '1.2.840.10008.1.2.4.57': { contentType: jpeg },
31
+ '1.2.840.10008.1.2.4.70': { contentType: jll, extension: '.jll' },
32
+ '1.2.840.10008.1.2.4.140': { contentType: jxl, extension: '.jxl' },
29
33
  // Lossy, original JPEG reconstruction mode
30
- "1.2.840.10008.1.2.4.141": { contentType: jxl, lossy: true },
31
- "1.2.840.10008.1.2.4.142": { contentType: jxl, lossy: true },
32
- "1.2.840.10008.1.2.4.80": { contentType: jls, extension: ".jls" },
33
- "1.2.840.10008.1.2.4.81": { contentType: jls, lossy: true },
34
- "1.2.840.10008.1.2.4.90": { contentType: jp2, extension: ".jp2" },
35
- "1.2.840.10008.1.2.4.91": { contentType: jp2 },
34
+ '1.2.840.10008.1.2.4.141': { contentType: jxl, lossy: true },
35
+ '1.2.840.10008.1.2.4.142': { contentType: jxl, lossy: true },
36
+ '1.2.840.10008.1.2.4.80': { contentType: jls, extension: '.jls' },
37
+ '1.2.840.10008.1.2.4.81': { contentType: jls, lossy: true },
38
+ '1.2.840.10008.1.2.4.90': { contentType: jp2, extension: '.jp2' },
39
+ '1.2.840.10008.1.2.4.91': { contentType: jp2 },
36
40
  // Private/test transfer syntax for HTJ2K
37
- "3.2.840.10008.1.2.4.96": { contentType: htj2k },
38
- "1.2.840.10008.1.2.4.201": { contentType: htj2k },
39
- "1.2.840.10008.1.2.4.202": { contentType: htj2k, extension: ".jhc" },
40
- "1.2.840.10008.1.2.4.203": { contentType: htj2k, lossy: true },
41
- "1.2.840.10008.1.2.5": { contentType: rle },
41
+ '3.2.840.10008.1.2.4.96': { contentType: htj2k },
42
+ '1.2.840.10008.1.2.4.201': { contentType: htj2k },
43
+ '1.2.840.10008.1.2.4.202': { contentType: htj2k, extension: '.jhc' },
44
+ '1.2.840.10008.1.2.4.203': { contentType: htj2k, lossy: true },
45
+ '1.2.840.10008.1.2.5': { contentType: rle },
42
46
  default: {},
43
47
  };
44
48
 
@@ -1,7 +1,7 @@
1
1
  // TODO review returning type of some methods
2
- const { JSONWriter } = require("@radicalimaging/static-wado-util");
3
- const { Tags } = require("@radicalimaging/static-wado-util");
4
- const TagLists = require("../model/TagLists");
2
+ const { JSONWriter } = require('@radicalimaging/static-wado-util');
3
+ const { Tags } = require('@radicalimaging/static-wado-util');
4
+ const TagLists = require('../model/TagLists');
5
5
 
6
6
  const { getValue, setValue } = Tags;
7
7
 
@@ -24,22 +24,27 @@ async function deduplicateSingleInstance(id, imageFrame, { force }) {
24
24
  const seriesUID = getValue(imageFrame, Tags.SeriesInstanceUID);
25
25
  const sopUID = getValue(imageFrame, Tags.SOPInstanceUID);
26
26
  if (!sopUID) {
27
- console.warn("No sop instance UID in", imageFrame);
27
+ console.warn('No sop instance UID in', imageFrame);
28
28
  return {};
29
29
  }
30
30
  if (!force && studyData.sopExists(sopUID)) {
31
- if (this.verbose) console.log("SOP Instance UID", sopUID, "already exists, skipping");
31
+ if (this.verbose) console.log('SOP Instance UID', sopUID, 'already exists, skipping');
32
32
  // TODO - allow replace as an option
33
33
  // Null value means skip writing this instance
34
34
  return null;
35
35
  }
36
36
 
37
- if (this.verbose) console.log("SOP Instance UID", sopUID, "being added");
37
+ if (this.verbose) console.log('SOP Instance UID', sopUID, 'being added');
38
38
  const deduplicated = { ...imageFrame };
39
39
 
40
40
  if (!this.extractors) this.extractors = extractors;
41
41
  for (const key of Object.keys(this.extractors)) {
42
- const extracted = TagLists.extract(deduplicated, key, this.extractors[key], TagLists.RemoveExtract);
42
+ const extracted = TagLists.extract(
43
+ deduplicated,
44
+ key,
45
+ this.extractors[key],
46
+ TagLists.RemoveExtract
47
+ );
43
48
  const hashKey = getValue(extracted, Tags.DeduppedHash);
44
49
  await studyData.addExtracted(this, hashKey, extracted);
45
50
  }
@@ -53,13 +58,13 @@ async function deduplicateSingleInstance(id, imageFrame, { force }) {
53
58
  }
54
59
 
55
60
  /** Canonicalize the JSON data, making Values always arrays, remote "undefined" from the tags etc */
56
- const canonicalize = (json) => {
61
+ const canonicalize = json => {
57
62
  if (!json) return undefined;
58
63
  if (Array.isArray(json)) {
59
64
  return json.map(canonicalize);
60
65
  }
61
- Object.keys(json).forEach((tag) => {
62
- if (!tag || tag === "undefined") {
66
+ Object.keys(json).forEach(tag => {
67
+ if (!tag || tag === 'undefined') {
63
68
  // console.error('Got an undefined tag:', tag, typeof(tag));
64
69
  // TODO check returning value
65
70
  return;
@@ -73,13 +78,13 @@ const canonicalize = (json) => {
73
78
  return json;
74
79
  };
75
80
 
76
- const InstanceDeduplicate = (options) =>
81
+ const InstanceDeduplicate = options =>
77
82
  async function run(id, sourceImageFrame) {
78
83
  // Notify the existing listeners, if any
79
84
  const imageFrame = canonicalize(sourceImageFrame);
80
85
  if (options.isInstance) {
81
- if (options.verbose) console.log("Writing instance metadata");
82
- await JSONWriter(id.sopInstanceRootPath, "metadata", imageFrame);
86
+ await JSONWriter(id.sopInstanceRootPath, 'metadata', imageFrame);
87
+ console.verbose('Wrote instance metadata', id.sopInstanceRootPath, 'metadata');
83
88
  }
84
89
  if (!options.isDeduplicate && !options.isGroup) {
85
90
  return;