larvitar 0.18.2 → 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.
Files changed (229) hide show
  1. package/.github/workflows/deploy.yml +3 -12
  2. package/MIGRATION.md +25 -0
  3. package/README.md +28 -27
  4. package/docs/documentation/Mixins.polygonSegmentationMixin%20-%20segmentation%20operations%20for%20polyline.html +171 -0
  5. package/docs/documentation/Tools.Annotation.ContoursTool.html +218 -0
  6. package/docs/documentation/Tools.Annotation.DiameterTool.html +219 -0
  7. package/docs/documentation/Tools.Annotation.SeedsTool.html +214 -0
  8. package/docs/documentation/Tools.Brush.BrushTool.html +218 -0
  9. package/docs/documentation/Tools.Brush.ThresholdsBrushTool.html +218 -0
  10. package/docs/documentation/Tools.PolylineScissorsTool.html +218 -0
  11. package/docs/documentation/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  12. package/docs/documentation/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  13. package/docs/documentation/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  14. package/docs/documentation/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  15. package/docs/documentation/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  16. package/docs/documentation/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  17. package/docs/documentation/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  18. package/docs/documentation/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  19. package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  20. package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
  21. package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  22. package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  23. package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  24. package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  25. package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
  26. package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  27. package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  28. package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  29. package/docs/documentation/global.html +1303 -0
  30. package/docs/documentation/imageAnonymization.js.html +245 -0
  31. package/docs/documentation/imageColormaps.js.html +283 -0
  32. package/docs/documentation/imageContours.js.html +278 -0
  33. package/docs/documentation/imageIo.js.html +291 -0
  34. package/docs/documentation/imageLayers.js.html +188 -0
  35. package/docs/documentation/imageLoading.js.html +297 -0
  36. package/docs/documentation/imageParsing.js.html +385 -0
  37. package/docs/documentation/imagePresets.js.html +207 -0
  38. package/docs/documentation/imageRendering.js.html +849 -0
  39. package/docs/documentation/imageReslice.js.html +162 -0
  40. package/docs/documentation/imageStore.js.html +360 -0
  41. package/docs/documentation/imageTools.js.html +784 -0
  42. package/docs/documentation/imageUtils.js.html +1609 -0
  43. package/docs/documentation/image_colormaps.js.html +283 -0
  44. package/docs/documentation/image_contours.js.html +279 -0
  45. package/docs/documentation/image_io.js.html +288 -0
  46. package/docs/documentation/image_layers.js.html +188 -0
  47. package/docs/documentation/image_loading.js.html +294 -0
  48. package/docs/documentation/image_parsing.js.html +391 -0
  49. package/docs/documentation/image_presets.js.html +207 -0
  50. package/docs/documentation/image_rendering.js.html +845 -0
  51. package/docs/documentation/image_reslice.js.html +164 -0
  52. package/docs/documentation/image_store.js.html +359 -0
  53. package/docs/documentation/image_tools.js.html +792 -0
  54. package/docs/documentation/image_utils.js.html +1609 -0
  55. package/docs/documentation/index.html +175 -0
  56. package/docs/documentation/loaders_commonLoader.js.html +306 -0
  57. package/docs/documentation/loaders_dicomLoader.js.html +130 -0
  58. package/docs/documentation/loaders_fileLoader.js.html +155 -0
  59. package/docs/documentation/loaders_multiframeLoader.js.html +443 -0
  60. package/docs/documentation/loaders_niftiLoader.js.html +150 -0
  61. package/docs/documentation/loaders_nrrdLoader.js.html +545 -0
  62. package/docs/documentation/loaders_resliceLoader.js.html +258 -0
  63. package/docs/documentation/module-imaging_contours.html +954 -0
  64. package/docs/documentation/module-imaging_imageAnonymization.html +544 -0
  65. package/docs/documentation/module-imaging_imageColormaps.html +1012 -0
  66. package/docs/documentation/module-imaging_imageContours.html +954 -0
  67. package/docs/documentation/module-imaging_imageIo.html +1057 -0
  68. package/docs/documentation/module-imaging_imageLayers.html +904 -0
  69. package/docs/documentation/module-imaging_imageLoading.html +1301 -0
  70. package/docs/documentation/module-imaging_imageParsing.html +1356 -0
  71. package/docs/documentation/module-imaging_imagePresets.html +679 -0
  72. package/docs/documentation/module-imaging_imageRendering.html +3223 -0
  73. package/docs/documentation/module-imaging_imageReslice.html +413 -0
  74. package/docs/documentation/module-imaging_imageStore-Larvitar_Store.html +284 -0
  75. package/docs/documentation/module-imaging_imageStore.html +1560 -0
  76. package/docs/documentation/module-imaging_imageTools.html +3617 -0
  77. package/docs/documentation/module-imaging_imageUtils.html +7253 -0
  78. package/docs/documentation/module-imaging_io.html +1057 -0
  79. package/docs/documentation/module-imaging_layers.html +904 -0
  80. package/docs/documentation/module-imaging_loading.html +1301 -0
  81. package/docs/documentation/module-imaging_parsing.html +1375 -0
  82. package/docs/documentation/module-imaging_presets.html +679 -0
  83. package/docs/documentation/module-imaging_rendering.html +8094 -0
  84. package/docs/documentation/module-imaging_reslice.html +411 -0
  85. package/docs/documentation/module-imaging_store-Larvitar_Store.html +284 -0
  86. package/docs/documentation/module-imaging_store.html +1537 -0
  87. package/docs/documentation/module-imaging_strategies_eraseFreehand.html +708 -0
  88. package/docs/documentation/module-imaging_strategies_fillFreehand.html +708 -0
  89. package/docs/documentation/module-imaging_tools.html +3617 -0
  90. package/docs/documentation/module-imaging_tools_custom_contourTool.html +207 -0
  91. package/docs/documentation/module-imaging_tools_custom_diameterTool.html +205 -0
  92. package/docs/documentation/module-imaging_tools_custom_editMaskTool.html +205 -0
  93. package/docs/documentation/module-imaging_tools_custom_polygonScissorsTool.html +203 -0
  94. package/docs/documentation/module-imaging_tools_custom_thresholdBrushTool.html +684 -0
  95. package/docs/documentation/module-imaging_tools_default.html +205 -0
  96. package/docs/documentation/module-imaging_tools_interaction.html +530 -0
  97. package/docs/documentation/module-imaging_tools_io.html +832 -0
  98. package/docs/documentation/module-imaging_tools_main.html +2028 -0
  99. package/docs/documentation/module-imaging_tools_polygonSegmentationMixin.html +567 -0
  100. package/docs/documentation/module-imaging_tools_segmentation.html +3586 -0
  101. package/docs/documentation/module-imaging_tools_state.html +494 -0
  102. package/docs/documentation/module-imaging_utils.html +7253 -0
  103. package/docs/documentation/module-loaders_commonLoader.html +1313 -0
  104. package/docs/documentation/module-loaders_dicomLoader.html +522 -0
  105. package/docs/documentation/module-loaders_fileLoader.html +593 -0
  106. package/docs/documentation/module-loaders_multiframeLoader.html +1169 -0
  107. package/docs/documentation/module-loaders_niftiLoader.html +565 -0
  108. package/docs/documentation/module-loaders_nrrdLoader.html +1459 -0
  109. package/docs/documentation/module-loaders_resliceLoader.html +590 -0
  110. package/docs/documentation/module-monitors_memory.html +980 -0
  111. package/docs/documentation/module-tools_default.html +740 -0
  112. package/docs/documentation/module.exports_module.exports.html +203 -0
  113. package/docs/documentation/monitors_memory.js.html +189 -0
  114. package/docs/documentation/parsers_nrrd.js.html +569 -0
  115. package/docs/documentation/scripts/collapse.js +20 -0
  116. package/docs/documentation/scripts/linenumber.js +25 -0
  117. package/docs/documentation/scripts/nav.js +12 -0
  118. package/docs/documentation/scripts/polyfill.js +4 -0
  119. package/docs/documentation/scripts/prettify/Apache-License-2.0.txt +202 -0
  120. package/docs/documentation/scripts/prettify/lang-css.js +2 -0
  121. package/docs/documentation/scripts/prettify/prettify.js +28 -0
  122. package/docs/documentation/scripts/search.js +83 -0
  123. package/docs/documentation/styles/jsdoc.css +765 -0
  124. package/docs/documentation/styles/prettify.css +80 -0
  125. package/docs/documentation/tools_contourTool.js.html +1963 -0
  126. package/docs/documentation/tools_custom_contourTool.js.html +1968 -0
  127. package/docs/documentation/tools_custom_diameterTool.js.html +225 -0
  128. package/docs/documentation/tools_custom_editMaskTool.js.html +225 -0
  129. package/docs/documentation/tools_custom_polylineScissorsTool.js.html +143 -0
  130. package/docs/documentation/tools_custom_thresholdsBrushTool.js.html +245 -0
  131. package/docs/documentation/tools_default.js.html +576 -0
  132. package/docs/documentation/tools_diameterTool.js.html +219 -0
  133. package/docs/documentation/tools_editMaskTool.js.html +219 -0
  134. package/docs/documentation/tools_interaction.js.html +258 -0
  135. package/docs/documentation/tools_io.js.html +297 -0
  136. package/docs/documentation/tools_main.js.html +443 -0
  137. package/docs/documentation/tools_polygonSegmentationMixin.js.html +329 -0
  138. package/docs/documentation/tools_polylineScissorsTool.js.html +136 -0
  139. package/docs/documentation/tools_seedTool.js.html +423 -0
  140. package/docs/documentation/tools_segmentation.js.html +558 -0
  141. package/docs/documentation/tools_state.js.html +163 -0
  142. package/docs/documentation/tools_strategies_eraseFreehand.js.html +160 -0
  143. package/docs/documentation/tools_strategies_fillFreehand.js.html +163 -0
  144. package/docs/documentation/tools_thresholdsBrushTool.js.html +239 -0
  145. package/docs/documentation/tools_tools.default.js.html +569 -0
  146. package/docs/documentation/tools_tools.interaction.js.html +251 -0
  147. package/docs/documentation/tools_tools.io.js.html +288 -0
  148. package/docs/documentation/tools_tools.main.js.html +442 -0
  149. package/docs/documentation/tools_tools.segmentation.js.html +445 -0
  150. package/docs/documentation/tools_tools.state.js.html +157 -0
  151. package/docs/examples/base.html +170 -0
  152. package/docs/examples/colorMaps.html +181 -0
  153. package/docs/examples/defaultTools.html +246 -0
  154. package/docs/examples/demo/anon1 +0 -0
  155. package/docs/examples/demo/anon10 +0 -0
  156. package/docs/examples/demo/anon11 +0 -0
  157. package/docs/examples/demo/anon12 +0 -0
  158. package/docs/examples/demo/anon13 +0 -0
  159. package/docs/examples/demo/anon14 +0 -0
  160. package/docs/examples/demo/anon15 +0 -0
  161. package/docs/examples/demo/anon16 +0 -0
  162. package/docs/examples/demo/anon17 +0 -0
  163. package/docs/examples/demo/anon18 +0 -0
  164. package/docs/examples/demo/anon19 +0 -0
  165. package/docs/examples/demo/anon2 +0 -0
  166. package/docs/examples/demo/anon20 +0 -0
  167. package/docs/examples/demo/anon21 +0 -0
  168. package/docs/examples/demo/anon22 +0 -0
  169. package/docs/examples/demo/anon23 +0 -0
  170. package/docs/examples/demo/anon24 +0 -0
  171. package/docs/examples/demo/anon3 +0 -0
  172. package/docs/examples/demo/anon4 +0 -0
  173. package/docs/examples/demo/anon5 +0 -0
  174. package/docs/examples/demo/anon6 +0 -0
  175. package/docs/examples/demo/anon7 +0 -0
  176. package/docs/examples/demo/anon8 +0 -0
  177. package/docs/examples/demo/anon9 +0 -0
  178. package/docs/examples/demo/example.nrrd +0 -0
  179. package/docs/examples/demo/segmentation.nrrd +0 -0
  180. package/docs/examples/demo/xa_integris.dcm +0 -0
  181. package/docs/examples/index.html +129 -0
  182. package/docs/examples/larvitar.js +108623 -0
  183. package/docs/examples/layers.html +250 -0
  184. package/docs/examples/masks.html +273 -0
  185. package/docs/examples/multiframe.html +200 -0
  186. package/docs/examples/nrrd.html +96 -0
  187. package/docs/examples/reslice.html +174 -0
  188. package/docs/index.html +92 -0
  189. package/imaging/dataDictionary.json +21865 -21865
  190. package/imaging/imageAnonymization.js +161 -0
  191. package/imaging/{image_colormaps.js → imageColormaps.js} +2 -2
  192. package/imaging/{image_contours.js → imageContours.js} +1 -2
  193. package/imaging/{image_io.js → imageIo.js} +18 -15
  194. package/imaging/{image_layers.js → imageLayers.js} +2 -2
  195. package/imaging/{image_loading.js → imageLoading.js} +9 -6
  196. package/imaging/imageParsing.js +301 -0
  197. package/imaging/{image_presets.js → imagePresets.js} +2 -2
  198. package/imaging/{image_rendering.js → imageRendering.js} +36 -32
  199. package/imaging/imageReslice.js +78 -0
  200. package/imaging/{image_store.js → imageStore.js} +8 -7
  201. package/imaging/{image_tools.js → imageTools.js} +15 -23
  202. package/imaging/{image_utils.js → imageUtils.js} +1 -1
  203. package/imaging/loaders/commonLoader.js +1 -1
  204. package/imaging/loaders/dicomLoader.js +1 -1
  205. package/imaging/loaders/fileLoader.js +2 -2
  206. package/imaging/loaders/multiframeLoader.js +6 -2
  207. package/imaging/loaders/nrrdLoader.js +11 -7
  208. package/imaging/tools/{contourTool.js → custom/contourTool.js} +25 -20
  209. package/imaging/tools/{diameterTool.js → custom/diameterTool.js} +9 -3
  210. package/imaging/tools/{editMaskTool.js → custom/editMaskTool.js} +7 -1
  211. package/imaging/tools/{polylineScissorsTool.js → custom/polylineScissorsTool.js} +12 -5
  212. package/imaging/tools/{seedTool.js → custom/seedTool.js} +3 -3
  213. package/imaging/tools/{thresholdsBrushTool.js → custom/thresholdsBrushTool.js} +7 -1
  214. package/imaging/tools/{tools.default.js → default.js} +10 -3
  215. package/imaging/tools/{tools.interaction.js → interaction.js} +13 -6
  216. package/imaging/tools/{tools.io.js → io.js} +15 -6
  217. package/imaging/tools/{tools.main.js → main.js} +16 -14
  218. package/imaging/tools/polygonSegmentationMixin.js +8 -4
  219. package/imaging/tools/{tools.segmentation.js → segmentation.js} +171 -58
  220. package/imaging/tools/segmentations.md +38 -0
  221. package/imaging/tools/setLabelMap3D.js +248 -0
  222. package/imaging/tools/{tools.state.js → state.js} +7 -1
  223. package/imaging/tools/strategies/eraseFreehand.js +8 -9
  224. package/imaging/tools/strategies/fillFreehand.js +8 -9
  225. package/index.js +44 -39
  226. package/modules/vuex/larvitar.js +13 -3
  227. package/package.json +13 -10
  228. package/imaging/image_parsing.js +0 -307
  229. package/imaging/image_reslice.js +0 -80
