@cornerstonejs/adapters 1.55.0 → 1.56.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters.es.js +542 -16
- package/dist/adapters.es.js.map +1 -1
- package/package.json +5 -5
package/dist/adapters.es.js
CHANGED
|
@@ -38700,6 +38700,9 @@ function isValidVolume(imageIds) {
|
|
|
38700
38700
|
|
|
38701
38701
|
function updateVTKImageDataWithCornerstoneImage(sourceImageData, image) {
|
|
38702
38702
|
const pixelData = image.getPixelData();
|
|
38703
|
+
if (!sourceImageData.getPointData) {
|
|
38704
|
+
return;
|
|
38705
|
+
}
|
|
38703
38706
|
const scalarData = sourceImageData.getPointData().getScalars().getData();
|
|
38704
38707
|
if (image.color && image.rgba) {
|
|
38705
38708
|
const newPixelData = new Uint8Array(image.columns * image.rows * 3);
|
|
@@ -40744,12 +40747,12 @@ class Viewport {
|
|
|
40744
40747
|
return;
|
|
40745
40748
|
}
|
|
40746
40749
|
const renderer = this.getRenderer();
|
|
40747
|
-
renderer
|
|
40750
|
+
renderer?.addActor(actor);
|
|
40748
40751
|
this._actors.set(actorUID, Object.assign({}, actorEntry));
|
|
40749
40752
|
this.updateCameraClippingPlanesAndRange();
|
|
40750
40753
|
}
|
|
40751
40754
|
removeAllActors() {
|
|
40752
|
-
this.getRenderer()
|
|
40755
|
+
this.getRenderer()?.removeAllViewProps();
|
|
40753
40756
|
this._actors = new Map();
|
|
40754
40757
|
return;
|
|
40755
40758
|
}
|
|
@@ -42155,10 +42158,213 @@ async function convertVolumeToStackViewport({
|
|
|
42155
42158
|
return stackViewport;
|
|
42156
42159
|
}
|
|
42157
42160
|
|
|
42161
|
+
class RLEVoxelMap {
|
|
42162
|
+
constructor(width, height, depth = 1) {
|
|
42163
|
+
this.rows = new Map();
|
|
42164
|
+
this.height = 1;
|
|
42165
|
+
this.width = 1;
|
|
42166
|
+
this.depth = 1;
|
|
42167
|
+
this.jMultiple = 1;
|
|
42168
|
+
this.kMultiple = 1;
|
|
42169
|
+
this.numComps = 1;
|
|
42170
|
+
this.defaultValue = 0;
|
|
42171
|
+
this.pixelDataConstructor = Uint8Array;
|
|
42172
|
+
this.get = index => {
|
|
42173
|
+
const i = index % this.jMultiple;
|
|
42174
|
+
const j = (index - i) / this.jMultiple;
|
|
42175
|
+
const rle = this.getRLE(i, j);
|
|
42176
|
+
return rle?.value || this.defaultValue;
|
|
42177
|
+
};
|
|
42178
|
+
this.getRun = (j, k) => {
|
|
42179
|
+
const runIndex = j + k * this.height;
|
|
42180
|
+
return this.rows.get(runIndex);
|
|
42181
|
+
};
|
|
42182
|
+
this.set = (index, value) => {
|
|
42183
|
+
if (value === undefined) {
|
|
42184
|
+
throw new Error(`Can't set undefined at ${index % this.width}`);
|
|
42185
|
+
}
|
|
42186
|
+
const i = index % this.width;
|
|
42187
|
+
const j = (index - i) / this.width;
|
|
42188
|
+
const row = this.rows.get(j);
|
|
42189
|
+
if (!row) {
|
|
42190
|
+
this.rows.set(j, [{
|
|
42191
|
+
start: i,
|
|
42192
|
+
end: i + 1,
|
|
42193
|
+
value
|
|
42194
|
+
}]);
|
|
42195
|
+
return;
|
|
42196
|
+
}
|
|
42197
|
+
const rleIndex = this.findIndex(row, i);
|
|
42198
|
+
const rle1 = row[rleIndex];
|
|
42199
|
+
const rle0 = row[rleIndex - 1];
|
|
42200
|
+
if (!rle1) {
|
|
42201
|
+
if (!rle0 || rle0.value !== value || rle0.end !== i) {
|
|
42202
|
+
row[rleIndex] = {
|
|
42203
|
+
start: i,
|
|
42204
|
+
end: i + 1,
|
|
42205
|
+
value
|
|
42206
|
+
};
|
|
42207
|
+
return;
|
|
42208
|
+
}
|
|
42209
|
+
rle0.end++;
|
|
42210
|
+
return;
|
|
42211
|
+
}
|
|
42212
|
+
const {
|
|
42213
|
+
start,
|
|
42214
|
+
end,
|
|
42215
|
+
value: oldValue
|
|
42216
|
+
} = rle1;
|
|
42217
|
+
if (value === oldValue && i >= start) {
|
|
42218
|
+
return;
|
|
42219
|
+
}
|
|
42220
|
+
const rleInsert = {
|
|
42221
|
+
start: i,
|
|
42222
|
+
end: i + 1,
|
|
42223
|
+
value
|
|
42224
|
+
};
|
|
42225
|
+
const isAfter = i > start;
|
|
42226
|
+
const insertIndex = isAfter ? rleIndex + 1 : rleIndex;
|
|
42227
|
+
const rlePrev = isAfter ? rle1 : rle0;
|
|
42228
|
+
let rleNext = isAfter ? row[rleIndex + 1] : rle1;
|
|
42229
|
+
if (rlePrev?.value === value && rlePrev?.end === i) {
|
|
42230
|
+
rlePrev.end++;
|
|
42231
|
+
if (rleNext?.value === value && rleNext.start === i + 1) {
|
|
42232
|
+
rlePrev.end = rleNext.end;
|
|
42233
|
+
row.splice(rleIndex, 1);
|
|
42234
|
+
} else if (rleNext?.start === i) {
|
|
42235
|
+
rleNext.start++;
|
|
42236
|
+
if (rleNext.start === rleNext.end) {
|
|
42237
|
+
row.splice(rleIndex, 1);
|
|
42238
|
+
rleNext = row[rleIndex];
|
|
42239
|
+
if (rleNext?.start === i + 1 && rleNext.value === value) {
|
|
42240
|
+
rlePrev.end = rleNext.end;
|
|
42241
|
+
row.splice(rleIndex, 1);
|
|
42242
|
+
}
|
|
42243
|
+
}
|
|
42244
|
+
}
|
|
42245
|
+
return;
|
|
42246
|
+
}
|
|
42247
|
+
if (rleNext?.value === value && rleNext.start === i + 1) {
|
|
42248
|
+
rleNext.start--;
|
|
42249
|
+
if (rlePrev?.end > i) {
|
|
42250
|
+
rlePrev.end = i;
|
|
42251
|
+
if (rlePrev.end === rlePrev.start) {
|
|
42252
|
+
row.splice(rleIndex, 1);
|
|
42253
|
+
}
|
|
42254
|
+
}
|
|
42255
|
+
return;
|
|
42256
|
+
}
|
|
42257
|
+
if (rleNext?.start === i && rleNext.end === i + 1) {
|
|
42258
|
+
rleNext.value = value;
|
|
42259
|
+
const nextnext = row[rleIndex + 1];
|
|
42260
|
+
if (nextnext?.start == i + 1 && nextnext.value === value) {
|
|
42261
|
+
row.splice(rleIndex + 1, 1);
|
|
42262
|
+
rleNext.end = nextnext.end;
|
|
42263
|
+
}
|
|
42264
|
+
return;
|
|
42265
|
+
}
|
|
42266
|
+
if (i === rleNext?.start) {
|
|
42267
|
+
rleNext.start++;
|
|
42268
|
+
}
|
|
42269
|
+
if (isAfter && end > i + 1) {
|
|
42270
|
+
row.splice(insertIndex, 0, rleInsert, {
|
|
42271
|
+
start: i + 1,
|
|
42272
|
+
end: rlePrev.end,
|
|
42273
|
+
value: rlePrev.value
|
|
42274
|
+
});
|
|
42275
|
+
} else {
|
|
42276
|
+
row.splice(insertIndex, 0, rleInsert);
|
|
42277
|
+
}
|
|
42278
|
+
if (rlePrev?.end > i) {
|
|
42279
|
+
rlePrev.end = i;
|
|
42280
|
+
}
|
|
42281
|
+
};
|
|
42282
|
+
this.width = width;
|
|
42283
|
+
this.height = height;
|
|
42284
|
+
this.depth = depth;
|
|
42285
|
+
this.jMultiple = width;
|
|
42286
|
+
this.kMultiple = this.jMultiple * height;
|
|
42287
|
+
}
|
|
42288
|
+
getRLE(i, j, k = 0) {
|
|
42289
|
+
const row = this.rows.get(j + k * this.height);
|
|
42290
|
+
if (!row) {
|
|
42291
|
+
return;
|
|
42292
|
+
}
|
|
42293
|
+
const index = this.findIndex(row, i);
|
|
42294
|
+
const rle = row[index];
|
|
42295
|
+
return i >= rle?.start ? rle : undefined;
|
|
42296
|
+
}
|
|
42297
|
+
findIndex(row, i) {
|
|
42298
|
+
for (let index = 0; index < row.length; index++) {
|
|
42299
|
+
const {
|
|
42300
|
+
end: iEnd
|
|
42301
|
+
} = row[index];
|
|
42302
|
+
if (i < iEnd) {
|
|
42303
|
+
return index;
|
|
42304
|
+
}
|
|
42305
|
+
}
|
|
42306
|
+
return row.length;
|
|
42307
|
+
}
|
|
42308
|
+
clear() {
|
|
42309
|
+
this.rows.clear();
|
|
42310
|
+
}
|
|
42311
|
+
keys() {
|
|
42312
|
+
return [...this.rows.keys()];
|
|
42313
|
+
}
|
|
42314
|
+
getPixelData(k = 0, pixelData) {
|
|
42315
|
+
if (!pixelData) {
|
|
42316
|
+
pixelData = new this.pixelDataConstructor(this.width * this.height * this.numComps);
|
|
42317
|
+
} else {
|
|
42318
|
+
pixelData.fill(0);
|
|
42319
|
+
}
|
|
42320
|
+
const {
|
|
42321
|
+
width,
|
|
42322
|
+
height,
|
|
42323
|
+
numComps
|
|
42324
|
+
} = this;
|
|
42325
|
+
for (let j = 0; j < height; j++) {
|
|
42326
|
+
const row = this.getRun(j, k);
|
|
42327
|
+
if (!row) {
|
|
42328
|
+
continue;
|
|
42329
|
+
}
|
|
42330
|
+
if (numComps === 1) {
|
|
42331
|
+
for (const rle of row) {
|
|
42332
|
+
const rowOffset = j * width;
|
|
42333
|
+
const {
|
|
42334
|
+
start,
|
|
42335
|
+
end,
|
|
42336
|
+
value
|
|
42337
|
+
} = rle;
|
|
42338
|
+
for (let i = start; i < end; i++) {
|
|
42339
|
+
pixelData[rowOffset + i] = value;
|
|
42340
|
+
}
|
|
42341
|
+
}
|
|
42342
|
+
} else {
|
|
42343
|
+
for (const rle of row) {
|
|
42344
|
+
const rowOffset = j * width * numComps;
|
|
42345
|
+
const {
|
|
42346
|
+
start,
|
|
42347
|
+
end,
|
|
42348
|
+
value
|
|
42349
|
+
} = rle;
|
|
42350
|
+
for (let i = start; i < end; i += numComps) {
|
|
42351
|
+
for (let comp = 0; comp < numComps; comp++) {
|
|
42352
|
+
pixelData[rowOffset + i + comp] = value[comp];
|
|
42353
|
+
}
|
|
42354
|
+
}
|
|
42355
|
+
}
|
|
42356
|
+
}
|
|
42357
|
+
}
|
|
42358
|
+
return pixelData;
|
|
42359
|
+
}
|
|
42360
|
+
}
|
|
42361
|
+
|
|
42362
|
+
const DEFAULT_RLE_SIZE = 5 * 1024;
|
|
42158
42363
|
class VoxelManager {
|
|
42159
42364
|
constructor(dimensions, _get, _set) {
|
|
42160
42365
|
this.modifiedSlices = new Set();
|
|
42161
42366
|
this.boundsIJK = [[Infinity, -Infinity], [Infinity, -Infinity], [Infinity, -Infinity]];
|
|
42367
|
+
this.numComps = 1;
|
|
42162
42368
|
this.getAtIJK = (i, j, k) => {
|
|
42163
42369
|
const index = i + j * this.width + k * this.frameSize;
|
|
42164
42370
|
return this._get(index);
|
|
@@ -42276,10 +42482,38 @@ class VoxelManager {
|
|
|
42276
42482
|
bounds[2][0] = Math.min(point[2], bounds[2][0]);
|
|
42277
42483
|
bounds[2][1] = Math.max(point[2], bounds[2][1]);
|
|
42278
42484
|
}
|
|
42279
|
-
static
|
|
42485
|
+
static createRGBVolumeVoxelManager(dimensions, scalarData, numComponents) {
|
|
42486
|
+
const voxels = new VoxelManager(dimensions, index => {
|
|
42487
|
+
index *= numComponents;
|
|
42488
|
+
return [scalarData[index++], scalarData[index++], scalarData[index++]];
|
|
42489
|
+
}, (index, v) => {
|
|
42490
|
+
index *= 3;
|
|
42491
|
+
const isChanged = !isEqual$2(scalarData[index], v);
|
|
42492
|
+
scalarData[index++] = v[0];
|
|
42493
|
+
scalarData[index++] = v[1];
|
|
42494
|
+
scalarData[index++] = v[2];
|
|
42495
|
+
return isChanged;
|
|
42496
|
+
});
|
|
42497
|
+
voxels.numComps = numComponents;
|
|
42498
|
+
voxels.scalarData = scalarData;
|
|
42499
|
+
return voxels;
|
|
42500
|
+
}
|
|
42501
|
+
static createVolumeVoxelManager(dimensions, scalarData, numComponents = 0) {
|
|
42280
42502
|
if (dimensions.length !== 3) {
|
|
42281
42503
|
throw new Error('Dimensions must be provided as [number, number, number] for [width, height, depth]');
|
|
42282
42504
|
}
|
|
42505
|
+
if (!numComponents) {
|
|
42506
|
+
numComponents = scalarData.length / dimensions[0] / dimensions[1] / dimensions[2];
|
|
42507
|
+
if (numComponents > 4 || numComponents < 1 || numComponents === 2) {
|
|
42508
|
+
throw new Error(`Number of components ${numComponents} must be 1, 3 or 4`);
|
|
42509
|
+
}
|
|
42510
|
+
}
|
|
42511
|
+
if (numComponents > 1) {
|
|
42512
|
+
return VoxelManager.createRGBVolumeVoxelManager(dimensions, scalarData, numComponents);
|
|
42513
|
+
}
|
|
42514
|
+
return VoxelManager.createNumberVolumeVoxelManager(dimensions, scalarData);
|
|
42515
|
+
}
|
|
42516
|
+
static createNumberVolumeVoxelManager(dimensions, scalarData) {
|
|
42283
42517
|
const voxels = new VoxelManager(dimensions, index => scalarData[index], (index, v) => {
|
|
42284
42518
|
const isChanged = scalarData[index] !== v;
|
|
42285
42519
|
scalarData[index] = v;
|
|
@@ -42316,6 +42550,44 @@ class VoxelManager {
|
|
|
42316
42550
|
voxelManager.sourceVoxelManager = sourceVoxelManager;
|
|
42317
42551
|
return voxelManager;
|
|
42318
42552
|
}
|
|
42553
|
+
static createLazyVoxelManager(dimensions, planeFactory) {
|
|
42554
|
+
const map = new Map();
|
|
42555
|
+
const [width, height, depth] = dimensions;
|
|
42556
|
+
const planeSize = width * height;
|
|
42557
|
+
const voxelManager = new VoxelManager(dimensions, index => map.get(Math.floor(index / planeSize))?.[index % planeSize], (index, v) => {
|
|
42558
|
+
const k = Math.floor(index / planeSize);
|
|
42559
|
+
let layer = map.get(k);
|
|
42560
|
+
if (!layer) {
|
|
42561
|
+
layer = planeFactory(width, height);
|
|
42562
|
+
map.set(k, layer);
|
|
42563
|
+
}
|
|
42564
|
+
layer[index % planeSize] = v;
|
|
42565
|
+
});
|
|
42566
|
+
voxelManager.map = map;
|
|
42567
|
+
return voxelManager;
|
|
42568
|
+
}
|
|
42569
|
+
static createRLEVoxelManager(dimensions) {
|
|
42570
|
+
const [width, height, depth] = dimensions;
|
|
42571
|
+
const map = new RLEVoxelMap(width, height, depth);
|
|
42572
|
+
const voxelManager = new VoxelManager(dimensions, index => map.get(index), (index, v) => map.set(index, v));
|
|
42573
|
+
voxelManager.map = map;
|
|
42574
|
+
voxelManager.getPixelData = map.getPixelData.bind(map);
|
|
42575
|
+
return voxelManager;
|
|
42576
|
+
}
|
|
42577
|
+
static addInstanceToImage(image) {
|
|
42578
|
+
const {
|
|
42579
|
+
width,
|
|
42580
|
+
height
|
|
42581
|
+
} = image;
|
|
42582
|
+
const scalarData = image.getPixelData();
|
|
42583
|
+
if (scalarData?.length >= width * height) {
|
|
42584
|
+
image.voxelManager = VoxelManager.createVolumeVoxelManager([width, height, 1], scalarData);
|
|
42585
|
+
return;
|
|
42586
|
+
}
|
|
42587
|
+
image.voxelManager = VoxelManager.createRLEVoxelManager([width, height, 1]);
|
|
42588
|
+
image.getPixelData = image.voxelManager.getPixelData;
|
|
42589
|
+
image.sizeInBytes = DEFAULT_RLE_SIZE;
|
|
42590
|
+
}
|
|
42319
42591
|
}
|
|
42320
42592
|
|
|
42321
42593
|
function roundNumber(value, precision = 2) {
|
|
@@ -46005,6 +46277,218 @@ class VolumeViewport3D extends BaseVolumeViewport$1 {
|
|
|
46005
46277
|
}
|
|
46006
46278
|
var VolumeViewport3D$1 = VolumeViewport3D;
|
|
46007
46279
|
|
|
46280
|
+
class CanvasProperties {
|
|
46281
|
+
constructor(actor) {
|
|
46282
|
+
this.opacity = 0.4;
|
|
46283
|
+
this.outlineOpacity = 0.4;
|
|
46284
|
+
this.transferFunction = [];
|
|
46285
|
+
this.actor = actor;
|
|
46286
|
+
}
|
|
46287
|
+
setRGBTransferFunction(index, cfun) {
|
|
46288
|
+
this.transferFunction[index] = cfun;
|
|
46289
|
+
}
|
|
46290
|
+
setScalarOpacity(opacity) {}
|
|
46291
|
+
setInterpolationTypeToNearest() {}
|
|
46292
|
+
setUseLabelOutline() {}
|
|
46293
|
+
setLabelOutlineOpacity(opacity) {
|
|
46294
|
+
this.outlineOpacity = opacity;
|
|
46295
|
+
}
|
|
46296
|
+
setLabelOutlineThickness() {}
|
|
46297
|
+
getColor(index) {
|
|
46298
|
+
const cfun = this.transferFunction[0];
|
|
46299
|
+
const r = cfun.getRedValue(index);
|
|
46300
|
+
const g = cfun.getGreenValue(index);
|
|
46301
|
+
const b = cfun.getBlueValue(index);
|
|
46302
|
+
return [r, g, b, this.opacity];
|
|
46303
|
+
}
|
|
46304
|
+
}
|
|
46305
|
+
|
|
46306
|
+
class CanvasMapper {
|
|
46307
|
+
constructor(actor) {
|
|
46308
|
+
this.actor = actor;
|
|
46309
|
+
}
|
|
46310
|
+
getInputData() {
|
|
46311
|
+
return this.actor.getImage();
|
|
46312
|
+
}
|
|
46313
|
+
}
|
|
46314
|
+
|
|
46315
|
+
class CanvasActor {
|
|
46316
|
+
constructor(viewport, derivedImage) {
|
|
46317
|
+
this.canvasProperties = new CanvasProperties(this);
|
|
46318
|
+
this.visibility = false;
|
|
46319
|
+
this.mapper = new CanvasMapper(this);
|
|
46320
|
+
this.className = 'CanvasActor';
|
|
46321
|
+
this.derivedImage = derivedImage;
|
|
46322
|
+
this.viewport = viewport;
|
|
46323
|
+
}
|
|
46324
|
+
renderRLE(viewport, context, voxelManager) {
|
|
46325
|
+
const {
|
|
46326
|
+
width,
|
|
46327
|
+
height
|
|
46328
|
+
} = this.image;
|
|
46329
|
+
let {
|
|
46330
|
+
canvas
|
|
46331
|
+
} = this;
|
|
46332
|
+
if (!canvas || canvas.width !== width || canvas.height !== height) {
|
|
46333
|
+
this.canvas = canvas = new window.OffscreenCanvas(width, height);
|
|
46334
|
+
}
|
|
46335
|
+
const localContext = canvas.getContext('2d');
|
|
46336
|
+
const imageData = localContext.createImageData(width, height);
|
|
46337
|
+
const {
|
|
46338
|
+
data: imageArray
|
|
46339
|
+
} = imageData;
|
|
46340
|
+
imageArray.fill(0);
|
|
46341
|
+
const {
|
|
46342
|
+
map
|
|
46343
|
+
} = voxelManager;
|
|
46344
|
+
let dirtyX = Infinity;
|
|
46345
|
+
let dirtyY = Infinity;
|
|
46346
|
+
let dirtyX2 = -Infinity;
|
|
46347
|
+
let dirtyY2 = -Infinity;
|
|
46348
|
+
for (let y = 0; y < height; y++) {
|
|
46349
|
+
const row = map.getRun(y, 0);
|
|
46350
|
+
if (!row) {
|
|
46351
|
+
continue;
|
|
46352
|
+
}
|
|
46353
|
+
dirtyY = Math.min(dirtyY, y);
|
|
46354
|
+
dirtyY2 = Math.max(dirtyY2, y);
|
|
46355
|
+
const baseOffset = y * width << 2;
|
|
46356
|
+
let indicesToDelete;
|
|
46357
|
+
for (const run of row) {
|
|
46358
|
+
const {
|
|
46359
|
+
start: start,
|
|
46360
|
+
end,
|
|
46361
|
+
value: segmentIndex
|
|
46362
|
+
} = run;
|
|
46363
|
+
if (segmentIndex === 0) {
|
|
46364
|
+
indicesToDelete ||= [];
|
|
46365
|
+
indicesToDelete.push(row.indexOf(run));
|
|
46366
|
+
continue;
|
|
46367
|
+
}
|
|
46368
|
+
dirtyX = Math.min(dirtyX, start);
|
|
46369
|
+
dirtyX2 = Math.max(dirtyX2, end);
|
|
46370
|
+
const rgb = this.canvasProperties.getColor(segmentIndex).map(v => v * 255);
|
|
46371
|
+
let startOffset = baseOffset + (start << 2);
|
|
46372
|
+
for (let i = start; i < end; i++) {
|
|
46373
|
+
imageArray[startOffset++] = rgb[0];
|
|
46374
|
+
imageArray[startOffset++] = rgb[1];
|
|
46375
|
+
imageArray[startOffset++] = rgb[2];
|
|
46376
|
+
imageArray[startOffset++] = rgb[3];
|
|
46377
|
+
}
|
|
46378
|
+
}
|
|
46379
|
+
}
|
|
46380
|
+
if (dirtyX > width) {
|
|
46381
|
+
return;
|
|
46382
|
+
}
|
|
46383
|
+
const dirtyWidth = dirtyX2 - dirtyX;
|
|
46384
|
+
const dirtyHeight = dirtyY2 - dirtyY;
|
|
46385
|
+
localContext.putImageData(imageData, 0, 0, dirtyX, dirtyY, dirtyWidth, dirtyHeight);
|
|
46386
|
+
context.drawImage(canvas, dirtyX, dirtyY, dirtyWidth, dirtyHeight, dirtyX, dirtyY, dirtyWidth, dirtyHeight);
|
|
46387
|
+
}
|
|
46388
|
+
render(viewport, context) {
|
|
46389
|
+
if (!this.visibility) {
|
|
46390
|
+
return;
|
|
46391
|
+
}
|
|
46392
|
+
const image = this.image || this.getImage();
|
|
46393
|
+
const {
|
|
46394
|
+
width,
|
|
46395
|
+
height
|
|
46396
|
+
} = image;
|
|
46397
|
+
const data = image.getScalarData();
|
|
46398
|
+
if (!data) {
|
|
46399
|
+
return;
|
|
46400
|
+
}
|
|
46401
|
+
const {
|
|
46402
|
+
voxelManager
|
|
46403
|
+
} = image;
|
|
46404
|
+
if (voxelManager) {
|
|
46405
|
+
if (voxelManager.map.getRun) {
|
|
46406
|
+
return this.renderRLE(viewport, context, voxelManager);
|
|
46407
|
+
}
|
|
46408
|
+
}
|
|
46409
|
+
let {
|
|
46410
|
+
canvas
|
|
46411
|
+
} = this;
|
|
46412
|
+
if (!canvas || canvas.width !== width || canvas.height !== height) {
|
|
46413
|
+
this.canvas = canvas = new window.OffscreenCanvas(width, height);
|
|
46414
|
+
}
|
|
46415
|
+
const localContext = canvas.getContext('2d');
|
|
46416
|
+
const imageData = localContext.createImageData(width, height);
|
|
46417
|
+
const {
|
|
46418
|
+
data: imageArray
|
|
46419
|
+
} = imageData;
|
|
46420
|
+
let offset = 0;
|
|
46421
|
+
let destOffset = 0;
|
|
46422
|
+
let dirtyX = Infinity;
|
|
46423
|
+
let dirtyY = Infinity;
|
|
46424
|
+
let dirtyX2 = -Infinity;
|
|
46425
|
+
let dirtyY2 = -Infinity;
|
|
46426
|
+
for (let y = 0; y < height; y++) {
|
|
46427
|
+
for (let x = 0; x < width; x++) {
|
|
46428
|
+
const segmentIndex = data[offset++];
|
|
46429
|
+
if (segmentIndex) {
|
|
46430
|
+
dirtyX = Math.min(x, dirtyX);
|
|
46431
|
+
dirtyY = Math.min(y, dirtyY);
|
|
46432
|
+
dirtyX2 = Math.max(x, dirtyX2);
|
|
46433
|
+
dirtyY2 = Math.max(y, dirtyY2);
|
|
46434
|
+
const rgb = this.canvasProperties.getColor(segmentIndex);
|
|
46435
|
+
imageArray[destOffset] = rgb[0] * 255;
|
|
46436
|
+
imageArray[destOffset + 1] = rgb[1] * 255;
|
|
46437
|
+
imageArray[destOffset + 2] = rgb[2] * 255;
|
|
46438
|
+
imageArray[destOffset + 3] = 127;
|
|
46439
|
+
}
|
|
46440
|
+
destOffset += 4;
|
|
46441
|
+
}
|
|
46442
|
+
}
|
|
46443
|
+
if (dirtyX > width) {
|
|
46444
|
+
return;
|
|
46445
|
+
}
|
|
46446
|
+
const dirtyWidth = dirtyX2 - dirtyX + 1;
|
|
46447
|
+
const dirtyHeight = dirtyY2 - dirtyY + 1;
|
|
46448
|
+
localContext.putImageData(imageData, 0, 0, dirtyX, dirtyY, dirtyWidth, dirtyHeight);
|
|
46449
|
+
context.drawImage(canvas, dirtyX, dirtyY, dirtyWidth, dirtyHeight, dirtyX, dirtyY, dirtyWidth, dirtyHeight);
|
|
46450
|
+
}
|
|
46451
|
+
getClassName() {
|
|
46452
|
+
return this.className;
|
|
46453
|
+
}
|
|
46454
|
+
getProperty() {
|
|
46455
|
+
return this.canvasProperties;
|
|
46456
|
+
}
|
|
46457
|
+
setVisibility(visibility) {
|
|
46458
|
+
this.visibility = visibility;
|
|
46459
|
+
}
|
|
46460
|
+
getMapper() {
|
|
46461
|
+
return this.mapper;
|
|
46462
|
+
}
|
|
46463
|
+
isA(actorType) {
|
|
46464
|
+
return actorType === this.className;
|
|
46465
|
+
}
|
|
46466
|
+
getImage() {
|
|
46467
|
+
if (this.image) {
|
|
46468
|
+
return this.image;
|
|
46469
|
+
}
|
|
46470
|
+
this.image = {
|
|
46471
|
+
...this.derivedImage
|
|
46472
|
+
};
|
|
46473
|
+
const imageData = this.viewport.getImageData();
|
|
46474
|
+
Object.assign(this.image, {
|
|
46475
|
+
worldToIndex: worldPos => imageData.imageData.worldToIndex(worldPos),
|
|
46476
|
+
indexToWorld: index => imageData.imageData.indexToWorld(index),
|
|
46477
|
+
getDimensions: () => imageData.dimensions,
|
|
46478
|
+
getScalarData: () => this.derivedImage?.getPixelData(),
|
|
46479
|
+
getDirection: () => imageData.direction,
|
|
46480
|
+
getSpacing: () => imageData.spacing,
|
|
46481
|
+
setOrigin: () => null,
|
|
46482
|
+
setDerivedImage: image => {
|
|
46483
|
+
this.derivedImage = image;
|
|
46484
|
+
this.image = null;
|
|
46485
|
+
},
|
|
46486
|
+
modified: () => null
|
|
46487
|
+
});
|
|
46488
|
+
return this.image;
|
|
46489
|
+
}
|
|
46490
|
+
}
|
|
46491
|
+
|
|
46008
46492
|
class VideoViewport extends Viewport$1 {
|
|
46009
46493
|
constructor(props) {
|
|
46010
46494
|
super({
|
|
@@ -46102,8 +46586,11 @@ class VideoViewport extends Viewport$1 {
|
|
|
46102
46586
|
const transformationMatrix = transform.getMatrix();
|
|
46103
46587
|
this.canvasContext.transform(transformationMatrix[0], transformationMatrix[1], transformationMatrix[2], transformationMatrix[3], transformationMatrix[4], transformationMatrix[5]);
|
|
46104
46588
|
this.canvasContext.drawImage(this.videoElement, 0, 0, this.videoWidth, this.videoHeight);
|
|
46589
|
+
for (const actor of this.getActors()) {
|
|
46590
|
+
actor.actor.render(this, this.canvasContext);
|
|
46591
|
+
}
|
|
46105
46592
|
this.canvasContext.resetTransform();
|
|
46106
|
-
triggerEvent(this.element, EVENTS.
|
|
46593
|
+
triggerEvent(this.element, EVENTS.STACK_NEW_IMAGE, {
|
|
46107
46594
|
element: this.element,
|
|
46108
46595
|
viewportId: this.id,
|
|
46109
46596
|
viewport: this,
|
|
@@ -46157,8 +46644,9 @@ class VideoViewport extends Viewport$1 {
|
|
|
46157
46644
|
this.removeEventListeners();
|
|
46158
46645
|
this.videoElement.remove();
|
|
46159
46646
|
}
|
|
46160
|
-
|
|
46161
|
-
const
|
|
46647
|
+
getImageDataMetadata(image) {
|
|
46648
|
+
const imageId = typeof image === 'string' ? image : image.imageId;
|
|
46649
|
+
const imagePlaneModule = getMetaData(MetadataModules$1.IMAGE_PLANE, imageId);
|
|
46162
46650
|
let rowCosines = imagePlaneModule.rowCosines;
|
|
46163
46651
|
let columnCosines = imagePlaneModule.columnCosines;
|
|
46164
46652
|
if (rowCosines == null || columnCosines == null) {
|
|
@@ -46171,8 +46659,6 @@ class VideoViewport extends Viewport$1 {
|
|
|
46171
46659
|
rows,
|
|
46172
46660
|
columns
|
|
46173
46661
|
} = imagePlaneModule;
|
|
46174
|
-
this.videoWidth = columns;
|
|
46175
|
-
this.videoHeight = rows;
|
|
46176
46662
|
const scanAxisNormal = vec3.create();
|
|
46177
46663
|
vec3.cross(scanAxisNormal, rowCosineVec, colCosineVec);
|
|
46178
46664
|
let origin = imagePlaneModule.imagePositionPatient;
|
|
@@ -46190,6 +46676,8 @@ class VideoViewport extends Viewport$1 {
|
|
|
46190
46676
|
bitsAllocated: 8,
|
|
46191
46677
|
numComps: 3,
|
|
46192
46678
|
origin,
|
|
46679
|
+
rows,
|
|
46680
|
+
columns,
|
|
46193
46681
|
direction: [...rowCosineVec, ...colCosineVec, ...scanAxisNormal],
|
|
46194
46682
|
dimensions: [xVoxels, yVoxels, zVoxels],
|
|
46195
46683
|
spacing: [xSpacing, ySpacing, zSpacing],
|
|
@@ -46205,7 +46693,7 @@ class VideoViewport extends Viewport$1 {
|
|
|
46205
46693
|
} = getMetaData(MetadataModules$1.IMAGE_URL, imageId);
|
|
46206
46694
|
const generalSeries = getMetaData(MetadataModules$1.GENERAL_SERIES, imageId);
|
|
46207
46695
|
this.modality = generalSeries?.Modality;
|
|
46208
|
-
this.metadata = this.
|
|
46696
|
+
this.metadata = this.getImageDataMetadata(imageId);
|
|
46209
46697
|
return this.setVideoURL(rendered).then(() => {
|
|
46210
46698
|
let {
|
|
46211
46699
|
cineRate,
|
|
@@ -46221,10 +46709,13 @@ class VideoViewport extends Viewport$1 {
|
|
|
46221
46709
|
this.numberOfFrames = numberOfFrames;
|
|
46222
46710
|
this.setFrameRange([1, numberOfFrames]);
|
|
46223
46711
|
this.play();
|
|
46224
|
-
|
|
46225
|
-
|
|
46226
|
-
|
|
46227
|
-
|
|
46712
|
+
return new Promise(resolve => {
|
|
46713
|
+
window.setTimeout(() => {
|
|
46714
|
+
this.pause();
|
|
46715
|
+
this.setFrameNumber(frameNumber || 1);
|
|
46716
|
+
resolve(this);
|
|
46717
|
+
}, 100);
|
|
46718
|
+
});
|
|
46228
46719
|
});
|
|
46229
46720
|
}
|
|
46230
46721
|
async setVideoURL(videoURL) {
|
|
@@ -46241,6 +46732,14 @@ class VideoViewport extends Viewport$1 {
|
|
|
46241
46732
|
this.videoElement.addEventListener('loadedmetadata', loadedMetadataEventHandler);
|
|
46242
46733
|
});
|
|
46243
46734
|
}
|
|
46735
|
+
getImageIds() {
|
|
46736
|
+
const imageIds = new Array(this.numberOfFrames);
|
|
46737
|
+
const baseImageId = this.imageId.replace(/[0-9]+$/, '');
|
|
46738
|
+
for (let i = 0; i < this.numberOfFrames; i++) {
|
|
46739
|
+
imageIds[i] = `${baseImageId}${i + 1}`;
|
|
46740
|
+
}
|
|
46741
|
+
return imageIds;
|
|
46742
|
+
}
|
|
46244
46743
|
togglePlayPause() {
|
|
46245
46744
|
if (this.isPlaying) {
|
|
46246
46745
|
this.pause();
|
|
@@ -46369,16 +46868,19 @@ class VideoViewport extends Viewport$1 {
|
|
|
46369
46868
|
});
|
|
46370
46869
|
}
|
|
46371
46870
|
getScalarData() {
|
|
46871
|
+
if (this.scalarData?.frameNumber === this.getFrameNumber()) {
|
|
46872
|
+
return this.scalarData;
|
|
46873
|
+
}
|
|
46372
46874
|
const canvas = document.createElement('canvas');
|
|
46373
46875
|
canvas.width = this.videoWidth;
|
|
46374
46876
|
canvas.height = this.videoHeight;
|
|
46375
46877
|
const context = canvas.getContext('2d');
|
|
46376
46878
|
context.drawImage(this.videoElement, 0, 0);
|
|
46377
46879
|
const canvasData = context.getImageData(0, 0, this.videoWidth, this.videoHeight);
|
|
46378
|
-
const
|
|
46379
|
-
data: scalarData
|
|
46380
|
-
} = canvasData;
|
|
46880
|
+
const scalarData = canvasData.data;
|
|
46381
46881
|
scalarData.getRange = () => [0, 255];
|
|
46882
|
+
scalarData.frameNumber = this.getFrameNumber();
|
|
46883
|
+
this.scalarData = scalarData;
|
|
46382
46884
|
return scalarData;
|
|
46383
46885
|
}
|
|
46384
46886
|
getImageData() {
|
|
@@ -46564,6 +47066,30 @@ class VideoViewport extends Viewport$1 {
|
|
|
46564
47066
|
transform.translate(-halfCanvasWorldCoordinates[0], -halfCanvasWorldCoordinates[1]);
|
|
46565
47067
|
return transform;
|
|
46566
47068
|
}
|
|
47069
|
+
updateCameraClippingPlanesAndRange() {}
|
|
47070
|
+
addImages(stackInputs) {
|
|
47071
|
+
const actors = this.getActors();
|
|
47072
|
+
stackInputs.forEach(stackInput => {
|
|
47073
|
+
const image = cache$1.getImage(stackInput.imageId);
|
|
47074
|
+
const imageActor = this.createActorMapper(image);
|
|
47075
|
+
if (imageActor) {
|
|
47076
|
+
actors.push({
|
|
47077
|
+
uid: stackInput.actorUID,
|
|
47078
|
+
actor: imageActor
|
|
47079
|
+
});
|
|
47080
|
+
if (stackInput.callback) {
|
|
47081
|
+
stackInput.callback({
|
|
47082
|
+
imageActor,
|
|
47083
|
+
imageId: stackInput.imageId
|
|
47084
|
+
});
|
|
47085
|
+
}
|
|
47086
|
+
}
|
|
47087
|
+
});
|
|
47088
|
+
this.setActors(actors);
|
|
47089
|
+
}
|
|
47090
|
+
createActorMapper(image) {
|
|
47091
|
+
return new CanvasActor(this, image);
|
|
47092
|
+
}
|
|
46567
47093
|
}
|
|
46568
47094
|
var VideoViewport$1 = VideoViewport;
|
|
46569
47095
|
|