larvitar 2.0.5 → 2.0.6

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 (71) hide show
  1. package/README.md +2 -2
  2. package/dist/larvitar.js +1 -1
  3. package/package.json +6 -2
  4. package/.github/workflows/build-docs.yml +0 -59
  5. package/.github/workflows/codeql-analysis.yml +0 -71
  6. package/.github/workflows/deploy.yml +0 -37
  7. package/.vscode/settings.json +0 -4
  8. package/CODE_OF_CONDUCT.md +0 -76
  9. package/MIGRATION.md +0 -25
  10. package/bundler/webpack.common.js +0 -27
  11. package/bundler/webpack.dev.js +0 -23
  12. package/bundler/webpack.prod.js +0 -19
  13. package/decs.d.ts +0 -12
  14. package/imaging/MetaDataReadable.ts +0 -42
  15. package/imaging/MetaDataTypes.ts +0 -3491
  16. package/imaging/dataDictionary.json +0 -21866
  17. package/imaging/imageAnonymization.ts +0 -135
  18. package/imaging/imageColormaps.ts +0 -217
  19. package/imaging/imageContours.ts +0 -196
  20. package/imaging/imageIo.ts +0 -251
  21. package/imaging/imageLayers.ts +0 -121
  22. package/imaging/imageLoading.ts +0 -299
  23. package/imaging/imageParsing.ts +0 -444
  24. package/imaging/imagePresets.ts +0 -156
  25. package/imaging/imageRendering.ts +0 -1091
  26. package/imaging/imageReslice.ts +0 -87
  27. package/imaging/imageStore.ts +0 -487
  28. package/imaging/imageTags.ts +0 -609
  29. package/imaging/imageTools.js +0 -708
  30. package/imaging/imageUtils.ts +0 -1079
  31. package/imaging/loaders/commonLoader.ts +0 -275
  32. package/imaging/loaders/dicomLoader.ts +0 -66
  33. package/imaging/loaders/fileLoader.ts +0 -71
  34. package/imaging/loaders/multiframeLoader.ts +0 -435
  35. package/imaging/loaders/nrrdLoader.ts +0 -630
  36. package/imaging/loaders/resliceLoader.ts +0 -205
  37. package/imaging/monitors/memory.ts +0 -151
  38. package/imaging/monitors/performance.ts +0 -34
  39. package/imaging/parsers/ecg.ts +0 -54
  40. package/imaging/parsers/nrrd.js +0 -485
  41. package/imaging/tools/README.md +0 -27
  42. package/imaging/tools/custom/4dSliceScrollTool.js +0 -146
  43. package/imaging/tools/custom/BorderMagnifyTool.js +0 -99
  44. package/imaging/tools/custom/contourTool.js +0 -1884
  45. package/imaging/tools/custom/diameterTool.js +0 -141
  46. package/imaging/tools/custom/editMaskTool.js +0 -141
  47. package/imaging/tools/custom/ellipticalRoiOverlayTool.js +0 -534
  48. package/imaging/tools/custom/polygonSegmentationMixin.js +0 -245
  49. package/imaging/tools/custom/polylineScissorsTool.js +0 -59
  50. package/imaging/tools/custom/rectangleRoiOverlayTool.js +0 -564
  51. package/imaging/tools/custom/seedTool.js +0 -342
  52. package/imaging/tools/custom/setLabelMap3D.ts +0 -242
  53. package/imaging/tools/custom/thresholdsBrushTool.js +0 -161
  54. package/imaging/tools/default.ts +0 -594
  55. package/imaging/tools/interaction.ts +0 -266
  56. package/imaging/tools/io.ts +0 -229
  57. package/imaging/tools/main.ts +0 -427
  58. package/imaging/tools/segmentation.ts +0 -532
  59. package/imaging/tools/segmentations.md +0 -38
  60. package/imaging/tools/state.ts +0 -74
  61. package/imaging/tools/strategies/eraseFreehand.js +0 -76
  62. package/imaging/tools/strategies/fillFreehand.js +0 -79
  63. package/imaging/tools/strategies/index.js +0 -2
  64. package/imaging/tools/types.d.ts +0 -243
  65. package/imaging/types.d.ts +0 -200
  66. package/imaging/waveforms/ecg.ts +0 -191
  67. package/index.ts +0 -431
  68. package/jsdoc.json +0 -52
  69. package/rollup.config.js +0 -51
  70. package/template/.gitkeep +0 -0
  71. package/tsconfig.json +0 -102
