File size: 1,366 Bytes
94193b5 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | /**
* Image compression utility for thumbnail uploads.
* Loads a File into an Image, draws onto a canvas at max 640×360
* (maintaining aspect ratio), and exports as JPEG base64.
*/
const MAX_WIDTH = 640;
const MAX_HEIGHT = 360;
const INITIAL_QUALITY = 0.7;
const FALLBACK_QUALITY = 0.5;
const MAX_SIZE_BYTES = 100_000; // 100 KB
export async function compressImage(file: File): Promise<string> {
const bitmap = await createImageBitmap(file);
// Calculate output dimensions maintaining aspect ratio
let width = bitmap.width;
let height = bitmap.height;
if (width > MAX_WIDTH || height > MAX_HEIGHT) {
const scale = Math.min(MAX_WIDTH / width, MAX_HEIGHT / height);
width = Math.round(width * scale);
height = Math.round(height * scale);
}
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
if (!ctx) throw new Error('Failed to get canvas context');
ctx.drawImage(bitmap, 0, 0, width, height);
bitmap.close();
// First attempt at normal quality
let dataUrl = canvas.toDataURL('image/jpeg', INITIAL_QUALITY);
// If too large, retry at lower quality
if (dataUrl.length > MAX_SIZE_BYTES * 1.37) {
// base64 is ~37% larger than raw bytes
dataUrl = canvas.toDataURL('image/jpeg', FALLBACK_QUALITY);
}
return dataUrl;
}
|