sharp-multer
Version:
Multer Engine for Image Optimization and tweaking using Sharp
133 lines (116 loc) • 3.44 kB
JavaScript
const fs = require("fs");
const sharp = require("sharp");
const getDestination = (req, file, cb) => {
cb(null, "/dev/null");
};
const getFilenameDefault = (name, input) =>
name.split(".").slice(0, -1).join(".") +
`${input.useTimestamp ? "-" + Date.now() : ""}` +
"." +
input.fileFormat;
const prepareSharpStream = (SharpStram, input) => {
if (input.resize) {
const { width, height, resizeMode, withoutEnlargement } = input.resize;
SharpStram.resize({
width,
height,
fit: resizeMode,
withoutEnlargement
});
}
switch (input.fileFormat) {
case "png":
return SharpStram.png(input.quality ? { quality: input.quality } : {});
case "webp":
return SharpStram.webp(input.quality ? { quality: input.quality } : {});
case "jpg":
return SharpStram.jpeg(input.quality ? { quality: input.quality } : {});
default:
return SharpStram.jpeg(input.quality ? { quality: input.quality } : {});
}
};
const handleWatermark = async (SharpStram, input) => {
let gravity = "";
switch (input.location) {
case "top-left":
gravity = "northwest";
break;
case "top-right":
gravity = "northeast";
break;
case "bottom-left":
gravity = "southwest";
break;
case "bottom-right":
gravity = "southeast";
break;
}
// preparing watermark with transparency
const opacity = input.opacity ? Number(input.opacity) * 2.55 : 255;
const watermarkStream = await sharp(input.input)
.composite([
{
input: Buffer.from([0, 0, 0, opacity]),
raw: {
width: 1,
height: 1,
channels: 4,
},
tile: true,
blend: "dest-in",
},
])
.toFormat("png")
.toBuffer();
return SharpStram.composite([
{ input: watermarkStream, gravity: gravity || "center", blend: "atop" },
]);
};
const handleSave = async (
req,
file,
cb,
imageOptions,
path,
watermarkOptions,
filename
) => {
let stream = sharp();
// preparing harp functions based on inputs
// checking if watermark is provided or not
if (watermarkOptions)
stream = await handleWatermark(stream, watermarkOptions);
//handling image Options
stream = prepareSharpStream(stream, imageOptions);
await stream.toFile(path + "/" + filename, function (err) {
if (err) console.log(err);
cb(null, {
filename: filename,
path: path + "/" + filename,
});
});
// finally
file.stream.pipe(stream);
};
function MyCustomStorage(options) {
this.getDestination = options.destination || getDestination;
this.imageOptions = options.imageOptions ||
options.sharpOptions || { fileFormat: "jpg", quality: 80 };
this.watermarkOptions = options.watermarkOptions;
this.getFilename = options.filename || getFilenameDefault;
}
MyCustomStorage.prototype._handleFile = function _handleFile(req, file, cb) {
const imageOptions = this.imageOptions;
const watermarkOptions = this.watermarkOptions;
const filename = this.getFilename(file.originalname, imageOptions, req);
this.getDestination(req, file, function (err, path) {
if (err) return cb(err);
handleSave(req, file, cb, imageOptions, path, watermarkOptions, filename);
});
};
MyCustomStorage.prototype._removeFile = function _removeFile(req, file, cb) {
fs.unlink(file.path, cb);
};
module.exports = function (opts) {
return new MyCustomStorage(opts);
};