/** * Shrinks an image so its longest side is at most `maxSize` px before upload. * GIFs are kept as is (canvas would drop the animation), as are images the * browser cannot decode — the server decides what to do with those. */ export async function resizeImage(file: File, maxSize: number): Promise { if (file.type === 'image/gif') return file let bitmap: ImageBitmap try { bitmap = await createImageBitmap(file) } catch { return file } const scale = Math.min(1, maxSize / Math.max(bitmap.width, bitmap.height)) const canvas = document.createElement('canvas') canvas.width = Math.round(bitmap.width * scale) canvas.height = Math.round(bitmap.height * scale) canvas.getContext('2d')?.drawImage(bitmap, 0, 0, canvas.width, canvas.height) bitmap.close() // Browsers without WebP encoding (Safari) fall back to PNG const blob = await new Promise((resolve) => canvas.toBlob(resolve, 'image/webp', 0.9)) if (!blob || blob.size >= file.size) return file const ext = blob.type === 'image/webp' ? 'webp' : 'png' return new File([blob], `${file.name.replace(/\.[^.]+$/, '')}.${ext}`, { type: blob.type }) }