SVG import (#1579)

* SVG import

* Fix error

* Transforms

* Code review nits

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
0HyperCube 2024-01-17 01:42:48 +00:00 committed by GitHub
parent 8eef96511e
commit 002151d9c0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 528 additions and 93 deletions

View file

@ -116,9 +116,15 @@
Array.from(dataTransfer.items).forEach(async (item) => {
const file = item.getAsFile();
if (file?.type.includes("svg")) {
const svgData = await file.text();
editor.instance.pasteSvg(svgData, e.clientX, e.clientY);
return;
}
if (file?.type.startsWith("image")) {
const imageData = await extractPixelData(file);
editor.instance.pasteImage(new Uint8Array(imageData.data), imageData.width, imageData.height, e.clientX, e.clientY);
}
});

View file

@ -272,7 +272,7 @@ export function createInputManager(editor: Editor, dialog: DialogState, portfoli
if (!dataTransfer || targetIsTextField(e.target || undefined)) return;
e.preventDefault();
Array.from(dataTransfer.items).forEach((item) => {
Array.from(dataTransfer.items).forEach(async (item) => {
if (item.type === "text/plain") {
item.getAsString((text) => {
if (text.startsWith("graphite/layer: ")) {
@ -284,10 +284,17 @@ export function createInputManager(editor: Editor, dialog: DialogState, portfoli
}
const file = item.getAsFile();
if (file?.type === "svg") {
const text = await file.text();
editor.instance.pasteSvg(text);
return;
}
if (file?.type.startsWith("image")) {
extractPixelData(file).then((imageData) => {
editor.instance.pasteImage(new Uint8Array(imageData.data), imageData.width, imageData.height);
});
const imageData = await extractPixelData(file);
editor.instance.pasteImage(new Uint8Array(imageData.data), imageData.width, imageData.height);
}
});
}
@ -327,6 +334,19 @@ export function createInputManager(editor: Editor, dialog: DialogState, portfoli
// Read an image from the clipboard and pass it to the editor to be loaded
const imageType = item.types.find((type) => type.startsWith("image/"));
if (imageType === "svg") {
const blob = await item.getType("text/plain");
const reader = new FileReader();
reader.onload = () => {
const text = reader.result as string;
editor.instance.pasteSvg(text);
};
reader.readAsText(blob);
return;
}
if (imageType) {
const blob = await item.getType(imageType);
const reader = new FileReader();

View file

@ -65,6 +65,14 @@ export function createPortfolioState(editor: Editor) {
});
editor.subscriptions.subscribeJsMessage(TriggerImport, async () => {
const data = await upload("image/*", "data");
if (data.type.includes("svg")) {
const svg = new TextDecoder().decode(data.content);
editor.instance.pasteSvg(svg);
return;
}
const imageData = await extractPixelData(new Blob([data.content], { type: data.type }));
editor.instance.pasteImage(new Uint8Array(imageData.data), imageData.width, imageData.height);
});

View file

@ -660,6 +660,13 @@ impl JsEditorHandle {
self.dispatch(message);
}
#[wasm_bindgen(js_name = pasteSvg)]
pub fn paste_svg(&self, svg: String, mouse_x: Option<f64>, mouse_y: Option<f64>) {
let mouse = mouse_x.and_then(|x| mouse_y.map(|y| (x, y)));
let message = DocumentMessage::PasteSvg { svg, mouse };
self.dispatch(message);
}
/// Toggle visibility of a layer from the layer list
#[wasm_bindgen(js_name = toggleLayerVisibility)]
pub fn toggle_layer_visibility(&self, id: u64) {