mirror of
https://github.com/usememos/memos.git
synced 2025-02-16 11:21:02 +01:00
fix: generate html image in safari (#123)
This commit is contained in:
parent
2a1e34fe03
commit
167e5596f2
@ -1,34 +1,33 @@
|
||||
import convertResourceToDataURL from "./convertResourceToDataURL";
|
||||
|
||||
const applyStyles = async (sourceElement: HTMLElement, clonedElement: HTMLElement) => {
|
||||
if (!sourceElement || !clonedElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sourceElement.tagName === "IMG") {
|
||||
try {
|
||||
const url = await convertResourceToDataURL(sourceElement.getAttribute("src") ?? "");
|
||||
(clonedElement as HTMLImageElement).src = url;
|
||||
} catch (error) {
|
||||
// do nth
|
||||
}
|
||||
}
|
||||
|
||||
const sourceStyles = window.getComputedStyle(sourceElement);
|
||||
for (const item of sourceStyles) {
|
||||
clonedElement.style.setProperty(item, sourceStyles.getPropertyValue(item), sourceStyles.getPropertyPriority(item));
|
||||
}
|
||||
|
||||
for (let i = 0; i < clonedElement.childElementCount; i++) {
|
||||
await applyStyles(sourceElement.children[i] as HTMLElement, clonedElement.children[i] as HTMLElement);
|
||||
}
|
||||
};
|
||||
|
||||
const getCloneStyledElement = async (element: HTMLElement) => {
|
||||
const clonedElementContainer = document.createElement(element.tagName);
|
||||
clonedElementContainer.innerHTML = element.innerHTML;
|
||||
|
||||
const applyStyles = async (sourceElement: HTMLElement, clonedElement: HTMLElement) => {
|
||||
if (!sourceElement || !clonedElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sourceStyles = window.getComputedStyle(sourceElement);
|
||||
|
||||
if (sourceElement.tagName === "IMG") {
|
||||
try {
|
||||
const url = await convertResourceToDataURL(sourceElement.getAttribute("src") ?? "");
|
||||
(clonedElement as HTMLImageElement).src = url;
|
||||
} catch (error) {
|
||||
// do nth
|
||||
}
|
||||
}
|
||||
|
||||
for (const item of sourceStyles) {
|
||||
clonedElement.style.setProperty(item, sourceStyles.getPropertyValue(item), sourceStyles.getPropertyPriority(item));
|
||||
}
|
||||
|
||||
for (let i = 0; i < clonedElement.childElementCount; i++) {
|
||||
await applyStyles(sourceElement.children[i] as HTMLElement, clonedElement.children[i] as HTMLElement);
|
||||
}
|
||||
};
|
||||
|
||||
await applyStyles(element, clonedElementContainer);
|
||||
|
||||
return clonedElementContainer;
|
||||
|
@ -6,6 +6,7 @@
|
||||
* 2. <foreignObject>: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/foreignObject
|
||||
*/
|
||||
import getCloneStyledElement from "./getCloneStyledElement";
|
||||
import waitImageLoaded from "./waitImageLoaded";
|
||||
|
||||
type Options = Partial<{
|
||||
backgroundColor: string;
|
||||
@ -51,7 +52,6 @@ const generateSVGElement = (width: number, height: number, element: HTMLElement)
|
||||
|
||||
export const toSVG = async (element: HTMLElement, options?: Options) => {
|
||||
const { width, height } = getElementSize(element);
|
||||
|
||||
const clonedElement = await getCloneStyledElement(element);
|
||||
|
||||
if (options?.backgroundColor) {
|
||||
@ -65,11 +65,6 @@ export const toSVG = async (element: HTMLElement, options?: Options) => {
|
||||
};
|
||||
|
||||
export const toCanvas = async (element: HTMLElement, options?: Options): Promise<HTMLCanvasElement> => {
|
||||
const url = await toSVG(element, options);
|
||||
|
||||
const imageEl = new Image();
|
||||
imageEl.src = url;
|
||||
|
||||
const ratio = options?.pixelRatio || 1;
|
||||
const { width, height } = getElementSize(element);
|
||||
|
||||
@ -91,18 +86,20 @@ export const toCanvas = async (element: HTMLElement, options?: Options): Promise
|
||||
context.fillRect(0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
imageEl.onload = () => {
|
||||
context.drawImage(imageEl, 0, 0, canvas.width, canvas.height);
|
||||
|
||||
resolve(canvas);
|
||||
};
|
||||
});
|
||||
const url = await toSVG(element, options);
|
||||
const imageEl = new Image();
|
||||
imageEl.style.zIndex = "-1";
|
||||
imageEl.style.position = "absolute";
|
||||
imageEl.style.top = "0";
|
||||
document.body.append(imageEl);
|
||||
await waitImageLoaded(imageEl, url);
|
||||
context.drawImage(imageEl, 0, 0, canvas.width, canvas.height);
|
||||
imageEl.remove();
|
||||
return canvas;
|
||||
};
|
||||
|
||||
const toImage = async (element: HTMLElement, options?: Options) => {
|
||||
const canvas = await toCanvas(element, options);
|
||||
|
||||
return canvas.toDataURL();
|
||||
};
|
||||
|
||||
|
17
web/src/labs/html2image/waitImageLoaded.ts
Normal file
17
web/src/labs/html2image/waitImageLoaded.ts
Normal file
@ -0,0 +1,17 @@
|
||||
const waitImageLoaded = (image: HTMLImageElement, url: string): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
image.loading = "eager";
|
||||
image.onload = () => {
|
||||
// NOTE: There is image loading problem in Safari, fix it with some trick
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, 200);
|
||||
};
|
||||
image.onerror = () => {
|
||||
reject("Image load failed");
|
||||
};
|
||||
image.src = url;
|
||||
});
|
||||
};
|
||||
|
||||
export default waitImageLoaded;
|
@ -63,14 +63,14 @@
|
||||
@apply flex flex-row justify-start items-center w-full py-3 px-6;
|
||||
|
||||
> .normal-text {
|
||||
@apply w-full flex flex-row justify-start items-center text-sm text-gray-500;
|
||||
|
||||
> .name-text {
|
||||
@apply text-black ml-2;
|
||||
}
|
||||
@apply w-full flex flex-row justify-start items-center text-sm leading-6 text-gray-500;
|
||||
|
||||
> .icon-text {
|
||||
@apply text-lg ml-1 mr-2;
|
||||
@apply text-lg ml-1 mr-2 leading-6;
|
||||
}
|
||||
|
||||
> .name-text {
|
||||
@apply text-black ml-2 leading-6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user