1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-01-17 18:44:45 +02:00

Desktop: Fixes #7521: Mermaid images are incorrectly sized when exported as PNG (#7546)

This commit is contained in:
Adarsh Singh 2023-02-05 17:09:26 +05:30 committed by GitHub
parent af7cbcbca7
commit 8aad67ccfe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 36 additions and 8 deletions

View File

@ -2,7 +2,7 @@ import ResourceEditWatcher from '@joplin/lib/services/ResourceEditWatcher/index'
import { _ } from '@joplin/lib/locale'; import { _ } from '@joplin/lib/locale';
import { copyHtmlToClipboard } from './clipboardUtils'; import { copyHtmlToClipboard } from './clipboardUtils';
import bridge from '../../../services/bridge'; import bridge from '../../../services/bridge';
import { ContextMenuItemType, ContextMenuOptions, ContextMenuItems, resourceInfo, textToDataUri, svgUriToPng } from './contextMenuUtils'; import { ContextMenuItemType, ContextMenuOptions, ContextMenuItems, resourceInfo, textToDataUri, svgUriToPng, svgDimensions } from './contextMenuUtils';
const Menu = bridge().Menu; const Menu = bridge().Menu;
const MenuItem = bridge().MenuItem; const MenuItem = bridge().MenuItem;
import Resource from '@joplin/lib/models/Resource'; import Resource from '@joplin/lib/models/Resource';
@ -106,8 +106,10 @@ export function menuItems(dispatch: Function): ContextMenuItems {
if (!options.filename) { if (!options.filename) {
throw new Error('Filename is needed to save as png'); throw new Error('Filename is needed to save as png');
} }
// double dimensions to make sure it's always big enough even on hdpi screens
const [width, height] = svgDimensions(document, options.textToCopy).map((x: number) => x * 2 || undefined);
const dataUri = textToDataUri(options.textToCopy, options.mime); const dataUri = textToDataUri(options.textToCopy, options.mime);
const png = await svgUriToPng(document, dataUri); const png = await svgUriToPng(document, dataUri, width, height);
const filename = options.filename.replace('.svg', '.png'); const filename = options.filename.replace('.svg', '.png');
await saveFileData(png, filename); await saveFileData(png, filename);
}, },

View File

@ -1,5 +1,6 @@
import Resource from '@joplin/lib/models/Resource'; import Resource from '@joplin/lib/models/Resource';
import Logger from '@joplin/lib/Logger';
const logger = Logger.create('contextMenuUtils');
export enum ContextMenuItemType { export enum ContextMenuItemType {
None = '', None = '',
Image = 'image', Image = 'image',
@ -40,8 +41,23 @@ export async function resourceInfo(options: ContextMenuOptions) {
export function textToDataUri(text: string, mime: string): string { export function textToDataUri(text: string, mime: string): string {
return `data:${mime};base64,${Buffer.from(text).toString('base64')}`; return `data:${mime};base64,${Buffer.from(text).toString('base64')}`;
} }
export const svgDimensions = (document: Document, svg: string) => {
export const svgUriToPng = (document: Document, svg: string) => { let width: number;
let height: number;
try {
const parser = new DOMParser();
const id = parser.parseFromString(svg, 'text/html').querySelector('svg').id;
({ width, height } = document.querySelector<HTMLIFrameElement>('.noteTextViewer').contentWindow.document.querySelector(`#${id}`).getBoundingClientRect());
} catch (error) {
logger.warn('Could not get SVG dimensions.');
logger.warn('Error was: ', error);
}
if (!width || !height) {
return [undefined, undefined];
}
return [width, height];
};
export const svgUriToPng = (document: Document, svg: string, width: number, height: number) => {
return new Promise<Uint8Array>((resolve, reject) => { return new Promise<Uint8Array>((resolve, reject) => {
let canvas: HTMLCanvasElement; let canvas: HTMLCanvasElement;
let img: HTMLImageElement; let img: HTMLImageElement;
@ -63,11 +79,21 @@ export const svgUriToPng = (document: Document, svg: string) => {
try { try {
canvas = document.createElement('canvas'); canvas = document.createElement('canvas');
if (!canvas) throw new Error('Failed to create canvas element'); if (!canvas) throw new Error('Failed to create canvas element');
canvas.width = img.width; if (!width || !height) {
canvas.height = img.height; const maxDimension = 1024;
if (img.width > img.height) {
width = maxDimension;
height = width * (img.height / img.width);
} else {
height = maxDimension;
width = height * (img.width / img.height);
}
}
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d'); const ctx = canvas.getContext('2d');
if (!ctx) throw new Error('Failed to get context'); if (!ctx) throw new Error('Failed to get context');
ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, img.width, img.height); ctx.drawImage(img, 0, 0, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height);
const pngUri = canvas.toDataURL('image/png'); const pngUri = canvas.toDataURL('image/png');
if (!pngUri) throw new Error('Failed to generate png uri'); if (!pngUri) throw new Error('Failed to generate png uri');
const pngBase64 = pngUri.split(',')[1]; const pngBase64 = pngUri.split(',')[1];