export const MAX_IMAGE_SIDE = 1000; /** * Re-encodes a picked image to WebP (JPEG where WebP encoding is unsupported), at most * MAX_IMAGE_SIDE px on the longer side. Re-encoding drops EXIF; orientation is applied first. */ export async function compressImage(file: Blob): Promise { const bitmap = await createImageBitmap(file, { imageOrientation: 'from-image' }); try { const scale = Math.min(1, MAX_IMAGE_SIDE / Math.max(bitmap.width, bitmap.height)); const width = Math.max(1, Math.round(bitmap.width * scale)); const height = Math.max(1, Math.round(bitmap.height * scale)); const canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; const ctx = canvas.getContext('2d'); if (!ctx) throw new Error('Canvas is not available'); ctx.drawImage(bitmap, 0, 0, width, height); const encode = (type: string) => new Promise((resolve) => canvas.toBlob(resolve, type, 0.85)); const webp = await encode('image/webp'); if (webp?.type === 'image/webp') return webp; const jpeg = await encode('image/jpeg'); if (!jpeg) throw new Error('Could not encode the image'); return jpeg; } finally { bitmap.close(); } } export function fileNameFor(blob: Blob, base: string): string { return `${base}.${blob.type === 'image/webp' ? 'webp' : 'jpg'}`; }