@radicalimaging/static-wado-creator 0.6.5 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +67 -0
- package/README.md +3 -1
- package/bin/mkdicomweb.js +1 -1
- package/lib/DeleteStudy.js +2 -2
- package/lib/RejectInstance.js +18 -11
- package/lib/StaticWado.js +52 -22
- package/lib/createMain.js +6 -2
- package/lib/groupMain.js +3 -0
- package/lib/index.js +1 -0
- package/lib/instanceMain.js +2 -0
- package/lib/metadataMain.js +3 -2
- package/lib/mkdicomwebConfig.js +44 -8
- package/lib/model/TagLists.js +1 -1
- package/lib/model/uids.js +9 -10
- package/lib/operation/InstanceDeduplicate.js +4 -4
- package/lib/operation/ScanStudy.js +4 -3
- package/lib/operation/StudyData.js +94 -46
- package/lib/operation/ThumbnailService.js +21 -42
- package/lib/operation/adapter/transcodeImage.js +51 -23
- package/lib/operation/extractImageFrames.js +3 -0
- package/lib/operation/getDataSet.js +7 -2
- package/lib/operation/getVR.js +1 -1
- package/lib/operation/getValue.js +22 -11
- package/lib/rejectMain.js +2 -2
- package/lib/util/adaptProgramOpts.js +10 -29
- package/lib/writer/CompleteStudyWriter.js +8 -5
- package/lib/writer/DeduplicateWriter.js +5 -2
- package/lib/writer/HashDataWriter.js +2 -3
- package/lib/writer/ImageFrameWriter.js +25 -9
- package/lib/writer/RawDicomWriter.js +36 -0
- package/lib/writer/ThumbnailWriter.js +7 -14
- package/lib/writer/VideoWriter.js +1 -1
- package/lib/writer/WriteStream.js +12 -1
- package/package.json +11 -15
- package/lib/dictionary/Tags.js +0 -119
- package/lib/dictionary/dataDictionary.js +0 -22268
- package/lib/writer/JSONWriter.js +0 -18
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Change Log
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
|
+
|
|
6
|
+
## [0.6.4](https://github.com/OHIF/static-wado/compare/@radicalimaging/static-wado-creator@0.6.3...@radicalimaging/static-wado-creator@0.6.4) (2022-04-04)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @radicalimaging/static-wado-creator
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [0.6.3](https://github.com/OHIF/static-wado/compare/@radicalimaging/static-wado-creator@0.6.2...@radicalimaging/static-wado-creator@0.6.3) (2022-03-14)
|
|
15
|
+
|
|
16
|
+
**Note:** Version bump only for package @radicalimaging/static-wado-creator
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
## [0.6.2](https://github.com/OHIF/static-wado/compare/@radicalimaging/static-wado-creator@0.6.1...@radicalimaging/static-wado-creator@0.6.2) (2022-03-04)
|
|
23
|
+
|
|
24
|
+
**Note:** Version bump only for package @radicalimaging/static-wado-creator
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
## [0.6.1](https://github.com/OHIF/static-wado/compare/@radicalimaging/static-wado-creator@0.6.0...@radicalimaging/static-wado-creator@0.6.1) (2022-03-04)
|
|
31
|
+
|
|
32
|
+
**Note:** Version bump only for package @radicalimaging/static-wado-creator
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# [0.6.0](https://github.com/OHIF/static-wado/compare/@radicalimaging/static-wado-creator@0.5.1...@radicalimaging/static-wado-creator@0.6.0) (2022-03-03)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
### Bug Fixes
|
|
42
|
+
|
|
43
|
+
* **static-wado:** make the various constructors use a straight configuration without using the program data ([1997d9f](https://github.com/OHIF/static-wado/commit/1997d9f0fe2e0a084d31edeb475494bcec78fd77))
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
### Features
|
|
47
|
+
|
|
48
|
+
* **static-wado:** qido series fallback to retrieve from proxyAe ([#8](https://github.com/OHIF/static-wado/issues/8)) ([47b5550](https://github.com/OHIF/static-wado/commit/47b55503732e25be08b215bdc201593f64de52e6))
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
## 0.5.1 (2022-02-16)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
### Bug Fixes
|
|
58
|
+
|
|
59
|
+
* **pencil:** add more files to lint, increase test config and README ([89b667c](https://github.com/OHIF/static-wado/commit/89b667c83d324ab9fa540cda0c037af8fe088f72))
|
|
60
|
+
* **pencil:** adding must package and minor test changes ([9194f3f](https://github.com/OHIF/static-wado/commit/9194f3f1bb52da57e20bb8bb9f07262bcebdffbf))
|
|
61
|
+
* **pencil:** code review.lint ([fa1a58a](https://github.com/OHIF/static-wado/commit/fa1a58a0c62015503575fbeb172b71810c6833de))
|
|
62
|
+
* **pencil:** fix format ([68fbc9b](https://github.com/OHIF/static-wado/commit/68fbc9bf5a3e9bf85e3fbcddfb3e0759e79b769d))
|
|
63
|
+
* **pencil:** fix lint and add pre-commit restr ([deec345](https://github.com/OHIF/static-wado/commit/deec34524531d5a8595a775bac414f63f60e9f23))
|
|
64
|
+
* **pencil:** lint/prettier ([d6ecbc6](https://github.com/OHIF/static-wado/commit/d6ecbc6b5961e03e8a557f4fcc78af53549132cd))
|
|
65
|
+
* **pencil:** moving from wado-js to wado repo ([5916aec](https://github.com/OHIF/static-wado/commit/5916aecd7c77dbc4882681877e2b51210976427f))
|
|
66
|
+
* **pencil:** readme link name ([40408ab](https://github.com/OHIF/static-wado/commit/40408ab6b4e97c8656e30b1dd2c30b92440b9f90))
|
|
67
|
+
* **pencil:** unit tests migration ([d9d56dd](https://github.com/OHIF/static-wado/commit/d9d56dd619fb1f41ed1d5ad85f7f804e013c6527))
|
package/README.md
CHANGED
|
@@ -158,11 +158,13 @@ There is currently no notification of what studies have been updated between sta
|
|
|
158
158
|
### To Serve Instances As a Web Server
|
|
159
159
|
```
|
|
160
160
|
cd ~/dicomweb
|
|
161
|
-
npx http-server -p 5000 -g --cors
|
|
161
|
+
npx http-server -p 5000 -g --cors -e json
|
|
162
162
|
```
|
|
163
163
|
|
|
164
164
|
The -g option serves up compressed files ending in .gz as compressed http streams.
|
|
165
165
|
|
|
166
|
+
The -e option will mark json files as the default extension, so when requesting `GET dicomweb/studies/` the `./studies/index.json.gz` file will be served.
|
|
167
|
+
|
|
166
168
|
### To Create DICOM part 10 from DICOMweb files
|
|
167
169
|
TODO
|
|
168
170
|
|
package/bin/mkdicomweb.js
CHANGED
package/lib/DeleteStudy.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const { JSONReader } = require("@radicalimaging/static-wado-util");
|
|
2
|
-
const JSONWriter = require("
|
|
3
|
-
const Tags = require("
|
|
2
|
+
const { JSONWriter } = require("@radicalimaging/static-wado-util");
|
|
3
|
+
const { Tags } = require("@radicalimaging/static-wado-util");
|
|
4
4
|
|
|
5
5
|
module.exports = (options) =>
|
|
6
6
|
async function (studyInstanceUid) {
|
package/lib/RejectInstance.js
CHANGED
|
@@ -1,16 +1,23 @@
|
|
|
1
|
-
const dataExtractor = /^(.*studies)?[\\/]?([
|
|
1
|
+
const dataExtractor = /^(.*studies)?[\\/]?([0-9.a-zA-Z]+)[\\/](series[\\/])?([0-9.a-zA-Z]+)([\\/]instances[\\/]([0-9.a-zA-Z]*))?$/;
|
|
2
2
|
|
|
3
|
-
module.exports = (
|
|
4
|
-
async function (
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
module.exports = () =>
|
|
4
|
+
async function rejectInstanceWithOptions(args) {
|
|
5
|
+
let studyInstanceUid = args[0];
|
|
6
|
+
let seriesInstanceUid;
|
|
7
|
+
let sopInstanceUid;
|
|
8
|
+
const reason = args[2] || "REJECT";
|
|
9
|
+
const extracted = args[0].match(dataExtractor);
|
|
10
|
+
if (extracted) {
|
|
11
|
+
studyInstanceUid = extracted[2];
|
|
12
|
+
seriesInstanceUid = extracted[4];
|
|
13
|
+
sopInstanceUid = extracted[6];
|
|
14
|
+
console.log("Extracted", studyInstanceUid, seriesInstanceUid, sopInstanceUid, reason);
|
|
15
|
+
} else {
|
|
16
|
+
console.log("Not extracting from URL", studyInstanceUid, seriesInstanceUid, reason);
|
|
17
|
+
seriesInstanceUid = args[1];
|
|
10
18
|
}
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
if (options.verbose) console.log("Trying to reject", seriesInstanceUid, "because", reason);
|
|
19
|
+
const studyData = await this.scanStudy(studyInstanceUid);
|
|
20
|
+
console.verbose("Trying to reject", seriesInstanceUid, "because", reason);
|
|
14
21
|
await studyData.reject(seriesInstanceUid, sopInstanceUid, reason);
|
|
15
22
|
await studyData.writeDeduplicatedGroup();
|
|
16
23
|
return studyData.writeMetadata();
|
package/lib/StaticWado.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
const dicomCodec = require("@cornerstonejs/dicom-codec");
|
|
2
|
-
const
|
|
2
|
+
const staticCS = require("@radicalimaging/static-cs-lite");
|
|
3
|
+
const { Stats, handleHomeRelative, dirScanner, JSONReader, JSONWriter, asyncIterableToBuffer, Tags } = require("@radicalimaging/static-wado-util");
|
|
3
4
|
const dicomParser = require("dicom-parser");
|
|
4
5
|
const fs = require("fs");
|
|
5
6
|
const path = require("path");
|
|
6
|
-
const {
|
|
7
|
-
const { JSONReader } = require("@radicalimaging/static-wado-util");
|
|
8
|
-
const asyncIterableToBuffer = require("@radicalimaging/static-wado-util/lib/asyncIterableToBuffer");
|
|
7
|
+
const { NotificationService } = require("@radicalimaging/static-wado-util");
|
|
9
8
|
const getDataSet = require("./operation/getDataSet");
|
|
10
9
|
const InstanceDeduplicate = require("./operation/InstanceDeduplicate");
|
|
11
10
|
const DeduplicateWriter = require("./writer/DeduplicateWriter");
|
|
@@ -17,15 +16,33 @@ const HashDataWriter = require("./writer/HashDataWriter");
|
|
|
17
16
|
const VideoWriter = require("./writer/VideoWriter");
|
|
18
17
|
const { transcodeImageFrame, transcodeId, transcodeMetadata } = require("./operation/adapter/transcodeImage");
|
|
19
18
|
const ThumbnailWriter = require("./writer/ThumbnailWriter");
|
|
19
|
+
const decodeImage = require("./operation/adapter/decodeImage");
|
|
20
20
|
const ThumbnailService = require("./operation/ThumbnailService");
|
|
21
21
|
const DeleteStudy = require("./DeleteStudy");
|
|
22
22
|
const RejectInstance = require("./RejectInstance");
|
|
23
|
-
const
|
|
23
|
+
const RawDicomWriter = require("./writer/RawDicomWriter");
|
|
24
|
+
const { isVideo } = require("./writer/VideoWriter");
|
|
24
25
|
|
|
25
26
|
function setStudyData(studyData) {
|
|
26
27
|
this.studyData = studyData;
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
function internalGenerateImage(originalImageFrame, dataset, metadata, transferSyntaxUid, doneCallback) {
|
|
31
|
+
decodeImage(originalImageFrame, dataset, transferSyntaxUid)
|
|
32
|
+
.then((decodeResult = {}) => {
|
|
33
|
+
if (isVideo(transferSyntaxUid)) {
|
|
34
|
+
console.log("Video data - no thumbnail generator yet");
|
|
35
|
+
} else {
|
|
36
|
+
const { imageFrame, imageInfo } = decodeResult;
|
|
37
|
+
const pixelData = dicomCodec.getPixelData(imageFrame, imageInfo, transferSyntaxUid);
|
|
38
|
+
staticCS.getRenderedBuffer(transferSyntaxUid, pixelData, metadata, doneCallback);
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
.catch((error) => {
|
|
42
|
+
console.log(`Error while generating thumbnail:: ${error}`);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
29
46
|
class StaticWado {
|
|
30
47
|
constructor(configuration) {
|
|
31
48
|
const { rootDir = "~/dicomweb", pathDeduplicated = "deduplicated", pathInstances = "instances", verbose } = configuration;
|
|
@@ -38,7 +55,8 @@ class StaticWado {
|
|
|
38
55
|
directoryName,
|
|
39
56
|
deduplicatedRoot: path.join(directoryName, pathDeduplicated),
|
|
40
57
|
deduplicatedInstancesRoot: path.join(directoryName, pathInstances),
|
|
41
|
-
|
|
58
|
+
// TODO - make this configurable and auto-detect by updating the parseDicom library
|
|
59
|
+
TransferSyntaxUID: "1.2.840.10008.1.2.1",
|
|
42
60
|
};
|
|
43
61
|
this.callback = {
|
|
44
62
|
uids: IdCreator(this.options),
|
|
@@ -53,6 +71,9 @@ class StaticWado {
|
|
|
53
71
|
reject: RejectInstance(this.options),
|
|
54
72
|
delete: DeleteStudy(this.options),
|
|
55
73
|
setStudyData,
|
|
74
|
+
rawDicomWriter: RawDicomWriter(this.options),
|
|
75
|
+
notificationService: new NotificationService(this.options.notificationDir),
|
|
76
|
+
internalGenerateImage
|
|
56
77
|
};
|
|
57
78
|
}
|
|
58
79
|
|
|
@@ -62,10 +83,8 @@ class StaticWado {
|
|
|
62
83
|
*
|
|
63
84
|
* @param {string} args listing the instances to remove (may remove entire series)
|
|
64
85
|
*/
|
|
65
|
-
async reject(
|
|
66
|
-
|
|
67
|
-
this.callback.reject(removal);
|
|
68
|
-
});
|
|
86
|
+
async reject(studyUID, seriesUID, reason) {
|
|
87
|
+
this.callback.reject(studyUID, seriesUID, reason);
|
|
69
88
|
}
|
|
70
89
|
|
|
71
90
|
/**
|
|
@@ -95,7 +114,7 @@ class StaticWado {
|
|
|
95
114
|
await this.importBinaryDicom(dicomp10stream, { ...params, file });
|
|
96
115
|
Stats.StudyStats.add("DICOM P10", "Parse DICOM P10 file");
|
|
97
116
|
} catch (e) {
|
|
98
|
-
console.error("Couldn't process", file
|
|
117
|
+
console.error("Couldn't process", file);
|
|
99
118
|
}
|
|
100
119
|
},
|
|
101
120
|
});
|
|
@@ -104,14 +123,13 @@ class StaticWado {
|
|
|
104
123
|
/**
|
|
105
124
|
* Processes a study directory, matching up study instance UIDs. Either processes the
|
|
106
125
|
* deduplicated group directory or the instances directory, or the notifications directory.
|
|
107
|
-
* @param {*}
|
|
126
|
+
* @param {*} options
|
|
108
127
|
*/
|
|
109
|
-
async processStudyDir(studyUids,
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
});
|
|
128
|
+
async processStudyDir(studyUids /* , options */) {
|
|
129
|
+
for (const studyUid of studyUids) {
|
|
130
|
+
const study = await this.callback.scanStudy(studyUid);
|
|
131
|
+
console.log("Processed study", study.studyInstanceUid);
|
|
132
|
+
}
|
|
115
133
|
}
|
|
116
134
|
|
|
117
135
|
async importBinaryDicom(dicomp10stream, params) {
|
|
@@ -124,7 +142,7 @@ class StaticWado {
|
|
|
124
142
|
const studyInstanceUid = dataSet.string("x0020000d");
|
|
125
143
|
|
|
126
144
|
if (!studyInstanceUid) {
|
|
127
|
-
console.log(
|
|
145
|
+
console.log("No study UID, can't import file", params.file, dataSet.elements);
|
|
128
146
|
return undefined;
|
|
129
147
|
}
|
|
130
148
|
|
|
@@ -139,7 +157,7 @@ class StaticWado {
|
|
|
139
157
|
params.file
|
|
140
158
|
);
|
|
141
159
|
|
|
142
|
-
const targetId = transcodeId(id, this.options);
|
|
160
|
+
const targetId = transcodeId(id, this.options, dataSet.uint16(Tags.RawSamplesPerPixel));
|
|
143
161
|
|
|
144
162
|
let bulkDataIndex = 0;
|
|
145
163
|
let imageFrameIndex = 0;
|
|
@@ -176,8 +194,10 @@ class StaticWado {
|
|
|
176
194
|
// convert to DICOMweb MetaData and BulkData
|
|
177
195
|
const result = await getDataSet(dataSet, generator, this.options);
|
|
178
196
|
|
|
197
|
+
await this.callback.rawDicomWriter?.(id, result, buffer);
|
|
198
|
+
|
|
179
199
|
const transcodedMeta = transcodeMetadata(result.metadata, id, this.options);
|
|
180
|
-
thumbnailService.generateThumbnails(id, dataSet, transcodedMeta, this.callback);
|
|
200
|
+
await thumbnailService.generateThumbnails(id, dataSet, transcodedMeta, this.callback);
|
|
181
201
|
|
|
182
202
|
await this.callback.metadata(targetId, transcodedMeta);
|
|
183
203
|
|
|
@@ -185,6 +205,14 @@ class StaticWado {
|
|
|
185
205
|
return {};
|
|
186
206
|
}
|
|
187
207
|
|
|
208
|
+
static async getDataSet(dataSet, generator, params) {
|
|
209
|
+
return await getDataSet(dataSet, generator, params);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
static internalGenerateImage(originalImageFrame, dataSet, metadata, transferSyntaxUid, doneCallback) {
|
|
213
|
+
return internalGenerateImage(originalImageFrame, dataSet, metadata, transferSyntaxUid, doneCallback)
|
|
214
|
+
}
|
|
215
|
+
|
|
188
216
|
/**
|
|
189
217
|
* The mkdicomweb command first runs mkdicomwebinstances, writing out the deduplicated data, and then runs the
|
|
190
218
|
* mkdicomwebstudy command, creating the deduplicated data set. This version, however, keeps the deduplicated
|
|
@@ -192,16 +220,18 @@ class StaticWado {
|
|
|
192
220
|
*/
|
|
193
221
|
async executeCommand(input) {
|
|
194
222
|
if (this.options.scanStudies) {
|
|
223
|
+
console.log("Scanning study dir", input);
|
|
195
224
|
// Scan one of the study directories - in this case, files is a set of study directories
|
|
196
225
|
await this.processStudyDir(input, this.options);
|
|
197
226
|
} else {
|
|
227
|
+
console.log("Scanning files", input);
|
|
198
228
|
await this.processFiles(input, this.options);
|
|
199
229
|
}
|
|
200
230
|
await this.close();
|
|
201
231
|
}
|
|
202
232
|
|
|
203
233
|
async close() {
|
|
204
|
-
await this.callback.completeStudy();
|
|
234
|
+
await this.callback.completeStudy(this.callback);
|
|
205
235
|
Stats.OverallStats.summarize("Completed Study Processing");
|
|
206
236
|
}
|
|
207
237
|
|
package/lib/createMain.js
CHANGED
|
@@ -4,10 +4,14 @@ const adaptProgramOpts = require("./util/adaptProgramOpts");
|
|
|
4
4
|
module.exports = function createMain(options, program) {
|
|
5
5
|
const finalOptions = adaptProgramOpts(options, {
|
|
6
6
|
...this,
|
|
7
|
-
|
|
7
|
+
// Instance metadata is the instances/<sopUID>/metadata.gz files
|
|
8
|
+
isInstance: true,
|
|
9
|
+
// Deduplicated data is single instance deduplicated data
|
|
10
|
+
isDeduplicate: false,
|
|
11
|
+
// Group data is the group file directories
|
|
8
12
|
isGroup: true,
|
|
9
|
-
isDeduplicate: true,
|
|
10
13
|
isStudyData: true,
|
|
14
|
+
isDeleteInstances: true,
|
|
11
15
|
});
|
|
12
16
|
const importer = new StaticWado(finalOptions);
|
|
13
17
|
return importer.executeCommand(program.args);
|
package/lib/groupMain.js
CHANGED
|
@@ -5,8 +5,11 @@ module.exports = function createMain(options, program) {
|
|
|
5
5
|
const finalOptions = adaptProgramOpts(options, {
|
|
6
6
|
...this,
|
|
7
7
|
isInstance: false,
|
|
8
|
+
isDeduplicate: true,
|
|
8
9
|
isGroup: true,
|
|
9
10
|
isStudyData: false,
|
|
11
|
+
scanStudies: true,
|
|
12
|
+
isDeleteInstances: true,
|
|
10
13
|
});
|
|
11
14
|
const importer = new StaticWado(finalOptions);
|
|
12
15
|
// Either do a scan or on specified studies
|
package/lib/index.js
CHANGED
|
@@ -4,5 +4,6 @@ const StaticWado = require("./StaticWado");
|
|
|
4
4
|
StaticWado.mkdicomwebConfig = mkdicomwebConfig;
|
|
5
5
|
StaticWado.createMain = require("./createMain");
|
|
6
6
|
StaticWado.deleteMain = require("./deleteMain");
|
|
7
|
+
StaticWado.adaptProgramOpts = require("./util/adaptProgramOpts");
|
|
7
8
|
|
|
8
9
|
module.exports = StaticWado;
|
package/lib/instanceMain.js
CHANGED
|
@@ -5,6 +5,8 @@ module.exports = function createMain(options, program) {
|
|
|
5
5
|
const finalOptions = adaptProgramOpts(options, {
|
|
6
6
|
...this,
|
|
7
7
|
isInstance: true,
|
|
8
|
+
// Deduplicated data is single instance deduplicated data
|
|
9
|
+
isDeduplicate: true,
|
|
8
10
|
isGroup: false,
|
|
9
11
|
isStudyData: false,
|
|
10
12
|
});
|
package/lib/metadataMain.js
CHANGED
|
@@ -5,8 +5,9 @@ module.exports = function createMain(options, program) {
|
|
|
5
5
|
const finalOptions = adaptProgramOpts(options, {
|
|
6
6
|
...this,
|
|
7
7
|
isInstance: false,
|
|
8
|
-
isGroup:
|
|
9
|
-
isStudyData:
|
|
8
|
+
isGroup: true,
|
|
9
|
+
isStudyData: true,
|
|
10
|
+
scanStudies: true,
|
|
10
11
|
});
|
|
11
12
|
const importer = new StaticWado(finalOptions);
|
|
12
13
|
// Either do a scan or on specified studies
|
package/lib/mkdicomwebConfig.js
CHANGED
|
@@ -25,6 +25,20 @@ const { mkdicomwebConfig } = ConfigPoint.register({
|
|
|
25
25
|
description: "Clean the outputs before generating/starting to write new values.",
|
|
26
26
|
defaultValue: false,
|
|
27
27
|
},
|
|
28
|
+
{
|
|
29
|
+
key: "-d, --deployments <listvalue...>",
|
|
30
|
+
description: "List of deployments from configuration to deploy to. Separated by space.",
|
|
31
|
+
defaultValue: undefined,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
key: "--no-notifications",
|
|
35
|
+
description: "Turns off notifications",
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
key: "--delete",
|
|
39
|
+
description: "Delete the imported instances",
|
|
40
|
+
defaultValue: false,
|
|
41
|
+
},
|
|
28
42
|
{
|
|
29
43
|
key: "-v, --verbose",
|
|
30
44
|
description: "Write verbose output",
|
|
@@ -32,10 +46,26 @@ const { mkdicomwebConfig } = ConfigPoint.register({
|
|
|
32
46
|
},
|
|
33
47
|
{
|
|
34
48
|
key: "-t, --content-type <type>",
|
|
35
|
-
description: 'Destination type to compress to (choices: "jls", "lei", "jls-lossy" or DICOM Transfer Syntax UID - default: "jls")',
|
|
49
|
+
description: 'Destination type to compress to (choices: "jpeg", "jls", "lei", "jls-lossy", "jhc", "jxl" or DICOM Transfer Syntax UID - default: "jls")',
|
|
36
50
|
defaultValue: "jls",
|
|
37
51
|
customParser: compressionOptionParser,
|
|
38
52
|
},
|
|
53
|
+
{
|
|
54
|
+
key: "--encapsulated-image",
|
|
55
|
+
description: "Avoid encapsulating the image frame. Writes with the extension and without multipart",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
key: "-e, --no-encapsulated-image",
|
|
59
|
+
description: "Avoid encapsulating the image frame. Writes with the extension and without multipart",
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
key: "--single-part-image",
|
|
63
|
+
description: "Writes single part image data",
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
key: "--no-single-part-image",
|
|
67
|
+
description: "Writes single part image data",
|
|
68
|
+
},
|
|
39
69
|
{
|
|
40
70
|
key: "-m, --maximum-inline-public-length <value>",
|
|
41
71
|
description: "Maximum length of public binary data",
|
|
@@ -49,8 +79,14 @@ const { mkdicomwebConfig } = ConfigPoint.register({
|
|
|
49
79
|
{
|
|
50
80
|
key: "-r, --recompress <listvalue...>",
|
|
51
81
|
description: "List of types to recompress separated by space",
|
|
52
|
-
defaultValue: ["uncompressed", "jp2"],
|
|
53
|
-
choices: ["uncompressed", "jp2", "jpeglossless", "rle", "none"],
|
|
82
|
+
defaultValue: ["uncompressed", "jp2", "jls", "jll"],
|
|
83
|
+
choices: ["uncompressed", "jp2", "jpeg", "jpeglossless", "rle", "jph", "jls", "true", "none"],
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
key: "--recompress-color <listvalue...>",
|
|
87
|
+
description: "List of types to recompress for color images, separated by space",
|
|
88
|
+
defaultValue: ["uncompressed"],
|
|
89
|
+
choices: ["uncompressed", "jpeg", "jp2", "jpeglossless", "rle", "jph", "jls", "true", "none"],
|
|
54
90
|
},
|
|
55
91
|
{
|
|
56
92
|
key: "--recompress-thumb <listvalue...>",
|
|
@@ -69,9 +105,9 @@ const { mkdicomwebConfig } = ConfigPoint.register({
|
|
|
69
105
|
defaultValue: false,
|
|
70
106
|
},
|
|
71
107
|
{
|
|
72
|
-
key: "-T, --
|
|
108
|
+
key: "-T, --color-content-type <value>",
|
|
73
109
|
description: "Colour content type",
|
|
74
|
-
defaultValue:
|
|
110
|
+
defaultValue: "jpeg",
|
|
75
111
|
},
|
|
76
112
|
{
|
|
77
113
|
key: "--path-deduplicated <path>",
|
|
@@ -136,7 +172,7 @@ const { mkdicomwebConfig } = ConfigPoint.register({
|
|
|
136
172
|
command: "metadata",
|
|
137
173
|
arguments: ["input"],
|
|
138
174
|
main: metadataMain,
|
|
139
|
-
helpDescription: "Write the metadata object (series and study details) from the deduplicated data.",
|
|
175
|
+
helpDescription: "Write the metadata object (series and study details) from the grouped deduplicated data.",
|
|
140
176
|
},
|
|
141
177
|
{
|
|
142
178
|
command: "delete",
|
|
@@ -144,9 +180,9 @@ const { mkdicomwebConfig } = ConfigPoint.register({
|
|
|
144
180
|
helpDescription: "Delete the given study, series or instance (not yet implemented)",
|
|
145
181
|
},
|
|
146
182
|
{
|
|
147
|
-
command: "reject",
|
|
183
|
+
command: "reject <studyUID...>",
|
|
148
184
|
main: rejectMain,
|
|
149
|
-
helpDescription: "Reject the specified series
|
|
185
|
+
helpDescription: "Reject the specified series",
|
|
150
186
|
},
|
|
151
187
|
],
|
|
152
188
|
},
|
package/lib/model/TagLists.js
CHANGED
package/lib/model/uids.js
CHANGED
|
@@ -12,7 +12,7 @@ const jpeg = "image/jpeg";
|
|
|
12
12
|
const jls = "image/jls";
|
|
13
13
|
const jll = "image/jll";
|
|
14
14
|
const jxl = "image/x-jxl";
|
|
15
|
-
const htj2k = "image/
|
|
15
|
+
const htj2k = "image/jphc";
|
|
16
16
|
const jp2 = "image/jp2";
|
|
17
17
|
const rle = "image/dicom-rle";
|
|
18
18
|
|
|
@@ -21,20 +21,19 @@ const uids = {
|
|
|
21
21
|
"1.2.840.10008.1.2.1": uncompressed,
|
|
22
22
|
"1.2.840.10008.1.2.1.99": uncompressed,
|
|
23
23
|
"1.2.840.10008.1.2.2": uncompressed,
|
|
24
|
-
"1.2.840.10008.1.2.4.50": { contentType: jpeg, lossy: true },
|
|
24
|
+
"1.2.840.10008.1.2.4.50": { contentType: jpeg, lossy: true, extension: ".jpeg" },
|
|
25
25
|
"1.2.840.10008.1.2.4.51": { contentType: jpeg, lossy: true },
|
|
26
26
|
"1.2.840.10008.1.2.4.57": { contentType: jpeg },
|
|
27
|
-
"1.2.840.10008.1.2.4.70": { contentType: jll },
|
|
28
|
-
"1.2.840.10008.1.2.4.140": { contentType: jxl },
|
|
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" },
|
|
29
|
+
// Lossy, original JPEG reconstruction mode
|
|
29
30
|
"1.2.840.10008.1.2.4.141": { contentType: jxl, lossy: true },
|
|
30
|
-
"1.2.840.10008.1.2.4.
|
|
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" },
|
|
31
33
|
"1.2.840.10008.1.2.4.81": { contentType: jls, lossy: true },
|
|
32
|
-
"1.2.840.10008.1.2.4.90": { contentType: jp2 },
|
|
34
|
+
"1.2.840.10008.1.2.4.90": { contentType: jp2, extension: ".jp2" },
|
|
33
35
|
"1.2.840.10008.1.2.4.91": { contentType: jp2 },
|
|
34
|
-
|
|
35
|
-
"1.2.840.10008.1.2.4.142": { contentType: jxl, lossy: true },
|
|
36
|
-
"1.2.840.10008.1.2.4.150": { contentType: htj2k },
|
|
37
|
-
// **
|
|
36
|
+
"3.2.840.10008.1.2.4.96": { contentType: htj2k, extension: ".jhc" },
|
|
38
37
|
"1.2.840.10008.1.2.5": { contentType: rle },
|
|
39
38
|
default: {},
|
|
40
39
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// TODO review returning type of some methods
|
|
2
|
-
const JSONWriter = require("
|
|
2
|
+
const { JSONWriter } = require("@radicalimaging/static-wado-util");
|
|
3
|
+
const { Tags } = require("@radicalimaging/static-wado-util");
|
|
3
4
|
const TagLists = require("../model/TagLists");
|
|
4
|
-
const Tags = require("../dictionary/Tags");
|
|
5
5
|
|
|
6
6
|
const { getValue, setValue } = Tags;
|
|
7
7
|
|
|
@@ -77,8 +77,8 @@ const InstanceDeduplicate = (options) =>
|
|
|
77
77
|
async function run(id, sourceImageFrame) {
|
|
78
78
|
// Notify the existing listeners, if any
|
|
79
79
|
const imageFrame = canonicalize(sourceImageFrame);
|
|
80
|
-
if (options.
|
|
81
|
-
|
|
80
|
+
if (options.isInstance) {
|
|
81
|
+
if (options.verbose) console.log("Writing instance metadata");
|
|
82
82
|
await JSONWriter(id.sopInstanceRootPath, "metadata", imageFrame);
|
|
83
83
|
}
|
|
84
84
|
if (!options.isDeduplicate && !options.isGroup) {
|
|
@@ -3,11 +3,12 @@ const path = require("path");
|
|
|
3
3
|
function ScanStudy(options) {
|
|
4
4
|
const { directoryName, deduplicatedRoot, deduplicatedInstancesRoot } = options;
|
|
5
5
|
|
|
6
|
-
return function
|
|
6
|
+
return function scanStudy(studyInstanceUid) {
|
|
7
|
+
console.verbose("scanStudy", studyInstanceUid);
|
|
7
8
|
const studyPath = path.join(directoryName, "studies", studyInstanceUid);
|
|
8
|
-
const deduplicatedPath = path.join(deduplicatedRoot, studyInstanceUid);
|
|
9
9
|
const deduplicatedInstancesPath = path.join(deduplicatedInstancesRoot, studyInstanceUid);
|
|
10
|
-
|
|
10
|
+
const deduplicatedPath = path.join(deduplicatedRoot, studyInstanceUid);
|
|
11
|
+
console.verbose("Importing", studyInstanceUid, studyPath, deduplicatedInstancesPath, deduplicatedPath);
|
|
11
12
|
return this.completeStudy.getCurrentStudyData(this, {
|
|
12
13
|
studyPath,
|
|
13
14
|
deduplicatedPath,
|