fix: SVG Inversion on Safari (#10712)
* invert image on safari * lint * Inversion to match theme filter * cleanup * Adjust canvas dimensions for device pixel ratio when inverting on Safari * revert inversion algo & handle darkMode placeholder --------- Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
This commit is contained in:
@@ -23,6 +23,7 @@ import {
|
|||||||
getVerticalOffset,
|
getVerticalOffset,
|
||||||
invariant,
|
invariant,
|
||||||
applyDarkModeFilter,
|
applyDarkModeFilter,
|
||||||
|
isSafari,
|
||||||
} from "@excalidraw/common";
|
} from "@excalidraw/common";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
@@ -360,8 +361,9 @@ IMAGE_ERROR_PLACEHOLDER_IMG.src = `data:${MIME_TYPES.svg},${encodeURIComponent(
|
|||||||
const drawImagePlaceholder = (
|
const drawImagePlaceholder = (
|
||||||
element: ExcalidrawImageElement,
|
element: ExcalidrawImageElement,
|
||||||
context: CanvasRenderingContext2D,
|
context: CanvasRenderingContext2D,
|
||||||
|
theme: StaticCanvasRenderConfig["theme"],
|
||||||
) => {
|
) => {
|
||||||
context.fillStyle = "#E7E7E7";
|
context.fillStyle = theme === THEME.DARK ? "#2E2E2E" : "#E7E7E7";
|
||||||
context.fillRect(0, 0, element.width, element.height);
|
context.fillRect(0, 0, element.width, element.height);
|
||||||
|
|
||||||
const imageMinWidthOrHeight = Math.min(element.width, element.height);
|
const imageMinWidthOrHeight = Math.min(element.width, element.height);
|
||||||
@@ -443,13 +445,6 @@ const drawElementOnCanvas = (
|
|||||||
? cacheEntry?.image
|
? cacheEntry?.image
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const shouldInvertImage =
|
|
||||||
renderConfig.theme === THEME.DARK &&
|
|
||||||
cacheEntry?.mimeType === MIME_TYPES.svg;
|
|
||||||
|
|
||||||
if (shouldInvertImage) {
|
|
||||||
context.filter = DARK_THEME_FILTER;
|
|
||||||
}
|
|
||||||
if (img != null && !(img instanceof Promise)) {
|
if (img != null && !(img instanceof Promise)) {
|
||||||
if (element.roundness && context.roundRect) {
|
if (element.roundness && context.roundRect) {
|
||||||
context.beginPath();
|
context.beginPath();
|
||||||
@@ -472,19 +467,78 @@ const drawElementOnCanvas = (
|
|||||||
height: img.naturalHeight,
|
height: img.naturalHeight,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.drawImage(
|
const shouldInvertImage =
|
||||||
img,
|
renderConfig.theme === THEME.DARK &&
|
||||||
x,
|
cacheEntry?.mimeType === MIME_TYPES.svg;
|
||||||
y,
|
|
||||||
width,
|
if (shouldInvertImage && isSafari) {
|
||||||
height,
|
const devicePixelRatio = window.devicePixelRatio || 1;
|
||||||
0 /* hardcoded for the selection box*/,
|
const tempCanvas = document.createElement("canvas");
|
||||||
0,
|
tempCanvas.width = element.width * devicePixelRatio;
|
||||||
element.width,
|
tempCanvas.height = element.height * devicePixelRatio;
|
||||||
element.height,
|
const tempContext = tempCanvas.getContext("2d");
|
||||||
);
|
|
||||||
|
if (tempContext) {
|
||||||
|
tempContext.scale(devicePixelRatio, devicePixelRatio);
|
||||||
|
tempContext.drawImage(
|
||||||
|
img,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
element.width,
|
||||||
|
element.height,
|
||||||
|
);
|
||||||
|
|
||||||
|
const imageData = tempContext.getImageData(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
tempCanvas.width,
|
||||||
|
tempCanvas.height,
|
||||||
|
);
|
||||||
|
|
||||||
|
const data = imageData.data;
|
||||||
|
|
||||||
|
for (let i = 0; i < data.length; i += 4) {
|
||||||
|
data[i] = 255 - data[i];
|
||||||
|
data[i + 1] = 255 - data[i + 1];
|
||||||
|
data[i + 2] = 255 - data[i + 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
tempContext.putImageData(imageData, 0, 0);
|
||||||
|
context.drawImage(
|
||||||
|
tempCanvas,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
tempCanvas.width,
|
||||||
|
tempCanvas.height,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
element.width,
|
||||||
|
element.height,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (shouldInvertImage) {
|
||||||
|
context.filter = DARK_THEME_FILTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.drawImage(
|
||||||
|
img,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
0 /* hardcoded for the selection box*/,
|
||||||
|
0,
|
||||||
|
element.width,
|
||||||
|
element.height,
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
drawImagePlaceholder(element, context);
|
drawImagePlaceholder(element, context, renderConfig.theme);
|
||||||
}
|
}
|
||||||
context.restore();
|
context.restore();
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user