update for shrink image size.
ci-cd-vm / ci-cd (push) Successful in 1m23s

This commit is contained in:
Chris Chen
2026-06-23 13:30:20 -07:00
parent 62592c29ae
commit 5dfca873dd
5 changed files with 68 additions and 16 deletions
@@ -0,0 +1,45 @@
import imageCompression from 'browser-image-compression';
/**
* Client-side image compression shared by every photo upload (expense receipts,
* offering paper-proofs). Phone cameras produce 12MP+ JPEGs that are several MB
* each; resizing the longest edge and re-encoding as JPEG keeps uploads small
* enough to clear the API's per-endpoint size limits (and the reverse proxy).
*
* Tunables: raise quality/edge if proofs look too soft; lower them if files are
* too large.
*/
export class ImageUtils {
/** Longest image edge (px) after compression. */
public static readonly MAX_EDGE_PX = 2000;
/** JPEG encoder quality, 0..1. */
public static readonly JPEG_QUALITY = 0.72;
/** Target ceiling per image, in megabytes. */
public static readonly MAX_SIZE_MB = 1;
/**
* Compresses a single image File to a resized JPEG. Non-image files (e.g. a
* PDF) are returned untouched.
*
* The result is always renamed to a ".jpg" extension with an "image/jpeg"
* type, because the API derives a stored receipt's content-type from its
* filename extension — keeping a ".png" name on JPEG bytes would make the
* download serve a broken image.
*/
public static async compressForUpload(file: File): Promise<File> {
if (!file.type.startsWith('image/')) {
return file;
}
const compressed = await imageCompression(file, {
maxWidthOrHeight: ImageUtils.MAX_EDGE_PX,
maxSizeMB: ImageUtils.MAX_SIZE_MB,
initialQuality: ImageUtils.JPEG_QUALITY,
fileType: 'image/jpeg',
useWebWorker: true,
});
const baseName = file.name.replace(/\.[^.]+$/, '');
return new File([compressed], `${baseName}.jpg`, { type: 'image/jpeg' });
}
}