@@ -1,630 +0,0 @@
1
- /** @module loaders/nrrdLoader
2
- * @desc This file provides functionalities for
3
- * custom NRRD Loader
4
- */
5
-
6
- // external libraries
7
- import cornerstone from "cornerstone-core";
8
- import { default as cornerstoneDICOMImageLoader } from "cornerstone-wado-image-loader";
9
- import { each, clone, range, findKey, filter, pickBy } from "lodash";
10
- import { v4 as uuidv4 } from "uuid";
11
- import { ImageLoader } from "cornerstone-core";
12
-
13
- // internal libraries
14
- import {
15
- getNormalOrientation,
16
- getPixelRepresentation,
17
- getTypedArrayFromDataType
18
- } from "../imageUtils";
19
-
20
- import {
21
- getImageFrame,
22
- getLarvitarImageTracker,
23
- getLarvitarManager
24
- } from "./commonLoader";
25
- import type {
26
- Image,
27
- Instance,
28
- Volume,
29
- LarvitarManager,
30
- ImageFrame,
31
- ImageTracker,
32
- MetaData
33
- } from "../types";
34
- import { DataSet } from "dicom-parser";
35
-
36
- // global module variables
37
- let customImageLoaderCounter = 0;
38
-
39
- /*
40
- * This module provides the following functions to be exported:
41
- * buildNrrdImage(volume, seriesId, custom_header)
42
- * getNrrdImageId(customLoaderName)
43
- * loadNrrdImage(imageId)
44
- * getImageIdFromSlice(sliceNumber, orientation)
45
- * getSliceNumberFromImageId(imageId, orientation)
46
- * getNrrdSerieDimensions()
47
- */
48
-
49
- type NrrdInputVolume = {
50
- header: {
51
- sizes: number[];
52
- "space directions": number[][]; // a property with a space in the name ?? Seriously ??
53
- "space origin": [number, number];
54
- kinds: string[];
55
- type: string;
56
- };
57
- data: Uint16Array; // TODO-ts: other typed arrays ?
58
- };
59
-
60
- export type NrrdSeries = {
61
- currentImageIdIndex: number;
62
- imageIds: string[];
63
- instances: { [key: string]: Instance };
64
- instanceUIDs: { [key: string]: string };
65
- numberOfImages: number;
66
- seriesDescription: string;
67
- seriesUID: string;
68
- customLoader: string;
69
- nrrdHeader: NrrdHeader;
70
- bytes: number;
71
- dataSet?: DataSet;
72
- metadata?: MetaData;
73
- ecgData?: number[];
74
- };
75
-
76
- type NrrdHeader = {
77
- volume: Volume;
78
- intercept: number;
79
- slope: number;
80
- repr: string;
81
- phase: string;
82
- study_description: string;
83
- series_description: string;
84
- acquisition_date: string;
85
- [imageId: string]: string | number | Volume | NrrdInstance; // TODO-ts: fix this: we need just NrrdInstance
86
- };
87
-
88
- type NrrdInstance = {
89
- instanceUID: string;
90
- seriesDescription: string;
91
- seriesModality: string;
92
- patientName: string;
93
- bitsAllocated: number;
94
- pixelRepresentation: string;
95
- };
96
-
97
- // TODO-ts: why it's different from cornerstone type ?
98
- // type Image = {
99
- // imageId: string;
100
- // rows: number;
101
- // columns: number;
102
- // minPixelValue: number;
103
- // maxPixelValue: number;
104
- // slope: number;
105
- // intercept: number;
106
- // windowCenter: number;
107
- // windowWidth: number;
108
- // render?: Function;
109
- // getPixelData?: Function;
110
- // getCanvas?: Function;
111
- // color: boolean;
112
- // columnPixelSpacing: number;
113
- // rowPixelSpacing: number;
114
- // invert: boolean;
115
- // sizeInBytes: number;
116
- // height: number;
117
- // width: number;
118
- // decodeTimeInMS?: number;
119
- // webWorkerTimeInMS?: number;
120
- // metadata: {[key: string]: MetadataValue};
121
- // }
122
-
123
- /**
124
- * Build the data structure for the provided image orientation
125
- * @instance
126
- * @function buildNrrdImage
127
- * @param {Object} volume The volume object
128
- * @param {String} seriesId The Id of the series
129
- * @param {Object} custom_header A custom header object
130
- * @return {Object} volume data
131
- */
132
- export const buildNrrdImage = function (
133
- volume: NrrdInputVolume,
134
- seriesId: string,
135
- custom_header: NrrdHeader
136
- ) {
137
- //TODO-ts: better definition
138
- let t0 = performance.now();
139
- // standard image structure
140
- let image: Partial<NrrdSeries> = {};
141
- let manager = getLarvitarManager() as LarvitarManager;
142
- let imageTracker = getLarvitarImageTracker() as ImageTracker;
143
- image.currentImageIdIndex = 0;
144
- image.imageIds = [];
145
- image.instances = {};
146
- image.numberOfImages = 0;
147
- image.seriesDescription = "";
148
- image.seriesUID = seriesId;
149
-
150
- let header: Partial<NrrdHeader> = {};
151
- header.volume = {} as Volume;
152
- // need to extract header from nrrd file format
153
- // sizes, spaceDirections and spaceOrigin
154
-
155
- const index = volume.header.kinds[0] == "domain" ? 0 : 1;
156
-
157
- let spacing_x = Math.sqrt(
158
- volume.header["space directions"][index + 0][0] *
159
- volume.header["space directions"][index + 0][0] +
160
- volume.header["space directions"][index + 0][1] *
161
- volume.header["space directions"][index + 0][1] +
162
- volume.header["space directions"][index + 0][2] *
163
- volume.header["space directions"][index + 0][2]
164
- );
165
- let spacing_y = Math.sqrt(
166
- volume.header["space directions"][index + 1][0] *
167
- volume.header["space directions"][index + 1][0] +
168
- volume.header["space directions"][index + 1][1] *
169
- volume.header["space directions"][index + 1][1] +
170
- volume.header["space directions"][index + 1][2] *
171
- volume.header["space directions"][index + 1][2]
172
- );
173
- let spacing_z = Math.sqrt(
174
- volume.header["space directions"][index + 2][0] *
175
- volume.header["space directions"][index + 2][0] +
176
- volume.header["space directions"][index + 2][1] *
177
- volume.header["space directions"][index + 2][1] +
178
- volume.header["space directions"][index + 2][2] *
179
- volume.header["space directions"][index + 2][2]
180
- );
181
- header.volume.rows = volume.header.sizes[index + 1];
182
- header.volume.cols = volume.header.sizes[index + 0];
183
- header.volume.numberOfSlices = volume.header.sizes[index + 2];
184
- header.volume.imagePosition = volume.header["space origin"];
185
- header.volume.pixelSpacing = [spacing_x, spacing_y];
186
- header.volume.sliceThickness = spacing_z;
187
- header.volume.repr =
188
- volume.header.type[0].toUpperCase() + volume.header.type.slice(1);
189
- header.volume.intercept = custom_header ? custom_header.intercept : 0;
190
- header.volume.slope = custom_header ? custom_header.slope : 1;
191
- header.volume.phase = custom_header ? custom_header.phase : "";
192
- header.volume.study_description = custom_header
193
- ? custom_header.study_description
194
- : "";
195
- header.volume.series_description = custom_header
196
- ? custom_header.series_description
197
- : "";
198
- header.volume.acquisition_date = custom_header
199
- ? custom_header.acquisition_date
200
- : "";
201
-
202
- let rows = volume.header.sizes[index + 1];
203
- let cols = volume.header.sizes[index + 0];
204
- let frames = volume.header.sizes[index + 2];
205
- let iopArr = volume.header["space directions"][index + 0].concat(
206
- volume.header["space directions"][index + 1]
207
- );
208
- if (iopArr.length !== 6) {
209
- throw new Error("Invalid Image Orientation");
210
- }
211
- let iop = iopArr as [number, number, number, number, number, number];
212
- let firstIpp = header.volume.imagePosition;
213
- let w = getNormalOrientation(iop);
214
- let ps = header.volume.pixelSpacing;
215
- let thickness = header.volume.sliceThickness;
216
- let intercept = header.volume.intercept;
217
- let slope = header.volume.slope;
218
-
219
- let metadata: Partial<Instance["metadata"]> = {
220
- x00280010: rows, // Rows
221
- x00280011: cols, // Columns
222
- x00200037: iop, // ImageOrientationPatient
223
- x00280030: ps, // PixelSpacing
224
- x00180050: [thickness][0], // SliceThickness
225
- x00281052: intercept ? [intercept] : [0],
226
- x00281053: slope ? [slope] : [1],
227
- x00200052: header.volume.imageIds
228
- ? (header[header.volume.imageIds[0]] as NrrdInstance).instanceUID
229
- : null,
230
- x0008103e: header.volume.imageIds
231
- ? (header[header.volume.imageIds[0]] as NrrdInstance).seriesDescription
232
- : null,
233
- x00080060: header.volume.imageIds
234
- ? (header[header.volume.imageIds[0]] as NrrdInstance).seriesModality
235
- : null,
236
- x00100010: header.volume.imageIds
237
- ? (header[header.volume.imageIds[0]] as NrrdInstance).patientName
238
- : null,
239
- x00280100: header.volume.imageIds
240
- ? (header[header.volume.imageIds[0]] as NrrdInstance).bitsAllocated
241
- : null,
242
- x00280103: header.volume.imageIds
243
- ? (header[header.volume.imageIds[0]] as NrrdInstance).pixelRepresentation
244
- : null,
245
- repr: header.volume.repr || null
246
- };
247
-
248
- // compute default ww/wl values here to use them also for resliced images
249
- let minMax = cornerstoneDICOMImageLoader.getMinMax(volume.data);
250
- let maxVoi =
251
- minMax.max * (metadata.x00281053 as number[])[0] +
252
- (metadata.x00281052 as number[])[0];
253
- let minVoi =
254
- minMax.min * (metadata.x00281053 as number[])[0] +
255
- (metadata.x00281052 as number[])[0];
256
- let ww = maxVoi - minVoi;
257
- let wl = (maxVoi + minVoi) / 2;
258
-
259
- metadata.x00280106 = minMax.min;
260
- metadata.x00280107 = minMax.max;
261
-
262
- // extract the pixelData of each frame, store the data into the image object
263
- each(range(frames), function (sliceIndex: number) {
264
- let sliceSize = rows * cols;
265
- let sliceBuffer = volume.data.subarray(
266
- sliceSize * sliceIndex,
267
- sliceSize * (sliceIndex + 1)
268
- );
269
-
270
- if (!metadata) {
271
- throw new Error("Metadata not found");
272
- }
273
-
274
- // @ts-ignore: TODO this is concepptually wrong, we already know the Pixel Representation
275
- // (see above, line 241), this function just returns the same value again
276
- let r = getPixelRepresentation(metadata);
277
- let typedArray = getTypedArrayFromDataType(r);
278
-
279
- if (!typedArray) {
280
- throw new Error("Typed array not found");
281
- }
282
-
283
- let pixelData = new typedArray(sliceBuffer);
284
- // assign these values to the metadata of all images
285
- metadata.x00281050 = wl;
286
- metadata.x00281051 = ww;
287
-
288
- let imageId = getNrrdImageId("nrrdLoader");
289
- if (!imageTracker) {
290
- throw new Error("Image tracker not initialized");
291
- }
292
- imageTracker[imageId] = seriesId;
293
-
294
- // store file references
295
- image.imageIds!.push(imageId);
296
- let frameMetadata: MetaData = clone(metadata);
297
- frameMetadata.x00200032 = firstIpp.map(function (val, i) {
298
- return val + thickness * sliceIndex * w[i];
299
- });
300
- image.instances![imageId] = {
301
- instanceId: uuidv4(),
302
- frame: sliceIndex,
303
- metadata: frameMetadata,
304
- pixelData: pixelData
305
- };
306
- });
307
-
308
- let middleSlice = Math.floor(image.imageIds.length / 2);
309
- image.currentImageIdIndex = middleSlice;
310
- image.numberOfImages = image.imageIds.length;
311
- // specify custom loader type and attach original header
312
- image.customLoader = "nrrdLoader";
313
- header.volume.imageIds = image.imageIds;
314
- image.nrrdHeader = header as NrrdHeader;
315
-
316
- if (!manager) {
317
- throw new Error("Larvitar manager not initialized");
318
- }
319
-
320
- manager[seriesId] = image as NrrdSeries;
321
-
322
- let t1 = performance.now();
323
- console.log(`Call to buildNrrdImage took ${t1 - t0} milliseconds.`);
324
- return image;
325
- };
326
-
327
- /**
328
- * Get the custom imageId from custom loader
329
- * @instance
330
- * @function getNrrdImageId
331
- * @param {String} customLoaderName The custom loader name
332
- * @return {String} the custom image id
333
- */
334
- export const getNrrdImageId = function (customLoaderName: string) {
335
- let imageId = customLoaderName + "://" + customImageLoaderCounter;
336
- customImageLoaderCounter++;
337
- return imageId;
338
- };
339
-
340
- /**
341
- * Custom cornerstone image loader for nrrd files
342
- * @instance
343
- * @function loadNrrdImage
344
- * @param {String} imageId The image id
345
- * @return {Object} custom image object
346
- */
347
- export const loadNrrdImage: ImageLoader = function (imageId: string) {
348
- let manager = getLarvitarManager() as LarvitarManager;
349
- let imageTracker = getLarvitarImageTracker() as ImageTracker;
350
- if (!manager || !imageTracker) {
351
- throw new Error("Larvitar manager or image tracker not initialized");
352
- }
353
- let seriesId = imageTracker[imageId];
354
- let instance = manager[seriesId].instances[imageId];
355
- //@ts-ignore TODO-ts: fix this why is different typed array?
356
- return createCustomImage(imageId, instance.metadata, instance.pixelData);
357
- };
358
-
359
- /**
360
- * Retrieve imageId for a slice in the given orientation
361
- * @instance
362
- * @function getImageIdFromSlice
363
- * @param {Integer} sliceNumber The image slice number
364
- * @param {String} orientation The orientation tag
365
- * @param {String} seriesId The series id
366
- * @return {String} image id
367
- */
368
- export const getImageIdFromSlice = function (
369
- sliceNumber: number,
370
- orientation: string,
371
- seriesId: string
372
- ) {
373
- var prefix = "nrrdLoader://";
374
- var serieImageTracker;
375
- let imageTracker = getLarvitarImageTracker() as ImageTracker;
376
-
377
- if (seriesId) {
378
- serieImageTracker = pickBy(imageTracker, image => {
379
- return image[0] == seriesId;
380
- });
381
- } else {
382
- serieImageTracker = imageTracker;
383
- }
384
-
385
- var firstImageIdStr = findKey(serieImageTracker, entry => {
386
- return entry[1] == orientation;
387
- });
388
-
389
- let firstImageId = firstImageIdStr?.split("//").pop();
390
-
391
- if (firstImageId == undefined) {
392
- console.error("cannot find imageId for orientation: " + orientation);
393
- return "";
394
- }
395
-
396
- var imageIndex = parseInt(firstImageId) + parseInt(sliceNumber.toString());
397
-
398
- var imageId = prefix.concat(imageIndex.toString());
399
-
400
- return imageId;
401
- };
402
-
403
- /**
404
- * Retrieve slice number for a the given orientation
405
- * @instance
406
- * @function getSliceNumberFromImageId
407
- * @param {String} imageId The image slice id
408
- * @param {String} orientation The orientation tag
409
- * @param {String} seriesId The series id
410
- * @return {Integer} The image slice number
411
- */
412
- export const getSliceNumberFromImageId = function (
413
- imageId: string,
414
- orientation: string
415
- ) {
416
- let imageTracker = getLarvitarImageTracker() as ImageTracker;
417
- var firstImageIdStr = findKey(imageTracker, entry => {
418
- return entry[1] == orientation;
419
- });
420
-
421
- if (firstImageIdStr == undefined) {
422
- console.error("cannot find imageId for orientation: " + orientation);
423
- return 0;
424
- }
425
-
426
- var imageNumber = imageId.split("//").pop() || imageId;
427
- let firstImageId = firstImageIdStr.split("//").pop();
428
-
429
- if (firstImageId == undefined) {
430
- console.error("cannot find imageId for orientation: " + orientation);
431
- return 0;
432
- }
433
-
434
- var imageIndex = parseInt(imageNumber) - parseInt(firstImageId);
435
-
436
- return imageIndex;
437
- };
438
-
439
- /**
440
- * Get series dimension for each view
441
- * @instance
442
- * @function getNrrdSerieDimensions
443
- * @return {Object} Series dimension for each view
444
- */
445
- export const getNrrdSerieDimensions = function () {
446
- let imageTracker = getLarvitarImageTracker() as ImageTracker;
447
- var dim_axial = filter(imageTracker, img => {
448
- return img[1] == "axial";
449
- });
450
- var dim_coronal = filter(imageTracker, img => {
451
- return img[1] == "coronal";
452
- });
453
- var dim_sagittal = filter(imageTracker, img => {
454
- return img[1] == "sagittal";
455
- });
456
-
457
- return {
458
- axial: [dim_coronal.length, dim_sagittal.length, dim_axial.length],
459
- coronal: [dim_sagittal.length, dim_axial.length, dim_coronal.length],
460
- sagittal: [dim_coronal.length, dim_axial.length, dim_sagittal.length]
461
- };
462
- };
463
-
464
- /* Internal functions */
465
-
466
- /**
467
- * Create the custom image object for conrnestone from nrrd file
468
- * @instance
469
- * @function createCustomImage
470
- * @param {String} imageId The series id
471
- * @param {Object} metadata The metadata object
472
- * @param {Object} pixelData The pixelData object
473
- * @param {Object} dataSet The dataset
474
- * @return {String} The image id
475
- */
476
- let createCustomImage = function (
477
- imageId: string,
478
- metadata: MetaData,
479
- pixelData: Uint8ClampedArray,
480
- dataSet?: any
481
- ) {
482
- //TODO-ts check this
483
- let canvas = window.document.createElement("canvas");
484
- let lastImageIdDrawn = "";
485
-
486
- let imageFrame = getImageFrame(metadata, dataSet) as ImageFrame;
487
-
488
- // This function uses the pixelData received as argument without manipulating
489
- // them: if the image is compressed, the decompress function should be called
490
- // before creating the custom image object (like the multiframe case).
491
- imageFrame.pixelData = pixelData;
492
-
493
- let pixelSpacing = metadata.x00280030;
494
- let rescaleIntercept = metadata.x00281052;
495
- let rescaleSlope = metadata.x00281053;
496
- let windowCenter = metadata.x00281050;
497
- let windowWidth = metadata.x00281051;
498
-
499
- function getSizeInBytes() {
500
- let bytesPerPixel = Math.round(imageFrame.bitsAllocated / 8);
501
- return (
502
- imageFrame.rows *
503
- imageFrame.columns *
504
- bytesPerPixel *
505
- imageFrame.samplesPerPixel
506
- );
507
- }
508
-
509
- let image: Partial<Image> = {
510
- imageId: imageId,
511
- color: cornerstoneDICOMImageLoader.isColorImage(
512
- imageFrame.photometricInterpretation
513
- ),
514
- columnPixelSpacing: pixelSpacing ? pixelSpacing[1] : undefined,
515
- columns: imageFrame.columns,
516
- height: imageFrame.rows,
517
- intercept: rescaleIntercept ? (rescaleIntercept as number[])[0] : 0,
518
- invert: imageFrame.photometricInterpretation === "MONOCHROME1",
519
- minPixelValue: imageFrame.smallestPixelValue,
520
- maxPixelValue: imageFrame.largestPixelValue,
521
- render: undefined, // set below
522
- rowPixelSpacing: pixelSpacing ? pixelSpacing[0] : undefined,
523
- rows: imageFrame.rows,
524
- sizeInBytes: getSizeInBytes(),
525
- slope: rescaleSlope ? (rescaleSlope as number[])[0] : 1,
526
- width: imageFrame.columns,
527
- windowCenter: windowCenter ? (windowCenter as number[])[0] : undefined,
528
- windowWidth: windowWidth ? (windowWidth as number[])[0] : undefined,
529
- decodeTimeInMS: undefined,
530
- webWorkerTimeInMS: undefined
531
- };
532
-
533
- // add function to return pixel data
534
- image.getPixelData = function () {
535
- if (!imageFrame.pixelData) {
536
- console.warn('no pixel data for imageId "' + imageId);
537
- return [];
538
- }
539
- return Array.from(imageFrame.pixelData);
540
- };
541
-
542
- // convert color space
543
- if (image.color) {
544
- // setup the canvas context
545
- canvas.height = imageFrame.rows;
546
- canvas.width = imageFrame.columns;
547
-
548
- let context = canvas.getContext("2d");
549
-
550
- if (!context) {
551
- throw new Error("Unable to get canvas context");
552
- }
553
-
554
- let imageData = context.createImageData(
555
- imageFrame.columns,
556
- imageFrame.rows
557
- );
558
- cornerstoneDICOMImageLoader.convertColorSpace(imageFrame, imageData);
559
-
560
- imageFrame.imageData = imageData;
561
- imageFrame.pixelData = imageData.data;
562
- }
563
-
564
- // Setup the renderer
565
- if (image.color) {
566
- image.render = cornerstone.renderColorImage;
567
- image.getCanvas = function () {
568
- if (lastImageIdDrawn === imageId) {
569
- return canvas;
570
- }
571
-
572
- canvas.height = image.rows || 0;
573
- canvas.width = image.columns || 0;
574
- let context = canvas.getContext("2d");
575
- if (!context) {
576
- throw new Error("Unable to get canvas context");
577
- }
578
- context.putImageData(imageFrame.imageData!, 0, 0);
579
- lastImageIdDrawn = imageId;
580
- return canvas;
581
- };
582
- } else {
583
- image.render = undefined; // will be set at need in cornerstone render pipeline, see drawImageSync.js (line 44)
584
- }
585
-
586
- // calculate min/max if not supplied
587
- if (image.minPixelValue === undefined || image.maxPixelValue === undefined) {
588
- let minMax = cornerstoneDICOMImageLoader.getMinMax(pixelData);
589
- image.minPixelValue = minMax.min;
590
- image.maxPixelValue = minMax.max;
591
- }
592
-
593
- // set the ww/wc to cover the dynamic range of the image if no values are supplied
594
- if (image.windowCenter === undefined || image.windowWidth === undefined) {
595
- if (image.color) {
596
- image.windowWidth = 255.0;
597
- image.windowCenter = 127.5;
598
- } else if (
599
- image.maxPixelValue != null &&
600
- image.minPixelValue != null &&
601
- image.slope != null &&
602
- image.intercept != null
603
- ) {
604
- let maxVoi = image.maxPixelValue * image.slope + image.intercept;
605
- let minVoi = image.minPixelValue * image.slope + image.intercept;
606
- image.windowWidth = maxVoi - minVoi;
607
- image.windowCenter = (maxVoi + minVoi) / 2;
608
- } else {
609
- console.error(
610
- "Unable to calculate default window width/center for imageId: " +
611
- imageId
612
- );
613
- }
614
- }
615
-
616
- // Custom images does not have the "data" attribute becaouse their dataset is
617
- // not available. The "metadata" attribute is used by the storeImageData
618
- // function to store custom image pixelData and metadata.
619
- image.metadata = metadata;
620
-
621
- let promise: Promise<Image> = new Promise(function (resolve) {
622
- resolve(image as Image);
623
- });
624
-
625
- // Return an object containing the Promise to cornerstone so it can setup callbacks to be
626
- // invoked asynchronously for the success/resolve and failure/reject scenarios.
627
- return {
628
- promise
629
- };
630
- };