diff --git a/src/components/ExportDialog.tsx b/src/components/ExportDialog.tsx index 52ceba1b..72d0218f 100644 --- a/src/components/ExportDialog.tsx +++ b/src/components/ExportDialog.tsx @@ -156,7 +156,6 @@ const ExportModal = ({ {actionManager.renderAction("changeExportBackground")} - {actionManager.renderAction("changeExportEmbedScene")} {someElementIsSelected && (
)} + {actionManager.renderAction("changeExportEmbedScene")} {actionManager.renderAction("changeShouldAddWatermark")} diff --git a/src/data/blob.ts b/src/data/blob.ts index b1ffa847..f2e84fb8 100644 --- a/src/data/blob.ts +++ b/src/data/blob.ts @@ -6,24 +6,14 @@ import { LibraryData, ImportedDataState } from "./types"; import { calculateScrollCenter } from "../scene"; import { MIME_TYPES } from "../constants"; import { base64ToString } from "../base64"; - export const parseFileContents = async (blob: Blob | File) => { let contents: string; if (blob.type === "image/png") { - const { default: decodePng } = await import("png-chunks-extract"); - const { default: tEXt } = await import("png-chunk-text"); - const chunks = decodePng(new Uint8Array(await blob.arrayBuffer())); - - const metadataChunk = chunks.find((chunk) => chunk.name === "tEXt"); - if (metadataChunk) { - const metadata = tEXt.decode(metadataChunk.data); - if (metadata.keyword === MIME_TYPES.excalidraw) { - return metadata.text; - } - throw new Error(t("alerts.imageDoesNotContainScene")); - } else { - throw new Error(t("alerts.imageDoesNotContainScene")); + const metadata = await (await import("./png")).getTEXtChunk(blob); + if (metadata?.keyword === MIME_TYPES.excalidraw) { + return metadata.text; } + throw new Error(t("alerts.imageDoesNotContainScene")); } else { if ("text" in Blob) { contents = await blob.text(); diff --git a/src/data/index.ts b/src/data/index.ts index a79aa0da..87e61d76 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -345,17 +345,10 @@ export const exportCanvas = async ( tempCanvas.toBlob(async (blob) => { if (blob) { if (appState.exportEmbedScene) { - const { default: tEXt } = await import("png-chunk-text"); - const { default: encodePng } = await import("png-chunks-encode"); - const { default: decodePng } = await import("png-chunks-extract"); - const chunks = decodePng(new Uint8Array(await blob.arrayBuffer())); - const metadata = tEXt.encode( - MIME_TYPES.excalidraw, - serializeAsJSON(elements, appState), - ); - // insert metadata before last chunk (iEND) - chunks.splice(-1, 0, metadata); - blob = new Blob([encodePng(chunks)], { type: "image/png" }); + blob = await (await import("./png")).encodeTEXtChunk(blob, { + keyword: MIME_TYPES.excalidraw, + text: serializeAsJSON(elements, appState), + }); } await fileSave(blob, { diff --git a/src/data/png.ts b/src/data/png.ts new file mode 100644 index 00000000..133ad72e --- /dev/null +++ b/src/data/png.ts @@ -0,0 +1,42 @@ +import decodePng from "png-chunks-extract"; +import tEXt from "png-chunk-text"; +import encodePng from "png-chunks-encode"; + +const blobToArrayBuffer = (blob: Blob): Promise => { + if ("arrayBuffer" in blob) { + return blob.arrayBuffer(); + } + // Safari + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = (event) => { + if (!event.target?.result) { + return reject(new Error("couldn't convert blob to ArrayBuffer")); + } + resolve(event.target.result as ArrayBuffer); + }; + reader.readAsArrayBuffer(blob); + }); +}; + +export const getTEXtChunk = async ( + blob: Blob, +): Promise<{ keyword: string; text: string } | null> => { + const chunks = decodePng(new Uint8Array(await blobToArrayBuffer(blob))); + const metadataChunk = chunks.find((chunk) => chunk.name === "tEXt"); + if (metadataChunk) { + return tEXt.decode(metadataChunk.data); + } + return null; +}; + +export const encodeTEXtChunk = async ( + blob: Blob, + chunk: { keyword: string; text: string }, +): Promise => { + const chunks = decodePng(new Uint8Array(await blobToArrayBuffer(blob))); + const metadata = tEXt.encode(chunk.keyword, chunk.text); + // insert metadata before last chunk (iEND) + chunks.splice(-1, 0, metadata); + return new Blob([encodePng(chunks)], { type: "image/png" }); +};