@radicalimaging/static-wado-creator 1.7.4 → 1.7.6

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 (50) hide show
  1. package/dist/DeleteStudy.js +16 -0
  2. package/dist/RejectInstance.js +25 -0
  3. package/dist/StaticWado.js +419 -0
  4. package/dist/canvas-xaqc8v6y.node +0 -0
  5. package/dist/createMain.js +18 -0
  6. package/dist/createPart10.js +113 -0
  7. package/dist/createThumbnail.js +163 -0
  8. package/dist/deleteMain.js +12 -0
  9. package/dist/groupMain.js +17 -0
  10. package/dist/index.js +500838 -0
  11. package/dist/index.mjs +18 -0
  12. package/dist/indexMain.js +10 -0
  13. package/dist/instanceMain.js +16 -0
  14. package/dist/metadataMain.js +15 -0
  15. package/dist/mkdicomwebConfig.js +342 -0
  16. package/dist/operation/InstanceDeduplicate.js +103 -0
  17. package/dist/operation/ScanStudy.js +47 -0
  18. package/dist/operation/StudyData.js +520 -0
  19. package/dist/operation/ThumbnailService.js +198 -0
  20. package/dist/operation/adapter/decodeImage.js +12 -0
  21. package/dist/operation/adapter/getImageInfo.js +38 -0
  22. package/dist/operation/adapter/transcodeImage.js +519 -0
  23. package/dist/operation/extractImageFrames.js +55 -0
  24. package/dist/operation/getDataSet.js +65 -0
  25. package/dist/operation/getEncapsulatedImageFrame.js +35 -0
  26. package/dist/operation/getNumberOfFrames.js +13 -0
  27. package/dist/operation/getUncompressedImageFrame.js +7 -0
  28. package/dist/operation/getVR.js +24 -0
  29. package/dist/operation/getValue.js +216 -0
  30. package/dist/operation/validateMetadata.js +40 -0
  31. package/dist/program/index.js +14 -0
  32. package/dist/rejectMain.js +12 -0
  33. package/dist/serverMain.js +21 -0
  34. package/dist/util/IdCreator.js +42 -0
  35. package/dist/util/adaptProgramOpts.js +39 -0
  36. package/dist/util/compressionOptionParser.js +13 -0
  37. package/dist/util/resultsReport.ts +87 -0
  38. package/dist/writer/CompleteStudyWriter.js +129 -0
  39. package/dist/writer/DeduplicateWriter.js +33 -0
  40. package/dist/writer/ExpandUriPath.js +16 -0
  41. package/dist/writer/HashDataWriter.js +74 -0
  42. package/dist/writer/ImageFrameWriter.js +59 -0
  43. package/dist/writer/MultipartAttribute.js +8 -0
  44. package/dist/writer/MultipartHeader.js +14 -0
  45. package/dist/writer/RawDicomWriter.js +44 -0
  46. package/dist/writer/ThumbnailWriter.js +14 -0
  47. package/dist/writer/VideoWriter.js +53 -0
  48. package/dist/writer/WriteMultipart.js +22 -0
  49. package/dist/writer/WriteStream.js +64 -0
  50. package/package.json +11 -2
