diff --git a/web/src/labs/html2image/getCloneStyledElement.ts b/web/src/labs/html2image/getCloneStyledElement.ts
index c5b6ac8c..35de3b79 100644
--- a/web/src/labs/html2image/getCloneStyledElement.ts
+++ b/web/src/labs/html2image/getCloneStyledElement.ts
@@ -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;
diff --git a/web/src/labs/html2image/index.ts b/web/src/labs/html2image/index.ts
index 1392b30f..c32f4644 100644
--- a/web/src/labs/html2image/index.ts
+++ b/web/src/labs/html2image/index.ts
@@ -6,6 +6,7 @@
* 2. : 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 => {
- 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();
};
diff --git a/web/src/labs/html2image/waitImageLoaded.ts b/web/src/labs/html2image/waitImageLoaded.ts
new file mode 100644
index 00000000..21263381
--- /dev/null
+++ b/web/src/labs/html2image/waitImageLoaded.ts
@@ -0,0 +1,17 @@
+const waitImageLoaded = (image: HTMLImageElement, url: string): Promise => {
+ 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;
diff --git a/web/src/less/share-memo-image-dialog.less b/web/src/less/share-memo-image-dialog.less
index 9cce2af5..721a0645 100644
--- a/web/src/less/share-memo-image-dialog.less
+++ b/web/src/less/share-memo-image-dialog.less
@@ -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;
}
}
}