@ohif/app 3.7.0-beta.11 → 3.7.0-beta.110

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 (66) hide show
  1. package/dist/{917.bundle.b9983325adf849bff6fd.js → 12.bundle.5ea15cb6633d8028e47d.js} +6 -6
  2. package/dist/{295.bundle.957b1159fec14b9199a1.js → 125.bundle.253395f320b72180da63.js} +6 -6
  3. package/dist/{351.bundle.0742237651aef9694a65.js → 181.bundle.ceb057236403bcb630ac.js} +226 -204
  4. package/dist/{351.css → 181.css} +1 -1
  5. package/dist/{744.bundle.4c4b884f90eb70482821.js → 19.bundle.03f809886c36c388d05c.js} +240 -381
  6. package/dist/{606.bundle.5d876f5f3dd8287f0a28.js → 202.bundle.d3490836f71e001dd30f.js} +2089 -692
  7. package/dist/{926.bundle.dbc9d0e591cb9217fda2.js → 220.bundle.f7e1c96c94245e70f2be.js} +990 -400
  8. package/dist/221.bundle.dc6dac346d724d6baeae.js +1779 -0
  9. package/dist/221.css +2 -0
  10. package/dist/{664.bundle.09abae984223969d1bde.js → 23.bundle.e008ad788170f2ed5569.js} +5 -6
  11. package/dist/{976.bundle.9cc2382162214ea0af2b.js → 236.bundle.7b906cd27864d65f32c0.js} +89 -105
  12. package/dist/{55.bundle.550a823e75eb608e8d5e.js → 250.bundle.8084960e3318cda37317.js} +52 -36
  13. package/dist/{973.bundle.4584df05b320b94cace5.js → 281.bundle.c9854cc25c839e49c2c8.js} +18 -14
  14. package/dist/{82.bundle.9a0e7f08d4bce18d302f.js → 342.bundle.7d6c1e6bda1c67d729a7.js} +1802 -489
  15. package/dist/{404.bundle.3d65ff813eead20462d3.js → 359.bundle.72d017719489ff11057b.js} +47 -134
  16. package/dist/{192.bundle.950e5380ea63c6d635d5.js → 370.bundle.e55d75ff1bdccee16cde.js} +117 -103
  17. package/dist/{790.bundle.7327fec7833ceea2784b.js → 410.bundle.5b41c68cb0f210a83f13.js} +11 -9
  18. package/dist/{151.bundle.31ea35044218837bf73f.js → 417.bundle.af0a207c29b109f84159.js} +49 -17
  19. package/dist/{569.bundle.c8e771a8d28e237b32be.js → 451.bundle.9fd36f52ff69594f0669.js} +86 -106
  20. package/dist/{581.bundle.dc6197189f7c88c27d4c.js → 471.bundle.b3d77b83b1593c09a504.js} +78 -99
  21. package/dist/{199.bundle.f50ffd85a4334de2f5c1.js → 506.bundle.468dc6db2a9bfa96bb44.js} +11 -9
  22. package/dist/{531.bundle.2a82fb1d69e5b57cc72b.js → 530.bundle.a03b6f942ace3e1baa1e.js} +726 -447
  23. package/dist/579.css +1 -0
  24. package/dist/{935.bundle.deeffff0e4f7b528e3c3.js → 604.bundle.a51f83e64004bca5f497.js} +2 -3
  25. package/dist/613.bundle.74d59dec1983ef3efcdc.js +532 -0
  26. package/dist/{984.bundle.119557c018e6371b4628.js → 663.bundle.a6196baf5853e7d3f7c7.js} +68 -38
  27. package/dist/{205.bundle.b5a473c200dcf2bbcdb4.js → 686.bundle.dccef1f36e4bc79bcc48.js} +6 -6
  28. package/dist/{50.bundle.65ff60818862eda39d12.js → 687.bundle.e2c9c42ad3989a14d513.js} +218 -9
  29. package/dist/{331.bundle.bd0c13931a21d53086c9.js → 743.bundle.489f7df3a089d4d374e1.js} +26294 -21326
  30. package/dist/757.bundle.ec8301d8e70d2b990f65.js +17067 -0
  31. package/dist/{728.bundle.d13856835357400fef82.js → 774.bundle.4b2dc46a35012b898e1a.js} +95 -64
  32. package/dist/{381.bundle.0905e683605fcbc0895f.js → 775.bundle.2285e7e0e67878948c0d.js} +16 -16
  33. package/dist/{283.bundle.1015e87c3a47b1f1379c.js → 788.bundle.f4493409508bdffa7af8.js} +120 -370
  34. package/dist/{642.bundle.8905e515ce593e57ceb1.js → 814.bundle.10a2cbf02b044387e68b.js} +6 -6
  35. package/dist/{707.bundle.f774f3e4a687ddd60a32.js → 82.bundle.9c6461625afd2e38b997.js} +1203 -804
  36. package/dist/{799.bundle.758558e64147e5aad612.js → 822.bundle.891f2e57b1b7bc2f4cb4.js} +81 -34
  37. package/dist/{953.bundle.3b0189ebc11cf0946f18.js → 886.bundle.4b3a7f2079d085fdbcb3.js} +34 -29
  38. package/dist/945.min.worker.js +1 -1
  39. package/dist/945.min.worker.js.map +1 -1
  40. package/dist/{270.bundle.4564621556b0f963a004.js → 957.bundle.9ea4506963ef8b2d84ba.js} +7095 -979
  41. package/dist/{208.bundle.7f610a302dc54c4924da.js → 99.bundle.334c4bd4e4e81aaf45ad.js} +86 -105
  42. package/dist/_redirects +1 -1
  43. package/dist/app-config.js +35 -17
  44. package/dist/app.bundle.css +13 -12
  45. package/dist/{app.bundle.3d598a4738bdc22950d3.js → app.bundle.fd6ac18b8874825722a0.js} +72771 -67313
  46. package/dist/assets/yandex-browser-manifest.json +1 -1
  47. package/dist/cornerstoneDICOMImageLoader.min.js +1 -1
  48. package/dist/cornerstoneDICOMImageLoader.min.js.map +1 -1
  49. package/dist/{dicom-microscopy-viewer.bundle.aa60bdf008c32c39cfd7.js → dicom-microscopy-viewer.bundle.2c146384eb9466d02ff8.js} +5 -4
  50. package/dist/es6-shim.min.js +3569 -2
  51. package/dist/google.js +8 -7
  52. package/dist/index.html +2 -1
  53. package/dist/{index.worker.1c69152d710fa7b84bce.worker.js → index.worker.e62ecca63f1a2e124230.worker.js} +2 -2
  54. package/dist/index.worker.e62ecca63f1a2e124230.worker.js.map +1 -0
  55. package/dist/init-service-worker.js +3 -5
  56. package/dist/oidc-client.min.js +10857 -39
  57. package/dist/polyfill.min.js +184 -1
  58. package/dist/silent-refresh.html +18 -9
  59. package/dist/sw.js +1 -1
  60. package/package.json +21 -22
  61. package/dist/616.bundle.de530ae226dfa5573f6e.js +0 -685
  62. package/dist/780.bundle.fd0f13dc92e9caa0581e.js +0 -4769
  63. package/dist/index.worker.1c69152d710fa7b84bce.worker.js.map +0 -1
  64. /package/dist/{806.css → 19.css} +0 -0
  65. /package/dist/{55.css → 250.css} +0 -0
  66. /package/dist/{707.css → 82.css} +0 -0
