diff --git a/src/public/app/services/utils.ts b/src/public/app/services/utils.ts index a4b0aa750..9d39bb279 100644 --- a/src/public/app/services/utils.ts +++ b/src/public/app/services/utils.ts @@ -650,47 +650,58 @@ function triggerDownload(fileName: string, dataUrl: string) { * * @param nameWithoutExtension the name of the file. The .png suffix is automatically added to it. * @param svgContent the content of the SVG file download. - * @returns `true` if the operation succeeded (width/height present), or `false` if the download was not triggered. + * @returns a promise which resolves if the operation was successful, or rejects if it failed (permissions issue or some other issue). */ function downloadSvgAsPng(nameWithoutExtension: string, svgContent: string) { - const mime = "image/svg+xml"; + return new Promise((resolve, reject) => { + const mime = "image/svg+xml"; - // First, we need to determine the width and the height from the input SVG. - const svgDocument = (new DOMParser()).parseFromString(svgContent, mime); - const width = svgDocument.documentElement?.getAttribute("width"); - const height = svgDocument.documentElement?.getAttribute("height"); + // First, we need to determine the width and the height from the input SVG. + const svgDocument = (new DOMParser()).parseFromString(svgContent, mime); + const width = svgDocument.documentElement?.getAttribute("width"); + const height = svgDocument.documentElement?.getAttribute("height"); - if (!width || !height) { - return false; - } + if (!width || !height) { + reject(); + return; + } - // Convert the image to a blob. - const svgBlob = new Blob([ svgContent ], { - type: mime - }) + // Convert the image to a blob. + const svgBlob = new Blob([ svgContent ], { + type: mime + }) - // Create an image element and load the SVG. - const imageEl = new Image(); - imageEl.width = parseFloat(width); - imageEl.height = parseFloat(height); - imageEl.src = URL.createObjectURL(svgBlob); - imageEl.onload = () => { - // Draw the image with a canvas. - const canvasEl = document.createElement("canvas"); - canvasEl.width = imageEl.width; - canvasEl.height = imageEl.height; - document.body.appendChild(canvasEl); + // Create an image element and load the SVG. + const imageEl = new Image(); + imageEl.width = parseFloat(width); + imageEl.height = parseFloat(height); + imageEl.onload = () => { + try { + // Draw the image with a canvas. + const canvasEl = document.createElement("canvas"); + canvasEl.width = imageEl.width; + canvasEl.height = imageEl.height; + document.body.appendChild(canvasEl); - const ctx = canvasEl.getContext("2d"); - ctx?.drawImage(imageEl, 0, 0); - URL.revokeObjectURL(imageEl.src); + const ctx = canvasEl.getContext("2d"); + if (!ctx) { + reject(); + } - const imgUri = canvasEl.toDataURL("image/png") - triggerDownload(`${nameWithoutExtension}.png`, imgUri); - document.body.removeChild(canvasEl); - }; + ctx?.drawImage(imageEl, 0, 0); + URL.revokeObjectURL(imageEl.src); - return true; + const imgUri = canvasEl.toDataURL("image/png") + triggerDownload(`${nameWithoutExtension}.png`, imgUri); + document.body.removeChild(canvasEl); + resolve(); + } catch (e) { + console.warn(e); + reject(); + } + }; + imageEl.src = URL.createObjectURL(svgBlob); + }); } /** diff --git a/src/public/app/widgets/type_widgets/abstract_svg_split_type_widget.ts b/src/public/app/widgets/type_widgets/abstract_svg_split_type_widget.ts index aeea96089..061694349 100644 --- a/src/public/app/widgets/type_widgets/abstract_svg_split_type_widget.ts +++ b/src/public/app/widgets/type_widgets/abstract_svg_split_type_widget.ts @@ -2,7 +2,9 @@ import type { EventData } from "../../components/app_context.js"; import type FNote from "../../entities/fnote.js"; import { t } from "../../services/i18n.js"; import server from "../../services/server.js"; +import toast from "../../services/toast.js"; import utils from "../../services/utils.js"; +import ws from "../../services/ws.js"; import OnClickButtonWidget from "../buttons/onclick_button.js"; import AbstractSplitTypeWidget from "./abstract_split_type_widget.js"; @@ -218,11 +220,18 @@ export default abstract class AbstractSvgSplitTypeWidget extends AbstractSplitTy } async exportPngEvent({ ntxId }: EventData<"exportPng">) { + console.log("Export to PNG", this.noteContext?.noteId, ntxId, this.svg); if (!this.isNoteContext(ntxId) || this.note?.type !== "mermaid" || !this.svg) { + console.log("Return"); return; } - utils.downloadSvgAsPng(this.note.title, this.svg); + try { + await utils.downloadSvgAsPng(this.note.title, this.svg); + } catch (e) { + console.warn(e); + toast.showError(t("svg.export_to_png")); + } } } diff --git a/src/public/translations/en/translation.json b/src/public/translations/en/translation.json index 13bb74dfd..e985ffc4d 100644 --- a/src/public/translations/en/translation.json +++ b/src/public/translations/en/translation.json @@ -1746,5 +1746,8 @@ }, "png_export_button": { "button_title": "Export diagram as PNG" + }, + "svg": { + "export_to_png": "The diagram could not be exported to PNG." } }