@radicalimaging/static-wado-creator 1.6.10 → 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 (51) hide show
  1. package/dist/index.js +84811 -54896
  2. package/lib/DeleteStudy.js +9 -14
  3. package/lib/RejectInstance.js +4 -15
  4. package/lib/StaticWado.js +92 -147
  5. package/lib/createMain.js +3 -3
  6. package/lib/createPart10.js +19 -23
  7. package/lib/createThumbnail.js +27 -45
  8. package/lib/deleteMain.js +2 -2
  9. package/lib/groupMain.js +2 -2
  10. package/lib/index.js +6 -6
  11. package/lib/indexMain.js +2 -2
  12. package/lib/instanceMain.js +2 -2
  13. package/lib/metadataMain.js +2 -2
  14. package/lib/mkdicomwebConfig.js +157 -165
  15. package/lib/model/TagLists.js +5 -17
  16. package/lib/model/uids.js +29 -29
  17. package/lib/operation/InstanceDeduplicate.js +14 -19
  18. package/lib/operation/ScanStudy.js +11 -18
  19. package/lib/operation/StudyData.js +87 -156
  20. package/lib/operation/ThumbnailService.js +29 -54
  21. package/lib/operation/adapter/decodeImage.js +2 -2
  22. package/lib/operation/adapter/getImageInfo.js +7 -8
  23. package/lib/operation/adapter/transcodeImage.js +95 -146
  24. package/lib/operation/extractImageFrames.js +13 -17
  25. package/lib/operation/getDataSet.js +9 -43
  26. package/lib/operation/getEncapsulatedImageFrame.js +7 -19
  27. package/lib/operation/getNumberOfFrames.js +2 -2
  28. package/lib/operation/getUncompressedImageFrame.js +2 -10
  29. package/lib/operation/getVR.js +5 -5
  30. package/lib/operation/getValue.js +42 -65
  31. package/lib/operation/validateMetadata.js +4 -4
  32. package/lib/program/index.js +2 -5
  33. package/lib/rejectMain.js +2 -2
  34. package/lib/serverMain.js +8 -14
  35. package/lib/util/IdCreator.js +8 -17
  36. package/lib/util/adaptProgramOpts.js +2 -2
  37. package/lib/util/compressionOptionParser.js +5 -14
  38. package/lib/util/resultsReport.ts +67 -68
  39. package/lib/writer/CompleteStudyWriter.js +24 -37
  40. package/lib/writer/DeduplicateWriter.js +7 -8
  41. package/lib/writer/ExpandUriPath.js +3 -5
  42. package/lib/writer/HashDataWriter.js +18 -18
  43. package/lib/writer/ImageFrameWriter.js +20 -33
  44. package/lib/writer/MultipartHeader.js +1 -1
  45. package/lib/writer/RawDicomWriter.js +12 -13
  46. package/lib/writer/ThumbnailWriter.js +2 -2
  47. package/lib/writer/VideoWriter.js +23 -34
  48. package/lib/writer/WriteMultipart.js +4 -6
  49. package/lib/writer/WriteStream.js +14 -20
  50. package/package.json +1 -1
  51. package/lib/writer/static-dicomweb.code-workspace +0 -8
@@ -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,18 +24,17 @@ 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)
32
- console.log("SOP Instance UID", sopUID, "already exists, skipping");
31
+ if (this.verbose) console.log('SOP Instance UID', sopUID, 'already exists, skipping');
33
32
  // TODO - allow replace as an option
34
33
  // Null value means skip writing this instance
35
34
  return null;
36
35
  }
37
36
 
38
- if (this.verbose) console.log("SOP Instance UID", sopUID, "being added");
37
+ if (this.verbose) console.log('SOP Instance UID', sopUID, 'being added');
39
38
  const deduplicated = { ...imageFrame };
40
39
 
41
40
  if (!this.extractors) this.extractors = extractors;
@@ -44,7 +43,7 @@ async function deduplicateSingleInstance(id, imageFrame, { force }) {
44
43
  deduplicated,
45
44
  key,
46
45
  this.extractors[key],
47
- TagLists.RemoveExtract,
46
+ TagLists.RemoveExtract
48
47
  );
49
48
  const hashKey = getValue(extracted, Tags.DeduppedHash);
50
49
  await studyData.addExtracted(this, hashKey, extracted);
