@radicalimaging/static-wado-creator 1.2.2 → 1.2.4
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/lib/StaticWado.js +2 -2
- package/lib/mkdicomwebConfig.js +17 -3
- package/lib/model/TagLists.js +1 -1
- package/lib/operation/StudyData.js +1 -1
- package/lib/operation/ThumbnailService.js +37 -9
- package/lib/operation/adapter/transcodeImage.js +2 -1
- package/lib/writer/DeduplicateWriter.js +1 -1
- package/lib/writer/HashDataWriter.js +15 -1
- package/package.json +2 -2
package/lib/StaticWado.js
CHANGED
|
@@ -198,8 +198,8 @@ class StaticWado {
|
|
|
198
198
|
await this.callback.rawDicomWriter?.(id, result, buffer);
|
|
199
199
|
|
|
200
200
|
const transcodedMeta = transcodeMetadata(result.metadata, id, this.options);
|
|
201
|
-
await thumbnailService.generateThumbnails(id, dataSet, transcodedMeta, this.callback);
|
|
202
|
-
|
|
201
|
+
await thumbnailService.generateThumbnails(id, dataSet, transcodedMeta, this.callback, this.options);
|
|
202
|
+
await thumbnailService.generateRendered(id, dataSet, transcodedMeta, this.callback, this.options);
|
|
203
203
|
await this.callback.metadata(targetId, transcodedMeta);
|
|
204
204
|
|
|
205
205
|
// resolve promise with statistics
|
package/lib/mkdicomwebConfig.js
CHANGED
|
@@ -109,6 +109,20 @@ const { mkdicomwebConfig } = ConfigPoint.register({
|
|
|
109
109
|
description: "Force no recompression thumbnail",
|
|
110
110
|
defaultValue: false,
|
|
111
111
|
},
|
|
112
|
+
{
|
|
113
|
+
key: "--no-thumb",
|
|
114
|
+
description: "Skip thumbnail generation",
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
key: "--dcm2jpg",
|
|
118
|
+
description: "Use dcm2jpg for thumbnail image generation",
|
|
119
|
+
defaultValue: false,
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
key: "--rendered",
|
|
123
|
+
description: "Use dcm2jpg to generate a rendered PNG image",
|
|
124
|
+
defaultValue: false,
|
|
125
|
+
},
|
|
112
126
|
{
|
|
113
127
|
key: "-T, --color-content-type <value>",
|
|
114
128
|
description: "Colour content type",
|
|
@@ -152,9 +166,9 @@ const { mkdicomwebConfig } = ConfigPoint.register({
|
|
|
152
166
|
arguments: ["input"],
|
|
153
167
|
main: createMain,
|
|
154
168
|
helpDescription:
|
|
155
|
-
"Make DICOMweb query and metadata from binary Part 10 DICOM files. Does a full read
|
|
156
|
-
"deduplicated files each time a study instance UID is found, and only updates
|
|
157
|
-
"having at least one ",
|
|
169
|
+
"Make DICOMweb query and metadata from binary Part 10 DICOM files. Does a full read\n" +
|
|
170
|
+
"of deduplicated files each time a study instance UID is found, and only updates\n" +
|
|
171
|
+
"those studies having at least one ",
|
|
158
172
|
},
|
|
159
173
|
{
|
|
160
174
|
command: "index",
|
package/lib/model/TagLists.js
CHANGED
|
@@ -3,7 +3,7 @@ const { Tags } = require("@radicalimaging/static-wado-util");
|
|
|
3
3
|
|
|
4
4
|
/* eslint "no-param-reassign": "off" */
|
|
5
5
|
|
|
6
|
-
const hasher = hashFactory();
|
|
6
|
+
const hasher = hashFactory.hasher();
|
|
7
7
|
|
|
8
8
|
const { PatientID, PatientName, IssuerOfPatientID } = Tags;
|
|
9
9
|
const { StudyDescription, AccessionNumber, StudyInstanceUID, StudyDate, StudyTime } = Tags;
|
|
@@ -6,7 +6,7 @@ const { Tags } = require("@radicalimaging/static-wado-util");
|
|
|
6
6
|
const TagLists = require("../model/TagLists");
|
|
7
7
|
|
|
8
8
|
const { getValue, setValue, getList, setList } = Tags;
|
|
9
|
-
const hasher = hashFactory();
|
|
9
|
+
const hasher = hashFactory.hasher();
|
|
10
10
|
|
|
11
11
|
const getSeriesInstanceUid = (seriesInstance) => getValue(seriesInstance, Tags.SeriesInstanceUID);
|
|
12
12
|
|
|
@@ -80,6 +80,26 @@ class ThumbnailService {
|
|
|
80
80
|
execSpawn(`ffmpeg -i "${input}" -vf "thumbnail,scale=640:360" -frames:v 1 -f singlejpeg "${output}"`);
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
dcm2jpg(input, output, options) {
|
|
84
|
+
const script = ["dcm2jpg", `"${input}" "${output}"`];
|
|
85
|
+
if (options?.format) {
|
|
86
|
+
script.push("-F", options.format);
|
|
87
|
+
}
|
|
88
|
+
execSpawn(script.join(" "));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Generates a rendered copy of this, assuming --rendered is set.
|
|
92
|
+
* Requires dcm2jpg to be available.
|
|
93
|
+
*/
|
|
94
|
+
async generateRendered(itemid, dataSet, metadata, callback, options) {
|
|
95
|
+
if (!options.rendered) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
const { id } = this.favoriteThumbnailObj;
|
|
99
|
+
const rendered = id.imageFrameRootPath.replace(/frames/, "rendered");
|
|
100
|
+
return this.dcm2jpg(id.filename, rendered, { format: "png" });
|
|
101
|
+
}
|
|
102
|
+
|
|
83
103
|
/**
|
|
84
104
|
* Generates thumbnails for the levels: instances, series, study. This is asynchronous
|
|
85
105
|
*
|
|
@@ -87,9 +107,13 @@ class ThumbnailService {
|
|
|
87
107
|
* @param {*} metadata
|
|
88
108
|
* @param {*} callback
|
|
89
109
|
*/
|
|
90
|
-
generateThumbnails(itemId, dataSet, metadata, callback) {
|
|
110
|
+
async generateThumbnails(itemId, dataSet, metadata, callback, options) {
|
|
91
111
|
const { imageFrame, id } = this.favoriteThumbnailObj;
|
|
92
112
|
|
|
113
|
+
if (!options.thumb) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
|
|
93
117
|
// There are various reasons no thumbnails might be generated, so just return
|
|
94
118
|
if (!id) {
|
|
95
119
|
const pixelData = metadata[Tags.PixelData];
|
|
@@ -101,16 +125,20 @@ class ThumbnailService {
|
|
|
101
125
|
const thumbPath = path.join(itemId.sopInstanceRootPath, "rendered");
|
|
102
126
|
console.log("MP4 - converting video format", mp4Path);
|
|
103
127
|
this.ffmpeg(mp4Path, thumbPath);
|
|
104
|
-
|
|
105
|
-
console.log("pixelData = ", pixelData, Tags.PixelData);
|
|
128
|
+
return thumbPath;
|
|
106
129
|
}
|
|
107
130
|
} else {
|
|
108
131
|
console.log("Series is of other type...", metadata[Tags.Modality]);
|
|
109
132
|
}
|
|
110
133
|
return null;
|
|
111
134
|
}
|
|
112
|
-
|
|
113
|
-
|
|
135
|
+
if( options.dcm2jpg ) {
|
|
136
|
+
return this.dcm2jpg(id.filename, id.imageFrameRootPath.replace(/frames/,"thumbnail"), {});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
console.log("Using CS2 to generate thumbnails", id, options);
|
|
140
|
+
|
|
141
|
+
await callback.internalGenerateImage(imageFrame, dataSet, metadata, id.transferSyntaxUid, async (thumbBuffer) => {
|
|
114
142
|
try {
|
|
115
143
|
if (thumbBuffer) {
|
|
116
144
|
await callback.thumbWriter(id.sopInstanceRootPath, this.thumbFileName, thumbBuffer);
|
|
@@ -119,11 +147,11 @@ class ThumbnailService {
|
|
|
119
147
|
this.copySyncThumbnail(id.seriesRootPath, id.studyPath);
|
|
120
148
|
Stats.StudyStats.add("Thumbnail Write", `Write thumbnail ${this.thumbFileName}`, 100);
|
|
121
149
|
}
|
|
122
|
-
|
|
123
|
-
} catch
|
|
124
|
-
|
|
150
|
+
return this.thumbFileName;
|
|
151
|
+
} catch(e) {
|
|
152
|
+
console.log("Couldn't generate thumbnail", this.thumbFileName, e);
|
|
125
153
|
}
|
|
126
|
-
|
|
154
|
+
|
|
127
155
|
});
|
|
128
156
|
}
|
|
129
157
|
|
|
@@ -194,7 +194,8 @@ async function transcodeImageFrame(id, targetIdSrc, imageFrame, dataSet, options
|
|
|
194
194
|
let result = {};
|
|
195
195
|
|
|
196
196
|
const samplesPerPixel = dataSet.uint16(Tags.RawSamplesPerPixel);
|
|
197
|
-
|
|
197
|
+
const planarConfiguration = dataSet.uint16("x00280006");
|
|
198
|
+
if (!shouldTranscodeImageFrame(id, options, samplesPerPixel) || planarConfiguration === 1) {
|
|
198
199
|
console.verbose("Shouldn't transcode");
|
|
199
200
|
return {
|
|
200
201
|
id,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const hashFactory = require("node-object-hash");
|
|
2
2
|
|
|
3
|
-
const hasher = hashFactory();
|
|
3
|
+
const hasher = hashFactory.hasher();
|
|
4
4
|
const { JSONWriter } = require("@radicalimaging/static-wado-util");
|
|
5
5
|
const { Tags } = require("@radicalimaging/static-wado-util");
|
|
6
6
|
const TagLists = require("../model/TagLists");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const hashFactory = require("node-object-hash");
|
|
2
|
+
const { createHash } = require("crypto");
|
|
2
3
|
|
|
3
|
-
const hasher = hashFactory();
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const { Tags } = require("@radicalimaging/static-wado-util");
|
|
6
6
|
const WriteStream = require("./WriteStream");
|
|
@@ -15,6 +15,20 @@ const extensions = {
|
|
|
15
15
|
"application/xml+cda": ".cda.xml",
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
+
const baseHasher = hashFactory.hasher();
|
|
19
|
+
const MAX_HASH = 1024*1024;
|
|
20
|
+
|
|
21
|
+
const hasher = {
|
|
22
|
+
hash: (v) => {
|
|
23
|
+
const type = v.constructor?.name;
|
|
24
|
+
if (type === "Buffer") {
|
|
25
|
+
return createHash('sha256').update(v).digest('hex');
|
|
26
|
+
}
|
|
27
|
+
return baseHasher.hash(v);
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
|
|
18
32
|
/** Writes out JSON files to the given file name. Automatically GZips them, and adds the extension */
|
|
19
33
|
const HashDataWriter =
|
|
20
34
|
(options) =>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@radicalimaging/static-wado-creator",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.4",
|
|
4
4
|
"description": "Library to convert DICOMP10 to DICOMweb format. Original upstream: https://github.com/chafey/dicomp10-to-dicomweb-js",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"dcmjs": "^0.29.5",
|
|
64
64
|
"dicom-parser": "^1.8.13",
|
|
65
65
|
"glob": "^7.2.0",
|
|
66
|
-
"node-object-hash": "^
|
|
66
|
+
"node-object-hash": "^3.0.0",
|
|
67
67
|
"uuid": "^8.3.2"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|