@@ -0,0 +1,161 @@
1
+ /** @module imaging/imageAnonymization
2
+ * @desc This file provides anonymization functionalities on DICOM images
3
+ * following http://dicom.nema.org/medical/dicom/current/output/html/part15.html#chapter_E
4
+ */
5
+
6
+ // external libraries
7
+ import aes from "crypto-js/aes";
8
+ import sha256 from "crypto-js/sha256";
9
+ import Hex from "crypto-js/enc-hex";
10
+ import { forEach } from "lodash";
11
+
12
+ // global vars
13
+ const TAGS = [
14
+ "x00080014", // Instance Creator UID
15
+ "x00080018", // SOP Instance UID
16
+ "x00080050", // Accession Number
17
+ "x00080080", // Institution Name
18
+ "x00080081", // Institution Address
19
+ "x00080081", // Institution Address
20
+ "x00080090", // Referring Physician's Name
21
+ "x00080092", // Referring Physician's Address
22
+ "x00080094", // Referring Physician's Telephone numbers
23
+ "x00081010", // Station Name
24
+ "x00081030", // Study Description
25
+ "x0008103e", // Series Description
26
+ "x00081040", // Institutional Department name
27
+ "x00081048", // Physician(s) of Record
28
+ "x00081050", // Performing Physicians' Name
29
+ "x00081060", // Name of Physician(s) Reading study
30
+ "x00081070", // Operator's Name
31
+ "x00081080", // Admitting Diagnoses Description
32
+ "x00081155", // Referenced SOP Instance UID
33
+ "x00082111", // Derivation Description
34
+ "x00100010", // Patient's Name
35
+ "x00100020", // Patient ID
36
+ "x00100030", // Patient's Birth Date
37
+ "x00100032", // Patient's Birth Time
38
+ "x00100040", // Patient's Sex
39
+ "x00101000", // Other Patient Ids
40
+ "x00101001", // Other Patient Names
41
+ "x00101010", // Patient's Age
42
+ "x00101020", // Patient's Size
43
+ "x00101030", // Patient's Weight
44
+ "x00101090", // Medical Record Locator
45
+ "x00102160", // Ethnic Group
46
+ "x00102180", // Occupation
47
+ "x001021b0", // Additional Patient's History
48
+ "x00104000", // Patient Comments
49
+ "x00181000", // Device Serial Number
50
+ "x00181030", // Protocol Name
51
+ "x0020000d", // Study Instance UID
52
+ "x0020000e", // Series Instance UID
53
+ "x00200010", // Study ID
54
+ "x00200052", // Frame of Reference UID
55
+ "x00200200", // Synchronization Frame of Reference UID
56
+ "x00204000", // Image Comments
57
+ "x00400275", // Request Attributes Sequence
58
+ "x0040a124", // UID
59
+ "x0040a730", // Content Sequence
60
+ "x00880140", // Storage Media File-set UID
61
+ "x30060024", // Referenced Frame of Reference UID
62
+ "x300600c2" // Related Frame of Reference UID
63
+ ];
64
+
65
+ /*
66
+ * This module provides the following functions to be exported:
67
+ * anonymize(series)
68
+ * encrypt(series, passphrase)
69
+ */
70
+
71
+ /**
72
+ * Anonymize DICOM series' metadata using sha256
73
+ * @function anonymize
74
+ * @param {Object} series - Cornerstone series object
75
+ * @returns {Object} anonymized_series: Cornerstone anonymized series object
76
+ */
77
+ export const anonymize = function (series) {
78
+ forEach(series.instances, function (instance) {
79
+ forEach(TAGS, function (tag) {
80
+ if (tag in instance.metadata) {
81
+ let anonymized_value = sha256(instance.metadata[tag]).toString(Hex);
82
+ instance.metadata[tag] = anonymized_value;
83
+ }
84
+ });
85
+ instance.metadata.seriesUID = instance.metadata["x0020000e"];
86
+ instance.metadata.instanceUID = instance.metadata["x00080018"];
87
+ instance.metadata.studyUID = instance.metadata["x0020000d"];
88
+ instance.metadata.accessionNumber = instance.metadata["x00080050"];
89
+ instance.metadata.studyDescription = instance.metadata["x00081030"];
90
+ instance.metadata.patientName = instance.metadata["x00100010"];
91
+ instance.metadata.patientBirthdate = instance.metadata["x00100030"];
92
+ instance.metadata.seriesDescription = instance.metadata["x0008103e"];
93
+ });
94
+
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();
159
+
160
+ return series;
161
+ };
@@ -1,6 +1,6 @@
1
- /** @module imaging/rendering
1
+ /** @module imaging/imageColormaps
2
2
  * @desc This file provides functionalities for
3
- * rendering images in html canvas using cornerstone
3
+ * handling colormaps
4
4
  */
