From 51cc26b91685b280a0f32a468c7ea6c2be9250f3 Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Wed, 19 Mar 2025 13:08:38 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B(frontend)=20improve=20svg=20export?= =?UTF-8?q?=20to=20be=20less=20pixelized?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some SVGs were pixelized in the exported files. We now add the wanted size to the svg conversion to make sure the images are exported with the correct size and so less pixelized. --- .../doc-export/blocks-mapping/imageDocx.tsx | 6 ++++- .../doc-export/blocks-mapping/imagePDF.tsx | 6 ++++- .../src/features/docs/doc-export/utils.ts | 25 +++++++++++++++++-- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/imageDocx.tsx b/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/imageDocx.tsx index 8fa3848e..e5c244dd 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/imageDocx.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/imageDocx.tsx @@ -22,9 +22,13 @@ export const blockMappingImageDocx: DocsExporterDocx['mappings']['blockMapping'] let pngConverted: string | undefined; let dimensions: { width: number; height: number } | undefined; + if (!blob.type.includes('image')) { + return []; + } + if (blob.type.includes('svg')) { const svgText = await blob.text(); - pngConverted = await convertSvgToPng(svgText); + pngConverted = await convertSvgToPng(svgText, block.props.previewWidth); const img = new Image(); img.src = pngConverted; await new Promise((resolve) => { diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/imagePDF.tsx b/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/imagePDF.tsx index 134bf391..a5551b48 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/imagePDF.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/imagePDF.tsx @@ -13,9 +13,13 @@ export const blockMappingImagePDF: DocsExporterPDF['mappings']['blockMapping'][' const blob = await exporter.resolveFile(block.props.url); let pngConverted: string | undefined; + if (!blob.type.includes('image')) { + return ; + } + if (blob.type.includes('svg')) { const svgText = await blob.text(); - pngConverted = await convertSvgToPng(svgText); + pngConverted = await convertSvgToPng(svgText, block.props.previewWidth); } return ( diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/utils.ts b/src/frontend/apps/impress/src/features/docs/doc-export/utils.ts index bdebc052..77bdf93b 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-export/utils.ts +++ b/src/frontend/apps/impress/src/features/docs/doc-export/utils.ts @@ -23,16 +23,37 @@ export function downloadFile(blob: Blob, filename: string) { * @param svgText - The SVG text to convert * @returns The PNG data URL */ -export async function convertSvgToPng(svgText: string) { +export async function convertSvgToPng(svgText: string, width: number) { // Create a canvas and render the SVG onto it const canvas = document.createElement('canvas'); - const ctx = canvas.getContext('2d'); + const ctx = canvas.getContext('2d', { + alpha: true, + }); if (!ctx) { throw new Error('Canvas context is null'); } + // Parse SVG to get original dimensions + const parser = new DOMParser(); + const svgDoc = parser.parseFromString(svgText, 'image/svg+xml'); + const svgElement = svgDoc.documentElement; + + // Get viewBox or fallback to width/height attributes + let height; + const svgWidth = svgElement.getAttribute?.('width'); + const svgHeight = svgElement.getAttribute?.('height'); + const viewBox = svgElement.getAttribute('viewBox')?.split(' ').map(Number); + + const originalWidth = svgWidth ? parseInt(svgWidth) : viewBox?.[2]; + const originalHeight = svgHeight ? parseInt(svgHeight) : viewBox?.[3]; + if (originalWidth && originalHeight) { + const aspectRatio = originalHeight / originalWidth; + height = Math.round(width * aspectRatio); + } + const svg = Canvg.fromString(ctx, svgText); + svg.resize(width, height, true); await svg.render(); return canvas.toDataURL('image/png');