/** * Downscales an image file in the browser to at most `maxEdge` px on its longest side * and re-encodes it as JPEG. Returns null when no processing is needed or possible. */ export async function downscaleImage(file: File, maxEdge = 1600, quality = 0.85): Promise { if (typeof createImageBitmap === 'undefined' || typeof document === 'undefined') return null; try { const bitmap = await createImageBitmap(file); const scale = Math.min(1, maxEdge / Math.max(bitmap.width, bitmap.height)); if (scale === 1 && file.type === 'image/jpeg') { bitmap.close(); return null; } const canvas = document.createElement('canvas'); canvas.width = Math.max(1, Math.round(bitmap.width * scale)); canvas.height = Math.max(1, Math.round(bitmap.height * scale)); const ctx = canvas.getContext('2d'); if (!ctx) return null; ctx.drawImage(bitmap, 0, 0, canvas.width, canvas.height); bitmap.close(); return await new Promise((resolve) => canvas.toBlob(resolve, 'image/jpeg', quality)); } catch { return null; } }