carbon-tokenization / frontend /src /editor /image-optimizer.ts
tfrere's picture
tfrere HF Staff
feat: add client-side image optimization (WebP variants)
7bafae7
/**
* Client-side image optimization.
*
* Resizes images and converts them to WebP before upload,
* reducing bandwidth and storage costs significantly.
*/
interface OptimizedVariant {
blob: Blob;
width: number;
height: number;
suffix: string;
}
export interface OptimizedImage {
original: { width: number; height: number };
variants: OptimizedVariant[];
}
const VARIANTS = [
{ suffix: "thumb", maxWidth: 400, quality: 0.7 },
{ suffix: "medium", maxWidth: 1000, quality: 0.8 },
{ suffix: "full", maxWidth: 2000, quality: 0.85 },
] as const;
/**
* Optimize an image file: resize to 3 WebP variants + extract dimensions.
* Returns the variants sorted small to large.
*/
export async function optimizeImage(file: File): Promise<OptimizedImage> {
const bitmap = await createImageBitmap(file);
const { width: origW, height: origH } = bitmap;
const variants: OptimizedVariant[] = [];
for (const { suffix, maxWidth, quality } of VARIANTS) {
// Skip variant if original is smaller than this tier
if (origW <= maxWidth && suffix !== "full") continue;
const scale = Math.min(1, maxWidth / origW);
const w = Math.round(origW * scale);
const h = Math.round(origH * scale);
const canvas = new OffscreenCanvas(w, h);
const ctx = canvas.getContext("2d");
if (!ctx) throw new Error("Canvas 2D context unavailable");
ctx.drawImage(bitmap, 0, 0, w, h);
const blob = await canvas.convertToBlob({
type: "image/webp",
quality,
});
variants.push({ blob, width: w, height: h, suffix });
}
// Always ensure at least one variant (the full size)
if (variants.length === 0) {
const canvas = new OffscreenCanvas(origW, origH);
const ctx = canvas.getContext("2d");
if (!ctx) throw new Error("Canvas 2D context unavailable");
ctx.drawImage(bitmap, 0, 0);
const blob = await canvas.convertToBlob({
type: "image/webp",
quality: 0.85,
});
variants.push({ blob, width: origW, height: origH, suffix: "full" });
}
bitmap.close();
return {
original: { width: origW, height: origH },
variants,
};
}
/**
* Check if the browser supports WebP encoding via OffscreenCanvas.
*/
export function supportsWebpOptimization(): boolean {
try {
return typeof OffscreenCanvas !== "undefined";
} catch {
return false;
}
}