@@ -0,0 +1,163 @@
1
+ const { Tags, readBulkData, handleHomeRelative } = require('@radicalimaging/static-wado-util');
2
+ const dcmjs = require('dcmjs');
3
+
4
+ const StaticWado = require('./StaticWado');
5
+ const adaptProgramOpts = require('./util/adaptProgramOpts');
6
+ const WriteStream = require('./writer/WriteStream');
7
+
8
+ const UncompressedLEIExplicit = '1.2.840.10008.1.2.1';
9
+ const { DicomDict, DicomMetaDictionary } = dcmjs.data;
10
+
11
+ const fileMetaInformationVersionArray = new Uint8Array(2);
12
+ fileMetaInformationVersionArray[1] = 1;
13
+
14
+ const readBulkDataValue = async (studyDir, instance, value, options) => {
15
+ const { BulkDataURI } = value;
16
+ value.vr = 'OB';
17
+ const seriesUid = Tags.getValue(instance, Tags.SeriesInstanceUID);
18
+ const numberOfFrames = Tags.getValue(instance, Tags.NumberOfFrames) || 1;
19
+ if (BulkDataURI.indexOf('/frames') !== -1) {
20
+ const seriesDir = `${studyDir}/series/${seriesUid}`;
21
+ if (options?.frame === false) {
22
+ return;
23
+ }
24
+ // Really only support a limited number of frames based on memory size
25
+ value.Value = [];
26
+ if (typeof options?.frame === 'number') {
27
+ console.noQuiet('Reading frame', options.frame);
28
+ const bulk = await readBulkData(seriesDir, BulkDataURI, options.frame);
29
+ if (!bulk) {
30
+ return;
31
+ }
32
+ value.Value[options.frame - 1] = bulk.binaryData;
33
+ value.transferSyntaxUid = bulk.transferSyntaxUid;
34
+ value.contentType = bulk.contentType;
35
+ return;
36
+ }
37
+ console.noQuiet('Reading frames', 1, '...', numberOfFrames);
38
+ for (let frame = 1; frame <= numberOfFrames; frame++) {
39
+ const bulk = await readBulkData(seriesDir, BulkDataURI, frame);
40
+ if (!bulk) break;
41
+ value.Value.push(bulk.binaryData);
42
+ value.transferSyntaxUid = bulk.transferSyntaxUid;
43
+ value.contentType = bulk.contentType;
44
+ }
45
+ } else {
46
+ const bulk = await readBulkData(studyDir, BulkDataURI);
47
+ value.Value = [new ArrayBuffer(bulk.binaryData)];
48
+ value.contentType = bulk.contentType;
49
+ }
50
+ };
51
+
52
+ const readBinaryData = async (dir, instance, options = { frame: true }) => {
53
+ for (const tag of Object.keys(instance)) {
54
+ const v = instance[tag];
55
+ if (v.BulkDataURI) {
56
+ await readBulkDataValue(dir, instance, v, options);
57
+ continue;
58
+ }
59
+ if (!v.vr) {
60
+ const value0 = v.Value?.[0];
61
+ if (typeof value0 === 'string') {
62
+ v.vr = 'LT';
63
+ } else {
64
+ console.log('Deleting', tag, v.Value, v);
65
+ delete instance[tag];
66
+ }
67
+ continue;
68
+ }
69
+ if (v.vr === 'SQ' && v.Values?.length) {
70
+ await Promise.all(v.Values.map(readBinaryData));
71
+ continue;
72
+ }
73
+ }
74
+ };
75
+
76
+ module.exports = async function createThumbnail(options, program) {
77
+ const finalOptions = adaptProgramOpts(options, {
78
+ ...this,
79
+ // Instance metadata is the instances/<sopUID>/metadata.gz files
80
+ isInstance: false,
81
+ // Deduplicated data is single instance deduplicated data
82
+ isDeduplicate: false,
83
+ // Group data is the group file directories
84
+ isGroup: false,
85
+ isStudyData: false,
86
+ isDeleteInstances: false,
87
+ });
88
+ const importer = new StaticWado(finalOptions);
89
+ const studyInstanceUid = program.args[0];
90
+ const dir = `${importer.options.rootDir}/studies/${studyInstanceUid}`;
91
+ console.noQuiet('Creating thumbnail for', studyInstanceUid, dir);
92
+ const study = await importer.callback.scanStudy(studyInstanceUid);
93
+ const outputPath = `./studies/${studyInstanceUid}`;
94
+ const { sopInstanceUid, seriesInstanceUid, seriesThumbnail, studyThumbnail } = options;
95
+ const sops = sopInstanceUid ? new Set() : null;
96
+ if (sopInstanceUid) {
97
+ for (const sop of sopInstanceUid.split(',').map(s => s.trim())) {
98
+ sops.add(sop);
99
+ }
100
+ }
101
+ const promises = [];
102
+
103
+ const writeThumbnail = async (id, buffer) => {
104
+ console.verbose('Write thumbnail', id, buffer);
105
+ await importer.callback.thumbWriter(id.sopInstanceRootPath, 'thumbnail', buffer);
106
+ if (seriesThumbnail) {
107
+ await importer.callback.thumbWriter(id.seriesRootPath, 'thumbnail', buffer);
108
+ }
109
+ if (studyThumbnail) {
110
+ await importer.callback.thumbWriter(id.studyPath, 'thumbnail', buffer);
111
+ }
112
+ };
113
+
114
+ // TODO - choose middle frame of multiframe and choose middle image of
115
+ // series for series thumbnail, and first series for study thumbnail
116
+ const codecOptions = { frame: 1 };
117
+
118
+ for (const sop of study.getSopUids()) {
119
+ if (sops && !sops.has(sop)) {
120
+ continue;
121
+ }
122
+ const instance = await study.recombine(sop);
123
+
124
+ if (
125
+ seriesInstanceUid &&
126
+ Tags.getValue(instance, Tags.SeriesInstanceUID) !== seriesInstanceUid
127
+ ) {
128
+ continue;
129
+ }
130
+
131
+ await readBinaryData(dir, instance, codecOptions);
132
+
133
+ const availableTransferSyntaxUID = Tags.getValue(instance, Tags.AvailableTransferSyntaxUID);
134
+ const pixelData = Tags.getValue(instance, Tags.PixelData);
135
+ if (!pixelData) {
136
+ console.warn('No pixel data found in instance');
137
+ continue;
138
+ }
139
+ const transferSyntaxUid =
140
+ instance[Tags.PixelData].transferSyntaxUid || availableTransferSyntaxUID;
141
+ const frame = Array.isArray(pixelData.Value) ? pixelData.Value[0] : pixelData;
142
+ console.verbose('Use transfer syntax uid:', transferSyntaxUid);
143
+ const id = importer.callback.uids({
144
+ studyInstanceUid,
145
+ seriesInstanceUid: Tags.getValue(instance, Tags.SeriesInstanceUID),
146
+ sopInstanceUid: sop,
147
+ transferSyntaxUid,
148
+ });
149
+
150
+ const promise = importer.callback.internalGenerateImage(
151
+ frame,
152
+ null,
153
+ instance,
154
+ id.transferSyntaxUid,
155
+ writeThumbnail.bind(null, id)
156
+ );
157
+ promises.push(promise);
158
+ if (seriesThumbnail) {
159
+ break;
160
+ }
161
+ }
162
+ await Promise.all(promises);
163
+ };
@@ -0,0 +1,12 @@
1
+ const StaticWado = require('./StaticWado');
2
+ const adaptProgramOpts = require('./util/adaptProgramOpts');
3
+
4
+ module.exports = function deleteMain(options, program) {
5
+ const finalOptions = adaptProgramOpts(options, {
6
+ ...this,
7
+ isGroup: true,
8
+ isStudyData: true,
9
+ });
10
+ const importer = new StaticWado(finalOptions);
11
+ return importer.delete(program.args);
12
+ };
@@ -0,0 +1,17 @@
1
+ const StaticWado = require('./StaticWado');
2
+ const adaptProgramOpts = require('./util/adaptProgramOpts');
3
+
4
+ module.exports = function createMain(options, program) {
5
+ const finalOptions = adaptProgramOpts(options, {
6
+ ...this,
7
+ isInstance: false,
8
+ isDeduplicate: true,
9
+ isGroup: true,
10
+ isStudyData: false,
11
+ scanStudies: true,
12
+ isDeleteInstances: true,
13
+ });
14
+ const importer = new StaticWado(finalOptions);
15
+ // Either do a scan or on specified studies
16
+ return importer.executeCommand(program.args);
17
+ };