larvitar 1.5.2 → 1.5.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.
@@ -38,6 +38,12 @@ jobs:
38
38
  repository: clenemt/docdash
39
39
  path: ./template/docdash/
40
40
 
41
+ # Install docdash node modules
42
+ - name: Install node modules
43
+ working-directory: ./template/docdash/
44
+ run: |
45
+ yarn install
46
+
41
47
  # Generate docs
42
48
  - name: Generate docs
43
49
  run: |
@@ -50,6 +56,4 @@ jobs:
50
56
  github_token: ${{ secrets.GITHUB_TOKEN }}
51
57
  message: "Update docs"
52
58
  branch: ${{ github.head_ref }}
53
- empty: true
54
-
55
-
59
+ empty: true
package/README.md CHANGED
@@ -6,15 +6,16 @@
6
6
 
7
7
  ## Dicom Image Toolkit for CornerstoneJS
8
8
 
9
- ### Current version: 1.5.2
9
+ ### Current version: 1.5.4
10
10
 
11
- ### Latest Published Release: 1.5.2
11
+ ### Latest Published Release: 1.5.4
12
12
 
13
13
  This library provides common DICOM functionalities to be used in web-applications: it's wrapper that simplifies the use of cornerstone-js environment.
14
14
  Orthogonal multiplanar reformat is included as well as custom loader/exporter for nrrd files and [Vuex](https://vuex.vuejs.org/) custom integration.
15
15
 
16
16
  - `index` main file
17
17
  - `dataDictionary` json file for dicom tags
18
+ - `imageAnonymization` provides anonymization functionalities
18
19
  - `imageColormaps` provides color maps functionalities
19
20
  - `imageContours` using to populate cornerstone tool for segmentation contours on 2D images
20
21
  - `imageIo` import a dicom image in .nrrd format and build contiguous array for exporting data as volume
@@ -4,19 +4,61 @@
4
4
  */
5
5
 
6
6
  // external libraries
7
- import aes from "crypto-js/aes";
8
7
  import sha256 from "crypto-js/sha256";
9
8
  import Hex from "crypto-js/enc-hex";
10
9
  import { forEach } from "lodash";
11
10
 
11
+ const SH = [
12
+ "x00080050" // Accession Number,
13
+ ];
14
+
15
+ const OPTIONAL = [
16
+ "x00100030", // Patient's Birth Date
17
+ "x00080090", // Referring Physician's Name,
18
+ "x00100020", // Patient ID
19
+ "x00100040", // Patient's Sex
20
+ "x00200010" // Study ID
21
+ ];
22
+
23
+ const REMOVE = [
24
+ "x00080014", // Instance Creator UID
25
+ "x00080080", // Institution Name
26
+ "x00080081", // Institution Address
27
+ "x00080092", // Referring Physician's Address
28
+ "x00080094", // Referring Physician's Telephone numbers
29
+ "x00081010", // Station Name
30
+ "x00081030", // Study Description
31
+ "x0008103e", // Series Description
32
+ "x00081040", // Institutional Department name
33
+ "x00081048", // Physician(s) of Record
34
+ "x00081050", // Performing Physicians' Name
35
+ "x00081060", // Name of Physician(s) Reading study
36
+ "x00081070", // Operator's Name
37
+ "x00081080", // Admitting Diagnoses Description
38
+ "x00082111", // Derivation Description
39
+ "x00100032", // Patient's Birth Time
40
+ "x00101000", // Other Patient Ids
41
+ "x00101001", // Other Patient Names
42
+ "x00101010", // Patient's Age
43
+ "x00101020", // Patient's Size
44
+ "x00101030", // Patient's Weight
45
+ "x00101090", // Medical Record Locator
46
+ "x00102160", // Ethnic Group
47
+ "x00102180", // Occupation
48
+ "x001021b0", // Additional Patient's History
49
+ "x00104000", // Patient Comments
50
+ "x00181000", // Device Serial Number
51
+ "x00181030", // Protocol Name
52
+ "x00204000", // Image Comments
53
+ "x00400275" // Request Attributes Sequence
54
+ ];
55
+
12
56
  // global vars
13
57
  const TAGS = [
14
58
  "x00080014", // Instance Creator UID
15
- "x00080018", // SOP Instance UID
16
59
  "x00080050", // Accession Number
17
60
  "x00080080", // Institution Name
18
61
  "x00080081", // Institution Address
19
- "x00080081", // Institution Address
20
62
  "x00080090", // Referring Physician's Name
21
63
  "x00080092", // Referring Physician's Address
22
64
  "x00080094", // Referring Physician's Telephone numbers
@@ -29,7 +71,6 @@ const TAGS = [
29
71
  "x00081060", // Name of Physician(s) Reading study
30
72
  "x00081070", // Operator's Name
31
73
  "x00081080", // Admitting Diagnoses Description
32
- "x00081155", // Referenced SOP Instance UID
33
74
  "x00082111", // Derivation Description
34
75
  "x00100010", // Patient's Name
35
76
  "x00100020", // Patient ID
@@ -48,15 +89,12 @@ const TAGS = [
48
89
  "x00104000", // Patient Comments
49
90
  "x00181000", // Device Serial Number
50
91
  "x00181030", // Protocol Name
51
- "x0020000d", // Study Instance UID
52
- "x0020000e", // Series Instance UID
53
92
  "x00200010", // Study ID
54
93
  "x00200052", // Frame of Reference UID
55
94
  "x00200200", // Synchronization Frame of Reference UID
56
95
  "x00204000", // Image Comments
57
96
  "x00400275", // Request Attributes Sequence
58
97
  "x0040a124", // UID
59
- "x0040a730", // Content Sequence
60
98
  "x00880140", // Storage Media File-set UID
61
99
  "x30060024", // Referenced Frame of Reference UID
62
100
  "x300600c2" // Related Frame of Reference UID
@@ -65,7 +103,6 @@ const TAGS = [
65
103
  /*
66
104
  * This module provides the following functions to be exported:
67
105
  * anonymize(series)
68
- * encrypt(series, passphrase)
69
106
  */
70
107
 
71
108
  /**
@@ -79,9 +116,30 @@ export const anonymize = function (series) {
79
116
  forEach(TAGS, function (tag) {
80
117
  if (tag in instance.metadata) {
81
118
  let anonymized_value = sha256(instance.metadata[tag]).toString(Hex);
82
- instance.metadata[tag] = anonymized_value;
119
+ // Patient Tag Anonymization
120
+ if (tag === "x00100010") {
121
+ instance.metadata[tag] =
122
+ "Anonymized^" + anonymized_value.substring(0, 6);
123
+ }
124
+ // Short string
125
+ else if (SH.includes(tag) === true) {
126
+ instance.metadata[tag] = anonymized_value.substring(0, 16);
127
+ }
128
+ // Required, empty if unknown
129
+ else if (OPTIONAL.includes(tag) === true) {
130
+ instance.metadata[tag] = "";
131
+ }
132
+ // Optional
133
+ else if (REMOVE.includes(tag) === true) {
134
+ delete instance.metadata[tag];
135
+ }
136
+ // Default sha256
137
+ else {
138
+ instance.metadata[tag] = anonymized_value;
139
+ }
83
140
  }
84
141
  });
142
+ instance.metadata["x00120062"] = "YES"; // Patient Identity Removed Attribute
85
143
  instance.metadata.seriesUID = instance.metadata["x0020000e"];
86
144
  instance.metadata.instanceUID = instance.metadata["x00080018"];
87
145
  instance.metadata.studyUID = instance.metadata["x0020000d"];
@@ -90,72 +148,11 @@ export const anonymize = function (series) {
90
148
  instance.metadata.patientName = instance.metadata["x00100010"];
91
149
  instance.metadata.patientBirthdate = instance.metadata["x00100030"];
92
150
  instance.metadata.seriesDescription = instance.metadata["x0008103e"];
151
+ instance.metadata.anonymized = true;
93
152
  });
94
153
 
95
- delete series["instanceUIDs"];
96
- series.instanceUIDs = {};
97
-
98
- forEach(series.imageIds, function (imageId) {
99
- series.instanceUIDs[series.instances[imageId].metadata.instanceUID] =
100
- imageId;
101
- });
102
-
103
- series.larvitarSeriesInstanceUID = sha256(
104
- series.larvitarSeriesInstanceUID
105
- ).toString(Hex);
106
- series.seriesUID = sha256(series.seriesUID).toString(Hex);
107
- series.seriesDescription = sha256(series.seriesDescription).toString(Hex);
108
- series.studyUID = sha256(series.studyUID).toString(Hex);
109
-
110
- return series;
111
- };
112
-
113
- /**
114
- * Encrypt DICOM series' metadata using AES
115
- * @function encrypt
116
- * @param {Object} series - Cornerstone series object
117
- * @param {String} passphrase - AES passphrase
118
- * @returns {Object} anonymized_series: Cornerstone encrypted series object
119
- */
120
- export const encrypt = function (series, passphrase) {
121
- if (!passphrase) {
122
- return "Error, provide a valid passphrase";
123
- }
124
- forEach(series.instances, function (instance) {
125
- forEach(TAGS, function (tag) {
126
- if (tag in instance.metadata) {
127
- let anonymized_value = aes
128
- .encrypt(instance.metadata[tag], passphrase)
129
- .toString();
130
- instance.metadata[tag] = anonymized_value;
131
- }
132
- });
133
- instance.metadata.seriesUID = instance.metadata["x0020000e"];
134
- instance.metadata.instanceUID = instance.metadata["x00080018"];
135
- instance.metadata.studyUID = instance.metadata["x0020000d"];
136
- instance.metadata.accessionNumber = instance.metadata["x00080050"];
137
- instance.metadata.studyDescription = instance.metadata["x00081030"];
138
- instance.metadata.patientName = instance.metadata["x00100010"];
139
- instance.metadata.patientBirthdate = instance.metadata["x00100030"];
140
- instance.metadata.seriesDescription = instance.metadata["x0008103e"];
141
- });
142
-
143
- delete series["instanceUIDs"];
144
- series.instanceUIDs = {};
145
-
146
- forEach(series.imageIds, function (imageId) {
147
- series.instanceUIDs[series.instances[imageId].metadata.instanceUID] =
148
- imageId;
149
- });
150
-
151
- series.larvitarSeriesInstanceUID = aes
152
- .encrypt(series.larvitarSeriesInstanceUID, passphrase)
153
- .toString();
154
- series.seriesUID = aes.encrypt(series.seriesUID, passphrase).toString();
155
- series.seriesDescription = aes
156
- .encrypt(series.seriesDescription, passphrase)
157
- .toString();
158
- series.studyUID = aes.encrypt(series.studyUID, passphrase).toString();
154
+ series.seriesDescription = undefined;
155
+ series.anonymized = true;
159
156
 
160
157
  return series;
161
158
  };
@@ -35,8 +35,8 @@ const globalConfig = {
35
35
  ),
36
36
  startWebWorkersOnDemand: true,
37
37
  webWorkerTaskPaths: [
38
- "https://unpkg.com/cornerstone-wado-image-loader@4.1.0/dist/610.bundle.min.worker.js",
39
- "https://unpkg.com/cornerstone-wado-image-loader@4.1.0/dist/888.bundle.min.worker.js"
38
+ "https://unpkg.com/cornerstone-wado-image-loader@4.8.0/dist/610.bundle.min.worker.js",
39
+ "https://unpkg.com/cornerstone-wado-image-loader@4.8.0/dist/888.bundle.min.worker.js"
40
40
  ],
41
41
  taskConfiguration: {
42
42
  decodeTask: {
@@ -150,6 +150,7 @@ export const updateLoadedStack = function (
150
150
  let is4D = seriesData.metadata.is4D;
151
151
  let SOPUID = seriesData.metadata["x00080016"];
152
152
  let isPDF = SOPUID == "1.2.840.10008.5.1.4.1.1.104.1" ? true : false;
153
+ let anonymized = seriesData.metadata.anonymized;
153
154
 
154
155
  let color = cornerstoneWADOImageLoader.isColorImage(
155
156
  seriesData.metadata["x00280004"]
@@ -173,6 +174,7 @@ export const updateLoadedStack = function (
173
174
  isMultiframe: isMultiframe,
174
175
  is4D: is4D,
175
176
  isPDF: isPDF,
177
+ anonymized: anonymized,
176
178
  modality: modality,
177
179
  color: color,
178
180
  bytes: 0
@@ -280,6 +280,7 @@ let parseFile = function (file) {
280
280
  dataSet: dataSet
281
281
  };
282
282
  imageObject.metadata = metadata;
283
+ imageObject.metadata.anonymized = false;
283
284
  imageObject.metadata.seriesUID = seriesInstanceUID;
284
285
  imageObject.metadata.instanceUID = instanceUID;
285
286
  imageObject.metadata.studyUID = metadata["x0020000d"];
@@ -175,6 +175,15 @@ export const clearMultiFrameCache = function (seriesId) {
175
175
  * @returns {Object} custom image object
176
176
  */
177
177
  let createCustomImage = function (id, imageId, frameIndex, metadata) {
178
+ let options = {};
179
+ // always preScale the pixel array unless it is asked not to
180
+ options.preScale = {
181
+ enabled:
182
+ options.preScale && options.preScale.enabled !== undefined
183
+ ? options.preScale.enabled
184
+ : false
185
+ };
186
+
178
187
  let dataSet = multiframeDatasetCache[id].dataSet;
179
188
  let pixelDataElement = dataSet.elements.x7fe00010;
180
189
  // Extract pixelData of the required frame
@@ -203,11 +212,27 @@ let createCustomImage = function (id, imageId, frameIndex, metadata) {
203
212
  ? window.document.getElementsByTagName("canvas")[0]
204
213
  : window.document.createElement("canvas");
205
214
 
215
+ // Get the scaling parameters from the metadata
216
+ if (options.preScale.enabled) {
217
+ const scalingParameters = cornerstoneWADOImageLoader.getScalingParameters(
218
+ cornerstone.metaData,
219
+ imageId
220
+ );
221
+
222
+ if (scalingParameters) {
223
+ options.preScale = {
224
+ ...options.preScale,
225
+ scalingParameters
226
+ };
227
+ }
228
+ }
229
+
206
230
  const decodePromise = cornerstoneWADOImageLoader.decodeImageFrame(
207
231
  imageFrame,
208
232
  transferSyntax,
209
233
  pixelData,
210
- canvas
234
+ canvas,
235
+ options
211
236
  );
212
237
 
213
238
  let promise = new Promise((resolve, reject) => {
package/index.js CHANGED
@@ -48,7 +48,7 @@ import {
48
48
  importNRRDImage
49
49
  } from "./imaging/imageIo";
50
50
 
51
- import { anonymize, encrypt } from "./imaging/imageAnonymization";
51
+ import { anonymize } from "./imaging/imageAnonymization";
52
52
 
53
53
  import {
54
54
  buildLayer,
@@ -251,7 +251,6 @@ export {
251
251
  importNRRDImage,
252
252
  // imageAnonymization
253
253
  anonymize,
254
- encrypt,
255
254
  // imageLayers
256
255
  buildLayer,
257
256
  updateLayer,
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "medical",
7
7
  "cornerstone"
8
8
  ],
9
- "version": "1.5.2",
9
+ "version": "1.5.4",
10
10
  "description": "javascript library for parsing, loading, rendering and interacting with DICOM images",
11
11
  "repository": {
12
12
  "url": "https://github.com/dvisionlab/Larvitar.git",
@@ -29,7 +29,7 @@
29
29
  "cornerstone-core": "^2.6.1",
30
30
  "cornerstone-file-image-loader": "^0.3.0",
31
31
  "cornerstone-tools": "^6.0.7",
32
- "cornerstone-wado-image-loader": "^4.1.3",
32
+ "cornerstone-wado-image-loader": "^4.8.0",
33
33
  "cornerstone-web-image-loader": "^2.1.1",
34
34
  "crypto-js": "^4.1.1",
35
35
  "dicom-character-set": "^1.0.3",