image optimization. Image resizing client side, index added to db, pagination
This commit is contained in:
91
frontend/src/utils/imageResizer.ts
Normal file
91
frontend/src/utils/imageResizer.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import imageCompression from "browser-image-compression";
|
||||
|
||||
interface ImageSizeVariant {
|
||||
size: "original" | "medium" | "thumbnail";
|
||||
maxWidth: number;
|
||||
quality: number;
|
||||
suffix: string;
|
||||
}
|
||||
|
||||
const IMAGE_VARIANTS: ImageSizeVariant[] = [
|
||||
{ size: "thumbnail", maxWidth: 200, quality: 0.8, suffix: "_th" },
|
||||
{ size: "medium", maxWidth: 800, quality: 0.8, suffix: "_md" },
|
||||
{ size: "original", maxWidth: 4096, quality: 0.9, suffix: "" },
|
||||
];
|
||||
|
||||
interface ResizedImage {
|
||||
variant: ImageSizeVariant;
|
||||
file: File;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resize an image to all size variants (thumbnail, medium, original)
|
||||
* Returns array of resized File objects
|
||||
*/
|
||||
export async function resizeImage(file: File): Promise<ResizedImage[]> {
|
||||
const results: ResizedImage[] = [];
|
||||
|
||||
for (const variant of IMAGE_VARIANTS) {
|
||||
const options = {
|
||||
maxWidthOrHeight: variant.maxWidth,
|
||||
useWebWorker: true,
|
||||
initialQuality: variant.quality,
|
||||
fileType: "image/jpeg" as const,
|
||||
};
|
||||
|
||||
try {
|
||||
const compressedFile = await imageCompression(file, options);
|
||||
|
||||
// Create new File with variant-specific name
|
||||
const variantFile = new File(
|
||||
[compressedFile],
|
||||
generateVariantFilename(file.name, variant.suffix),
|
||||
{ type: "image/jpeg" }
|
||||
);
|
||||
|
||||
results.push({
|
||||
variant,
|
||||
file: variantFile,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(`Failed to resize image for ${variant.size}:`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate filename with variant suffix
|
||||
* e.g., "photo.png" + "_th" => "photo_th.jpg"
|
||||
*/
|
||||
function generateVariantFilename(
|
||||
originalName: string,
|
||||
suffix: string
|
||||
): string {
|
||||
const lastDot = originalName.lastIndexOf(".");
|
||||
const baseName = lastDot === -1 ? originalName : originalName.substring(0, lastDot);
|
||||
return `${baseName}${suffix}.jpg`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive S3 key for a specific variant from the base key
|
||||
* e.g., "items/uuid.jpg" + "_th" => "items/uuid_th.jpg"
|
||||
*/
|
||||
export function getVariantKey(baseKey: string, suffix: string): string {
|
||||
if (!suffix) return baseKey;
|
||||
const lastDot = baseKey.lastIndexOf(".");
|
||||
if (lastDot === -1) return `${baseKey}${suffix}`;
|
||||
return `${baseKey.substring(0, lastDot)}${suffix}${baseKey.substring(lastDot)}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the suffix for a given size
|
||||
*/
|
||||
export function getSizeSuffix(
|
||||
size: "thumbnail" | "medium" | "original"
|
||||
): string {
|
||||
const variant = IMAGE_VARIANTS.find((v) => v.size === size);
|
||||
return variant?.suffix || "";
|
||||
}
|
||||
Reference in New Issue
Block a user