larvitar 2.0.5 → 2.0.7

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 (77) hide show
  1. package/README.md +2 -2
  2. package/dist/imaging/imageRendering.d.ts +1 -71
  3. package/dist/imaging/imageStore.d.ts +5 -0
  4. package/dist/imaging/loaders/commonLoader.d.ts +4 -4
  5. package/dist/imaging/loaders/nrrdLoader.d.ts +1 -51
  6. package/dist/larvitar.js +13 -1
  7. package/dist/larvitar.js.map +1 -1
  8. package/imaging/tools/types.d.ts +19 -19
  9. package/imaging/types.d.ts +110 -2
  10. package/package.json +7 -2
  11. package/.github/workflows/build-docs.yml +0 -59
  12. package/.github/workflows/codeql-analysis.yml +0 -71
  13. package/.github/workflows/deploy.yml +0 -37
  14. package/.vscode/settings.json +0 -4
  15. package/CODE_OF_CONDUCT.md +0 -76
  16. package/MIGRATION.md +0 -25
  17. package/bundler/webpack.common.js +0 -27
  18. package/bundler/webpack.dev.js +0 -23
  19. package/bundler/webpack.prod.js +0 -19
  20. package/decs.d.ts +0 -12
  21. package/dist/imaging/MetaDataReadable.d.ts +0 -41
  22. package/dist/imaging/MetaDataTypes.d.ts +0 -3489
  23. package/imaging/dataDictionary.json +0 -21866
  24. package/imaging/imageAnonymization.ts +0 -135
  25. package/imaging/imageColormaps.ts +0 -217
  26. package/imaging/imageContours.ts +0 -196
  27. package/imaging/imageIo.ts +0 -251
  28. package/imaging/imageLayers.ts +0 -121
  29. package/imaging/imageLoading.ts +0 -299
  30. package/imaging/imageParsing.ts +0 -444
  31. package/imaging/imagePresets.ts +0 -156
  32. package/imaging/imageRendering.ts +0 -1091
  33. package/imaging/imageReslice.ts +0 -87
  34. package/imaging/imageStore.ts +0 -487
  35. package/imaging/imageTags.ts +0 -609
  36. package/imaging/imageTools.js +0 -708
  37. package/imaging/imageUtils.ts +0 -1079
  38. package/imaging/loaders/commonLoader.ts +0 -275
  39. package/imaging/loaders/dicomLoader.ts +0 -66
  40. package/imaging/loaders/fileLoader.ts +0 -71
  41. package/imaging/loaders/multiframeLoader.ts +0 -435
  42. package/imaging/loaders/nrrdLoader.ts +0 -630
  43. package/imaging/loaders/resliceLoader.ts +0 -205
  44. package/imaging/monitors/memory.ts +0 -151
  45. package/imaging/monitors/performance.ts +0 -34
  46. package/imaging/parsers/ecg.ts +0 -54
  47. package/imaging/parsers/nrrd.js +0 -485
  48. package/imaging/tools/custom/4dSliceScrollTool.js +0 -146
  49. package/imaging/tools/custom/BorderMagnifyTool.js +0 -99
  50. package/imaging/tools/custom/contourTool.js +0 -1884
  51. package/imaging/tools/custom/diameterTool.js +0 -141
  52. package/imaging/tools/custom/editMaskTool.js +0 -141
  53. package/imaging/tools/custom/ellipticalRoiOverlayTool.js +0 -534
  54. package/imaging/tools/custom/polygonSegmentationMixin.js +0 -245
  55. package/imaging/tools/custom/polylineScissorsTool.js +0 -59
  56. package/imaging/tools/custom/rectangleRoiOverlayTool.js +0 -564
  57. package/imaging/tools/custom/seedTool.js +0 -342
  58. package/imaging/tools/custom/setLabelMap3D.ts +0 -242
  59. package/imaging/tools/custom/thresholdsBrushTool.js +0 -161
  60. package/imaging/tools/default.ts +0 -594
  61. package/imaging/tools/interaction.ts +0 -266
  62. package/imaging/tools/io.ts +0 -229
  63. package/imaging/tools/main.ts +0 -427
  64. package/imaging/tools/segmentation.ts +0 -532
  65. package/imaging/tools/segmentations.md +0 -38
  66. package/imaging/tools/state.ts +0 -74
  67. package/imaging/tools/strategies/eraseFreehand.js +0 -76
  68. package/imaging/tools/strategies/fillFreehand.js +0 -79
  69. package/imaging/tools/strategies/index.js +0 -2
  70. package/imaging/waveforms/ecg.ts +0 -191
  71. package/index.ts +0 -431
  72. package/jsdoc.json +0 -52
  73. package/rollup.config.js +0 -51
  74. package/template/.gitkeep +0 -0
  75. package/tsconfig.json +0 -102
  76. /package/imaging/{MetaDataReadable.ts → MetaDataReadable.d.ts} +0 -0
  77. /package/imaging/{MetaDataTypes.ts → MetaDataTypes.d.ts} +0 -0
@@ -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
- };