support embedding scene data to PNG/SVG (#2219)

Co-authored-by: Lipis <lipiridis@gmail.com>
This commit is contained in:
David Luzar 2020-10-13 14:47:07 +02:00 committed by GitHub
parent 7618ca48d7
commit 5950fa9a40
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 329 additions and 27 deletions

View file

@ -4,21 +4,52 @@ import { t } from "../i18n";
import { AppState } from "../types";
import { LibraryData, ImportedDataState } from "./types";
import { calculateScrollCenter } from "../scene";
import { MIME_TYPES } from "../constants";
import { base64ToString } from "../base64";
const loadFileContents = async (blob: any) => {
export const parseFileContents = async (blob: Blob | File) => {
let contents: string;
if ("text" in Blob) {
contents = await blob.text();
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"));
}
} else {
contents = await new Promise((resolve) => {
const reader = new FileReader();
reader.readAsText(blob, "utf8");
reader.onloadend = () => {
if (reader.readyState === FileReader.DONE) {
resolve(reader.result as string);
if ("text" in Blob) {
contents = await blob.text();
} else {
contents = await new Promise((resolve) => {
const reader = new FileReader();
reader.readAsText(blob, "utf8");
reader.onloadend = () => {
if (reader.readyState === FileReader.DONE) {
resolve(reader.result as string);
}
};
});
}
if (blob.type === "image/svg+xml") {
if (contents.includes(`payload-type:${MIME_TYPES.excalidraw}`)) {
const match = contents.match(
/<!-- payload-start -->(.+?)<!-- payload-end -->/,
);
if (!match) {
throw new Error(t("alerts.imageDoesNotContainScene"));
}
};
});
return base64ToString(match[1]);
}
throw new Error(t("alerts.imageDoesNotContainScene"));
}
}
return contents;
};
@ -33,7 +64,7 @@ export const loadFromBlob = async (
(window as any).handle = blob.handle;
}
const contents = await loadFileContents(blob);
const contents = await parseFileContents(blob);
try {
const data: ImportedDataState = JSON.parse(contents);
if (data.type !== "excalidraw") {
@ -57,8 +88,8 @@ export const loadFromBlob = async (
}
};
export const loadLibraryFromBlob = async (blob: any) => {
const contents = await loadFileContents(blob);
export const loadLibraryFromBlob = async (blob: Blob) => {
const contents = await parseFileContents(blob);
const data: LibraryData = JSON.parse(contents);
if (data.type !== "excalidrawlib") {
throw new Error(t("alerts.couldNotLoadInvalidFile"));