2020-09-22 21:51:49 +02:00
|
|
|
import { cleanAppStateForExport } from "../appState";
|
2020-10-19 10:53:37 +02:00
|
|
|
import { MIME_TYPES } from "../constants";
|
2020-11-11 15:55:22 +01:00
|
|
|
import { clearElementsForExport } from "../element";
|
2020-12-03 17:03:02 +02:00
|
|
|
import { CanvasError } from "../errors";
|
|
|
|
import { t } from "../i18n";
|
|
|
|
import { calculateScrollCenter } from "../scene";
|
|
|
|
import { AppState } from "../types";
|
|
|
|
import { restore } from "./restore";
|
|
|
|
import { ImportedDataState, LibraryData } from "./types";
|
2020-10-15 21:31:21 +02:00
|
|
|
|
2020-12-20 16:11:44 +01:00
|
|
|
const parseFileContents = async (blob: Blob | File) => {
|
2020-07-27 15:29:19 +03:00
|
|
|
let contents: string;
|
2020-10-15 21:31:21 +02:00
|
|
|
|
2020-10-13 14:47:07 +02:00
|
|
|
if (blob.type === "image/png") {
|
2020-10-15 21:31:21 +02:00
|
|
|
try {
|
2020-10-18 23:06:25 +05:30
|
|
|
return await (
|
|
|
|
await import(/* webpackChunkName: "image" */ "./image")
|
|
|
|
).decodePngMetadata(blob);
|
2020-10-15 21:31:21 +02:00
|
|
|
} catch (error) {
|
|
|
|
if (error.message === "INVALID") {
|
|
|
|
throw new Error(t("alerts.imageDoesNotContainScene"));
|
|
|
|
} else {
|
|
|
|
throw new Error(t("alerts.cannotRestoreFromImage"));
|
|
|
|
}
|
2020-10-13 14:47:07 +02:00
|
|
|
}
|
2020-03-07 10:20:38 -05:00
|
|
|
} else {
|
2020-10-13 14:47:07 +02:00
|
|
|
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") {
|
2020-10-15 21:31:21 +02:00
|
|
|
try {
|
2020-10-18 23:06:25 +05:30
|
|
|
return await (
|
|
|
|
await import(/* webpackChunkName: "image" */ "./image")
|
|
|
|
).decodeSvgMetadata({
|
2020-10-15 21:31:21 +02:00
|
|
|
svg: contents,
|
|
|
|
});
|
|
|
|
} catch (error) {
|
|
|
|
if (error.message === "INVALID") {
|
2020-10-13 14:47:07 +02:00
|
|
|
throw new Error(t("alerts.imageDoesNotContainScene"));
|
2020-10-15 21:31:21 +02:00
|
|
|
} else {
|
|
|
|
throw new Error(t("alerts.cannotRestoreFromImage"));
|
2020-03-07 10:20:38 -05:00
|
|
|
}
|
2020-10-13 14:47:07 +02:00
|
|
|
}
|
|
|
|
}
|
2020-03-07 10:20:38 -05:00
|
|
|
}
|
2020-07-27 15:29:19 +03:00
|
|
|
return contents;
|
|
|
|
};
|
|
|
|
|
2020-10-30 21:01:41 +01:00
|
|
|
export const getMimeType = (blob: Blob | string): string => {
|
|
|
|
let name: string;
|
|
|
|
if (typeof blob === "string") {
|
|
|
|
name = blob;
|
|
|
|
} else {
|
|
|
|
if (blob.type) {
|
|
|
|
return blob.type;
|
|
|
|
}
|
|
|
|
name = blob.name || "";
|
2020-10-19 10:53:37 +02:00
|
|
|
}
|
|
|
|
if (/\.(excalidraw|json)$/.test(name)) {
|
|
|
|
return "application/json";
|
2020-10-30 21:01:41 +01:00
|
|
|
} else if (/\.png$/.test(name)) {
|
|
|
|
return "image/png";
|
|
|
|
} else if (/\.jpe?g$/.test(name)) {
|
|
|
|
return "image/jpeg";
|
|
|
|
} else if (/\.svg$/.test(name)) {
|
|
|
|
return "image/svg+xml";
|
2020-10-19 10:53:37 +02:00
|
|
|
}
|
|
|
|
return "";
|
|
|
|
};
|
|
|
|
|
2020-10-13 13:46:52 +02:00
|
|
|
export const loadFromBlob = async (
|
2020-10-19 10:53:37 +02:00
|
|
|
blob: Blob,
|
2020-10-13 13:46:52 +02:00
|
|
|
/** @see restore.localAppState */
|
|
|
|
localAppState: AppState | null,
|
|
|
|
) => {
|
2020-10-13 14:47:07 +02:00
|
|
|
const contents = await parseFileContents(blob);
|
2020-07-27 17:18:49 +05:30
|
|
|
try {
|
2020-09-22 21:51:49 +02:00
|
|
|
const data: ImportedDataState = JSON.parse(contents);
|
2020-07-27 17:18:49 +05:30
|
|
|
if (data.type !== "excalidraw") {
|
|
|
|
throw new Error(t("alerts.couldNotLoadInvalidFile"));
|
|
|
|
}
|
2020-12-02 23:57:51 +02:00
|
|
|
const result = restore(
|
2020-10-13 13:46:52 +02:00
|
|
|
{
|
2020-11-11 15:55:22 +01:00
|
|
|
elements: clearElementsForExport(data.elements || []),
|
2020-10-13 13:46:52 +02:00
|
|
|
appState: {
|
|
|
|
appearance: localAppState?.appearance,
|
2020-10-19 10:53:37 +02:00
|
|
|
fileHandle:
|
|
|
|
blob.handle &&
|
|
|
|
["application/json", MIME_TYPES.excalidraw].includes(
|
|
|
|
getMimeType(blob),
|
|
|
|
)
|
|
|
|
? blob.handle
|
|
|
|
: null,
|
2020-10-13 13:46:52 +02:00
|
|
|
...cleanAppStateForExport(data.appState || {}),
|
|
|
|
...(localAppState
|
|
|
|
? calculateScrollCenter(data.elements || [], localAppState, null)
|
|
|
|
: {}),
|
|
|
|
},
|
2020-09-22 21:51:49 +02:00
|
|
|
},
|
2020-10-13 13:46:52 +02:00
|
|
|
localAppState,
|
|
|
|
);
|
2020-12-02 23:57:51 +02:00
|
|
|
|
|
|
|
return result;
|
2020-11-05 19:06:18 +02:00
|
|
|
} catch (error) {
|
|
|
|
console.error(error.message);
|
2020-07-27 17:18:49 +05:30
|
|
|
throw new Error(t("alerts.couldNotLoadInvalidFile"));
|
|
|
|
}
|
2020-05-20 16:21:37 +03:00
|
|
|
};
|
2020-07-27 15:29:19 +03:00
|
|
|
|
2020-10-13 14:47:07 +02:00
|
|
|
export const loadLibraryFromBlob = async (blob: Blob) => {
|
|
|
|
const contents = await parseFileContents(blob);
|
2020-07-27 15:29:19 +03:00
|
|
|
const data: LibraryData = JSON.parse(contents);
|
|
|
|
if (data.type !== "excalidrawlib") {
|
|
|
|
throw new Error(t("alerts.couldNotLoadInvalidFile"));
|
|
|
|
}
|
|
|
|
return data;
|
|
|
|
};
|
2020-10-28 20:52:53 +01:00
|
|
|
|
|
|
|
export const canvasToBlob = async (
|
|
|
|
canvas: HTMLCanvasElement,
|
|
|
|
): Promise<Blob> => {
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
try {
|
|
|
|
canvas.toBlob((blob) => {
|
|
|
|
if (!blob) {
|
|
|
|
return reject(
|
|
|
|
new CanvasError(
|
|
|
|
t("canvasError.canvasTooBig"),
|
|
|
|
"CANVAS_POSSIBLY_TOO_BIG",
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
resolve(blob);
|
|
|
|
});
|
|
|
|
} catch (error) {
|
|
|
|
reject(error);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|