Skip to content

Commit 27bfacc

Browse files
fix(SegRendering): preserve canvas transform matrix after seg render
Previously after rendering the segmentation cornerstone was always transforming the canvas to follow the identity matrix, but in cases where we had an overlay using a different transformation matrix, it old undesirably affect the original overlay.
1 parent 73cd522 commit 27bfacc

File tree

3 files changed

+71
-28
lines changed

3 files changed

+71
-28
lines changed

src/eventListeners/internals/renderSegmentationFill.js

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
import { getModule } from '../../store/index.js';
2-
import {
3-
getNewContext,
4-
resetCanvasContextTransform,
5-
transformCanvasContext,
6-
} from '../../drawing/index.js';
2+
import { getNewContext, transformCanvasContext } from '../../drawing/index.js';
73
import external from '../../externalModules';
84

95
const segmentationModule = getModule('segmentation');
@@ -80,25 +76,25 @@ export function getLabelmapCanvas(evt, labelmap3D, labelmap2D) {
8076
export function renderFill(evt, labelmapCanvas, isActiveLabelMap) {
8177
const { configuration } = segmentationModule;
8278
const eventData = evt.detail;
83-
const context = getNewContext(eventData.canvasContext.canvas);
79+
const { canvasContext, element, image, viewport } = eventData;
8480

85-
const canvasTopLeft = external.cornerstone.pixelToCanvas(eventData.element, {
81+
const previousTransform = canvasContext.getTransform();
82+
const context = getNewContext(canvasContext.canvas);
83+
84+
const canvasTopLeft = external.cornerstone.pixelToCanvas(element, {
8685
x: 0,
8786
y: 0,
8887
});
8988

90-
const canvasTopRight = external.cornerstone.pixelToCanvas(eventData.element, {
91-
x: eventData.image.width,
89+
const canvasTopRight = external.cornerstone.pixelToCanvas(element, {
90+
x: image.width,
9291
y: 0,
9392
});
9493

95-
const canvasBottomRight = external.cornerstone.pixelToCanvas(
96-
eventData.element,
97-
{
98-
x: eventData.image.width,
99-
y: eventData.image.height,
100-
}
101-
);
94+
const canvasBottomRight = external.cornerstone.pixelToCanvas(element, {
95+
x: image.width,
96+
y: image.height,
97+
});
10298

10399
const cornerstoneCanvasWidth = external.cornerstoneMath.point.distance(
104100
canvasTopLeft,
@@ -109,8 +105,7 @@ export function renderFill(evt, labelmapCanvas, isActiveLabelMap) {
109105
canvasBottomRight
110106
);
111107

112-
const canvas = eventData.canvasContext.canvas;
113-
const viewport = eventData.viewport;
108+
const canvas = canvasContext.canvas;
114109

115110
const previousImageSmoothingEnabled = context.imageSmoothingEnabled;
116111
const previousGlobalAlpha = context.globalAlpha;
@@ -137,7 +132,7 @@ export function renderFill(evt, labelmapCanvas, isActiveLabelMap) {
137132
context.globalAlpha = previousGlobalAlpha;
138133
context.imageSmoothingEnabled = previousImageSmoothingEnabled;
139134

140-
resetCanvasContextTransform(context);
135+
context.setTransform(previousTransform);
141136
}
142137

143138
/**

src/eventListeners/internals/renderSegmentationOutline.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export function renderOutline(
4444

4545
const lineWidth = configuration.outlineWidth || 1;
4646

47+
const previousTransform = canvasContext.getTransform();
4748
const context = getNewContext(canvasContext.canvas);
4849
const colorLutTable = state.colorLutTables[colorLUTIndex];
4950

@@ -74,6 +75,7 @@ export function renderOutline(
7475
});
7576

7677
context.globalAlpha = previousAlpha;
78+
context.setTransform(previousTransform);
7779
}
7880

7981
/**

src/eventListeners/internals/renderSegmentationOutline.test.js

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,21 @@ import * as drawing from '../../drawing/index.js';
55

66
const { state } = getModule('segmentation');
77

8-
jest.mock('../../drawing/index.js', () => ({
9-
getNewContext: () => ({
8+
jest.mock('../../drawing/index.js', () => {
9+
const getNewContextMock = {
1010
globalAlpha: 1.0,
11-
}),
12-
draw: (context, callback) => {
13-
callback(context);
14-
},
15-
drawLines: jest.fn(),
16-
drawJoinedLines: jest.fn(),
17-
}));
11+
setTransform: jest.fn(),
12+
};
13+
14+
return {
15+
getNewContext: jest.fn(() => getNewContextMock),
16+
draw: (context, callback) => {
17+
callback(context);
18+
},
19+
drawLines: jest.fn(),
20+
drawJoinedLines: jest.fn(),
21+
};
22+
});
1823

1924
jest.mock('../../externalModules', () => ({
2025
cornerstone: {
@@ -132,6 +137,15 @@ function resetEvents() {
132137

133138
lineWidth = 1;
134139

140+
const canvasTransformState = {
141+
a: 0.078,
142+
b: 0,
143+
c: 0,
144+
d: 0.078,
145+
e: 52.9,
146+
f: 0,
147+
};
148+
135149
eventData = {
136150
element: null,
137151
image: {
@@ -154,6 +168,7 @@ function resetEvents() {
154168
width: canvasScale * width,
155169
height: canvasScale * width,
156170
},
171+
getTransform: jest.fn(() => canvasTransformState),
157172
},
158173
};
159174

@@ -224,8 +239,14 @@ function setCanvasTransform(options = {}) {
224239
}
225240

226241
describe('renderSegmentationOutline.js', () => {
242+
let getNewContext;
243+
227244
beforeEach(() => {
228245
resetEvents();
246+
247+
getNewContext = drawing.getNewContext;
248+
249+
jest.clearAllMocks();
229250
});
230251

231252
describe('Initialization', () => {
@@ -365,6 +386,31 @@ describe('renderSegmentationOutline.js', () => {
365386
});
366387

367388
describe('renderOutline', () => {
389+
it('should preserve the canvas transform matrix', () => {
390+
const outline = getOutline(evt, labelmap3D, labelmap2D, lineWidth);
391+
392+
// Fake colormap to stop renderOutline breaking.
393+
state.colorLutTables[0] = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]];
394+
395+
const beforeCallTransformMatrix = evt.detail.canvasContext.getTransform();
396+
const newContextSetTransform = getNewContext().setTransform;
397+
398+
evt.detail.canvasContext.getTransform.mockClear();
399+
getNewContext.mockClear();
400+
401+
renderOutline(evt, outline, 0, true);
402+
403+
expect(evt.detail.canvasContext.getTransform).toHaveBeenCalledTimes(1);
404+
expect(getNewContext).toHaveBeenCalledTimes(1);
405+
expect(getNewContext).toHaveBeenCalledWith(
406+
evt.detail.canvasContext.canvas
407+
);
408+
expect(newContextSetTransform).toHaveBeenCalledTimes(1);
409+
expect(newContextSetTransform).toHaveBeenCalledWith(
410+
beforeCallTransformMatrix
411+
);
412+
});
413+
368414
it('Should call drawLines twice', () => {
369415
const outline = getOutline(evt, labelmap3D, labelmap2D, lineWidth);
370416

0 commit comments

Comments
 (0)