blob.ts 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import { cleanAppStateForExport } from "../appState";
  2. import { restore } from "./restore";
  3. import { t } from "../i18n";
  4. import { AppState } from "../types";
  5. import { LibraryData, ImportedDataState } from "./types";
  6. import { calculateScrollCenter } from "../scene";
  7. export const parseFileContents = async (blob: Blob | File) => {
  8. let contents: string;
  9. if (blob.type === "image/png") {
  10. try {
  11. return await (
  12. await import(/* webpackChunkName: "image" */ "./image")
  13. ).decodePngMetadata(blob);
  14. } catch (error) {
  15. if (error.message === "INVALID") {
  16. throw new Error(t("alerts.imageDoesNotContainScene"));
  17. } else {
  18. throw new Error(t("alerts.cannotRestoreFromImage"));
  19. }
  20. }
  21. } else {
  22. if ("text" in Blob) {
  23. contents = await blob.text();
  24. } else {
  25. contents = await new Promise((resolve) => {
  26. const reader = new FileReader();
  27. reader.readAsText(blob, "utf8");
  28. reader.onloadend = () => {
  29. if (reader.readyState === FileReader.DONE) {
  30. resolve(reader.result as string);
  31. }
  32. };
  33. });
  34. }
  35. if (blob.type === "image/svg+xml") {
  36. try {
  37. return await (
  38. await import(/* webpackChunkName: "image" */ "./image")
  39. ).decodeSvgMetadata({
  40. svg: contents,
  41. });
  42. } catch (error) {
  43. if (error.message === "INVALID") {
  44. throw new Error(t("alerts.imageDoesNotContainScene"));
  45. } else {
  46. throw new Error(t("alerts.cannotRestoreFromImage"));
  47. }
  48. }
  49. }
  50. }
  51. return contents;
  52. };
  53. export const loadFromBlob = async (
  54. blob: any,
  55. /** @see restore.localAppState */
  56. localAppState: AppState | null,
  57. ) => {
  58. if (blob.handle) {
  59. // TODO: Make this part of `AppState`.
  60. (window as any).handle = blob.handle;
  61. }
  62. const contents = await parseFileContents(blob);
  63. try {
  64. const data: ImportedDataState = JSON.parse(contents);
  65. if (data.type !== "excalidraw") {
  66. throw new Error(t("alerts.couldNotLoadInvalidFile"));
  67. }
  68. return restore(
  69. {
  70. elements: data.elements,
  71. appState: {
  72. appearance: localAppState?.appearance,
  73. ...cleanAppStateForExport(data.appState || {}),
  74. ...(localAppState
  75. ? calculateScrollCenter(data.elements || [], localAppState, null)
  76. : {}),
  77. },
  78. },
  79. localAppState,
  80. );
  81. } catch {
  82. throw new Error(t("alerts.couldNotLoadInvalidFile"));
  83. }
  84. };
  85. export const loadLibraryFromBlob = async (blob: Blob) => {
  86. const contents = await parseFileContents(blob);
  87. const data: LibraryData = JSON.parse(contents);
  88. if (data.type !== "excalidrawlib") {
  89. throw new Error(t("alerts.couldNotLoadInvalidFile"));
  90. }
  91. return data;
  92. };