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;
}