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 { 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"); } } }