feat: add image transform route with Sharp resize and crop
This commit is contained in:
65
backend/src/routes/image.ts
Normal file
65
backend/src/routes/image.ts
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import { Router } from "express";
|
||||||
|
import multer from "multer";
|
||||||
|
import sharp from "sharp";
|
||||||
|
import { TransformRequest } from "../types/image";
|
||||||
|
|
||||||
|
const upload = multer({ storage: multer.memoryStorage() });
|
||||||
|
const router = Router();
|
||||||
|
|
||||||
|
router.post(
|
||||||
|
"/transform",
|
||||||
|
upload.single("file"),
|
||||||
|
async (req, res): Promise<void> => {
|
||||||
|
if (!req.file) {
|
||||||
|
res.status(400).json({ error: "No file uploaded" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
quality,
|
||||||
|
format = "png",
|
||||||
|
fit = "inside",
|
||||||
|
position = "center"
|
||||||
|
} = req.body as any;
|
||||||
|
|
||||||
|
const numericWidth = width ? Number(width) : undefined;
|
||||||
|
const numericHeight = height ? Number(height) : undefined;
|
||||||
|
const numericQuality = quality ? Number(quality) : 80;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let image = sharp(req.file.buffer);
|
||||||
|
|
||||||
|
image = image.resize({
|
||||||
|
width: numericWidth,
|
||||||
|
height: numericHeight,
|
||||||
|
fit, // "inside" (no crop) or "cover" (crop to fill)
|
||||||
|
position, // where to crop when fit === "cover"
|
||||||
|
withoutEnlargement: true
|
||||||
|
});
|
||||||
|
|
||||||
|
if (format === "webp") {
|
||||||
|
image = image.webp({ quality: numericQuality });
|
||||||
|
} else if (format === "jpeg") {
|
||||||
|
image = image.jpeg({ quality: numericQuality });
|
||||||
|
} else {
|
||||||
|
image = image.png({ quality: numericQuality, compressionLevel: 9 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const outputBuffer = await image.toBuffer();
|
||||||
|
|
||||||
|
res.setHeader("Content-Type", `image/${format}`);
|
||||||
|
res.setHeader(
|
||||||
|
"Content-Disposition",
|
||||||
|
`attachment; filename="output.${format}"`
|
||||||
|
);
|
||||||
|
res.send(outputBuffer);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
res.status(500).json({ error: "Image processing failed" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export default router;
|
||||||
Reference in New Issue
Block a user