5
5
 
6
6
  import cornerstone from "cornerstone-core";
@@ -1,4 +1,4 @@
1
- /** @module imaging/contours
1
+ /** @module imaging/imageContours
2
2
  * @desc This file provides functionalities to render a set of points on a canvas.
3
3
  * Use this in order to render image contours (e.g. from binary masks).
4
4
  */
@@ -21,7 +21,6 @@ import { each, range } from "lodash";
21
21
  * @param {Array} viewports - Viewport array ids
22
22
  * @returns {Number} Number of array elements consumed
23
23
  */
24
-
25
24
  export const parseContours = function (
26
25
  contoursData,
27
26
  pointBatchSize,
@@ -1,4 +1,4 @@
1
- /** @module imaging/io
1
+ /** @module imaging/imageIo
2
2
  * @desc This file provides I/O functionalities on NRRD files and DICOM images
3
3
  */
4
4
 
@@ -11,8 +11,8 @@ import {
11
11
  getMeanValue,
12
12
  getDistanceBetweenSlices,
13
13
  getTypedArrayFromDataType
14
- } from "./image_utils.js";
15
- import { larvitar_store } from "./image_store";
14
+ } from "./imageUtils.js";
15
+ import { larvitar_store } from "./imageStore";
16
16
  import { parse } from "./parsers/nrrd";