@@ -0,0 +1,1779 @@
1
+ (self["webpackChunk"] = self["webpackChunk"] || []).push([[221,579],{
2
+
3
+ /***/ 9943:
4
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
5
+
6
+ "use strict";
7
+ // ESM COMPAT FLAG
8
+ __webpack_require__.r(__webpack_exports__);
9
+
10
+ // EXPORTS
11
+ __webpack_require__.d(__webpack_exports__, {
12
+ "default": () => (/* binding */ cornerstone_dicom_seg_src)
13
+ });
14
+
15
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone-dicom-seg/package.json
16
+ const package_namespaceObject = JSON.parse('{"u2":"@ohif/extension-cornerstone-dicom-seg"}');
17
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone-dicom-seg/src/id.js
18
+
19
+ const id = package_namespaceObject.u2;
20
+ const SOPClassHandlerName = 'dicom-seg';
21
+ const SOPClassHandlerId = `${id}.sopClassHandlerModule.${SOPClassHandlerName}`;
22
+
23
+ // EXTERNAL MODULE: ../../../node_modules/react/index.js
24
+ var react = __webpack_require__(43001);
25
+ // EXTERNAL MODULE: ../../core/src/index.ts + 65 modules
26
+ var src = __webpack_require__(71771);
27
+ // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/core/dist/esm/index.js + 331 modules
28
+ var esm = __webpack_require__(3743);
29
+ // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/adapters/dist/adapters.es.js
30
+ var adapters_es = __webpack_require__(91202);
31
+ // EXTERNAL MODULE: ../../../node_modules/dcmjs/build/dcmjs.es.js
32
+ var dcmjs_es = __webpack_require__(67540);
33
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone-dicom-seg/src/utils/dicomlabToRGB.ts
34
+
35
+
36
+ /**
37
+ * Converts a CIELAB color to an RGB color using the dcmjs library.
38
+ * @param cielab - The CIELAB color to convert.
39
+ * @returns The RGB color as an array of three integers between 0 and 255.
40
+ */
41
+ function dicomlabToRGB(cielab) {
42
+ const rgb = dcmjs_es["default"].data.Colors.dicomlab2RGB(cielab).map(x => Math.round(x * 255));
43
+ return rgb;
44
+ }
45
+
46
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone-dicom-seg/src/getSopClassHandlerModule.js
47
+
48
+
49
+
50
+
51
+
52
+ const sopClassUids = ['1.2.840.10008.5.1.4.1.1.66.4'];
53
+ let loadPromises = {};
54
+ function _getDisplaySetsFromSeries(instances, servicesManager, extensionManager) {
55
+ const instance = instances[0];
56
+ const {
57
+ StudyInstanceUID,
58
+ SeriesInstanceUID,
59
+ SOPInstanceUID,
60
+ SeriesDescription,
61
+ SeriesNumber,
62
+ SeriesDate,
63
+ SOPClassUID,
64
+ wadoRoot,
65
+ wadoUri,
66
+ wadoUriRoot
67
+ } = instance;
68
+ const displaySet = {
69
+ Modality: 'SEG',
70
+ loading: false,
71
+ isReconstructable: true,
72
+ // by default for now since it is a volumetric SEG currently
73
+ displaySetInstanceUID: src.utils.guid(),
74
+ SeriesDescription,
75
+ SeriesNumber,
76
+ SeriesDate,
77
+ SOPInstanceUID,
78
+ SeriesInstanceUID,
79
+ StudyInstanceUID,
80
+ SOPClassHandlerId: SOPClassHandlerId,
81
+ SOPClassUID,
82
+ referencedImages: null,
83
+ referencedSeriesInstanceUID: null,
84
+ referencedDisplaySetInstanceUID: null,
85
+ isDerivedDisplaySet: true,
86
+ isLoaded: false,
87
+ isHydrated: false,
88
+ segments: {},
89
+ sopClassUids,
90
+ instance,
91
+ instances: [instance],
92
+ wadoRoot,
93
+ wadoUriRoot,
94
+ wadoUri,
95
+ isOverlayDisplaySet: true
96
+ };
97
+ const referencedSeriesSequence = instance.ReferencedSeriesSequence;
98
+ if (!referencedSeriesSequence) {
99
+ console.error('ReferencedSeriesSequence is missing for the SEG');
100
+ return;
101
+ }
102
+ const referencedSeries = referencedSeriesSequence[0] || referencedSeriesSequence;
103
+ displaySet.referencedImages = instance.ReferencedSeriesSequence.ReferencedInstanceSequence;
104
+ displaySet.referencedSeriesInstanceUID = referencedSeries.SeriesInstanceUID;
105
+ displaySet.getReferenceDisplaySet = () => {
106
+ const {
107
+ displaySetService
108
+ } = servicesManager.services;
109
+ const referencedDisplaySets = displaySetService.getDisplaySetsForSeries(displaySet.referencedSeriesInstanceUID);
110
+ if (!referencedDisplaySets || referencedDisplaySets.length === 0) {
111
+ throw new Error('Referenced DisplaySet is missing for the SEG');
112
+ }
113
+ const referencedDisplaySet = referencedDisplaySets[0];
114
+ displaySet.referencedDisplaySetInstanceUID = referencedDisplaySet.displaySetInstanceUID;
115
+
116
+ // Todo: this needs to be able to work with other reference volumes (other than streaming) such as nifti, etc.
117
+ displaySet.referencedVolumeURI = referencedDisplaySet.displaySetInstanceUID;
118
+ const referencedVolumeId = `cornerstoneStreamingImageVolume:${displaySet.referencedVolumeURI}`;
119
+ displaySet.referencedVolumeId = referencedVolumeId;
120
+ return referencedDisplaySet;
121
+ };
122
+ displaySet.load = async _ref => {
123
+ let {
124
+ headers
125
+ } = _ref;
126
+ return await _load(displaySet, servicesManager, extensionManager, headers);
127
+ };
128
+ return [displaySet];
129
+ }
130
+ function _load(segDisplaySet, servicesManager, extensionManager, headers) {
131
+ const {
132
+ SOPInstanceUID
133
+ } = segDisplaySet;
134
+ const {
135
+ segmentationService
136
+ } = servicesManager.services;
137
+ if ((segDisplaySet.loading || segDisplaySet.isLoaded) && loadPromises[SOPInstanceUID] && _segmentationExists(segDisplaySet, segmentationService)) {
138
+ return loadPromises[SOPInstanceUID];
139
+ }
140
+ segDisplaySet.loading = true;
141
+
142
+ // We don't want to fire multiple loads, so we'll wait for the first to finish
143
+ // and also return the same promise to any other callers.
144
+ loadPromises[SOPInstanceUID] = new Promise(async (resolve, reject) => {
145
+ if (!segDisplaySet.segments || Object.keys(segDisplaySet.segments).length === 0) {
146
+ await _loadSegments({
147
+ extensionManager,
148
+ servicesManager,
149
+ segDisplaySet,
150
+ headers
151
+ });
152
+ }
153
+ const suppressEvents = true;
154
+ segmentationService.createSegmentationForSEGDisplaySet(segDisplaySet, null, suppressEvents).then(() => {
155
+ segDisplaySet.loading = false;
156
+ resolve();
157
+ }).catch(error => {
158
+ segDisplaySet.loading = false;
159
+ reject(error);
160
+ });
161
+ });
162
+ return loadPromises[SOPInstanceUID];
163
+ }
164
+ async function _loadSegments(_ref2) {
165
+ let {
166
+ extensionManager,
167
+ servicesManager,
168
+ segDisplaySet,
169
+ headers
170
+ } = _ref2;
171
+ const utilityModule = extensionManager.getModuleEntry('@ohif/extension-cornerstone.utilityModule.common');
172
+ const {
173
+ segmentationService
174
+ } = servicesManager.services;
175
+ const {
176
+ dicomLoaderService
177
+ } = utilityModule.exports;
178
+ const arrayBuffer = await dicomLoaderService.findDicomDataPromise(segDisplaySet, null, headers);
179
+ const cachedReferencedVolume = esm.cache.getVolume(segDisplaySet.referencedVolumeId);
180
+ if (!cachedReferencedVolume) {
181
+ throw new Error('Referenced Volume is missing for the SEG, and stack viewport SEG is not supported yet');
182
+ }
183
+ const {
184
+ imageIds
185
+ } = cachedReferencedVolume;
186
+
187
+ // Todo: what should be defaults here
188
+ const tolerance = 0.001;
189
+ const skipOverlapping = true;
190
+ esm.eventTarget.addEventListener(adapters_es/* Enums */.Y.Events.SEGMENTATION_LOAD_PROGRESS, evt => {
191
+ const {
192
+ percentComplete
193
+ } = evt.detail;
194
+ segmentationService._broadcastEvent(segmentationService.EVENTS.SEGMENT_LOADING_COMPLETE, {
195
+ percentComplete
196
+ });
197
+ });
198
+ const results = await adapters_es.adaptersSEG.Cornerstone3D.Segmentation.generateToolState(imageIds, arrayBuffer, esm.metaData, {
199
+ skipOverlapping,
200
+ tolerance,
201
+ eventTarget: esm.eventTarget,
202
+ triggerEvent: esm.triggerEvent
203
+ });
204
+ results.segMetadata.data.forEach((data, i) => {
205
+ if (i > 0) {
206
+ data.rgba = dicomlabToRGB(data.RecommendedDisplayCIELabValue);
207
+ }
208
+ });
209
+ Object.assign(segDisplaySet, results);
210
+ }
211
+ function _segmentationExists(segDisplaySet, segmentationService) {
212
+ // This should be abstracted with the CornerstoneCacheService
213
+ return segmentationService.getSegmentation(segDisplaySet.displaySetInstanceUID);
214
+ }
215
+ function getSopClassHandlerModule(_ref3) {
216
+ let {
217
+ servicesManager,
218
+ extensionManager
219
+ } = _ref3;
220
+ const getDisplaySetsFromSeries = instances => {
221
+ return _getDisplaySetsFromSeries(instances, servicesManager, extensionManager);
222
+ };
223
+ return [{
224
+ name: 'dicom-seg',
225
+ sopClassUids,
226
+ getDisplaySetsFromSeries
227
+ }];
228
+ }
229
+ /* harmony default export */ const src_getSopClassHandlerModule = (getSopClassHandlerModule);
230
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone-dicom-seg/src/getHangingProtocolModule.ts
231
+ const segProtocol = {
232
+ id: '@ohif/seg',
233
+ // Don't store this hanging protocol as it applies to the currently active
234
+ // display set by default
235
+ // cacheId: null,
236
+ name: 'Segmentations',
237
+ // Just apply this one when specifically listed
238
+ protocolMatchingRules: [],
239
+ toolGroupIds: ['default'],
240
+ // -1 would be used to indicate active only, whereas other values are
241
+ // the number of required priors referenced - so 0 means active with
242
+ // 0 or more priors.
243
+ numberOfPriorsReferenced: 0,
244
+ // Default viewport is used to define the viewport when
245
+ // additional viewports are added using the layout tool
246
+ defaultViewport: {
247
+ viewportOptions: {
248
+ viewportType: 'stack',
249
+ toolGroupId: 'default',
250
+ allowUnmatchedView: true
251
+ },
252
+ displaySets: [{
253
+ id: 'segDisplaySetId',
254
+ matchedDisplaySetsIndex: -1
255
+ }]
256
+ },
257
+ displaySetSelectors: {
258
+ segDisplaySetId: {
259
+ seriesMatchingRules: [{
260
+ attribute: 'Modality',
261
+ constraint: {
262
+ equals: 'SEG'
263
+ }
264
+ }]
265
+ }
266
+ },
267
+ stages: [{
268
+ name: 'Segmentations',
269
+ viewportStructure: {
270
+ layoutType: 'grid',
271
+ properties: {
272
+ rows: 1,
273
+ columns: 1
274
+ }
275
+ },
276
+ viewports: [{
277
+ viewportOptions: {
278
+ allowUnmatchedView: true
279
+ },
280
+ displaySets: [{
281
+ id: 'segDisplaySetId'
282
+ }]
283
+ }]
284
+ }]
285
+ };
286
+ function getHangingProtocolModule() {
287
+ return [{
288
+ name: segProtocol.id,
289
+ protocol: segProtocol
290
+ }];
291
+ }
292
+ /* harmony default export */ const src_getHangingProtocolModule = (getHangingProtocolModule);
293
+
294
+ // EXTERNAL MODULE: ./state/index.js + 1 modules
295
+ var state = __webpack_require__(62657);
296
+ // EXTERNAL MODULE: ../../../extensions/default/src/index.ts + 76 modules
297
+ var default_src = __webpack_require__(56342);
298
+ // EXTERNAL MODULE: ../../../node_modules/prop-types/index.js
299
+ var prop_types = __webpack_require__(3827);
300
+ var prop_types_default = /*#__PURE__*/__webpack_require__.n(prop_types);
301
+ // EXTERNAL MODULE: ../../ui/src/index.js + 485 modules
302
+ var ui_src = __webpack_require__(71783);
303
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone-dicom-seg/src/panels/callInputDialog.tsx
304
+
305
+
306
+ function callInputDialog(uiDialogService, label, callback) {
307
+ const dialogId = 'enter-segment-label';
308
+ const onSubmitHandler = _ref => {
309
+ let {
310
+ action,
311
+ value
312
+ } = _ref;
313
+ switch (action.id) {
314
+ case 'save':
315
+ callback(value.label, action.id);
316
+ break;
317
+ case 'cancel':
318
+ callback('', action.id);
319
+ break;
320
+ }
321
+ uiDialogService.dismiss({
322
+ id: dialogId
323
+ });
324
+ };
325
+ if (uiDialogService) {
326
+ uiDialogService.create({
327
+ id: dialogId,
328
+ centralize: true,
329
+ isDraggable: false,
330
+ showOverlay: true,
331
+ content: ui_src/* Dialog */.Vq,
332
+ contentProps: {
333
+ title: 'Segment',
334
+ value: {
335
+ label
336
+ },
337
+ noCloseButton: true,
338
+ onClose: () => uiDialogService.dismiss({
339
+ id: dialogId
340
+ }),
341
+ actions: [{
342
+ id: 'cancel',
343
+ text: 'Cancel',
344
+ type: ui_src/* ButtonEnums.type */.LZ.dt.secondary
345
+ }, {
346
+ id: 'save',
347
+ text: 'Confirm',
348
+ type: ui_src/* ButtonEnums.type */.LZ.dt.primary
349
+ }],
350
+ onSubmit: onSubmitHandler,
351
+ body: _ref2 => {
352
+ let {
353
+ value,
354
+ setValue
355
+ } = _ref2;
356
+ return /*#__PURE__*/react.createElement(ui_src/* Input */.II, {
357
+ label: "Enter the segment label",
358
+ labelClassName: "text-white text-[14px] leading-[1.2]",
359
+ autoFocus: true,
360
+ className: "border-primary-main bg-black",
361
+ type: "text",
362
+ value: value.label,
363
+ onChange: event => {
364
+ event.persist();
365
+ setValue(value => ({
366
+ ...value,
367
+ label: event.target.value
368
+ }));
369
+ },
370
+ onKeyPress: event => {
371
+ if (event.key === 'Enter') {
372
+ onSubmitHandler({
373
+ value,
374
+ action: {
375
+ id: 'save'
376
+ }
377
+ });
378
+ }
379
+ }
380
+ });
381
+ }
382
+ }
383
+ });
384
+ }
385
+ }
386
+ /* harmony default export */ const panels_callInputDialog = (callInputDialog);
387
+ // EXTERNAL MODULE: ../../../node_modules/react-color/es/index.js + 219 modules
388
+ var es = __webpack_require__(22831);
389
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone-dicom-seg/src/panels/colorPickerDialog.css
390
+ // extracted by mini-css-extract-plugin
391
+
392
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone-dicom-seg/src/panels/colorPickerDialog.tsx
393
+
394
+
395
+
396
+
397
+ function callColorPickerDialog(uiDialogService, rgbaColor, callback) {
398
+ const dialogId = 'pick-color';
399
+ const onSubmitHandler = _ref => {
400
+ let {
401
+ action,
402
+ value
403
+ } = _ref;
404
+ switch (action.id) {
405
+ case 'save':
406
+ callback(value.rgbaColor, action.id);
407
+ break;
408
+ case 'cancel':
409
+ callback('', action.id);
410
+ break;
411
+ }
412
+ uiDialogService.dismiss({
413
+ id: dialogId
414
+ });
415
+ };
416
+ if (uiDialogService) {
417
+ uiDialogService.create({
418
+ id: dialogId,
419
+ centralize: true,
420
+ isDraggable: false,
421
+ showOverlay: true,
422
+ content: ui_src/* Dialog */.Vq,
423
+ contentProps: {
424
+ title: 'Segment Color',
425
+ value: {
426
+ rgbaColor
427
+ },
428
+ noCloseButton: true,
429
+ onClose: () => uiDialogService.dismiss({
430
+ id: dialogId
431
+ }),
432
+ actions: [{
433
+ id: 'cancel',
434
+ text: 'Cancel',
435
+ type: 'primary'
436
+ }, {
437
+ id: 'save',
438
+ text: 'Save',
439
+ type: 'secondary'
440
+ }],
441
+ onSubmit: onSubmitHandler,
442
+ body: _ref2 => {
443
+ let {
444
+ value,
445
+ setValue
446
+ } = _ref2;
447
+ const handleChange = color => {
448
+ setValue({
449
+ rgbaColor: color.rgb
450
+ });
451
+ };
452
+ return /*#__PURE__*/react.createElement(es/* ChromePicker */.AI, {
453
+ color: value.rgbaColor,
454
+ onChange: handleChange,
455
+ presetColors: [],
456
+ width: 300
457
+ });
458
+ }
459
+ }
460
+ });
461
+ }
462
+ }
463
+ /* harmony default export */ const colorPickerDialog = (callColorPickerDialog);
464
+ // EXTERNAL MODULE: ../../../node_modules/react-i18next/dist/es/index.js + 15 modules
465
+ var dist_es = __webpack_require__(69190);
466
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone-dicom-seg/src/panels/PanelSegmentation.tsx
467
+
468
+
469
+
470
+
471
+
472
+
473
+
474
+ function PanelSegmentation(_ref) {
475
+ let {
476
+ servicesManager,
477
+ commandsManager,
478
+ extensionManager,
479
+ configuration
480
+ } = _ref;
481
+ const {
482
+ segmentationService,
483
+ viewportGridService,
484
+ uiDialogService
485
+ } = servicesManager.services;
486
+ const {
487
+ t
488
+ } = (0,dist_es/* useTranslation */.$G)('PanelSegmentation');
489
+ const [selectedSegmentationId, setSelectedSegmentationId] = (0,react.useState)(null);
490
+ const [segmentationConfiguration, setSegmentationConfiguration] = (0,react.useState)(segmentationService.getConfiguration());
491
+ const [segmentations, setSegmentations] = (0,react.useState)(() => segmentationService.getSegmentations());
492
+ (0,react.useEffect)(() => {
493
+ // ~~ Subscription
494
+ const added = segmentationService.EVENTS.SEGMENTATION_ADDED;
495
+ const updated = segmentationService.EVENTS.SEGMENTATION_UPDATED;
496
+ const removed = segmentationService.EVENTS.SEGMENTATION_REMOVED;
497
+ const subscriptions = [];
498
+ [added, updated, removed].forEach(evt => {
499
+ const {
500
+ unsubscribe
501
+ } = segmentationService.subscribe(evt, () => {
502
+ const segmentations = segmentationService.getSegmentations();
503
+ setSegmentations(segmentations);
504
+ setSegmentationConfiguration(segmentationService.getConfiguration());
505
+ });
506
+ subscriptions.push(unsubscribe);
507
+ });
508
+ return () => {
509
+ subscriptions.forEach(unsub => {
510
+ unsub();
511
+ });
512
+ };
513
+ }, []);
514
+ const getToolGroupIds = segmentationId => {
515
+ const toolGroupIds = segmentationService.getToolGroupIdsWithSegmentation(segmentationId);
516
+ return toolGroupIds;
517
+ };
518
+ const onSegmentationAdd = async () => {
519
+ commandsManager.runCommand('createEmptySegmentationForViewport');
520
+ };
521
+ const onSegmentationClick = segmentationId => {
522
+ segmentationService.setActiveSegmentationForToolGroup(segmentationId);
523
+ };
524
+ const onSegmentationDelete = segmentationId => {
525
+ segmentationService.remove(segmentationId);
526
+ };
527
+ const onSegmentAdd = segmentationId => {
528
+ segmentationService.addSegment(segmentationId);
529
+ };
530
+ const onSegmentClick = (segmentationId, segmentIndex) => {
531
+ segmentationService.setActiveSegment(segmentationId, segmentIndex);
532
+ const toolGroupIds = getToolGroupIds(segmentationId);
533
+ toolGroupIds.forEach(toolGroupId => {
534
+ // const toolGroupId =
535
+ segmentationService.setActiveSegmentationForToolGroup(segmentationId, toolGroupId);
536
+ segmentationService.jumpToSegmentCenter(segmentationId, segmentIndex, toolGroupId);
537
+ });
538
+ };
539
+ const onSegmentEdit = (segmentationId, segmentIndex) => {
540
+ const segmentation = segmentationService.getSegmentation(segmentationId);
541
+ const segment = segmentation.segments[segmentIndex];
542
+ const {
543
+ label
544
+ } = segment;
545
+ panels_callInputDialog(uiDialogService, label, (label, actionId) => {
546
+ if (label === '') {
547
+ return;
548
+ }
549
+ segmentationService.setSegmentLabel(segmentationId, segmentIndex, label);
550
+ });
551
+ };
552
+ const onSegmentationEdit = segmentationId => {
553
+ const segmentation = segmentationService.getSegmentation(segmentationId);
554
+ const {
555
+ label
556
+ } = segmentation;
557
+ panels_callInputDialog(uiDialogService, label, (label, actionId) => {
558
+ if (label === '') {
559
+ return;
560
+ }
561
+ segmentationService.addOrUpdateSegmentation({
562
+ id: segmentationId,
563
+ label
564
+ }, false,
565
+ // suppress event
566
+ true // notYetUpdatedAtSource
567
+ );
568
+ });
569
+ };
570
+
571
+ const onSegmentColorClick = (segmentationId, segmentIndex) => {
572
+ const segmentation = segmentationService.getSegmentation(segmentationId);
573
+ const segment = segmentation.segments[segmentIndex];
574
+ const {
575
+ color,
576
+ opacity
577
+ } = segment;
578
+ const rgbaColor = {
579
+ r: color[0],
580
+ g: color[1],
581
+ b: color[2],
582
+ a: opacity / 255.0
583
+ };
584
+ colorPickerDialog(uiDialogService, rgbaColor, (newRgbaColor, actionId) => {
585
+ if (actionId === 'cancel') {
586
+ return;
587
+ }
588
+ segmentationService.setSegmentRGBAColor(segmentationId, segmentIndex, [newRgbaColor.r, newRgbaColor.g, newRgbaColor.b, newRgbaColor.a * 255.0]);
589
+ });
590
+ };
591
+ const onSegmentDelete = (segmentationId, segmentIndex) => {
592
+ segmentationService.removeSegment(segmentationId, segmentIndex);
593
+ };
594
+ const onToggleSegmentVisibility = (segmentationId, segmentIndex) => {
595
+ const segmentation = segmentationService.getSegmentation(segmentationId);
596
+ const segmentInfo = segmentation.segments[segmentIndex];
597
+ const isVisible = !segmentInfo.isVisible;
598
+ const toolGroupIds = getToolGroupIds(segmentationId);
599
+
600
+ // Todo: right now we apply the visibility to all tool groups
601
+ toolGroupIds.forEach(toolGroupId => {
602
+ segmentationService.setSegmentVisibility(segmentationId, segmentIndex, isVisible, toolGroupId);
603
+ });
604
+ };
605
+ const onToggleSegmentLock = (segmentationId, segmentIndex) => {
606
+ segmentationService.toggleSegmentLocked(segmentationId, segmentIndex);
607
+ };
608
+ const onToggleSegmentationVisibility = segmentationId => {
609
+ segmentationService.toggleSegmentationVisibility(segmentationId);
610
+ };
611
+ const _setSegmentationConfiguration = (0,react.useCallback)((segmentationId, key, value) => {
612
+ segmentationService.setConfiguration({
613
+ segmentationId,
614
+ [key]: value
615
+ });
616
+ }, [segmentationService]);
617
+ const onSegmentationDownload = segmentationId => {
618
+ commandsManager.runCommand('downloadSegmentation', {
619
+ segmentationId
620
+ });
621
+ };
622
+ const storeSegmentation = async segmentationId => {
623
+ const datasources = extensionManager.getActiveDataSource();
624
+ const displaySetInstanceUIDs = await (0,default_src.createReportAsync)({
625
+ servicesManager,
626
+ getReport: () => commandsManager.runCommand('storeSegmentation', {
627
+ segmentationId,
628
+ dataSource: datasources[0]
629
+ }),
630
+ reportType: 'Segmentation'
631
+ });
632
+
633
+ // Show the exported report in the active viewport as read only (similar to SR)
634
+ if (displaySetInstanceUIDs) {
635
+ // clear the segmentation that we exported, similar to the storeMeasurement
636
+ // where we remove the measurements and prompt again the user if they would like
637
+ // to re-read the measurements in a SR read only viewport
638
+ segmentationService.remove(segmentationId);
639
+ viewportGridService.setDisplaySetsForViewport({
640
+ viewportId: viewportGridService.getActiveViewportId(),
641
+ displaySetInstanceUIDs
642
+ });
643
+ }
644
+ };
645
+ const onSegmentationDownloadRTSS = segmentationId => {
646
+ commandsManager.runCommand('downloadRTSS', {
647
+ segmentationId
648
+ });
649
+ };
650
+ return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("div", {
651
+ className: "ohif-scrollbar flex min-h-0 flex-auto select-none flex-col justify-between overflow-auto"
652
+ }, /*#__PURE__*/react.createElement(ui_src/* SegmentationGroupTable */.cX, {
653
+ title: t('Segmentations'),
654
+ segmentations: segmentations,
655
+ disableEditing: configuration.disableEditing,
656
+ activeSegmentationId: selectedSegmentationId || '',
657
+ onSegmentationAdd: onSegmentationAdd,
658
+ onSegmentationClick: onSegmentationClick,
659
+ onSegmentationDelete: onSegmentationDelete,
660
+ onSegmentationDownload: onSegmentationDownload,
661
+ onSegmentationDownloadRTSS: onSegmentationDownloadRTSS,
662
+ storeSegmentation: storeSegmentation,
663
+ onSegmentationEdit: onSegmentationEdit,
664
+ onSegmentClick: onSegmentClick,
665
+ onSegmentEdit: onSegmentEdit,
666
+ onSegmentAdd: onSegmentAdd,
667
+ onSegmentColorClick: onSegmentColorClick,
668
+ onSegmentDelete: onSegmentDelete,
669
+ onToggleSegmentVisibility: onToggleSegmentVisibility,
670
+ onToggleSegmentLock: onToggleSegmentLock,
671
+ onToggleSegmentationVisibility: onToggleSegmentationVisibility,
672
+ showDeleteSegment: true,
673
+ segmentationConfig: {
674
+ initialConfig: segmentationConfiguration
675
+ },
676
+ setRenderOutline: value => _setSegmentationConfiguration(selectedSegmentationId, 'renderOutline', value),
677
+ setOutlineOpacityActive: value => _setSegmentationConfiguration(selectedSegmentationId, 'outlineOpacity', value),
678
+ setRenderFill: value => _setSegmentationConfiguration(selectedSegmentationId, 'renderFill', value),
679
+ setRenderInactiveSegmentations: value => _setSegmentationConfiguration(selectedSegmentationId, 'renderInactiveSegmentations', value),
680
+ setOutlineWidthActive: value => _setSegmentationConfiguration(selectedSegmentationId, 'outlineWidthActive', value),
681
+ setFillAlpha: value => _setSegmentationConfiguration(selectedSegmentationId, 'fillAlpha', value),
682
+ setFillAlphaInactive: value => _setSegmentationConfiguration(selectedSegmentationId, 'fillAlphaInactive', value)
683
+ })));
684
+ }
685
+ PanelSegmentation.propTypes = {
686
+ commandsManager: prop_types_default().shape({
687
+ runCommand: (prop_types_default()).func.isRequired
688
+ }),
689
+ servicesManager: prop_types_default().shape({
690
+ services: prop_types_default().shape({
691
+ segmentationService: prop_types_default().shape({
692
+ getSegmentation: (prop_types_default()).func.isRequired,
693
+ getSegmentations: (prop_types_default()).func.isRequired,
694
+ toggleSegmentationVisibility: (prop_types_default()).func.isRequired,
695
+ subscribe: (prop_types_default()).func.isRequired,
696
+ EVENTS: (prop_types_default()).object.isRequired
697
+ }).isRequired
698
+ }).isRequired
699
+ }).isRequired
700
+ };
701
+ // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/tools/dist/esm/index.js + 348 modules
702
+ var dist_esm = __webpack_require__(14957);
703
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone-dicom-seg/src/panels/SegmentationToolbox.tsx
704
+
705
+
706
+
707
+ const {
708
+ segmentation: segmentationUtils
709
+ } = dist_esm.utilities;
710
+ const TOOL_TYPES = {
711
+ CIRCULAR_BRUSH: 'CircularBrush',
712
+ SPHERE_BRUSH: 'SphereBrush',
713
+ CIRCULAR_ERASER: 'CircularEraser',
714
+ SPHERE_ERASER: 'SphereEraser',
715
+ CIRCLE_SHAPE: 'CircleScissor',
716
+ RECTANGLE_SHAPE: 'RectangleScissor',
717
+ SPHERE_SHAPE: 'SphereScissor',
718
+ THRESHOLD_CIRCULAR_BRUSH: 'ThresholdCircularBrush',
719
+ THRESHOLD_SPHERE_BRUSH: 'ThresholdSphereBrush'
720
+ };
721
+ const ACTIONS = {
722
+ SET_TOOL_CONFIG: 'SET_TOOL_CONFIG',
723
+ SET_ACTIVE_TOOL: 'SET_ACTIVE_TOOL'
724
+ };
725
+ const initialState = {
726
+ Brush: {
727
+ brushSize: 15,
728
+ mode: 'CircularBrush' // Can be 'CircularBrush' or 'SphereBrush'
729
+ },
730
+
731
+ Eraser: {
732
+ brushSize: 15,
733
+ mode: 'CircularEraser' // Can be 'CircularEraser' or 'SphereEraser'
734
+ },
735
+
736
+ Shapes: {
737
+ brushSize: 15,
738
+ mode: 'CircleScissor' // E.g., 'CircleScissor', 'RectangleScissor', or 'SphereScissor'
739
+ },
740
+
741
+ ThresholdBrush: {
742
+ brushSize: 15,
743
+ thresholdRange: [-500, 500]
744
+ },
745
+ activeTool: null
746
+ };
747
+ function toolboxReducer(state, action) {
748
+ switch (action.type) {
749
+ case ACTIONS.SET_TOOL_CONFIG:
750
+ const {
751
+ tool,
752
+ config
753
+ } = action.payload;
754
+ return {
755
+ ...state,
756
+ [tool]: {
757
+ ...state[tool],
758
+ ...config
759
+ }
760
+ };
761
+ case ACTIONS.SET_ACTIVE_TOOL:
762
+ return {
763
+ ...state,
764
+ activeTool: action.payload
765
+ };
766
+ default:
767
+ return state;
768
+ }
769
+ }
770
+ function SegmentationToolbox(_ref) {
771
+ let {
772
+ servicesManager,
773
+ extensionManager
774
+ } = _ref;
775
+ const {
776
+ toolbarService,
777
+ segmentationService,
778
+ toolGroupService
779
+ } = servicesManager.services;
780
+ const [viewportGrid] = (0,ui_src/* useViewportGrid */.O_)();
781
+ const {
782
+ viewports,
783
+ activeViewportId
784
+ } = viewportGrid;
785
+ const [toolsEnabled, setToolsEnabled] = (0,react.useState)(false);
786
+ const [state, dispatch] = (0,react.useReducer)(toolboxReducer, initialState);
787
+ const updateActiveTool = (0,react.useCallback)(() => {
788
+ if (!viewports?.size || activeViewportId === undefined) {
789
+ return;
790
+ }
791
+ const viewport = viewports.get(activeViewportId);
792
+ if (!viewport) {
793
+ return;
794
+ }
795
+ dispatch({
796
+ type: ACTIONS.SET_ACTIVE_TOOL,
797
+ payload: toolGroupService.getActiveToolForViewport(viewport.viewportId)
798
+ });
799
+ }, [activeViewportId, viewports, toolGroupService, dispatch]);
800
+ const setToolActive = (0,react.useCallback)(toolName => {
801
+ toolbarService.recordInteraction({
802
+ interactionType: 'tool',
803
+ commands: [{
804
+ commandName: 'setToolActive',
805
+ commandOptions: {
806
+ toolName
807
+ }
808
+ }]
809
+ });
810
+ dispatch({
811
+ type: ACTIONS.SET_ACTIVE_TOOL,
812
+ payload: toolName
813
+ });
814
+ }, [toolbarService, dispatch]);
815
+
816
+ /**
817
+ * sets the tools enabled IF there are segmentations
818
+ */
819
+ (0,react.useEffect)(() => {
820
+ const events = [segmentationService.EVENTS.SEGMENTATION_ADDED, segmentationService.EVENTS.SEGMENTATION_UPDATED, segmentationService.EVENTS.SEGMENTATION_REMOVED];
821
+ const unsubscriptions = [];
822
+ events.forEach(event => {
823
+ const {
824
+ unsubscribe
825
+ } = segmentationService.subscribe(event, () => {
826
+ const segmentations = segmentationService.getSegmentations();
827
+ const activeSegmentation = segmentations?.find(seg => seg.isActive);
828
+ setToolsEnabled(activeSegmentation?.segmentCount > 0);
829
+ });
830
+ unsubscriptions.push(unsubscribe);
831
+ });
832
+ updateActiveTool();
833
+ return () => {
834
+ unsubscriptions.forEach(unsubscribe => unsubscribe());
835
+ };
836
+ }, [activeViewportId, viewports, segmentationService, updateActiveTool]);
837
+
838
+ /**
839
+ * Update the active tool when the toolbar state changes
840
+ */
841
+ (0,react.useEffect)(() => {
842
+ const {
843
+ unsubscribe
844
+ } = toolbarService.subscribe(toolbarService.EVENTS.TOOL_BAR_STATE_MODIFIED, () => {
845
+ updateActiveTool();
846
+ });
847
+ return () => {
848
+ unsubscribe();
849
+ };
850
+ }, [toolbarService, updateActiveTool]);
851
+ (0,react.useEffect)(() => {
852
+ // if the active tool is not a brush tool then do nothing
853
+ if (!Object.values(TOOL_TYPES).includes(state.activeTool)) {
854
+ return;
855
+ }
856
+
857
+ // if the tool is Segmentation and it is enabled then do nothing
858
+ if (toolsEnabled) {
859
+ return;
860
+ }
861
+
862
+ // if the tool is Segmentation and it is disabled, then switch
863
+ // back to the window level tool to not confuse the user when no
864
+ // segmentation is active or when there is no segment in the segmentation
865
+ setToolActive('WindowLevel');
866
+ }, [toolsEnabled, state.activeTool, setToolActive]);
867
+ const updateBrushSize = (0,react.useCallback)((toolName, brushSize) => {
868
+ toolGroupService.getToolGroupIds()?.forEach(toolGroupId => {
869
+ segmentationUtils.setBrushSizeForToolGroup(toolGroupId, brushSize, toolName);
870
+ });
871
+ }, [toolGroupService]);
872
+ const onBrushSizeChange = (0,react.useCallback)((valueAsStringOrNumber, toolCategory) => {
873
+ const value = Number(valueAsStringOrNumber);
874
+ _getToolNamesFromCategory(toolCategory).forEach(toolName => {
875
+ updateBrushSize(toolName, value);
876
+ });
877
+ dispatch({
878
+ type: ACTIONS.SET_TOOL_CONFIG,
879
+ payload: {
880
+ tool: toolCategory,
881
+ config: {
882
+ brushSize: value
883
+ }
884
+ }
885
+ });
886
+ }, [toolGroupService, dispatch]);
887
+ const handleRangeChange = (0,react.useCallback)(newRange => {
888
+ if (newRange[0] === state.ThresholdBrush.thresholdRange[0] && newRange[1] === state.ThresholdBrush.thresholdRange[1]) {
889
+ return;
890
+ }
891
+ const toolNames = _getToolNamesFromCategory('ThresholdBrush');
892
+ toolNames.forEach(toolName => {
893
+ toolGroupService.getToolGroupIds()?.forEach(toolGroupId => {
894
+ const toolGroup = toolGroupService.getToolGroup(toolGroupId);
895
+ toolGroup.setToolConfiguration(toolName, {
896
+ strategySpecificConfiguration: {
897
+ THRESHOLD_INSIDE_CIRCLE: {
898
+ threshold: newRange
899
+ }
900
+ }
901
+ });
902
+ });
903
+ });
904
+ dispatch({
905
+ type: ACTIONS.SET_TOOL_CONFIG,
906
+ payload: {
907
+ tool: 'ThresholdBrush',
908
+ config: {
909
+ thresholdRange: newRange
910
+ }
911
+ }
912
+ });
913
+ }, [toolGroupService, dispatch, state.ThresholdBrush.thresholdRange]);
914
+ return /*#__PURE__*/react.createElement(ui_src/* AdvancedToolbox */.bY, {
915
+ title: "Segmentation Tools",
916
+ items: [{
917
+ name: 'Brush',
918
+ icon: 'icon-tool-brush',
919
+ disabled: !toolsEnabled,
920
+ active: state.activeTool === TOOL_TYPES.CIRCULAR_BRUSH || state.activeTool === TOOL_TYPES.SPHERE_BRUSH,
921
+ onClick: () => setToolActive(TOOL_TYPES.CIRCULAR_BRUSH),
922
+ options: [{
923
+ name: 'Radius (mm)',
924
+ id: 'brush-radius',
925
+ type: 'range',
926
+ min: 0.5,
927
+ max: 99.5,
928
+ value: state.Brush.brushSize,
929
+ step: 0.5,
930
+ onChange: value => onBrushSizeChange(value, 'Brush')
931
+ }, {
932
+ name: 'Mode',
933
+ type: 'radio',
934
+ id: 'brush-mode',
935
+ value: state.Brush.mode,
936
+ values: [{
937
+ value: TOOL_TYPES.CIRCULAR_BRUSH,
938
+ label: 'Circle'
939
+ }, {
940
+ value: TOOL_TYPES.SPHERE_BRUSH,
941
+ label: 'Sphere'
942
+ }],
943
+ onChange: value => setToolActive(value)
944
+ }]
945
+ }, {
946
+ name: 'Eraser',
947
+ icon: 'icon-tool-eraser',
948
+ disabled: !toolsEnabled,
949
+ active: state.activeTool === TOOL_TYPES.CIRCULAR_ERASER || state.activeTool === TOOL_TYPES.SPHERE_ERASER,
950
+ onClick: () => setToolActive(TOOL_TYPES.CIRCULAR_ERASER),
951
+ options: [{
952
+ name: 'Radius (mm)',
953
+ type: 'range',
954
+ id: 'eraser-radius',
955
+ min: 0.5,
956
+ max: 99.5,
957
+ value: state.Eraser.brushSize,
958
+ step: 0.5,
959
+ onChange: value => onBrushSizeChange(value, 'Eraser')
960
+ }, {
961
+ name: 'Mode',
962
+ type: 'radio',
963
+ id: 'eraser-mode',
964
+ value: state.Eraser.mode,
965
+ values: [{
966
+ value: TOOL_TYPES.CIRCULAR_ERASER,
967
+ label: 'Circle'
968
+ }, {
969
+ value: TOOL_TYPES.SPHERE_ERASER,
970
+ label: 'Sphere'
971
+ }],
972
+ onChange: value => setToolActive(value)
973
+ }]
974
+ }, {
975
+ name: 'Shapes',
976
+ icon: 'icon-tool-shape',
977
+ disabled: !toolsEnabled,
978
+ active: state.activeTool === TOOL_TYPES.CIRCLE_SHAPE || state.activeTool === TOOL_TYPES.RECTANGLE_SHAPE || state.activeTool === TOOL_TYPES.SPHERE_SHAPE,
979
+ onClick: () => setToolActive(TOOL_TYPES.CIRCLE_SHAPE),
980
+ options: [{
981
+ name: 'Mode',
982
+ type: 'radio',
983
+ value: state.Shapes.mode,
984
+ id: 'shape-mode',
985
+ values: [{
986
+ value: TOOL_TYPES.CIRCLE_SHAPE,
987
+ label: 'Circle'
988
+ }, {
989
+ value: TOOL_TYPES.RECTANGLE_SHAPE,
990
+ label: 'Rectangle'
991
+ }, {
992
+ value: TOOL_TYPES.SPHERE_SHAPE,
993
+ label: 'Sphere'
994
+ }],
995
+ onChange: value => setToolActive(value)
996
+ }]
997
+ }, {
998
+ name: 'Threshold Tool',
999
+ icon: 'icon-tool-threshold',
1000
+ disabled: !toolsEnabled,
1001
+ active: state.activeTool === TOOL_TYPES.THRESHOLD_CIRCULAR_BRUSH || state.activeTool === TOOL_TYPES.THRESHOLD_SPHERE_BRUSH,
1002
+ onClick: () => setToolActive(TOOL_TYPES.THRESHOLD_CIRCULAR_BRUSH),
1003
+ options: [{
1004
+ name: 'Radius (mm)',
1005
+ id: 'threshold-radius',
1006
+ type: 'range',
1007
+ min: 0.5,
1008
+ max: 99.5,
1009
+ value: state.ThresholdBrush.brushSize,
1010
+ step: 0.5,
1011
+ onChange: value => onBrushSizeChange(value, 'ThresholdBrush')
1012
+ }, {
1013
+ name: 'Mode',
1014
+ type: 'radio',
1015
+ id: 'threshold-mode',
1016
+ value: state.activeTool,
1017
+ values: [{
1018
+ value: TOOL_TYPES.THRESHOLD_CIRCULAR_BRUSH,
1019
+ label: 'Circle'
1020
+ }, {
1021
+ value: TOOL_TYPES.THRESHOLD_SPHERE_BRUSH,
1022
+ label: 'Sphere'
1023
+ }],
1024
+ onChange: value => setToolActive(value)
1025
+ }, {
1026
+ type: 'custom',
1027
+ id: 'segmentation-threshold-range',
1028
+ children: () => {
1029
+ return /*#__PURE__*/react.createElement("div", null, /*#__PURE__*/react.createElement("div", {
1030
+ className: "bg-secondary-light h-[1px]"
1031
+ }), /*#__PURE__*/react.createElement("div", {
1032
+ className: "mt-1 text-[13px] text-white"
1033
+ }, "Threshold"), /*#__PURE__*/react.createElement(ui_src/* InputDoubleRange */.R0, {
1034
+ values: state.ThresholdBrush.thresholdRange,
1035
+ onChange: handleRangeChange,
1036
+ minValue: -1000,
1037
+ maxValue: 1000,
1038
+ step: 1,
1039
+ showLabel: true,
1040
+ allowNumberEdit: true,
1041
+ showAdjustmentArrows: false
1042
+ }));
1043
+ }
1044
+ }]
1045
+ }]
1046
+ });
1047
+ }
1048
+ function _getToolNamesFromCategory(category) {
1049
+ let toolNames = [];
1050
+ switch (category) {
1051
+ case 'Brush':
1052
+ toolNames = ['CircularBrush', 'SphereBrush'];
1053
+ break;
1054
+ case 'Eraser':
1055
+ toolNames = ['CircularEraser', 'SphereEraser'];
1056
+ break;
1057
+ case 'ThresholdBrush':
1058
+ toolNames = ['ThresholdCircularBrush', 'ThresholdSphereBrush'];
1059
+ break;
1060
+ default:
1061
+ break;
1062
+ }
1063
+ return toolNames;
1064
+ }
1065
+ /* harmony default export */ const panels_SegmentationToolbox = (SegmentationToolbox);
1066
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone-dicom-seg/src/getPanelModule.tsx
1067
+
1068
+
1069
+
1070
+
1071
+ const getPanelModule = _ref => {
1072
+ let {
1073
+ commandsManager,
1074
+ servicesManager,
1075
+ extensionManager,
1076
+ configuration
1077
+ } = _ref;
1078
+ const {
1079
+ customizationService
1080
+ } = servicesManager.services;
1081
+ const wrappedPanelSegmentation = configuration => {
1082
+ const [appConfig] = (0,state/* useAppConfig */.M)();
1083
+ const disableEditingForMode = customizationService.get('segmentation.disableEditing');
1084
+ return /*#__PURE__*/react.createElement(PanelSegmentation, {
1085
+ commandsManager: commandsManager,
1086
+ servicesManager: servicesManager,
1087
+ extensionManager: extensionManager,
1088
+ configuration: {
1089
+ ...configuration,
1090
+ disableEditing: appConfig.disableEditing || disableEditingForMode?.value
1091
+ }
1092
+ });
1093
+ };
1094
+ const wrappedPanelSegmentationWithTools = configuration => {
1095
+ const [appConfig] = (0,state/* useAppConfig */.M)();
1096
+ return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement(panels_SegmentationToolbox, {
1097
+ commandsManager: commandsManager,
1098
+ servicesManager: servicesManager,
1099
+ extensionManager: extensionManager,
1100
+ configuration: {
1101
+ ...configuration
1102
+ }
1103
+ }), /*#__PURE__*/react.createElement(PanelSegmentation, {
1104
+ commandsManager: commandsManager,
1105
+ servicesManager: servicesManager,
1106
+ extensionManager: extensionManager,
1107
+ configuration: {
1108
+ ...configuration
1109
+ }
1110
+ }));
1111
+ };
1112
+ return [{
1113
+ name: 'panelSegmentation',
1114
+ iconName: 'tab-segmentation',
1115
+ iconLabel: 'Segmentation',
1116
+ label: 'Segmentation',
1117
+ component: wrappedPanelSegmentation
1118
+ }, {
1119
+ name: 'panelSegmentationWithTools',
1120
+ iconName: 'tab-segmentation',
1121
+ iconLabel: 'Segmentation',
1122
+ label: 'Segmentation',
1123
+ component: wrappedPanelSegmentationWithTools
1124
+ }];
1125
+ };
1126
+ /* harmony default export */ const src_getPanelModule = (getPanelModule);
1127
+ // EXTERNAL MODULE: ../../../node_modules/@kitware/vtk.js/Filters/General/ImageMarchingSquares.js + 2 modules
1128
+ var ImageMarchingSquares = __webpack_require__(49399);
1129
+ // EXTERNAL MODULE: ../../../node_modules/@kitware/vtk.js/Common/Core/DataArray.js
1130
+ var DataArray = __webpack_require__(54131);
1131
+ // EXTERNAL MODULE: ../../../node_modules/@kitware/vtk.js/Common/DataModel/ImageData.js + 2 modules
1132
+ var ImageData = __webpack_require__(96372);
1133
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone-dicom-seg/src/utils/hydrationUtils.ts
1134
+
1135
+
1136
+ /**
1137
+ * Updates the viewports in preparation for rendering segmentations.
1138
+ * Evaluates each viewport to determine which need modifications,
1139
+ * then for those viewports, changes them to a volume type and ensures
1140
+ * they are ready for segmentation rendering.
1141
+ *
1142
+ * @param {Object} params - Parameters for the function.
1143
+ * @param params.viewportId - ID of the viewport to be updated.
1144
+ * @param params.loadFn - Function to load the segmentation data.
1145
+ * @param params.servicesManager - The services manager.
1146
+ * @param params.referencedDisplaySetInstanceUID - Optional UID for the referenced display set instance.
1147
+ *
1148
+ * @returns Returns true upon successful update of viewports for segmentation rendering.
1149
+ */
1150
+ async function updateViewportsForSegmentationRendering(_ref) {
1151
+ let {
1152
+ viewportId,
1153
+ loadFn,
1154
+ servicesManager,
1155
+ referencedDisplaySetInstanceUID
1156
+ } = _ref;
1157
+ const {
1158
+ cornerstoneViewportService,
1159
+ segmentationService,
1160
+ viewportGridService
1161
+ } = servicesManager.services;
1162
+ const viewport = getTargetViewport({
1163
+ viewportId,
1164
+ viewportGridService
1165
+ });
1166
+ const targetViewportId = viewport.viewportOptions.viewportId;
1167
+ referencedDisplaySetInstanceUID = referencedDisplaySetInstanceUID || viewport?.displaySetInstanceUIDs[0];
1168
+ const updatedViewports = getUpdatedViewportsForSegmentation({
1169
+ servicesManager,
1170
+ viewportId,
1171
+ referencedDisplaySetInstanceUID
1172
+ });
1173
+
1174
+ // create Segmentation callback which needs to be waited until
1175
+ // the volume is created (if coming from stack)
1176
+ const createSegmentationForVolume = async () => {
1177
+ const segmentationId = await loadFn();
1178
+ segmentationService.hydrateSegmentation(segmentationId);
1179
+ };
1180
+
1181
+ // the reference volume that is used to draw the segmentation. so check if the
1182
+ // volume exists in the cache (the target Viewport is already a volume viewport)
1183
+ const volumeExists = Array.from(esm.cache._volumeCache.keys()).some(volumeId => volumeId.includes(referencedDisplaySetInstanceUID));
1184
+ updatedViewports.forEach(async viewport => {
1185
+ viewport.viewportOptions = {
1186
+ ...viewport.viewportOptions,
1187
+ viewportType: 'volume',
1188
+ needsRerendering: true
1189
+ };
1190
+ const viewportId = viewport.viewportId;
1191
+ const csViewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
1192
+ const prevCamera = csViewport.getCamera();
1193
+
1194
+ // only run the createSegmentationForVolume for the targetViewportId
1195
+ // since the rest will get handled by cornerstoneViewportService
1196
+ if (volumeExists && viewportId === targetViewportId) {
1197
+ await createSegmentationForVolume();
1198
+ return;
1199
+ }
1200
+ const createNewSegmentationWhenVolumeMounts = async evt => {
1201
+ const isTheActiveViewportVolumeMounted = evt.detail.volumeActors?.find(ac => ac.uid.includes(referencedDisplaySetInstanceUID));
1202
+
1203
+ // Note: make sure to re-grab the viewport since it might have changed
1204
+ // during the time it took for the volume to be mounted, for instance
1205
+ // the stack viewport has been changed to a volume viewport
1206
+ const volumeViewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
1207
+ volumeViewport.setCamera(prevCamera);
1208
+ volumeViewport.element.removeEventListener(esm.Enums.Events.VOLUME_VIEWPORT_NEW_VOLUME, createNewSegmentationWhenVolumeMounts);
1209
+ if (!isTheActiveViewportVolumeMounted) {
1210
+ // it means it is one of those other updated viewports so just update the camera
1211
+ return;
1212
+ }
1213
+ if (viewportId === targetViewportId) {
1214
+ await createSegmentationForVolume();
1215
+ }
1216
+ };
1217
+ csViewport.element.addEventListener(esm.Enums.Events.VOLUME_VIEWPORT_NEW_VOLUME, createNewSegmentationWhenVolumeMounts);
1218
+ });
1219
+
1220
+ // Set the displaySets for the viewports that require to be updated
1221
+ viewportGridService.setDisplaySetsForViewports(updatedViewports);
1222
+ return true;
1223
+ }
1224
+ const getTargetViewport = _ref2 => {
1225
+ let {
1226
+ viewportId,
1227
+ viewportGridService
1228
+ } = _ref2;
1229
+ const {
1230
+ viewports,
1231
+ activeViewportId
1232
+ } = viewportGridService.getState();
1233
+ const targetViewportId = viewportId || activeViewportId;
1234
+ const viewport = viewports.get(targetViewportId);
1235
+ return viewport;
1236
+ };
1237
+
1238
+ /**
1239
+ * Retrieves a list of viewports that require updates in preparation for segmentation rendering.
1240
+ * This function evaluates viewports based on their compatibility with the provided segmentation's
1241
+ * frame of reference UID and appends them to the updated list if they should render the segmentation.
1242
+ *
1243
+ * @param {Object} params - Parameters for the function.
1244
+ * @param params.viewportId - the ID of the viewport to be updated.
1245
+ * @param params.servicesManager - The services manager
1246
+ * @param params.referencedDisplaySetInstanceUID - Optional UID for the referenced display set instance.
1247
+ *
1248
+ * @returns {Array} Returns an array of viewports that require updates for segmentation rendering.
1249
+ */
1250
+ function getUpdatedViewportsForSegmentation(_ref3) {
1251
+ let {
1252
+ viewportId,
1253
+ servicesManager,
1254
+ referencedDisplaySetInstanceUID
1255
+ } = _ref3;
1256
+ const {
1257
+ hangingProtocolService,
1258
+ displaySetService,
1259
+ segmentationService,
1260
+ viewportGridService
1261
+ } = servicesManager.services;
1262
+ const {
1263
+ viewports
1264
+ } = viewportGridService.getState();
1265
+ const viewport = getTargetViewport({
1266
+ viewportId,
1267
+ viewportGridService
1268
+ });
1269
+ const targetViewportId = viewport.viewportOptions.viewportId;
1270
+ const displaySetInstanceUIDs = viewports.get(targetViewportId).displaySetInstanceUIDs;
1271
+ const referenceDisplaySetInstanceUID = referencedDisplaySetInstanceUID || displaySetInstanceUIDs[0];
1272
+ const referencedDisplaySet = displaySetService.getDisplaySetByUID(referenceDisplaySetInstanceUID);
1273
+ const segmentationFrameOfReferenceUID = referencedDisplaySet.instances[0].FrameOfReferenceUID;
1274
+ const updatedViewports = hangingProtocolService.getViewportsRequireUpdate(targetViewportId, referenceDisplaySetInstanceUID);
1275
+ viewports.forEach((viewport, viewportId) => {
1276
+ if (targetViewportId === viewportId || updatedViewports.find(v => v.viewportId === viewportId)) {
1277
+ return;
1278
+ }
1279
+ const shouldDisplaySeg = segmentationService.shouldRenderSegmentation(viewport.displaySetInstanceUIDs, segmentationFrameOfReferenceUID);
1280
+ if (shouldDisplaySeg) {
1281
+ updatedViewports.push({
1282
+ viewportId,
1283
+ displaySetInstanceUIDs: viewport.displaySetInstanceUIDs,
1284
+ viewportOptions: {
1285
+ viewportType: 'volume',
1286
+ needsRerendering: true
1287
+ }
1288
+ });
1289
+ }
1290
+ });
1291
+ return updatedViewports;
1292
+ }
1293
+
1294
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone-dicom-seg/src/commandsModule.ts
1295
+
1296
+
1297
+
1298
+
1299
+
1300
+
1301
+
1302
+
1303
+
1304
+
1305
+ const {
1306
+ datasetToBlob
1307
+ } = dcmjs_es["default"].data;
1308
+ const {
1309
+ Cornerstone3D: {
1310
+ Segmentation: {
1311
+ generateLabelMaps2DFrom3D,
1312
+ generateSegmentation
1313
+ }
1314
+ }
1315
+ } = adapters_es.adaptersSEG;
1316
+ const {
1317
+ Cornerstone3D: {
1318
+ RTSS: {
1319
+ generateRTSSFromSegmentations
1320
+ }
1321
+ }
1322
+ } = adapters_es.adaptersRT;
1323
+ const {
1324
+ downloadDICOMData
1325
+ } = adapters_es.helpers;
1326
+ const commandsModule = _ref => {
1327
+ let {
1328
+ servicesManager,
1329
+ extensionManager
1330
+ } = _ref;
1331
+ const {
1332
+ uiNotificationService,
1333
+ segmentationService,
1334
+ uiDialogService,
1335
+ displaySetService,
1336
+ viewportGridService
1337
+ } = servicesManager.services;
1338
+ const actions = {
1339
+ /**
1340
+ * Retrieves a list of viewports that require updates in preparation for segmentation rendering.
1341
+ * This function evaluates viewports based on their compatibility with the provided segmentation's
1342
+ * frame of reference UID and appends them to the updated list if they should render the segmentation.
1343
+ *
1344
+ * @param {Object} params - Parameters for the function.
1345
+ * @param params.viewportId - the ID of the viewport to be updated.
1346
+ * @param params.servicesManager - The services manager
1347
+ * @param params.referencedDisplaySetInstanceUID - Optional UID for the referenced display set instance.
1348
+ *
1349
+ * @returns {Array} Returns an array of viewports that require updates for segmentation rendering.
1350
+ */
1351
+ getUpdatedViewportsForSegmentation: getUpdatedViewportsForSegmentation,
1352
+ /**
1353
+ * Creates an empty segmentation for a specified viewport.
1354
+ * It first checks if the display set associated with the viewport is reconstructable.
1355
+ * If not, it raises a notification error. Otherwise, it creates a new segmentation
1356
+ * for the display set after handling the necessary steps for making the viewport
1357
+ * a volume viewport first
1358
+ *
1359
+ * @param {Object} params - Parameters for the function.
1360
+ * @param params.viewportId - the target viewport ID.
1361
+ *
1362
+ */
1363
+ createEmptySegmentationForViewport: async _ref2 => {
1364
+ let {
1365
+ viewportId
1366
+ } = _ref2;
1367
+ const viewport = getTargetViewport({
1368
+ viewportId,
1369
+ viewportGridService
1370
+ });
1371
+ // Todo: add support for multiple display sets
1372
+ const displaySetInstanceUID = viewport.displaySetInstanceUIDs[0];
1373
+ const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
1374
+ if (!displaySet.isReconstructable) {
1375
+ uiNotificationService.show({
1376
+ title: 'Segmentation',
1377
+ message: 'Segmentation is not supported for non-reconstructible displaysets yet',
1378
+ type: 'error'
1379
+ });
1380
+ return;
1381
+ }
1382
+ updateViewportsForSegmentationRendering({
1383
+ viewportId,
1384
+ servicesManager,
1385
+ loadFn: async () => {
1386
+ const currentSegmentations = segmentationService.getSegmentations();
1387
+ const segmentationId = await segmentationService.createSegmentationForDisplaySet(displaySetInstanceUID, {
1388
+ label: `Segmentation ${currentSegmentations.length + 1}`
1389
+ });
1390
+ const toolGroupId = viewport.viewportOptions.toolGroupId;
1391
+ await segmentationService.addSegmentationRepresentationToToolGroup(toolGroupId, segmentationId);
1392
+
1393
+ // Add only one segment for now
1394
+ segmentationService.addSegment(segmentationId, {
1395
+ toolGroupId,
1396
+ segmentIndex: 1,
1397
+ properties: {
1398
+ label: 'Segment 1'
1399
+ }
1400
+ });
1401
+ return segmentationId;
1402
+ }
1403
+ });
1404
+ },
1405
+ /**
1406
+ * Loads segmentations for a specified viewport.
1407
+ * The function prepares the viewport for rendering, then loads the segmentation details.
1408
+ * Additionally, if the segmentation has scalar data, it is set for the corresponding label map volume.
1409
+ *
1410
+ * @param {Object} params - Parameters for the function.
1411
+ * @param params.segmentations - Array of segmentations to be loaded.
1412
+ * @param params.viewportId - the target viewport ID.
1413
+ *
1414
+ */
1415
+ loadSegmentationsForViewport: async _ref3 => {
1416
+ let {
1417
+ segmentations,
1418
+ viewportId
1419
+ } = _ref3;
1420
+ updateViewportsForSegmentationRendering({
1421
+ viewportId,
1422
+ servicesManager,
1423
+ loadFn: async () => {
1424
+ // Todo: handle adding more than one segmentation
1425
+ const viewport = getTargetViewport({
1426
+ viewportId,
1427
+ viewportGridService
1428
+ });
1429
+ const displaySetInstanceUID = viewport.displaySetInstanceUIDs[0];
1430
+ const segmentation = segmentations[0];
1431
+ const segmentationId = segmentation.id;
1432
+ const label = segmentation.label;
1433
+ const segments = segmentation.segments;
1434
+ delete segmentation.segments;
1435
+ await segmentationService.createSegmentationForDisplaySet(displaySetInstanceUID, {
1436
+ segmentationId,
1437
+ label
1438
+ });
1439
+ if (segmentation.scalarData) {
1440
+ const labelmapVolume = segmentationService.getLabelmapVolume(segmentationId);
1441
+ labelmapVolume.scalarData.set(segmentation.scalarData);
1442
+ }
1443
+ segmentationService.addOrUpdateSegmentation(segmentation);
1444
+ const toolGroupId = viewport.viewportOptions.toolGroupId;
1445
+ await segmentationService.addSegmentationRepresentationToToolGroup(toolGroupId, segmentationId);
1446
+ segments.forEach(segment => {
1447
+ if (segment === null) {
1448
+ return;
1449
+ }
1450
+ segmentationService.addSegment(segmentationId, {
1451
+ segmentIndex: segment.segmentIndex,
1452
+ toolGroupId,
1453
+ properties: {
1454
+ color: segment.color,
1455
+ label: segment.label,
1456
+ opacity: segment.opacity,
1457
+ isLocked: segment.isLocked,
1458
+ visibility: segment.isVisible,
1459
+ active: segmentation.activeSegmentIndex === segment.segmentIndex
1460
+ }
1461
+ });
1462
+ });
1463
+ if (segmentation.centroidsIJK) {
1464
+ segmentationService.setCentroids(segmentation.id, segmentation.centroidsIJK);
1465
+ }
1466
+ return segmentationId;
1467
+ }
1468
+ });
1469
+ },
1470
+ /**
1471
+ * Loads segmentation display sets for a specified viewport.
1472
+ * Depending on the modality of the display set (SEG or RTSTRUCT),
1473
+ * it chooses the appropriate service function to create
1474
+ * the segmentation for the display set.
1475
+ * The function then prepares the viewport for rendering segmentation.
1476
+ *
1477
+ * @param {Object} params - Parameters for the function.
1478
+ * @param params.viewportId - ID of the viewport where the segmentation display sets should be loaded.
1479
+ * @param params.displaySets - Array of display sets to be loaded for segmentation.
1480
+ *
1481
+ */
1482
+ loadSegmentationDisplaySetsForViewport: async _ref4 => {
1483
+ let {
1484
+ viewportId,
1485
+ displaySets
1486
+ } = _ref4;
1487
+ // Todo: handle adding more than one segmentation
1488
+ const displaySet = displaySets[0];
1489
+ updateViewportsForSegmentationRendering({
1490
+ viewportId,
1491
+ servicesManager,
1492
+ referencedDisplaySetInstanceUID: displaySet.referencedDisplaySetInstanceUID,
1493
+ loadFn: async () => {
1494
+ const segDisplaySet = displaySet;
1495
+ const suppressEvents = false;
1496
+ const serviceFunction = segDisplaySet.Modality === 'SEG' ? 'createSegmentationForSEGDisplaySet' : 'createSegmentationForRTDisplaySet';
1497
+ const boundFn = segmentationService[serviceFunction].bind(segmentationService);
1498
+ const segmentationId = await boundFn(segDisplaySet, null, suppressEvents);
1499
+ return segmentationId;
1500
+ }
1501
+ });
1502
+ },
1503
+ /**
1504
+ * Generates a segmentation from a given segmentation ID.
1505
+ * This function retrieves the associated segmentation and
1506
+ * its referenced volume, extracts label maps from the
1507
+ * segmentation volume, and produces segmentation data
1508
+ * alongside associated metadata.
1509
+ *
1510
+ * @param {Object} params - Parameters for the function.
1511
+ * @param params.segmentationId - ID of the segmentation to be generated.
1512
+ * @param params.options - Optional configuration for the generation process.
1513
+ *
1514
+ * @returns Returns the generated segmentation data.
1515
+ */
1516
+ generateSegmentation: _ref5 => {
1517
+ let {
1518
+ segmentationId,
1519
+ options = {}
1520
+ } = _ref5;
1521
+ const segmentation = dist_esm.segmentation.state.getSegmentation(segmentationId);
1522
+ const {
1523
+ referencedVolumeId
1524
+ } = segmentation.representationData.LABELMAP;
1525
+ const segmentationVolume = esm.cache.getVolume(segmentationId);
1526
+ const referencedVolume = esm.cache.getVolume(referencedVolumeId);
1527
+ const referencedImages = referencedVolume.getCornerstoneImages();
1528
+ const labelmapObj = generateLabelMaps2DFrom3D(segmentationVolume);
1529
+
1530
+ // Generate fake metadata as an example
1531
+ labelmapObj.metadata = [];
1532
+ const segmentationInOHIF = segmentationService.getSegmentation(segmentationId);
1533
+ labelmapObj.segmentsOnLabelmap.forEach(segmentIndex => {
1534
+ // segmentation service already has a color for each segment
1535
+ const segment = segmentationInOHIF?.segments[segmentIndex];
1536
+ const {
1537
+ label,
1538
+ color
1539
+ } = segment;
1540
+ const RecommendedDisplayCIELabValue = dcmjs_es["default"].data.Colors.rgb2DICOMLAB(color.slice(0, 3).map(value => value / 255)).map(value => Math.round(value));
1541
+ const segmentMetadata = {
1542
+ SegmentNumber: segmentIndex.toString(),
1543
+ SegmentLabel: label,
1544
+ SegmentAlgorithmType: 'MANUAL',
1545
+ SegmentAlgorithmName: 'OHIF Brush',
1546
+ RecommendedDisplayCIELabValue,
1547
+ SegmentedPropertyCategoryCodeSequence: {
1548
+ CodeValue: 'T-D0050',
1549
+ CodingSchemeDesignator: 'SRT',
1550
+ CodeMeaning: 'Tissue'
1551
+ },
1552
+ SegmentedPropertyTypeCodeSequence: {
1553
+ CodeValue: 'T-D0050',
1554
+ CodingSchemeDesignator: 'SRT',
1555
+ CodeMeaning: 'Tissue'
1556
+ }
1557
+ };
1558
+ labelmapObj.metadata[segmentIndex] = segmentMetadata;
1559
+ });
1560
+ const generatedSegmentation = generateSegmentation(referencedImages, labelmapObj, esm.metaData, options);
1561
+ return generatedSegmentation;
1562
+ },
1563
+ /**
1564
+ * Downloads a segmentation based on the provided segmentation ID.
1565
+ * This function retrieves the associated segmentation and
1566
+ * uses it to generate the corresponding DICOM dataset, which
1567
+ * is then downloaded with an appropriate filename.
1568
+ *
1569
+ * @param {Object} params - Parameters for the function.
1570
+ * @param params.segmentationId - ID of the segmentation to be downloaded.
1571
+ *
1572
+ */
1573
+ downloadSegmentation: _ref6 => {
1574
+ let {
1575
+ segmentationId
1576
+ } = _ref6;
1577
+ const segmentationInOHIF = segmentationService.getSegmentation(segmentationId);
1578
+ const generatedSegmentation = actions.generateSegmentation({
1579
+ segmentationId
1580
+ });
1581
+ downloadDICOMData(generatedSegmentation.dataset, `${segmentationInOHIF.label}`);
1582
+ },
1583
+ /**
1584
+ * Stores a segmentation based on the provided segmentationId into a specified data source.
1585
+ * The SeriesDescription is derived from user input or defaults to the segmentation label,
1586
+ * and in its absence, defaults to 'Research Derived Series'.
1587
+ *
1588
+ * @param {Object} params - Parameters for the function.
1589
+ * @param params.segmentationId - ID of the segmentation to be stored.
1590
+ * @param params.dataSource - Data source where the generated segmentation will be stored.
1591
+ *
1592
+ * @returns {Object|void} Returns the naturalized report if successfully stored,
1593
+ * otherwise throws an error.
1594
+ */
1595
+ storeSegmentation: async _ref7 => {
1596
+ let {
1597
+ segmentationId,
1598
+ dataSource
1599
+ } = _ref7;
1600
+ const promptResult = await (0,default_src.createReportDialogPrompt)(uiDialogService, {
1601
+ extensionManager
1602
+ });
1603
+ if (promptResult.action !== 1 && promptResult.value) {
1604
+ return;
1605
+ }
1606
+ const segmentation = segmentationService.getSegmentation(segmentationId);
1607
+ if (!segmentation) {
1608
+ throw new Error('No segmentation found');
1609
+ }
1610
+ const {
1611
+ label
1612
+ } = segmentation;
1613
+ const SeriesDescription = promptResult.value || label || 'Research Derived Series';
1614
+ const generatedData = actions.generateSegmentation({
1615
+ segmentationId,
1616
+ options: {
1617
+ SeriesDescription
1618
+ }
1619
+ });
1620
+ if (!generatedData || !generatedData.dataset) {
1621
+ throw new Error('Error during segmentation generation');
1622
+ }
1623
+ const {
1624
+ dataset: naturalizedReport
1625
+ } = generatedData;
1626
+ await dataSource.store.dicom(naturalizedReport);
1627
+
1628
+ // The "Mode" route listens for DicomMetadataStore changes
1629
+ // When a new instance is added, it listens and
1630
+ // automatically calls makeDisplaySets
1631
+
1632
+ // add the information for where we stored it to the instance as well
1633
+ naturalizedReport.wadoRoot = dataSource.getConfig().wadoRoot;
1634
+ src.DicomMetadataStore.addInstances([naturalizedReport], true);
1635
+ return naturalizedReport;
1636
+ },
1637
+ /**
1638
+ * Converts segmentations into RTSS for download.
1639
+ * This sample function retrieves all segentations and passes to
1640
+ * cornerstone tool adapter to convert to DICOM RTSS format. It then
1641
+ * converts dataset to downloadable blob.
1642
+ *
1643
+ */
1644
+ downloadRTSS: _ref8 => {
1645
+ let {
1646
+ segmentationId
1647
+ } = _ref8;
1648
+ const segmentations = segmentationService.getSegmentation(segmentationId);
1649
+ const vtkUtils = {
1650
+ vtkImageMarchingSquares: ImageMarchingSquares/* default */.ZP,
1651
+ vtkDataArray: DataArray/* default */.ZP,
1652
+ vtkImageData: ImageData/* default */.ZP
1653
+ };
1654
+ const RTSS = generateRTSSFromSegmentations(segmentations, src.classes.MetadataProvider, src.DicomMetadataStore, esm.cache, dist_esm.Enums, vtkUtils);
1655
+ try {
1656
+ const reportBlob = datasetToBlob(RTSS);
1657
+
1658
+ //Create a URL for the binary.
1659
+ const objectUrl = URL.createObjectURL(reportBlob);
1660
+ window.location.assign(objectUrl);
1661
+ } catch (e) {
1662
+ console.warn(e);
1663
+ }
1664
+ }
1665
+ };
1666
+ const definitions = {
1667
+ getUpdatedViewportsForSegmentation: {
1668
+ commandFn: actions.getUpdatedViewportsForSegmentation
1669
+ },
1670
+ loadSegmentationDisplaySetsForViewport: {
1671
+ commandFn: actions.loadSegmentationDisplaySetsForViewport
1672
+ },
1673
+ loadSegmentationsForViewport: {
1674
+ commandFn: actions.loadSegmentationsForViewport
1675
+ },
1676
+ createEmptySegmentationForViewport: {
1677
+ commandFn: actions.createEmptySegmentationForViewport
1678
+ },
1679
+ generateSegmentation: {
1680
+ commandFn: actions.generateSegmentation
1681
+ },
1682
+ downloadSegmentation: {
1683
+ commandFn: actions.downloadSegmentation
1684
+ },
1685
+ storeSegmentation: {
1686
+ commandFn: actions.storeSegmentation
1687
+ },
1688
+ downloadRTSS: {
1689
+ commandFn: actions.downloadRTSS
1690
+ }
1691
+ };
1692
+ return {
1693
+ actions,
1694
+ definitions
1695
+ };
1696
+ };
1697
+ /* harmony default export */ const src_commandsModule = (commandsModule);
1698
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone-dicom-seg/src/init.ts
1699
+
1700
+ function init(_ref) {
1701
+ let {
1702
+ configuration = {}
1703
+ } = _ref;
1704
+ (0,dist_esm.addTool)(dist_esm.BrushTool);
1705
+ }
1706
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone-dicom-seg/src/index.tsx
1707
+ function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
1708
+
1709
+
1710
+
1711
+
1712
+
1713
+
1714
+
1715
+ const Component = /*#__PURE__*/react.lazy(() => {
1716
+ return __webpack_require__.e(/* import() */ 451).then(__webpack_require__.bind(__webpack_require__, 4451));
1717
+ });
1718
+ const OHIFCornerstoneSEGViewport = props => {
1719
+ return /*#__PURE__*/react.createElement(react.Suspense, {
1720
+ fallback: /*#__PURE__*/react.createElement("div", null, "Loading...")
1721
+ }, /*#__PURE__*/react.createElement(Component, props));
1722
+ };
1723
+
1724
+ /**
1725
+ * You can remove any of the following modules if you don't need them.
1726
+ */
1727
+ const extension = {
1728
+ /**
1729
+ * Only required property. Should be a unique value across all extensions.
1730
+ * You ID can be anything you want, but it should be unique.
1731
+ */
1732
+ id: id,
1733
+ preRegistration: init,
1734
+ /**
1735
+ * PanelModule should provide a list of panels that will be available in OHIF
1736
+ * for Modes to consume and render. Each panel is defined by a {name,
1737
+ * iconName, iconLabel, label, component} object. Example of a panel module
1738
+ * is the StudyBrowserPanel that is provided by the default extension in OHIF.
1739
+ */
1740
+ getPanelModule: src_getPanelModule,
1741
+ getCommandsModule: src_commandsModule,
1742
+ getViewportModule(_ref) {
1743
+ let {
1744
+ servicesManager,
1745
+ extensionManager
1746
+ } = _ref;
1747
+ const ExtendedOHIFCornerstoneSEGViewport = props => {
1748
+ return /*#__PURE__*/react.createElement(OHIFCornerstoneSEGViewport, _extends({
1749
+ servicesManager: servicesManager,
1750
+ extensionManager: extensionManager,
1751
+ commandsManager: commandsManager
1752
+ }, props));
1753
+ };
1754
+ return [{
1755
+ name: 'dicom-seg',
1756
+ component: ExtendedOHIFCornerstoneSEGViewport
1757
+ }];
1758
+ },
1759
+ /**
1760
+ * SopClassHandlerModule should provide a list of sop class handlers that will be
1761
+ * available in OHIF for Modes to consume and use to create displaySets from Series.
1762
+ * Each sop class handler is defined by a { name, sopClassUids, getDisplaySetsFromSeries}.
1763
+ * Examples include the default sop class handler provided by the default extension
1764
+ */
1765
+ getSopClassHandlerModule: src_getSopClassHandlerModule,
1766
+ getHangingProtocolModule: src_getHangingProtocolModule
1767
+ };
1768
+ /* harmony default export */ const cornerstone_dicom_seg_src = (extension);
1769
+
1770
+ /***/ }),
1771
+
1772
+ /***/ 78753:
1773
+ /***/ (() => {
1774
+
1775
+ /* (ignored) */
1776
+
1777
+ /***/ })
1778
+
1779
+ }]);