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.
|
|
9
|
+
### Current version: 1.5.4
|
|
10
10
|
|
|
11
|
-
### Latest Published Release: 1.5.
|
|
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
|
-
|
|
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
|
-
|
|
96
|
-
series.
|
|
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
|
};
|
package/imaging/imageLoading.js
CHANGED
|
@@ -35,8 +35,8 @@ const globalConfig = {
|
|
|
35
35
|
),
|
|
36
36
|
startWebWorkersOnDemand: true,
|
|
37
37
|
webWorkerTaskPaths: [
|
|
38
|
-
"https://unpkg.com/cornerstone-wado-image-loader@4.
|
|
39
|
-
"https://unpkg.com/cornerstone-wado-image-loader@4.
|
|
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
|
package/imaging/imageParsing.js
CHANGED
|
@@ -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
|
|
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.
|
|
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.
|
|
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",
|