17
17
  import { checkMemoryAllocation } from "./monitors/memory";
18
18
 
@@ -71,22 +71,25 @@ export const buildHeader = function (series) {
71
71
  * Get cached pixel data
72
72
  * @function getCachedPixelData
73
73
  * @param {String} imageId - ImageId of the cached image
74
- * @returns {Array} Pixel data array or null if not cached
74
+ * @returns {Promise} A promise which will resolve to a pixel data array or fail if an error occurs
75
75
  */
76
76
 
77
- export const getCachedPixelData = function (imageId, callback) {
77
+ export const getCachedPixelData = function (imageId) {
78
78
  let cachedImage = find(cornerstone.imageCache.cachedImages, [
79
79
  "imageId",
80
80
  imageId
81
81
  ]);
82
- if (cachedImage && cachedImage.image) {
83
- callback(cachedImage.image.getPixelData());
84
- } else {
85
- cornerstone.loadAndCacheImage(imageId).then(function (image) {
86
- callback(image.getPixelData());
87
- cornerstone.imageCache.removeImageLoadObject(imageId);
88
- });
89
- }
82
+ let promise = new Promise((resolve, reject) => {
83
+ if (cachedImage && cachedImage.image) {
84
+ resolve(cachedImage.image.getPixelData());
85
+ } else {
86
+ cornerstone
87
+ .loadImage(imageId)
88
+ .then(image => resolve(image.getPixelData()))
89
+ .catch(err => reject(err));
90
+ }
91
+ });
92
+ return promise;
90
93
  };
91
94
 
92
95
  /**
@@ -122,7 +125,7 @@ export const buildData = function (series, useSeriesData) {
122
125
  } else {
123
126
  larvitar_store.addSeriesIds(series.seriesUID, series.imageIds);
124
127
  forEach(series.imageIds, function (imageId) {
125
- getCachedPixelData(imageId, function (sliceData) {
128
+ getCachedPixelData(imageId).then(sliceData => {
126
129
  data.set(sliceData, offsetData);
127
130
  offsetData += sliceData.length;
128
131
  });
@@ -166,7 +169,7 @@ export const buildDataAsync = function (series, time, resolve, reject) {
166
169
  function runFillPixelData(data) {
167
170
  let imageId = imageIds.shift();
168
171
  if (imageId) {
169
- getCachedPixelData(imageId, function (sliceData) {
172
+ getCachedPixelData(imageId).then(sliceData => {
170
173
  data.set(sliceData, offsetData);
171
174
  offsetData += sliceData.length;
172
175
  // this does the trick: delay next computation to next tick
@@ -1,4 +1,4 @@
1
- /** @module imaging/layers
1
+ /** @module imaging/imageLayers
2
2
  * @desc This file provides functionalities for
3
3
  * rendering image layers using cornerstone stack
4
4
  */
@@ -7,7 +7,7 @@
7
7
  import cornerstone from "cornerstone-core";
8
8
 
9
9
  // internal libraries
10
- import { isElement } from "./image_utils";
10
+ import { isElement } from "./imageUtils";
11
11
 
12
12
  /*
13
13
  * This module provides the following functions to be exported:
@@ -1,4 +1,4 @@
1
- /** @module imaging/loading
1
+ /** @module imaging/imageLoading
2
2
  * @desc This file provides functionalities for
3
3
  * initialize, configure and update WadoImageLoader
4
4
  */
@@ -12,8 +12,8 @@ import cornerstoneFileImageLoader from "cornerstone-file-image-loader";
12
12
  import { forEach } from "lodash";
13
13
 
14
14
  // internal libraries
15
- import { larvitar_store } from "./image_store";
16
- import { getSortedStack, getSortedUIDs } from "./image_utils";
15
+ import { larvitar_store } from "./imageStore";
16
+ import { getSortedStack, getSortedUIDs } from "./imageUtils";
17
17
  import { loadNrrdImage } from "./loaders/nrrdLoader";
18
18
  import { loadReslicedImage } from "./loaders/resliceLoader";
19
19
  import { loadMultiFrameImage } from "./loaders/multiframeLoader";
@@ -26,16 +26,19 @@ import { loadMultiFrameImage } from "./loaders/multiframeLoader";
26
26
  * @property {String} webWorkerPath - path to default WADO web worker
27
27
  * @property {} - see https://github.com/cornerstonejs/cornerstoneWADOImageLoader/blob/master/docs/WebWorkers.md
28
28
  */
29
+
29
30
  const globalConfig = {
30
31
  maxWebWorkers: navigator.hardwareConcurrency || 1,
31
- webWorkerPath: "/cornerstoneWADOImageLoaderWebWorker.js",
32
32
  startWebWorkersOnDemand: true,
33
+ webWorkerTaskPaths: [
34
+ "https://unpkg.com/cornerstone-wado-image-loader@4.1.0/dist/610.bundle.min.worker.js",
35
+ "https://unpkg.com/cornerstone-wado-image-loader@4.1.0/dist/888.bundle.min.worker.js"
36
+ ],
33
37
  taskConfiguration: {
34
38
  decodeTask: {
35
39
  loadCodecsOnStartup: true,
36
40
  initializeCodecsOnStartup: false,
37
- codecsPath: "/cornerstoneWADOImageLoaderCodecs.js",
38
- usePDFJS: false
41
+ strict: true
39
42
  }
40
43
  }
41
44
  };
@@ -0,0 +1,301 @@
1
+ /** @module imaging/imageParsing
2
+ * @desc This file provides functionalities for parsing DICOM image files
3
+ */
4
+
5
+ // external libraries
6
+ import { parseDicom } from "dicom-parser";
7
+ import { forEach, each, has, pick } from "lodash";
8
+
9
+ // internal libraries
10
+ import { getPixelRepresentation, randomId, parseTag } from "./imageUtils.js";
11
+ import { updateLoadedStack } from "./imageLoading.js";
12
+ import { checkMemoryAllocation } from "./monitors/memory.js";
13
+
14
+ // global module variables
15
+ var t0 = null; // t0 variable for timing debugging purpose
16
+
17
+ /*
18
+ * This module provides the following functions to be exported:
19
+ * readFiles(fileList)
20
+ * readFile(file)
21
+ * parseDataSet(dataSet, metadata, customFilter)
22
+ * clearImageParsing(seriesStack)
23
+ */
24
+
25
+ /**
26
+ * Reset series stack object and its internal data
27
+ * @instance
28
+ * @function clearImageParsing
29
+ * @param {Object} seriesStack - Parsed series stack object
30
+ */
31
+ export const clearImageParsing = function (seriesStack) {
32
+ each(seriesStack, function (stack) {
33
+ each(stack.instances, function (instance) {
34
+ if (instance.dataSet) {
35
+ instance.dataSet.byteArray = null;
36
+ }
37
+ instance.dataSet = null;
38
+ instance.file = null;
39
+ instance.metadata = null;
40
+ });
41
+ });
42
+ seriesStack = null;
43
+ };
44
+
45
+ /**
46
+ * Read dicom files and return allSeriesStack object
47
+ * @instance
48
+ * @function readFiles
49
+ * @param {Array} entries - List of file objects
50
+ * @returns {Promise} - Return a promise which will resolve to a image object list or fail if an error occurs
51
+ */
52
+ export const readFiles = function (entries) {
53
+ let promise = new Promise((resolve, reject) => {
54
+ parseFiles(entries).then(resolve).catch(reject);
55
+ });
56
+ return promise;
57
+ };
58
+
59
+ /**
60
+ * Read a single dicom file and return parsed object
61
+ * @instance
62
+ * @function readFile
63
+ * @param {File} entry - File object
64
+ * @returns {Promise} - Return a promise which will resolve to a image object or fail if an error occurs
65
+ */
66
+ export const readFile = function (entry) {
67
+ let promise = new Promise((resolve, reject) => {
68
+ parseFile(entry).then(resolve).catch(reject);
69
+ });
70
+ return promise;
71
+ };
72
+
73
+ /* Internal module functions */
74
+
75
+ /**
76
+ * Parse metadata from dicom parser dataSet object
77
+ * @instance
78
+ * @function parseDataSet
79
+ * @param {Object} dataSet - dicom parser dataSet object
80
+ * @param {Array} metadata - Initialized metadata object
81
+ * @param {Array} customFilter - Optional filter: {tags:[], frameId: 0}
82
+ */
83
+ // This function iterates through dataSet recursively and adds new HTML strings
84
+ // to the output array passed into it
85
+ export const parseDataSet = function (dataSet, metadata, customFilter) {
86
+ // customFilter= {tags:[], frameId:xxx}
87
+ // the dataSet.elements object contains properties for each element parsed. The name of the property
88
+ // is based on the elements tag and looks like 'xGGGGEEEE' where GGGG is the group number and EEEE is the
89
+ // element number both with lowercase hexadecimal letters. For example, the Series Description DICOM element 0008,103E would
90
+ // be named 'x0008103e'. Here we iterate over each property (element) so we can build a string describing its
91
+ // contents to add to the output array
92
+ try {
93
+ let elements =
94
+ customFilter && has(customFilter, "tags")
95
+ ? pick(dataSet.elements, customFilter.tags)
96
+ : dataSet.elements;
97
+ for (let propertyName in elements) {
98
+ let element = elements[propertyName];
99
+ // Here we check for Sequence items and iterate over them if present. items will not be set in the
100
+ // element object for elements that don't have SQ VR type. Note that implicit little endian
101
+ // sequences will are currently not parsed.
102
+ if (element.items) {
103
+ // each item contains its own data set so we iterate over the items
104
+ // and recursively call this function
105
+ if (customFilter && has(customFilter, "frameId")) {
106
+ let item = element.items[customFilter.frameId];
107
+ parseDataSet(item.dataSet, metadata);
108
+ } else {
109
+ element.items.forEach(function (item) {
110
+ parseDataSet(item.dataSet, metadata);
111
+ });
112
+ }
113
+ } else {
114
+ let tagValue = parseTag(dataSet, propertyName, element);
115
+ metadata[propertyName] = tagValue;
116
+ }
117
+ }
118
+ } catch (err) {
119
+ console.log(err);
120
+ }
121
+ };
122
+
123
+ /**
124
+ * Manage the parsing process waiting for the parsed object before proceeding with the next parse request
125
+ * @inner
126
+ * @function parseNextFile
127
+ * @param {Array} parsingQueue - Array of queued files to be parsed
128
+ * @param {Object} allSeriesStack - Series stack object to be populated
129
+ * @param {Function} resolve - Promise resolve function
130
+ * @param {Function} reject - Promise reject function
131
+ */
132
+ let parseNextFile = function (parsingQueue, allSeriesStack, resolve, reject) {
133
+ // initialize t0 on first file of the queue
134
+ if (
135
+ Object.keys(allSeriesStack).length === 0 &&
136
+ allSeriesStack.constructor === Object
137
+ ) {
138
+ t0 = performance.now();
139
+ }
140
+
141
+ if (parsingQueue.length === 0) {
142
+ let t1 = performance.now();
143
+ console.log(`Call to readFiles took ${t1 - t0} milliseconds.`);
144
+ resolve(allSeriesStack);
145
+ return;
146
+ }
147
+
148
+ // remove and return first item from queue
149
+ let file = parsingQueue.shift();
150
+
151
+ // Check if there is enough memory to parse the file
152
+ if (checkMemoryAllocation(file.size) === false) {
153
+ // do not parse the file and stop parsing
154
+ clearImageParsing(allSeriesStack);
155
+ let t1 = performance.now();
156
+ console.log(`Call to readFiles took ${t1 - t0} milliseconds.`);
157
+ file = null;
158
+ reject(allSeriesStack, "Available memory is not enough");
159
+ return;
160
+ } else {
161
+ // parse the file and wait for results
162
+ parseFile(file)
163
+ .then(seriesData => {
164
+ // add file to cornerstoneWADOImageLoader file manager
165
+ updateLoadedStack(seriesData, allSeriesStack);
166
+ // proceed with the next file to parse
167
+ parseNextFile(parsingQueue, allSeriesStack, resolve, reject);
168
+ seriesData = null;
169
+ file = null;
170
+ })
171
+ .catch(err => {
172
+ console.warn(err);
173
+ parseNextFile(parsingQueue, allSeriesStack, resolve, reject);
174
+ file = null;
175
+ });
176
+ }
177
+ };
178
+
179
+ /**
180
+ * Push files in queue and start parsing next file
181
+ * @inner
182
+ * @function parseFiles
183
+ * @param {Array} fileList - Array of file objects
184
+ * @returns {Promise} - Return a promise which will resolve to a image object list or fail if an error occurs
185
+ */
186
+ let parseFiles = function (fileList) {
187
+ let allSeriesStack = {};
188
+ let parsingQueue = [];
189
+
190
+ forEach(fileList, function (file) {
191
+ if (!file.name.startsWith(".") && !file.name.startsWith("DICOMDIR")) {
192
+ parsingQueue.push(file);
193
+ }
194
+ });
195
+ return new Promise((resolve, reject) => {
196
+ parseNextFile(parsingQueue, allSeriesStack, resolve, reject);
197
+ });
198
+ };
199
+
200
+ /**
201
+ * Parse a single DICOM File (metaData and pixelData)
202
+ * @inner
203
+ * @function parseFile
204
+ * @param {File} file - File object to be parsed
205
+ * @returns {Promise} - Return a promise which will resolve to a image object or fail if an error occurs
206
+ */
207
+ let parseFile = function (file) {
208
+ let parsePromise = new Promise((resolve, reject) => {
209
+ let reader = new FileReader();
210
+ reader.onload = function () {
211
+ let arrayBuffer = reader.result;
212
+ // Here we have the file data as an ArrayBuffer.
213
+ // dicomParser requires as input a Uint8Array so we create that here.
214
+ let byteArray = new Uint8Array(arrayBuffer);
215
+ let dataSet;
216
+
217
+ try {
218
+ dataSet = parseDicom(byteArray);
219
+ byteArray = null;
220
+ let metadata = {};
221
+ parseDataSet(dataSet, metadata);
222
+
223
+ let numberOfFrames = metadata["x00280008"];
224
+ let isMultiframe = numberOfFrames > 1 ? true : false;
225
+ // Overwrite SOPInstanceUID to manage multiframes.
226
+ // Usually different SeriesInstanceUID means different series and that value
227
+ // is used into the application to group different instances into the same series,
228
+ // but if a DICOM file contains a multiframe series, then the SeriesInstanceUID
229
+ // can be shared by other files of the same study.
230
+ // In multiframe cases, the SOPInstanceUID (unique) is used as SeriesInstanceUID.
231
+ let seriesInstanceUID = isMultiframe
232
+ ? metadata["x00080018"]
233
+ : metadata["x0020000e"];
234
+ let pixelSpacing = metadata["x00280030"];
235
+ let imageOrientation = metadata["x00200037"];
236
+ let imagePosition = metadata["x00200032"];
237
+ let sliceThickness = metadata["x00180050"];
238
+
239
+ if (dataSet.warnings.length > 0) {
240
+ // warnings
241
+ reject(dataSet.warnings);
242
+ } else {
243
+ let pixelDataElement = dataSet.elements.x7fe00010;
244
+
245
+ if (pixelDataElement) {
246
+ // done, pixelDataElement found
247
+ let instanceUID = metadata["x00080018"] || randomId();
248
+ let imageObject = {
249
+ // data needed for rendering
250
+ file: file,
251
+ dataSet: dataSet
252
+ };
253
+ imageObject.metadata = metadata;
254
+ imageObject.metadata.seriesUID = seriesInstanceUID;
255
+ imageObject.metadata.instanceUID = instanceUID;
256
+ imageObject.metadata.studyUID = metadata["x0020000d"];
257
+ imageObject.metadata.accessionNumber = metadata["x00080050"];
258
+ imageObject.metadata.studyDescription = metadata["x00081030"];
259
+ imageObject.metadata.patientName = metadata["x00100010"];
260
+ imageObject.metadata.patientBirthdate = metadata["x00100030"];
261
+ imageObject.metadata.seriesDescription = metadata["x0008103e"];
262
+ imageObject.metadata.seriesDate = metadata["x00080021"];
263
+ imageObject.metadata.seriesModality =
264
+ metadata["x00080060"].toLowerCase();
265
+ imageObject.metadata.intercept = metadata["x00281052"];
266
+ imageObject.metadata.slope = metadata["x00281053"];
267
+ imageObject.metadata.pixelSpacing = pixelSpacing;
268
+ imageObject.metadata.sliceThickness = sliceThickness;
269
+ imageObject.metadata.imageOrientation = imageOrientation;
270
+ imageObject.metadata.imagePosition = imagePosition;
271
+ imageObject.metadata.rows = metadata["x00280010"];
272
+ imageObject.metadata.cols = metadata["x00280011"];
273
+ imageObject.metadata.numberOfSlices = metadata["x00540081"]
274
+ ? metadata["x00540081"] // number of slices
275
+ : metadata["x00201002"]; // number of instances
276
+ imageObject.metadata.numberOfFrames = numberOfFrames;
277
+ if (isMultiframe) {
278
+ imageObject.metadata.frameTime = metadata["x00181063"];
279
+ imageObject.metadata.frameDelay = metadata["x00181066"];
280
+ }
281
+ imageObject.metadata.windowCenter = metadata["x00281050"];
282
+ imageObject.metadata.windowWidth = metadata["x00281051"];
283
+ imageObject.metadata.minPixelValue = metadata["x00280106"];
284
+ imageObject.metadata.maxPixelValue = metadata["x00280107"];
285
+ imageObject.metadata.length = pixelDataElement.length;
286
+ imageObject.metadata.repr = getPixelRepresentation(dataSet);
287
+ resolve(imageObject);
288
+ } else {
289
+ // done, no pixelData
290
+ reject("no pixelData");
291
+ }
292
+ }
293
+ } catch (err) {
294
+ console.error(err);
295
+ reject("can not read this file");
296
+ }
297
+ };
298
+ reader.readAsArrayBuffer(file);
299
+ });
300
+ return parsePromise;
301
+ };
@@ -1,4 +1,4 @@
1
- /** @module imaging/presets
1
+ /** @module imaging/imagePresets
2
2
  * @desc This file provides functionalities for
3
3
  * image presets for ww and wc
4
4
  */
@@ -8,7 +8,7 @@ import cornerstone from "cornerstone-core";
8
8
  import { each, find } from "lodash";
9
9
 
10
10
  // internal libraries
11
- import { larvitar_store } from "./image_store";
11
+ import { larvitar_store } from "./imageStore";
12
12
 
13
13
  /**
14
14
  * Object used to list image presets