Files
memegoat/backend/src/media/strategies/image-processor.strategy.ts
Mathis HERRIOT 47d6fcb6a0 feat(media): add image resizing support for processImage
Extend the `processImage` method to support optional resizing with `width` and `height` parameters. Update processing pipeline to handle resizing while maintaining existing format processing for `webp` and `avif`.
2026-01-14 21:44:00 +01:00

56 lines
1.5 KiB
TypeScript

import { BadRequestException, Injectable, Logger } from "@nestjs/common";
import sharp from "sharp";
import type { MediaProcessingResult } from "../../common/interfaces/media.interface";
import type { IMediaProcessorStrategy } from "./media-processor.strategy";
@Injectable()
export class ImageProcessorStrategy implements IMediaProcessorStrategy {
private readonly logger = new Logger(ImageProcessorStrategy.name);
canHandle(mimeType: string): boolean {
return mimeType.startsWith("image/");
}
async process(
buffer: Buffer,
options: {
format: "webp" | "avif";
resize?: { width?: number; height?: number };
} = { format: "webp" },
): Promise<MediaProcessingResult> {
try {
const { format, resize } = options;
let pipeline = sharp(buffer);
if (resize) {
pipeline = pipeline.resize(resize.width, resize.height, {
fit: "cover",
position: "center",
});
}
const metadata = await pipeline.metadata();
if (format === "webp") {
pipeline = pipeline.webp({ quality: 80, effort: 6 });
} else {
pipeline = pipeline.avif({ quality: 65, effort: 6 });
}
const processedBuffer = await pipeline.toBuffer();
return {
buffer: processedBuffer,
mimeType: `image/${format}`,
extension: format,
width: metadata.width,
height: metadata.height,
size: processedBuffer.length,
};
} catch (error) {
this.logger.error(`Error processing image: ${error.message}`);
throw new BadRequestException("Failed to process image");
}
}
}