From 531f0cb3b3b12469539d072fd89804dccdb7407c Mon Sep 17 00:00:00 2001 From: jason Date: Sun, 8 Mar 2026 17:05:07 -0500 Subject: [PATCH] Fix preview file size calculation and format conversion --- frontend/src/lib/preview.ts | 45 ++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/frontend/src/lib/preview.ts b/frontend/src/lib/preview.ts index 5c4fb6e..da1bf56 100644 --- a/frontend/src/lib/preview.ts +++ b/frontend/src/lib/preview.ts @@ -38,10 +38,29 @@ export async function generateClientPreview( ctx.drawImage(img, 0, 0, width, height); } - // Convert to data URL with quality + // Convert to data URL with quality - fix MIME type mapping const quality = options.quality / 100; - const mimeType = `image/${options.format === 'jpeg' ? 'jpeg' : 'png'}`; - const dataUrl = canvas.toDataURL(mimeType, quality); + let mimeType: string; + + // Map format to proper MIME type + switch (options.format) { + case 'jpeg': + mimeType = 'image/jpeg'; + break; + case 'webp': + mimeType = 'image/webp'; + break; + case 'png': + default: + mimeType = 'image/png'; + break; + } + + // For PNG, quality doesn't apply in Canvas API (always lossless) + // For JPEG and WebP, quality matters + const dataUrl = options.format === 'png' + ? canvas.toDataURL(mimeType) + : canvas.toDataURL(mimeType, quality); resolve(dataUrl); } catch (error) { @@ -183,12 +202,26 @@ function getPositionOffset( /** * Estimate file size from data URL + * More accurate calculation that accounts for base64 overhead */ export function estimateSize(dataUrl: string): number { - const base64 = dataUrl.split(',')[1]; + const parts = dataUrl.split(','); + if (parts.length < 2) return 0; + + const base64 = parts[1]; if (!base64) return 0; - // Base64 is ~33% larger than binary, so divide by 1.33 - return Math.ceil((base64.length * 3) / 4); + + // Remove padding characters for accurate calculation + const withoutPadding = base64.replace(/=/g, ''); + + // Base64 encoding: 3 bytes -> 4 characters + // So to get original bytes: (length * 3) / 4 + const bytes = (withoutPadding.length * 3) / 4; + + // Account for padding bytes if present + const paddingCount = base64.length - withoutPadding.length; + + return Math.round(bytes - paddingCount); } /**