fix: png-exporting does not preserve angles correctly for flipped images (#6085)

* fix: png-exporting does not preserve angles correctly for flipped images

* refactor related code

* simplify further and comment
This commit is contained in:
David Luzar 2023-01-08 16:22:04 +01:00 committed by GitHub
parent 40d53d9231
commit 809d5ba17f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 31 additions and 28 deletions

View File

@ -713,22 +713,8 @@ const drawElementFromCanvas = (
const cx = ((x1 + x2) / 2 + renderConfig.scrollX) * window.devicePixelRatio; const cx = ((x1 + x2) / 2 + renderConfig.scrollX) * window.devicePixelRatio;
const cy = ((y1 + y2) / 2 + renderConfig.scrollY) * window.devicePixelRatio; const cy = ((y1 + y2) / 2 + renderConfig.scrollY) * window.devicePixelRatio;
const _isPendingImageElement = isPendingImageElement(element, renderConfig);
const scaleXFactor =
"scale" in elementWithCanvas.element && !_isPendingImageElement
? elementWithCanvas.element.scale[0]
: 1;
const scaleYFactor =
"scale" in elementWithCanvas.element && !_isPendingImageElement
? elementWithCanvas.element.scale[1]
: 1;
context.save(); context.save();
context.scale( context.scale(1 / window.devicePixelRatio, 1 / window.devicePixelRatio);
(1 / window.devicePixelRatio) * scaleXFactor,
(1 / window.devicePixelRatio) * scaleYFactor,
);
const boundTextElement = getBoundTextElement(element); const boundTextElement = getBoundTextElement(element);
if (isArrowElement(element) && boundTextElement) { if (isArrowElement(element) && boundTextElement) {
@ -793,7 +779,7 @@ const drawElementFromCanvas = (
zoom, zoom,
); );
context.translate(cx * scaleXFactor, cy * scaleYFactor); context.translate(cx, cy);
context.drawImage( context.drawImage(
tempCanvas, tempCanvas,
(-(x2 - x1) / 2) * window.devicePixelRatio - offsetX / zoom - padding, (-(x2 - x1) / 2) * window.devicePixelRatio - offsetX / zoom - padding,
@ -802,15 +788,30 @@ const drawElementFromCanvas = (
tempCanvas.height / zoom, tempCanvas.height / zoom,
); );
} else { } else {
context.translate(cx * scaleXFactor, cy * scaleYFactor); // we translate context to element center so that rotation and scale
// originates from the element center
context.translate(cx, cy);
context.rotate(element.angle * scaleXFactor * scaleYFactor); context.rotate(element.angle);
if (
"scale" in elementWithCanvas.element &&
!isPendingImageElement(element, renderConfig)
) {
context.scale(
elementWithCanvas.element.scale[0],
elementWithCanvas.element.scale[1],
);
}
// revert afterwards we don't have account for it during drawing
context.translate(-cx, -cy);
context.drawImage( context.drawImage(
elementWithCanvas.canvas!, elementWithCanvas.canvas!,
(-(x2 - x1) / 2) * window.devicePixelRatio - (x1 + renderConfig.scrollX) * window.devicePixelRatio -
(padding * elementWithCanvas.canvasZoom) / elementWithCanvas.canvasZoom, (padding * elementWithCanvas.canvasZoom) / elementWithCanvas.canvasZoom,
(-(y2 - y1) / 2) * window.devicePixelRatio - (y1 + renderConfig.scrollY) * window.devicePixelRatio -
(padding * elementWithCanvas.canvasZoom) / elementWithCanvas.canvasZoom, (padding * elementWithCanvas.canvasZoom) / elementWithCanvas.canvasZoom,
elementWithCanvas.canvas!.width / elementWithCanvas.canvasZoom, elementWithCanvas.canvas!.width / elementWithCanvas.canvasZoom,
elementWithCanvas.canvas!.height / elementWithCanvas.canvasZoom, elementWithCanvas.canvas!.height / elementWithCanvas.canvasZoom,
@ -905,9 +906,6 @@ export const renderElement = (
} }
context.save(); context.save();
context.translate(cx, cy); context.translate(cx, cy);
if (element.type === "image") {
context.scale(element.scale[0], element.scale[1]);
}
if (shouldResetImageFilter(element, renderConfig)) { if (shouldResetImageFilter(element, renderConfig)) {
context.filter = "none"; context.filter = "none";
@ -973,6 +971,12 @@ export const renderElement = (
); );
} else { } else {
context.rotate(element.angle); context.rotate(element.angle);
if (element.type === "image") {
// note: scale must be applied *after* rotating
context.scale(element.scale[0], element.scale[1]);
}
context.translate(-shiftX, -shiftY); context.translate(-shiftX, -shiftY);
drawElementOnCanvas(element, rc, context, renderConfig); drawElementOnCanvas(element, rc, context, renderConfig);
} }

View File

@ -41,8 +41,8 @@ export const centerScrollOn = ({
zoom: Zoom; zoom: Zoom;
}) => { }) => {
return { return {
scrollX: (viewportDimensions.width / 2) * (1 / zoom.value) - scenePoint.x, scrollX: viewportDimensions.width / 2 / zoom.value - scenePoint.x,
scrollY: (viewportDimensions.height / 2) * (1 / zoom.value) - scenePoint.y, scrollY: viewportDimensions.height / 2 / zoom.value - scenePoint.y,
}; };
}; };

View File

@ -352,9 +352,8 @@ export const viewportCoordsToSceneCoords = (
scrollY: number; scrollY: number;
}, },
) => { ) => {
const invScale = 1 / zoom.value; const x = (clientX - offsetLeft) / zoom.value - scrollX;
const x = (clientX - offsetLeft) * invScale - scrollX; const y = (clientY - offsetTop) / zoom.value - scrollY;
const y = (clientY - offsetTop) * invScale - scrollY;
return { x, y }; return { x, y };
}; };