@@ -59,13 +58,13 @@ async function deduplicateSingleInstance(id, imageFrame, { force }) {
59
58
  }
60
59
 
61
60
  /** Canonicalize the JSON data, making Values always arrays, remote "undefined" from the tags etc */
62
- const canonicalize = (json) => {
61
+ const canonicalize = json => {
63
62
  if (!json) return undefined;
64
63
  if (Array.isArray(json)) {
65
64
  return json.map(canonicalize);
66
65
  }
67
- Object.keys(json).forEach((tag) => {
68
- if (!tag || tag === "undefined") {
66
+ Object.keys(json).forEach(tag => {
67
+ if (!tag || tag === 'undefined') {
69
68
  // console.error('Got an undefined tag:', tag, typeof(tag));
70
69
  // TODO check returning value
71
70
  return;
@@ -79,13 +78,13 @@ const canonicalize = (json) => {
79
78
  return json;
80
79
  };
81
80
 
82
- const InstanceDeduplicate = (options) =>
81
+ const InstanceDeduplicate = options =>
83
82
  async function run(id, sourceImageFrame) {
84
83
  // Notify the existing listeners, if any
85
84
  const imageFrame = canonicalize(sourceImageFrame);
86
85
  if (options.isInstance) {
87
- console.verbose("Writing instance metadata");
88
- await JSONWriter(id.sopInstanceRootPath, "metadata", imageFrame);
86
+ await JSONWriter(id.sopInstanceRootPath, 'metadata', imageFrame);
87
+ console.verbose('Wrote instance metadata', id.sopInstanceRootPath, 'metadata');
89
88
  }
90
89
  if (!options.isDeduplicate && !options.isGroup) {
91
90
  return;
@@ -96,11 +95,7 @@ const InstanceDeduplicate = (options) =>
96
95
  this.verbose = options.verbose;
97
96
  }
98
97
 
99
- const deduppedInstance = await this.deduplicateSingleInstance(
100
- id,
101
- imageFrame,
102
- options,
103
- );
98
+ const deduppedInstance = await this.deduplicateSingleInstance(id, imageFrame, options);
104
99
  if (deduppedInstance) {
105
100
  // this refers to callee
106
101
  await this.deduplicated(id, deduppedInstance);
@@ -1,46 +1,39 @@
1
- const {
2
- getStudyUIDPathAndSubPath,
3
- } = require("@radicalimaging/static-wado-util");
1
+ const { getStudyUIDPathAndSubPath } = require('@radicalimaging/static-wado-util');
4
2
 
5
- const path = require("path");
3
+ const path = require('path');
6
4
 
7
5
  function ScanStudy(options) {
8
- const {
9
- directoryName,
10
- deduplicatedRoot,
11
- deduplicatedInstancesRoot,
12
- hashStudyUidPath,
13
- } = options;
6
+ const { directoryName, deduplicatedRoot, deduplicatedInstancesRoot, hashStudyUidPath } = options;
14
7
 
15
8
  return function scanStudy(studyInstanceUid) {
16
- const { path: hashPath = "", subpath: hashSubpath = "" } = hashStudyUidPath
9
+ const { path: hashPath = '', subpath: hashSubpath = '' } = hashStudyUidPath
17
10
  ? getStudyUIDPathAndSubPath(studyInstanceUid)
18
11
  : {};
19
12
 
20
- console.verbose("scanStudy", studyInstanceUid);
13
+ console.verbose('scanStudy', studyInstanceUid);
21
14
 
22
15
  if (hashPath && hashSubpath) {
23
- console.verbose("hashPath", hashPath);
24
- console.verbose("hashSubpath", hashSubpath);
16
+ console.verbose('hashPath', hashPath);
17
+ console.verbose('hashSubpath', hashSubpath);
25
18
  }
26
19
 
27
20
  const studySubDir = hashStudyUidPath
28
21
  ? path.join(hashPath, hashSubpath, studyInstanceUid)
29
22
  : studyInstanceUid;
30
23
 
31
- const studyPath = path.join(directoryName, "studies", studySubDir);
24
+ const studyPath = path.join(directoryName, 'studies', studySubDir);
32
25
  const deduplicatedInstancesPath = path.join(
33
26
  deduplicatedInstancesRoot,
34
27
  // studyInstanceUid,
35
- studySubDir,
28
+ studySubDir
36
29
  );
37
30
  const deduplicatedPath = path.join(deduplicatedRoot, studySubDir);
38
31
  console.verbose(
39
- "Importing",
32
+ 'Importing',
40
33
  studyInstanceUid,
41
34
  studyPath,
42
35
  deduplicatedInstancesPath,
43
- deduplicatedPath,
36
+ deduplicatedPath
44
37
  );
45
38
  return this.completeStudy.getCurrentStudyData(this, {
46
39
  studyPath,
@@ -1,15 +1,14 @@
1
- const path = require("path");
2
- const fs = require("fs");
3
- const hashFactory = require("node-object-hash");
4
- const { JSONReader, JSONWriter } = require("@radicalimaging/static-wado-util");
5
- const { Tags } = require("@radicalimaging/static-wado-util");
6
- const TagLists = require("../model/TagLists");
1
+ const path = require('path');
2
+ const fs = require('fs');
3
+ const hashFactory = require('node-object-hash');
4
+ const { JSONReader, JSONWriter } = require('@radicalimaging/static-wado-util');
5
+ const { Tags } = require('@radicalimaging/static-wado-util');
6
+ const TagLists = require('../model/TagLists');
7
7
 
8
8
  const { getValue, setValue, getList, setList } = Tags;
9
9
  const hasher = hashFactory.hasher();
10
10
 
11
- const getSeriesInstanceUid = (seriesInstance) =>
12
- getValue(seriesInstance, Tags.SeriesInstanceUID);
11
+ const getSeriesInstanceUid = seriesInstance => getValue(seriesInstance, Tags.SeriesInstanceUID);
13
12
 
14
13
  /**
15
14
  * StudyData contains information about the grouped study data. It is used to create
@@ -23,13 +22,8 @@ const getSeriesInstanceUid = (seriesInstance) =>
23
22
  */
24
23
  class StudyData {
25
24
  constructor(
26
- {
27
- studyInstanceUid,
28
- studyPath,
29
- deduplicatedPath,
30
- deduplicatedInstancesPath,
31
- },
32
- { isGroup, clean, hashStudyUidPath },
25
+ { studyInstanceUid, studyPath, deduplicatedPath, deduplicatedInstancesPath },
26
+ { isGroup, clean, hashStudyUidPath }
33
27
  ) {
34
28
  this.studyInstanceUid = studyInstanceUid;
35
29
  this.studyPath = studyPath;
@@ -66,48 +60,37 @@ class StudyData {
66
60
  // Wipe out the study directory entirely, as well as the deduplicatedRoot and instancesRoot
67
61
  }
68
62
 
69
- console.verbose("studyInstanceUid", this.studyInstanceUid);
70
- console.verbose("studyPath", this.studyPath);
71
- console.verbose("deduplicatedPath", this.deduplicatedPath);
72
- console.verbose(
73
- "deduplicatedInstancesPath",
74
- this.deduplicatedInstancesPath,
75
- );
63
+ console.verbose('studyInstanceUid', this.studyInstanceUid);
64
+ console.verbose('studyPath', this.studyPath);
65
+ console.verbose('deduplicatedPath', this.deduplicatedPath);
66
+ console.verbose('deduplicatedInstancesPath', this.deduplicatedInstancesPath);
76
67
 
77
68
  this.groupFiles = 0;
78
- const studyDeduplicated = await JSONReader(
79
- this.studyPath,
80
- "deduplicated/index.json.gz",
81
- [],
82
- );
69
+ const studyDeduplicated = await JSONReader(this.studyPath, 'deduplicated/index.json.gz', []);
83
70
  const info = studyDeduplicated[0];
84
71
  if (info) {
85
72
  const hash = getValue(info, Tags.DeduppedHash);
86
73
  if (this.hashStudyUidPath) {
87
74
  console.verbose(
88
- "Reading studies/<studyUIDPath>/<studyUIDSubpath>/<studyUID>/deduplicated/index.json.gz",
75
+ 'Reading studies/<studyUIDPath>/<studyUIDSubpath>/<studyUID>/deduplicated/index.json.gz'
89
76
  );
90
77
  } else {
91
- console.verbose(
92
- "Reading studies/<studyUID>/deduplicated/index.json.gz",
93
- );
78
+ console.verbose('Reading studies/<studyUID>/deduplicated/index.json.gz');
94
79
  }
95
- this.readDeduplicatedData("index.json.gz", studyDeduplicated, hash);
80
+ this.readDeduplicatedData('index.json.gz', studyDeduplicated, hash);
96
81
  } else {
97
82
  console.log(
98
- "No deduplicated/index.json to read in",
83
+ 'No deduplicated/index.json to read in',
99
84
  this.studyPath,
100
- "/deduplicated/index.json.gz",
85
+ '/deduplicated/index.json.gz'
101
86
  );
102
87
  }
103
88
  if (this.deduplicatedPath) {
104
89
  this.groupFiles = await this.readDeduplicated(this.deduplicatedPath);
105
- console.verbose("Read groupFiles:", this.groupFiles);
90
+ console.verbose('Read groupFiles:', this.groupFiles);
106
91
  }
107
92
  if (this.deduplicatedInstancesPath) {
108
- this.instanceFiles = await this.readDeduplicated(
109
- this.deduplicatedInstancesPath,
110
- );
93
+ this.instanceFiles = await this.readDeduplicated(this.deduplicatedInstancesPath);
111
94
  }
112
95
  }
113
96
 
@@ -121,40 +104,31 @@ class StudyData {
121
104
  * a separate type of check.
122
105
  */
123
106
  get dirty() {
124
- return (
125
- this.newInstancesAdded > 0 ||
126
- this.existingFiles.length > 1 ||
127
- this.instanceFiles > 0
128
- );
107
+ return this.newInstancesAdded > 0 || this.existingFiles.length > 1 || this.instanceFiles > 0;
129
108
  }
130
109
 
131
110
  async dirtyMetadata() {
132
111
  if (this.dirty) {
133
- console.verbose("dirtyMetadata::Group data is dirty");
112
+ console.verbose('dirtyMetadata::Group data is dirty');
134
113
  return true;
135
114
  }
136
115
  if (this.groupFiles > 0) {
137
- console.verbose(
138
- "dirtyMetadata::Study level deduplicated doesn't match group files",
139
- );
116
+ console.verbose("dirtyMetadata::Study level deduplicated doesn't match group files");
140
117
  }
141
118
  try {
142
- const studyFile = await JSONReader(this.studyPath, "index.json.gz", null);
119
+ const studyFile = await JSONReader(this.studyPath, 'index.json.gz', null);
143
120
  if (!studyFile) {
144
- console.verbose("dirtyMetadata::studyIndex");
121
+ console.verbose('dirtyMetadata::studyIndex');
145
122
  return true;
146
123
  }
147
124
  const hashValue = getValue(studyFile, Tags.DeduppedHash);
148
125
  if (this.existingFiles[0].indexOf(hashValue) == -1) {
149
126
  return false;
150
127
  }
151
- console.verbose("dirtyMetadata::Dedupped hash missing");
128
+ console.verbose('dirtyMetadata::Dedupped hash missing');
152
129
  return true;
153
130
  } catch (e) {
154
- console.verbose(
155
- "dirtyMetadata::Exception, assume study metadata is dirty",
156
- e,
157
- );
131
+ console.verbose('dirtyMetadata::Exception, assume study metadata is dirty', e);
158
132
  return true;
159
133
  }
160
134
  }
@@ -169,7 +143,7 @@ class StudyData {
169
143
  const reSop = getValue(recombined, Tags.SOPInstanceUID);
170
144
  if (!reSop) continue;
171
145
  if (sopInstanceUid && reSop !== sopInstanceUid) continue;
172
- setValue(this.deduplicated[i], Tags.DeduppedType, "deleted");
146
+ setValue(this.deduplicated[i], Tags.DeduppedType, 'deleted');
173
147
  }
174
148
  }
175
149
 
@@ -188,7 +162,7 @@ class StudyData {
188
162
  if (!item) {
189
163
  item = await JSONReader.readHashData(this.studyPath, hashKey);
190
164
  if (!item) {
191
- console.error("Unable to read hashdata", hashKey);
165
+ console.error('Unable to read hashdata', hashKey);
192
166
  return item;
193
167
  }
194
168
  this.extractData[hashKey] = item;
@@ -198,7 +172,7 @@ class StudyData {
198
172
 
199
173
  assignUndefined(ret, item) {
200
174
  if (!item) return;
201
- Object.keys(item).forEach((key) => {
175
+ Object.keys(item).forEach(key => {
202
176
  if (ret[key]) return;
203
177
  ret[key] = item[key];
204
178
  });
@@ -208,19 +182,14 @@ class StudyData {
208
182
  * Create a full study instance data for instance at index
209
183
  */
210
184
  async recombine(indexOrSop) {
211
- const index =
212
- typeof indexOrSop === "string"
213
- ? this.sopInstances[indexOrSop]
214
- : indexOrSop;
185
+ const index = typeof indexOrSop === 'string' ? this.sopInstances[indexOrSop] : indexOrSop;
215
186
  const deduplicated = this.deduplicated[index];
216
187
  if (index < 0 || index >= this.deduplicated.length) {
217
- throw new Error(
218
- `Can't read index ${index}, out of bounds [0..${this.deduplicated.length})`,
219
- );
188
+ throw new Error(`Can't read index ${index}, out of bounds [0..${this.deduplicated.length})`);
220
189
  }
221
190
  const refs = getList(deduplicated, Tags.DeduppedRef);
222
191
  if (!refs) {
223
- console.log("No refs for", deduplicated);
192
+ console.log('No refs for', deduplicated);
224
193
  return deduplicated;
225
194
  }
226
195
  const ret = { ...deduplicated };
@@ -234,11 +203,7 @@ class StudyData {
234
203
  async addExtracted(callback, hashKey, item) {
235
204
  if (this.extractData[hashKey]) {
236
205
  if (this.verbose)
237
- console.log(
238
- "Already have extracted",
239
- hashKey,
240
- getValue(item, Tags.DeduppedType),
241
- );
206
+ console.log('Already have extracted', hashKey, getValue(item, Tags.DeduppedType));
242
207
  return;
243
208
  }
244
209
  await callback.bulkdata(this, hashKey, item);
@@ -259,7 +224,7 @@ class StudyData {
259
224
  }
260
225
 
261
226
  /** Add the instance if not already present */
262
- internalAddDeduplicated(data, filename = "internal") {
227
+ internalAddDeduplicated(data, filename = 'internal') {
263
228
  const hashValue = TagLists.addHash(data, Tags.InstanceType);
264
229
  if (!hashValue || this.deduplicatedHashes[hashValue]) {
265
230
  // console.log('Not adding', hashValue, 'because the hash exists');
@@ -268,13 +233,13 @@ class StudyData {
268
233
  const sopValue = getValue(data, Tags.SOPInstanceUID);
269
234
  const sopIndex = this.sopInstances[sopValue];
270
235
  if (!sopValue) {
271
- console.warn("No sop value in", filename, "reading", data);
236
+ console.warn('No sop value in', filename, 'reading', data);
272
237
  return false;
273
238
  }
274
239
  this.deduplicatedHashes[hashValue] = data;
275
240
  this.readHashes[hashValue] = filename;
276
241
  if (sopIndex !== undefined) {
277
- console.noQuiet("Replacing SOP", sopValue, "at index", sopIndex);
242
+ console.noQuiet('Replacing SOP', sopValue, 'at index', sopIndex);
278
243
  this.deduplicated[sopIndex] = data;
279
244
  } else {
280
245
  this.sopInstances[sopValue] = this.deduplicated.length;
@@ -287,9 +252,9 @@ class StudyData {
287
252
  async listJsonFiles(dir) {
288
253
  const names = await fs.promises.readdir(dir);
289
254
  if (!names || names.length == 0) return [];
290
- const gzNames = names.filter((name) => name.indexOf(".gz") > 0);
255
+ const gzNames = names.filter(name => name.indexOf('.gz') > 0);
291
256
  const statInfo = gzNames
292
- .map((name) => {
257
+ .map(name => {
293
258
  const stat = fs.statSync(path.join(dir, name));
294
259
  return {
295
260
  ...stat,
@@ -318,10 +283,10 @@ class StudyData {
318
283
  try {
319
284
  const files = await this.listJsonFiles(deduplicatedDirectory);
320
285
  if (!files || !files.length) {
321
- console.verbose("No deduplicated for", deduplicatedDirectory);
286
+ console.verbose('No deduplicated for', deduplicatedDirectory);
322
287
  return 0;
323
288
  }
324
- console.verbose("There are", files.length, "files to check");
289
+ console.verbose('There are', files.length, 'files to check');
325
290
  for (let i = 0; i < files.length; i++) {
326
291
  const stat = files[i];
327
292
  const { hash } = stat;
@@ -331,7 +296,7 @@ class StudyData {
331
296
  readCount += 1;
332
297
  await this.readDeduplicatedFile(deduplicatedDirectory, stat);
333
298
  }
334
- console.verbose("Done checking", deduplicatedDirectory);
299
+ console.verbose('Done checking', deduplicatedDirectory);
335
300
  } catch (e) {
336
301
  // No-op console.log(e);
337
302
  }
@@ -341,11 +306,11 @@ class StudyData {
341
306
  async readDeduplicatedFile(dir, stat) {
342
307
  const { hash, name } = stat;
343
308
  try {
344
- console.verbose("Reading deduplicated file", name);
309
+ console.verbose('Reading deduplicated file', name);
345
310
  const data = await JSONReader(dir, name);
346
311
  this.readDeduplicatedData(name, data, hash);
347
312
  } catch (e) {
348
- console.error("Unable to read", dir, name);
313
+ console.error('Unable to read', dir, name);
349
314
  }
350
315
  }
351
316
 
@@ -353,14 +318,14 @@ class StudyData {
353
318
  this.readHashes[hash] = name;
354
319
  this.existingFiles.push(name);
355
320
  const listData = (Array.isArray(data) && data) || [data];
356
- listData.forEach((item) => {
321
+ listData.forEach(item => {
357
322
  const type = getValue(item, Tags.DeduppedType);
358
323
  if (type === Tags.InstanceType || type === Tags.DeletedType) {
359
324
  this.internalAddDeduplicated(item, name);
360
- } else if (type == "info") {
325
+ } else if (type == 'info') {
361
326
  const refs = getList(item, Tags.DeduppedRef);
362
327
  if (refs) {
363
- refs.forEach((hashValue) => {
328
+ refs.forEach(hashValue => {
364
329
  this.readHashes[hashValue] = `${hashValue}.gz`;
365
330
  });
366
331
  }
@@ -380,34 +345,22 @@ class StudyData {
380
345
  for (let i = 0; i < this.numberOfInstances; i++) {
381
346
  const seriesInstance = await this.recombine(i);
382
347
  const type = getValue(seriesInstance, Tags.DeduppedType);
383
- if (type == "deleted") {
348
+ if (type == 'deleted') {
384
349
  console.log(
385
- "Skipping deleted instance",
350
+ 'Skipping deleted instance',
386
351
  type,
387
- getValue(seriesInstance, Tags.SeriesInstanceUID),
352
+ getValue(seriesInstance, Tags.SeriesInstanceUID)
388
353
  );
389
354
  continue;
390
355
  }
391
356
  const seriesInstanceUid = getSeriesInstanceUid(seriesInstance);
392
357
  if (!seriesInstanceUid) {
393
- console.log(
394
- "Cant get seriesUid from",
395
- Tags.SeriesInstanceUID,
396
- seriesInstance,
397
- );
358
+ console.log('Cant get seriesUid from', Tags.SeriesInstanceUID, seriesInstance);
398
359
  continue;
399
360
  }
400
361
  if (!series[seriesInstanceUid]) {
401
- const seriesQuery = TagLists.extract(
402
- seriesInstance,
403
- "series",
404
- TagLists.SeriesQuery,
405
- );
406
- const seriesPath = path.join(
407
- this.studyPath,
408
- "series",
409
- seriesInstanceUid,
410
- );
362
+ const seriesQuery = TagLists.extract(seriesInstance, 'series', TagLists.SeriesQuery);
363
+ const seriesPath = path.join(this.studyPath, 'series', seriesInstanceUid);
411
364
  series[seriesInstanceUid] = {
412
365
  seriesPath,
413
366
  seriesQuery,
@@ -417,7 +370,7 @@ class StudyData {
417
370
  }
418
371
  series[seriesInstanceUid].instances.push(seriesInstance);
419
372
  series[seriesInstanceUid].instancesQuery.push(
420
- TagLists.extract(seriesInstance, "instance", TagLists.InstanceQuery),
373
+ TagLists.extract(seriesInstance, 'instance', TagLists.InstanceQuery)
421
374
  );
422
375
  }
423
376
 
@@ -428,73 +381,57 @@ class StudyData {
428
381
 
429
382
  for (const seriesUid of Object.keys(series)) {
430
383
  const singleSeries = series[seriesUid];
431
- const { seriesQuery, seriesPath, instances, instancesQuery } =
432
- singleSeries;
384
+ const { seriesQuery, seriesPath, instances, instancesQuery } = singleSeries;
433
385
  seriesQuery[Tags.NumberOfSeriesRelatedInstances] = {
434
- vr: "IS",
386
+ vr: 'IS',
435
387
  Value: [instances.length],
436
388
  };
437
389
  numberOfInstances += instances.length;
438
390
  numberOfSeries += 1;
439
391
  const modality = getValue(seriesQuery, Tags.Modality);
440
392
  seriesList.push(seriesQuery);
441
- if (modalitiesInStudy.indexOf(modality) == -1)
442
- modalitiesInStudy.push(modality);
443
- await JSONWriter(seriesPath, "metadata", instances, {
393
+ if (modalitiesInStudy.indexOf(modality) == -1) modalitiesInStudy.push(modality);
394
+ await JSONWriter(seriesPath, 'metadata', instances, {
444
395
  gzip: true,
445
396
  index: false,
446
397
  });
447
398
  // Write out a series singleton that has just the series response for a single series.
448
- await JSONWriter(seriesPath, "series-singleton.json", [seriesQuery], {
399
+ await JSONWriter(seriesPath, 'series-singleton.json', [seriesQuery], {
449
400
  gzip: true,
450
401
  index: false,
451
402
  });
452
- await JSONWriter(seriesPath, "instances", instancesQuery);
453
- console.noQuiet(
454
- "Wrote instances",
455
- seriesUid,
456
- "with",
457
- instancesQuery.length,
458
- );
403
+ await JSONWriter(seriesPath, 'instances', instancesQuery);
404
+ console.noQuiet('Wrote instances', seriesUid, 'with', instancesQuery.length);
459
405
  }
460
406
 
461
- await JSONWriter(this.studyPath, "series", seriesList);
462
- console.noQuiet(
463
- "Wrote series",
464
- this.studyInstanceUid,
465
- "with",
466
- seriesList.length,
467
- );
407
+ await JSONWriter(this.studyPath, 'series', seriesList);
408
+ console.noQuiet('Wrote series', this.studyInstanceUid, 'with', seriesList.length);
468
409
 
469
- const studyQuery = TagLists.extract(
470
- anInstance,
471
- "study",
472
- TagLists.PatientStudyQuery,
473
- );
474
- studyQuery[Tags.ModalitiesInStudy] = { Value: modalitiesInStudy, vr: "CS" };
410
+ const studyQuery = TagLists.extract(anInstance, 'study', TagLists.PatientStudyQuery);
411
+ studyQuery[Tags.ModalitiesInStudy] = { Value: modalitiesInStudy, vr: 'CS' };
475
412
  studyQuery[Tags.NumberOfStudyRelatedInstances] = {
476
413
  Value: [numberOfInstances],
477
- vr: "IS",
414
+ vr: 'IS',
478
415
  };
479
416
  studyQuery[Tags.NumberOfStudyRelatedSeries] = {
480
417
  Value: [numberOfSeries],
481
- vr: "IS",
418
+ vr: 'IS',
482
419
  };
483
420
  // Write the index.json directly in the studyPath directory.
484
- await JSONWriter(this.studyPath, "index.json", [studyQuery], {
421
+ await JSONWriter(this.studyPath, 'index.json', [studyQuery], {
485
422
  gzip: true,
486
423
  index: false,
487
424
  });
488
425
 
489
426
  const infoItem = this.createInfo();
490
427
  console.noQuiet(
491
- "Writing deduplicated study data with",
428
+ 'Writing deduplicated study data with',
492
429
  Object.values(this.extractData).length,
493
- "extract items and",
430
+ 'extract items and',
494
431
  this.deduplicated.length,
495
- "instance items",
432
+ 'instance items'
496
433
  );
497
- await JSONWriter(this.studyPath, "deduplicated", [
434
+ await JSONWriter(this.studyPath, 'deduplicated', [
498
435
  infoItem,
499
436
  ...Object.values(this.extractData),
500
437
  ...this.deduplicated,
@@ -510,12 +447,12 @@ class StudyData {
510
447
  const data = {};
511
448
  const hashValue = hasher.hash(this.deduplicated);
512
449
  setValue(data, Tags.DeduppedHash, hashValue);
513
- setValue(data, Tags.DeduppedType, "info");
450
+ setValue(data, Tags.DeduppedType, 'info');
514
451
  return data;
515
452
  }
516
453
 
517
454
  removeGz(name) {
518
- const gzIndex = name.indexOf(".gz");
455
+ const gzIndex = name.indexOf('.gz');
519
456
  return (gzIndex > 0 && name.substring(0, gzIndex)) || name;
520
457
  }
521
458
 
@@ -523,28 +460,28 @@ class StudyData {
523
460
  const deduplicatedDirectory = this.deduplicatedInstancesPath;
524
461
  if (!fs.existsSync(deduplicatedDirectory)) return;
525
462
  console.log(
526
- "Deleting instances referenced in",
463
+ 'Deleting instances referenced in',
527
464
  this.studyInstanceUid,
528
- this.deduplicatedInstancesPath,
465
+ this.deduplicatedInstancesPath
529
466
  );
530
467
  const files = await this.listJsonFiles(deduplicatedDirectory);
531
- console.noQuiet("Deleting", files.length, "files");
468
+ console.noQuiet('Deleting', files.length, 'files');
532
469
  let deleteCount = 0;
533
470
  for (let i = 0; i < files.length; i++) {
534
471
  const stat = files[i];
535
472
  const { hash } = stat;
536
473
  if (this.readHashes[hash]) {
537
- console.noQuiet("Deleting", deduplicatedDirectory, stat.name);
474
+ console.noQuiet('Deleting', deduplicatedDirectory, stat.name);
538
475
  try {
539
476
  fs.unlinkSync(path.join(deduplicatedDirectory, stat.name));
540
477
  deleteCount += 1;
541
478
  } catch (e) {
542
- console.log("Delete failed", e);
479
+ console.log('Delete failed', e);
543
480
  }
544
481
  }
545
482
  }
546
483
  if (deleteCount === files.length) {
547
- console.noQuiet("Deleting instances directory", deduplicatedDirectory);
484
+ console.noQuiet('Deleting instances directory', deduplicatedDirectory);
548
485
  fs.rmdirSync(deduplicatedDirectory);
549
486
  }
550
487
  }
@@ -554,24 +491,18 @@ class StudyData {
554
491
  const data = this.createInfo();
555
492
  const hashValue = getValue(data, Tags.DeduppedHash);
556
493
  console.noQuiet(
557
- "Writing deduplicated hash data set data with",
494
+ 'Writing deduplicated hash data set data with',
558
495
  Object.values(this.extractData).length,
559
- "extract items and",
496
+ 'extract items and',
560
497
  this.deduplicated.length,
561
- "instance items",
498
+ 'instance items'
562
499
  );
563
500
  setList(
564
501
  data,
565
502
  Tags.DeduppedRef,
566
- Object.keys(this.readHashes).filter(
567
- () => this.deduplicatedHashes[hashValue] == undefined,
568
- ),
503
+ Object.keys(this.readHashes).filter(() => this.deduplicatedHashes[hashValue] == undefined)
569
504
  );
570
- const deduplicatedList = [
571
- data,
572
- ...Object.values(this.extractData),
573
- ...this.deduplicated,
574
- ];
505
+ const deduplicatedList = [data, ...Object.values(this.extractData), ...this.deduplicated];
575
506
  // const naturalList = deduplicatedList.map(Tags.naturalizeDataset);
576
507
  // // console.log("naturalList=", JSON.stringify(naturalList,null,2));
577
508
  // console.log("Going to write study data", naturalList.length);
@@ -580,7 +511,7 @@ class StudyData {
580
511
  gzip: true,
581
512
  index: false,
582
513
  });
583
- console.noQuiet("Wrote naturalized dataset");
514
+ console.noQuiet('Wrote naturalized dataset');
584
515
  }
585
516
 
586
517
  getSopUids() {