mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
feat: resave to png/svg with metadata if you loaded your scene from a png/svg file (#3645)
Co-authored-by: dwelle <luzar.david@gmail.com>
This commit is contained in:
parent
9581c45522
commit
685abac81a
7 changed files with 108 additions and 15 deletions
|
@ -1,3 +1,4 @@
|
|||
import { FileSystemHandle } from "browser-fs-access";
|
||||
import { cleanAppStateForExport } from "../appState";
|
||||
import { EXPORT_DATA_TYPES } from "../constants";
|
||||
import { clearElementsForExport } from "../element";
|
||||
|
@ -80,6 +81,25 @@ export const getMimeType = (blob: Blob | string): string => {
|
|||
return "";
|
||||
};
|
||||
|
||||
export const getFileHandleType = (handle: FileSystemHandle | null) => {
|
||||
if (!handle) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return handle.name.match(/\.(json|excalidraw|png|svg)$/)?.[1] || null;
|
||||
};
|
||||
|
||||
export const isImageFileHandleType = (
|
||||
type: string | null,
|
||||
): type is "png" | "svg" => {
|
||||
return type === "png" || type === "svg";
|
||||
};
|
||||
|
||||
export const isImageFileHandle = (handle: FileSystemHandle | null) => {
|
||||
const type = getFileHandleType(handle);
|
||||
return type === "png" || type === "svg";
|
||||
};
|
||||
|
||||
export const loadFromBlob = async (
|
||||
blob: Blob,
|
||||
/** @see restore.localAppState */
|
||||
|
@ -97,7 +117,7 @@ export const loadFromBlob = async (
|
|||
elements: clearElementsForExport(data.elements || []),
|
||||
appState: {
|
||||
theme: localAppState?.theme,
|
||||
fileHandle: (!blob.type.startsWith("image/") && blob.handle) || null,
|
||||
fileHandle: blob.handle || null,
|
||||
...cleanAppStateForExport(data.appState || {}),
|
||||
...(localAppState
|
||||
? calculateScrollCenter(data.elements || [], localAppState, null)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { fileSave } from "browser-fs-access";
|
||||
import { fileSave, FileSystemHandle } from "browser-fs-access";
|
||||
import {
|
||||
copyBlobToClipboardAsPng,
|
||||
copyTextToSystemClipboard,
|
||||
|
@ -24,11 +24,13 @@ export const exportCanvas = async (
|
|||
exportPadding = DEFAULT_EXPORT_PADDING,
|
||||
viewBackgroundColor,
|
||||
name,
|
||||
fileHandle = null,
|
||||
}: {
|
||||
exportBackground: boolean;
|
||||
exportPadding?: number;
|
||||
viewBackgroundColor: string;
|
||||
name: string;
|
||||
fileHandle?: FileSystemHandle | null;
|
||||
},
|
||||
) => {
|
||||
if (elements.length === 0) {
|
||||
|
@ -44,11 +46,14 @@ export const exportCanvas = async (
|
|||
exportEmbedScene: appState.exportEmbedScene && type === "svg",
|
||||
});
|
||||
if (type === "svg") {
|
||||
await fileSave(new Blob([tempSvg.outerHTML], { type: "image/svg+xml" }), {
|
||||
fileName: `${name}.svg`,
|
||||
extensions: [".svg"],
|
||||
});
|
||||
return;
|
||||
return await fileSave(
|
||||
new Blob([tempSvg.outerHTML], { type: "image/svg+xml" }),
|
||||
{
|
||||
fileName: `${name}.svg`,
|
||||
extensions: [".svg"],
|
||||
},
|
||||
fileHandle,
|
||||
);
|
||||
} else if (type === "clipboard-svg") {
|
||||
await copyTextToSystemClipboard(tempSvg.outerHTML);
|
||||
return;
|
||||
|
@ -76,10 +81,14 @@ export const exportCanvas = async (
|
|||
});
|
||||
}
|
||||
|
||||
await fileSave(blob, {
|
||||
fileName,
|
||||
extensions: [".png"],
|
||||
});
|
||||
return await fileSave(
|
||||
blob,
|
||||
{
|
||||
fileName,
|
||||
extensions: [".png"],
|
||||
},
|
||||
fileHandle,
|
||||
);
|
||||
} else if (type === "clipboard") {
|
||||
try {
|
||||
await copyBlobToClipboardAsPng(blob);
|
||||
|
|
|
@ -4,7 +4,7 @@ import { EXPORT_DATA_TYPES, EXPORT_SOURCE, MIME_TYPES } from "../constants";
|
|||
import { clearElementsForExport } from "../element";
|
||||
import { ExcalidrawElement } from "../element/types";
|
||||
import { AppState } from "../types";
|
||||
import { loadFromBlob } from "./blob";
|
||||
import { isImageFileHandle, loadFromBlob } from "./blob";
|
||||
|
||||
import {
|
||||
ExportedDataState,
|
||||
|
@ -44,7 +44,7 @@ export const saveAsJSON = async (
|
|||
description: "Excalidraw file",
|
||||
extensions: [".excalidraw"],
|
||||
},
|
||||
appState.fileHandle,
|
||||
isImageFileHandle(appState.fileHandle) ? null : appState.fileHandle,
|
||||
);
|
||||
return { fileHandle };
|
||||
};
|
||||
|
|
38
src/data/resave.ts
Normal file
38
src/data/resave.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
import { ExcalidrawElement } from "../element/types";
|
||||
import { AppState } from "../types";
|
||||
import { exportCanvas } from ".";
|
||||
import { getNonDeletedElements } from "../element";
|
||||
import { getFileHandleType, isImageFileHandleType } from "./blob";
|
||||
|
||||
export const resaveAsImageWithScene = async (
|
||||
elements: readonly ExcalidrawElement[],
|
||||
appState: AppState,
|
||||
) => {
|
||||
const { exportBackground, viewBackgroundColor, name, fileHandle } = appState;
|
||||
|
||||
const fileHandleType = getFileHandleType(fileHandle);
|
||||
|
||||
if (!fileHandle || !isImageFileHandleType(fileHandleType)) {
|
||||
throw new Error(
|
||||
"fileHandle should exist and should be of type svg or png when resaving",
|
||||
);
|
||||
}
|
||||
appState = {
|
||||
...appState,
|
||||
exportEmbedScene: true,
|
||||
};
|
||||
|
||||
await exportCanvas(
|
||||
fileHandleType,
|
||||
getNonDeletedElements(elements),
|
||||
appState,
|
||||
{
|
||||
exportBackground,
|
||||
viewBackgroundColor,
|
||||
name,
|
||||
fileHandle,
|
||||
},
|
||||
);
|
||||
|
||||
return { fileHandle };
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue