@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 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
@@ -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 of\n" +
156
- "deduplicated files each time a study instance UID is found, and only updates those studies\n" +
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",
@@ -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
- } else {
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
- return new Promise((resolve, reject) => {
113
- callback.internalGenerateImage(imageFrame, dataSet, metadata, id.transferSyntaxUid, async (thumbBuffer) => {
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
- resolve(this.thumbFileName);
123
- } catch (e) {
124
- reject(e);
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
- if (!shouldTranscodeImageFrame(id, options, samplesPerPixel)) {
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.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": "^2.3.10",
66
+ "node-object-hash": "^3.0.0",
67
67
  "uuid": "^8.3.2"
68
68
  },
69
69
  "devDependencies": {