mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-07-27 18:12:29 +08:00
fix(mermaid): fix export to PNG for some diagram types
This commit is contained in:
parent
3cdbc76fff
commit
3d0ec27038
22
src/public/app/services/utils.spec.ts
Normal file
22
src/public/app/services/utils.spec.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { getSizeFromSvg } from "./utils.js";
|
||||
|
||||
describe("getSizeFromSvg", () => {
|
||||
it("parses width & height attribute", () => {
|
||||
const svg = `<svg aria-roledescription="sequence" role="graphics-document document" viewBox="-50 -10 714 574" height="574" xmlns="http://www.w3.org/2000/svg" width="714" id="mermaid-graph-2"></svg>`;
|
||||
const result = getSizeFromSvg(svg);
|
||||
expect(result).toMatchObject({
|
||||
width: 714,
|
||||
height: 574,
|
||||
});
|
||||
});
|
||||
|
||||
it("parses viewbox", () => {
|
||||
const svg = `<svg aria-roledescription="er" role="graphics-document document" viewBox="0 0 872.2750244140625 655" style="max-width: 872.2750244140625px;" class="erDiagram" xmlns="http://www.w3.org/2000/svg" width="100%" id="mermaid-graph-2">`;
|
||||
const result = getSizeFromSvg(svg);
|
||||
expect(result).toMatchObject({
|
||||
width: 872.2750244140625,
|
||||
height: 655
|
||||
});
|
||||
});
|
||||
});
|
@ -2,6 +2,8 @@ import dayjs from "dayjs";
|
||||
import { Modal } from "bootstrap";
|
||||
import type { ViewScope } from "./link.js";
|
||||
|
||||
const SVG_MIME = "image/svg+xml";
|
||||
|
||||
function reloadFrontendApp(reason?: string) {
|
||||
if (reason) {
|
||||
logInfo(`Frontend app reload: ${reason}`);
|
||||
@ -654,27 +656,23 @@ function triggerDownload(fileName: string, dataUrl: string) {
|
||||
*/
|
||||
function downloadSvgAsPng(nameWithoutExtension: string, svgContent: string) {
|
||||
return new Promise<void>((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");
|
||||
|
||||
if (!width || !height) {
|
||||
const result = getSizeFromSvg(svgContent);
|
||||
if (!result) {
|
||||
reject();
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert the image to a blob.
|
||||
const { width, height } = result;
|
||||
const svgBlob = new Blob([ svgContent ], {
|
||||
type: mime
|
||||
type: SVG_MIME
|
||||
})
|
||||
|
||||
// Create an image element and load the SVG.
|
||||
const imageEl = new Image();
|
||||
imageEl.width = parseFloat(width);
|
||||
imageEl.height = parseFloat(height);
|
||||
imageEl.width = width;
|
||||
imageEl.height = height;
|
||||
imageEl.onload = () => {
|
||||
try {
|
||||
// Draw the image with a canvas.
|
||||
@ -704,6 +702,34 @@ function downloadSvgAsPng(nameWithoutExtension: string, svgContent: string) {
|
||||
});
|
||||
}
|
||||
|
||||
export function getSizeFromSvg(svgContent: string) {
|
||||
const svgDocument = (new DOMParser()).parseFromString(svgContent, SVG_MIME);
|
||||
|
||||
// Try to use width & height attributes if available.
|
||||
let width = svgDocument.documentElement?.getAttribute("width");
|
||||
let height = svgDocument.documentElement?.getAttribute("height");
|
||||
|
||||
// If not, use the viewbox.
|
||||
if (!width || !height) {
|
||||
const viewBox = svgDocument.documentElement?.getAttribute("viewBox");
|
||||
if (viewBox) {
|
||||
const viewBoxParts = viewBox.split(" ");
|
||||
width = viewBoxParts[2];
|
||||
height = viewBoxParts[3];
|
||||
}
|
||||
}
|
||||
|
||||
if (width && height) {
|
||||
return {
|
||||
width: parseFloat(width),
|
||||
height: parseFloat(height)
|
||||
}
|
||||
} else {
|
||||
console.warn("SVG export error", svgDocument.documentElement);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two semantic version strings.
|
||||
* Returns:
|
||||
|
Loading…
x
Reference in New Issue
Block a user