From ec24b39d1a233e5b5add322097999609dc80d8a5 Mon Sep 17 00:00:00 2001 From: taogaetz <59668529+taogaetz@users.noreply.github.com> Date: Thu, 11 Sep 2025 13:19:12 -0400 Subject: [PATCH] Enhance image compression logic for recipe uploads by allowing dynamic adjustment of quality and dimensions. Update UI to reflect changes in photo handling, including improved feedback on compression status and file sizes. Adjust form elements for better responsiveness and usability. --- src/lib/utils/imageCompression.ts | 82 +++++++++++++----- src/routes/recipe/[id]/edit/+page.svelte | 93 ++++++++++---------- src/routes/recipe/new/+page.svelte | 104 +++++++++++++---------- 3 files changed, 169 insertions(+), 110 deletions(-) diff --git a/src/lib/utils/imageCompression.ts b/src/lib/utils/imageCompression.ts index a7400fb..8c63f16 100644 --- a/src/lib/utils/imageCompression.ts +++ b/src/lib/utils/imageCompression.ts @@ -56,8 +56,15 @@ export async function compressImage( // Draw and compress the image ctx?.drawImage(img, 0, 0, width, height); - // Try different quality levels if file is still too large - const tryCompress = (currentQuality: number): void => { + // Try different quality levels and dimensions if file is still too large + const tryCompress = (currentQuality: number, currentWidth: number, currentHeight: number): void => { + // Update canvas dimensions + canvas.width = currentWidth; + canvas.height = currentHeight; + + // Redraw with new dimensions + ctx?.drawImage(img, 0, 0, currentWidth, currentHeight); + canvas.toBlob( (blob) => { if (!blob) { @@ -67,10 +74,28 @@ export async function compressImage( const sizeKB = blob.size / 1024; - // If still too large and we can reduce quality further, try again - if (sizeKB > maxSizeKB && currentQuality > 0.3) { - tryCompress(currentQuality - 0.1); - return; + console.log(`Compression attempt: ${currentWidth}x${currentHeight}, quality: ${currentQuality}, size: ${sizeKB.toFixed(1)}KB, target: ${maxSizeKB}KB`); + + // If still too large, try more aggressive compression + if (sizeKB > maxSizeKB) { + // First try reducing quality more aggressively + if (currentQuality > 0.1) { + tryCompress(Math.max(0.1, currentQuality - 0.15), currentWidth, currentHeight); + return; + } + // Then try reducing dimensions + else if (currentWidth > 400 && currentHeight > 300) { + const newWidth = Math.max(400, Math.floor(currentWidth * 0.8)); + const newHeight = Math.max(300, Math.floor(currentHeight * 0.8)); + tryCompress(0.1, newWidth, newHeight); + return; + } + // If we've exhausted all compression options and still too large, reject + else { + console.error(`Failed to compress image below ${maxSizeKB}KB. Final size: ${sizeKB.toFixed(1)}KB`); + reject(new Error(`Unable to compress image below ${maxSizeKB}KB. Please try a different image.`)); + return; + } } // Create new file with compressed data @@ -79,6 +104,8 @@ export async function compressImage( lastModified: Date.now() }); + console.log(`Compression successful: ${sizeKB.toFixed(1)}KB (${((blob.size / file.size) * 100).toFixed(1)}% of original)`); + resolve({ file: compressedFile, originalSize: file.size, @@ -91,7 +118,7 @@ export async function compressImage( ); }; - tryCompress(quality); + tryCompress(quality, width, height); } catch (error) { reject(error); } @@ -132,29 +159,42 @@ export function isImageFile(file: File): boolean { export function getCompressionSettings(file: File): CompressionOptions { const sizeMB = file.size / (1024 * 1024); + let settings: CompressionOptions; + if (sizeMB > 5) { - // Very large files - aggressive compression - return { + // Very large files - moderate compression (food photos need detail) + settings = { maxWidth: 1200, - maxHeight: 800, - quality: 0.6, + maxHeight: 900, + quality: 0.7, maxSizeKB: 400 }; } else if (sizeMB > 2) { - // Large files - moderate compression - return { - maxWidth: 1600, - maxHeight: 1000, - quality: 0.7, + // Large files - light compression + settings = { + maxWidth: 1400, + maxHeight: 1050, + quality: 0.75, maxSizeKB: 450 }; - } else { - // Smaller files - light compression - return { - maxWidth: 1920, - maxHeight: 1080, + } else if (sizeMB > 1) { + // Medium files - minimal compression + settings = { + maxWidth: 1600, + maxHeight: 1200, quality: 0.8, + maxSizeKB: 480 + }; + } else { + // Smaller files - very light compression + settings = { + maxWidth: 1800, + maxHeight: 1350, + quality: 0.85, maxSizeKB: 500 }; } + + console.log(`Compression settings for ${sizeMB.toFixed(1)}MB file:`, settings); + return settings; } diff --git a/src/routes/recipe/[id]/edit/+page.svelte b/src/routes/recipe/[id]/edit/+page.svelte index c755ca7..738f0b1 100644 --- a/src/routes/recipe/[id]/edit/+page.svelte +++ b/src/routes/recipe/[id]/edit/+page.svelte @@ -383,11 +383,21 @@ formData.set('description', descriptionText); formData.set('instructions', instructionsText); + // Remove the original photo from FormData (if it exists) + formData.delete('photo'); + // Add parsed ingredients as JSON formData.append('parsedIngredients', JSON.stringify(parsedIngredients)); - // Add photo if selected + // Add compressed photo if selected if (selectedPhoto) { + console.log('Uploading compressed photo:', { + name: selectedPhoto.file.name, + size: selectedPhoto.file.size, + type: selectedPhoto.file.type, + originalSize: selectedPhoto.originalSize, + compressedSize: selectedPhoto.compressedSize + }); formData.append('photo', selectedPhoto.file); } @@ -459,7 +469,7 @@ method="POST" action="?/update" {onsubmit} - class="card relative grid gap-4 border border-base-200 bg-base-100 p-3 shadow-xl sm:p-6" + class="card relative grid gap-4 overflow-hidden border border-base-200 bg-base-100 p-3 shadow-xl sm:p-6" > {#if pending}
-