@cornerstonejs/core 4.2.3 → 4.3.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.
@@ -9,6 +9,7 @@ import type vtkRenderer from '@kitware/vtk.js/Rendering/Core/Renderer';
9
9
  declare abstract class BaseVolumeViewport extends Viewport {
10
10
  useCPURendering: boolean;
11
11
  private _FrameOfReferenceUID;
12
+ private sharpening;
12
13
  protected initialTransferFunctionNodes: TransferFunctionNodes;
13
14
  private globalDefaultProperties;
14
15
  private perVolumeIdDefaultProperties;
@@ -47,7 +48,10 @@ declare abstract class BaseVolumeViewport extends Viewport {
47
48
  setViewPlane(planeRestriction: PlaneRestriction): void;
48
49
  setViewReference(viewRef: ViewReference): void;
49
50
  private setThreshold;
50
- setProperties({ voiRange, VOILUTFunction, invert, colormap, preset, interpolationType, slabThickness, sampleDistanceMultiplier, }?: VolumeViewportProperties, volumeId?: string, suppressEvents?: boolean): void;
51
+ setProperties({ voiRange, VOILUTFunction, invert, colormap, preset, interpolationType, slabThickness, sampleDistanceMultiplier, sharpening, }?: VolumeViewportProperties, volumeId?: string, suppressEvents?: boolean): void;
52
+ private setSharpening;
53
+ protected shouldUseCustomRenderPass(): boolean;
54
+ getRenderPasses: () => any[];
51
55
  resetToDefaultProperties(volumeId: string): void;
52
56
  private setPreset;
53
57
  setSampleDistanceMultiplier(multiplier: number): void;
@@ -30,10 +30,12 @@ import * as metaData from '../metaData';
30
30
  import { getCameraVectors } from './helpers/getCameraVectors';
31
31
  import { isContextPoolRenderingEngine } from './helpers/isContextPoolRenderingEngine';
32
32
  import mprCameraValues from '../constants/mprCameraValues';
33
+ import { createSharpeningRenderPass } from './renderPasses';
33
34
  class BaseVolumeViewport extends Viewport {
34
35
  constructor(props) {
35
36
  super(props);
36
37
  this.useCPURendering = false;
38
+ this.sharpening = 0;
37
39
  this.perVolumeIdDefaultProperties = new Map();
38
40
  this.viewportProperties = {};
39
41
  this.volumeIds = new Set();
@@ -69,6 +71,22 @@ class BaseVolumeViewport extends Viewport {
69
71
  };
70
72
  triggerEvent(this.element, Events.CAMERA_MODIFIED, eventDetail);
71
73
  };
74
+ this.setSharpening = (sharpening) => {
75
+ this.sharpening = sharpening;
76
+ this.render();
77
+ };
78
+ this.getRenderPasses = () => {
79
+ if (!this.shouldUseCustomRenderPass()) {
80
+ return null;
81
+ }
82
+ try {
83
+ return [createSharpeningRenderPass(this.sharpening)];
84
+ }
85
+ catch (e) {
86
+ console.warn('Failed to create sharpening render passes:', e);
87
+ return null;
88
+ }
89
+ };
72
90
  this.getDefaultProperties = (volumeId) => {
73
91
  let volumeProperties;
74
92
  if (volumeId !== undefined) {
@@ -114,6 +132,7 @@ class BaseVolumeViewport extends Viewport {
114
132
  invert: invert,
115
133
  slabThickness: slabThickness,
116
134
  preset,
135
+ sharpening: this.sharpening,
117
136
  };
118
137
  };
119
138
  this.getColormap = (volumeId) => {
@@ -172,13 +191,16 @@ class BaseVolumeViewport extends Viewport {
172
191
  const devicePixelRatio = window.devicePixelRatio || 1;
173
192
  const { width, height } = this.canvas;
174
193
  const aspectRatio = width / height;
194
+ const [xMin, yMin, xMax, yMax] = renderer.getViewport();
195
+ const viewportWidth = xMax - xMin;
196
+ const viewportHeight = yMax - yMin;
175
197
  const canvasPosWithDPR = [
176
198
  canvasPos[0] * devicePixelRatio,
177
199
  canvasPos[1] * devicePixelRatio,
178
200
  ];
179
201
  const normalizedDisplay = [
180
- canvasPosWithDPR[0] / width,
181
- 1 - canvasPosWithDPR[1] / height,
202
+ xMin + (canvasPosWithDPR[0] / width) * viewportWidth,
203
+ yMin + (1 - canvasPosWithDPR[1] / height) * viewportHeight,
182
204
  0,
183
205
  ];
184
206
  const projCoords = renderer.normalizedDisplayToProjection(normalizedDisplay[0], normalizedDisplay[1], normalizedDisplay[2]);
@@ -209,8 +231,14 @@ class BaseVolumeViewport extends Viewport {
209
231
  canvasPos[0] * devicePixelRatio,
210
232
  canvasPos[1] * devicePixelRatio,
211
233
  ];
212
- const { height } = this.canvas;
213
- const displayCoord = [canvasPosWithDPR[0], height - canvasPosWithDPR[1]];
234
+ const renderer = this.getRenderer();
235
+ const { width, height } = this.canvas;
236
+ const [xMin, yMin, xMax, yMax] = renderer.getViewport();
237
+ const viewportWidth = xMax - xMin;
238
+ const viewportHeight = yMax - yMin;
239
+ const scaledX = (canvasPosWithDPR[0] / width) * viewportWidth * width;
240
+ const scaledY = (canvasPosWithDPR[1] / height) * viewportHeight * height;
241
+ const displayCoord = [scaledX, viewportHeight * height - scaledY];
214
242
  return [displayCoord[0], displayCoord[1], 0];
215
243
  };
216
244
  this.worldToCanvasTiled = (worldPos) => {
@@ -240,11 +268,16 @@ class BaseVolumeViewport extends Viewport {
240
268
  const renderer = this.getRenderer();
241
269
  const { width, height } = this.canvas;
242
270
  const aspectRatio = width / height;
271
+ const [xMin, yMin, xMax, yMax] = renderer.getViewport();
272
+ const viewportWidth = xMax - xMin;
273
+ const viewportHeight = yMax - yMin;
243
274
  const viewCoords = renderer.worldToView(worldPos[0], worldPos[1], worldPos[2]);
244
275
  const projCoords = renderer.viewToProjection(viewCoords[0], viewCoords[1], viewCoords[2], aspectRatio);
245
276
  const normalizedDisplay = renderer.projectionToNormalizedDisplay(projCoords[0], projCoords[1], projCoords[2]);
246
- const canvasX = normalizedDisplay[0] * width;
247
- const canvasY = (1 - normalizedDisplay[1]) * height;
277
+ const canvasNormalizedX = (normalizedDisplay[0] - xMin) / viewportWidth;
278
+ const canvasNormalizedY = (normalizedDisplay[1] - yMin) / viewportHeight;
279
+ const canvasX = canvasNormalizedX * width;
280
+ const canvasY = (1 - canvasNormalizedY) * height;
248
281
  const devicePixelRatio = window.devicePixelRatio || 1;
249
282
  const canvasCoordWithDPR = [
250
283
  canvasX / devicePixelRatio,
@@ -720,7 +753,7 @@ class BaseVolumeViewport extends Viewport {
720
753
  };
721
754
  triggerEvent(this.element, Events.COLORMAP_MODIFIED, eventDetail);
722
755
  }
723
- setProperties({ voiRange, VOILUTFunction, invert, colormap, preset, interpolationType, slabThickness, sampleDistanceMultiplier, } = {}, volumeId, suppressEvents = false) {
756
+ setProperties({ voiRange, VOILUTFunction, invert, colormap, preset, interpolationType, slabThickness, sampleDistanceMultiplier, sharpening, } = {}, volumeId, suppressEvents = false) {
724
757
  if (this.globalDefaultProperties == null) {
725
758
  this.setDefaultProperties({
726
759
  voiRange,
@@ -761,6 +794,12 @@ class BaseVolumeViewport extends Viewport {
761
794
  if (sampleDistanceMultiplier !== undefined) {
762
795
  this.setSampleDistanceMultiplier(sampleDistanceMultiplier);
763
796
  }
797
+ if (typeof sharpening !== 'undefined') {
798
+ this.setSharpening(sharpening);
799
+ }
800
+ }
801
+ shouldUseCustomRenderPass() {
802
+ return this.sharpening > 0 && !this.useCPURendering;
764
803
  }
765
804
  resetToDefaultProperties(volumeId) {
766
805
  const properties = this.globalDefaultProperties;
@@ -20,6 +20,7 @@ declare class ContextPoolRenderingEngine extends BaseRenderingEngine {
20
20
  private _copyToOnscreenCanvas;
21
21
  private _resize;
22
22
  private getWidgetRenderers;
23
+ private getViewportRenderPasses;
23
24
  getRenderer(viewportId: string): vtkRenderer | undefined;
24
25
  disableElement(viewportId: string): void;
25
26
  destroy(): void;
@@ -200,6 +200,12 @@ class ContextPoolRenderingEngine extends BaseRenderingEngine {
200
200
  });
201
201
  }
202
202
  const renderWindow = offscreenMultiRenderWindow.getRenderWindow();
203
+ const view = renderWindow.getViews()[0];
204
+ const originalRenderPasses = view.getRenderPasses();
205
+ const viewportRenderPasses = this.getViewportRenderPasses(viewport.id);
206
+ if (viewportRenderPasses) {
207
+ view.setRenderPasses(viewportRenderPasses);
208
+ }
203
209
  this._resizeOffScreenCanvasForViewport(viewport, offScreenCanvasContainer, offscreenMultiRenderWindow);
204
210
  const renderer = offscreenMultiRenderWindow.getRenderer(viewport.id);
205
211
  const contextIndex = this.contextPool.getContextIndexForViewport(viewport.id);
@@ -222,6 +228,9 @@ class ContextPoolRenderingEngine extends BaseRenderingEngine {
222
228
  widgetRenderers.forEach((_, renderer) => {
223
229
  renderer.setDraw(false);
224
230
  });
231
+ if (originalRenderPasses) {
232
+ view.setRenderPasses(originalRenderPasses);
233
+ }
225
234
  const openGLRenderWindow = offscreenMultiRenderWindow.getOpenGLRenderWindow();
226
235
  const context = openGLRenderWindow.get3DContext();
227
236
  const offScreenCanvas = context.canvas;
@@ -310,6 +319,10 @@ class ContextPoolRenderingEngine extends BaseRenderingEngine {
310
319
  });
311
320
  return widgetRenderers;
312
321
  }
322
+ getViewportRenderPasses(viewportId) {
323
+ const viewport = this.getViewport(viewportId);
324
+ return viewport?.getRenderPasses ? viewport.getRenderPasses() : null;
325
+ }
313
326
  getRenderer(viewportId) {
314
327
  const contextIndex = this.contextPool?.getContextIndexForViewport(viewportId);
315
328
  const contextData = this.contextPool.getContextByIndex(contextIndex);
@@ -27,6 +27,7 @@ declare class StackViewport extends Viewport {
27
27
  private colormap;
28
28
  private voiRange;
29
29
  private voiUpdatedWithSetProperties;
30
+ private sharpening;
30
31
  private VOILUTFunction;
31
32
  private invert;
32
33
  private initialInvert;
@@ -76,6 +77,9 @@ declare class StackViewport extends Viewport {
76
77
  protected setInterpolationType: (interpolationType: InterpolationType) => void;
77
78
  private setInvertColor;
78
79
  private setColormap;
80
+ private setSharpening;
81
+ protected shouldUseCustomRenderPass(): boolean;
82
+ getRenderPasses: () => any[];
79
83
  private initializeElementDisabledHandler;
80
84
  resize: () => void;
81
85
  private _resizeCPU;
@@ -88,7 +92,7 @@ declare class StackViewport extends Viewport {
88
92
  private calibrateIfNecessary;
89
93
  setDefaultProperties(ViewportProperties: StackViewportProperties, imageId?: string): void;
90
94
  clearDefaultProperties(imageId?: string): void;
91
- setProperties({ colormap, voiRange, VOILUTFunction, invert, interpolationType, }?: StackViewportProperties, suppressEvents?: boolean): void;
95
+ setProperties({ colormap, voiRange, VOILUTFunction, invert, interpolationType, sharpening, }?: StackViewportProperties, suppressEvents?: boolean): void;
92
96
  getDefaultProperties: (imageId?: string) => StackViewportProperties;
93
97
  getProperties: () => StackViewportProperties;
94
98
  resetCameraForResize: () => boolean;
@@ -44,7 +44,7 @@ import getSpacingInNormalDirection from '../utilities/getSpacingInNormalDirectio
44
44
  import getClosestImageId from '../utilities/getClosestImageId';
45
45
  import { adjustInitialViewUp } from '../utilities/adjustInitialViewUp';
46
46
  import { isContextPoolRenderingEngine } from './helpers/isContextPoolRenderingEngine';
47
- const EPSILON = 1;
47
+ import { createSharpeningRenderPass } from './renderPasses';
48
48
  const log = coreLog.getLogger('RenderingEngine', 'StackViewport');
49
49
  class StackViewport extends Viewport {
50
50
  constructor(props) {
@@ -57,6 +57,7 @@ class StackViewport extends Viewport {
57
57
  this.globalDefaultProperties = {};
58
58
  this.perImageIdDefaultProperties = new Map();
59
59
  this.voiUpdatedWithSetProperties = false;
60
+ this.sharpening = 0;
60
61
  this.invert = false;
61
62
  this.initialInvert = false;
62
63
  this.initialTransferFunctionNodes = null;
@@ -65,6 +66,22 @@ class StackViewport extends Viewport {
65
66
  this.updateRenderingPipeline = () => {
66
67
  this._configureRenderingPipeline();
67
68
  };
69
+ this.setSharpening = (sharpening) => {
70
+ this.sharpening = sharpening;
71
+ this.render();
72
+ };
73
+ this.getRenderPasses = () => {
74
+ if (!this.shouldUseCustomRenderPass()) {
75
+ return null;
76
+ }
77
+ try {
78
+ return [createSharpeningRenderPass(this.sharpening)];
79
+ }
80
+ catch (e) {
81
+ console.warn('Failed to create sharpening render passes:', e);
82
+ return null;
83
+ }
84
+ };
68
85
  this.resize = () => {
69
86
  if (this.useCPURendering) {
70
87
  this._resizeCPU();
@@ -115,6 +132,7 @@ class StackViewport extends Viewport {
115
132
  interpolationType,
116
133
  invert,
117
134
  isComputedVOI: !voiUpdatedWithSetProperties,
135
+ sharpening: this.sharpening,
118
136
  };
119
137
  };
120
138
  this.resetCameraForResize = () => {
@@ -209,9 +227,13 @@ class StackViewport extends Viewport {
209
227
  canvasPos[0] * devicePixelRatio,
210
228
  canvasPos[1] * devicePixelRatio,
211
229
  ];
230
+ const viewport = renderer.getViewport();
231
+ const [xStart, yStart, xEnd, yEnd] = viewport;
232
+ const viewportWidth = xEnd - xStart;
233
+ const viewportHeight = yEnd - yStart;
212
234
  const normalizedDisplay = [
213
- canvasPosWithDPR[0] / width,
214
- 1 - canvasPosWithDPR[1] / height,
235
+ xStart + (canvasPosWithDPR[0] / width) * viewportWidth,
236
+ yStart + (1 - canvasPosWithDPR[1] / height) * viewportHeight,
215
237
  0,
216
238
  ];
217
239
  const projCoords = renderer.normalizedDisplayToProjection(normalizedDisplay[0], normalizedDisplay[1], normalizedDisplay[2]);
@@ -255,8 +277,12 @@ class StackViewport extends Viewport {
255
277
  const viewCoords = renderer.worldToView(worldPos[0], worldPos[1], worldPos[2]);
256
278
  const projCoords = renderer.viewToProjection(viewCoords[0], viewCoords[1], viewCoords[2], aspectRatio);
257
279
  const normalizedDisplay = renderer.projectionToNormalizedDisplay(projCoords[0], projCoords[1], projCoords[2]);
258
- const canvasX = normalizedDisplay[0] * width;
259
- const canvasY = (1 - normalizedDisplay[1]) * height;
280
+ const viewport = renderer.getViewport();
281
+ const [xStart, yStart, xEnd, yEnd] = viewport;
282
+ const viewportWidth = xEnd - xStart;
283
+ const viewportHeight = yEnd - yStart;
284
+ const canvasX = ((normalizedDisplay[0] - xStart) / viewportWidth) * width;
285
+ const canvasY = (1 - (normalizedDisplay[1] - yStart) / viewportHeight) * height;
260
286
  vtkCamera.setClippingRange(crange[0], crange[1]);
261
287
  const canvasCoordWithDPR = [
262
288
  canvasX / devicePixelRatio,
@@ -508,6 +534,9 @@ class StackViewport extends Viewport {
508
534
  camera.setThicknessFromFocalPoint(0.1);
509
535
  camera.setFreezeFocalPoint(true);
510
536
  }
537
+ shouldUseCustomRenderPass() {
538
+ return this.sharpening > 0 && !this.useCPURendering;
539
+ }
511
540
  initializeElementDisabledHandler() {
512
541
  eventTarget.addEventListener(Events.ELEMENT_DISABLED, function elementDisabledHandler() {
513
542
  clearTimeout(this.debouncedTimeout);
@@ -629,7 +658,7 @@ class StackViewport extends Viewport {
629
658
  this.resetToDefaultProperties();
630
659
  }
631
660
  }
632
- setProperties({ colormap, voiRange, VOILUTFunction, invert, interpolationType, } = {}, suppressEvents = false) {
661
+ setProperties({ colormap, voiRange, VOILUTFunction, invert, interpolationType, sharpening, } = {}, suppressEvents = false) {
633
662
  this.viewportStatus = this.csImage
634
663
  ? ViewportStatus.PRE_RENDER
635
664
  : ViewportStatus.LOADING;
@@ -639,6 +668,7 @@ class StackViewport extends Viewport {
639
668
  VOILUTFunction: this.globalDefaultProperties.VOILUTFunction ?? VOILUTFunction,
640
669
  invert: this.globalDefaultProperties.invert ?? invert,
641
670
  interpolationType: this.globalDefaultProperties.interpolationType ?? interpolationType,
671
+ sharpening: this.globalDefaultProperties.sharpening ?? sharpening,
642
672
  };
643
673
  if (typeof colormap !== 'undefined') {
644
674
  this.setColormap(colormap);
@@ -656,6 +686,9 @@ class StackViewport extends Viewport {
656
686
  if (typeof interpolationType !== 'undefined') {
657
687
  this.setInterpolationType(interpolationType);
658
688
  }
689
+ if (typeof sharpening !== 'undefined') {
690
+ this.setSharpening(sharpening);
691
+ }
659
692
  }
660
693
  resetProperties() {
661
694
  this.cpuRenderingInvalidated = true;
@@ -1452,7 +1485,7 @@ class StackViewport extends Viewport {
1452
1485
  renderingEngineId: this.renderingEngineId,
1453
1486
  };
1454
1487
  triggerEvent(this.element, Events.PRE_STACK_NEW_IMAGE, eventDetail);
1455
- return this.imagesLoader.loadImages([imageId], this).then((v) => {
1488
+ return this.imagesLoader.loadImages([imageId], this).then(() => {
1456
1489
  return imageId;
1457
1490
  });
1458
1491
  }
@@ -1776,7 +1809,7 @@ class StackViewport extends Viewport {
1776
1809
  return true;
1777
1810
  }
1778
1811
  viewRef.referencedImageURI ||= imageIdToURI(referencedImageId);
1779
- const { referencedImageURI: referencedImageURI } = viewRef;
1812
+ const { referencedImageURI } = viewRef;
1780
1813
  const foundSliceIndex = this.imageKeyToIndexMap.get(referencedImageURI);
1781
1814
  if (options.asOverlay) {
1782
1815
  const matchedImageId = this.matchImagesForOverlay(currentImageId, referencedImageId);
@@ -1843,7 +1876,7 @@ class StackViewport extends Viewport {
1843
1876
  }
1844
1877
  const { referencedImageId } = viewRef;
1845
1878
  viewRef.referencedImageURI ||= imageIdToURI(referencedImageId);
1846
- const { referencedImageURI: referencedImageURI } = viewRef;
1879
+ const { referencedImageURI } = viewRef;
1847
1880
  const sliceIndex = this.imageKeyToIndexMap.get(referencedImageURI);
1848
1881
  if (sliceIndex === undefined) {
1849
1882
  log.error(`No image URI found for ${referencedImageURI}`);
@@ -51,6 +51,7 @@ declare class Viewport {
51
51
  addWidget: (widgetId: any, widget: any) => void;
52
52
  getWidget: (id: any) => any;
53
53
  getWidgets: () => any[];
54
+ getRenderPasses: () => any;
54
55
  removeWidgets: () => void;
55
56
  setRendered(): void;
56
57
  protected setColorTransform(voiRange: any, averageWhite: any): any;
@@ -50,6 +50,9 @@ class Viewport {
50
50
  this.getWidgets = () => {
51
51
  return Array.from(this.viewportWidgets.values());
52
52
  };
53
+ this.getRenderPasses = () => {
54
+ return null;
55
+ };
53
56
  this.removeWidgets = () => {
54
57
  const widgets = this.getWidgets();
55
58
  widgets.forEach((widget) => {
@@ -0,0 +1,2 @@
1
+ import { createSharpeningRenderPass } from './sharpeningRenderPass';
2
+ export { createSharpeningRenderPass };
@@ -0,0 +1,2 @@
1
+ import { createSharpeningRenderPass } from './sharpeningRenderPass';
2
+ export { createSharpeningRenderPass };
@@ -0,0 +1,2 @@
1
+ declare function createSharpeningRenderPass(intensity: number): any;
2
+ export { createSharpeningRenderPass };
@@ -0,0 +1,15 @@
1
+ import vtkConvolution2DPass from '@kitware/vtk.js/Rendering/OpenGL/Convolution2DPass';
2
+ import vtkForwardPass from '@kitware/vtk.js/Rendering/OpenGL/ForwardPass';
3
+ function createSharpeningRenderPass(intensity) {
4
+ let renderPass = vtkForwardPass.newInstance();
5
+ if (intensity > 0) {
6
+ const convolutionPass = vtkConvolution2DPass.newInstance();
7
+ convolutionPass.setDelegates([renderPass]);
8
+ const k = Math.max(0, intensity);
9
+ convolutionPass.setKernelDimension(3);
10
+ convolutionPass.setKernel([-k, -k, -k, -k, 1 + 8 * k, -k, -k, -k, -k]);
11
+ renderPass = convolutionPass;
12
+ }
13
+ return renderPass;
14
+ }
15
+ export { createSharpeningRenderPass };
@@ -9,4 +9,5 @@ export interface ViewportProperties {
9
9
  interpolationType?: InterpolationType;
10
10
  preset?: string;
11
11
  sampleDistanceMultiplier?: number;
12
+ sharpening?: number;
12
13
  }
@@ -1 +1 @@
1
- export declare const version = "4.2.3";
1
+ export declare const version = "4.3.0";
@@ -1 +1 @@
1
- export const version = '4.2.3';
1
+ export const version = '4.3.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cornerstonejs/core",
3
- "version": "4.2.3",
3
+ "version": "4.3.0",
4
4
  "description": "Cornerstone3D Core",
5
5
  "module": "./dist/esm/index.js",
6
6
  "types": "./dist/esm/index.d.ts",
@@ -97,5 +97,5 @@
97
97
  "type": "individual",
98
98
  "url": "https://ohif.org/donate"
99
99
  },
100
- "gitHead": "d924485f9e0adcb67e8064f8a6356519d43cf36c"
100
+ "gitHead": "cf613e09e1bb68bd7859092ba02e9ce3603ce3da"
101
101
  }