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`.
56 lines
1.5 KiB
TypeScript
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");
|
|
}
|
|
}
|
|
}
|