I\'m developing a web app on Node.js (+ express 4) where users can set their profile image by uploading it to the server. We already limit the file mimetype and max filesize
Canvas is 2.3 times faster than ImageMagic.
You can try to compare Node.js modules for images manipulation - https://github.com/ivanoff/images-manipulation-performance
author's results:
sharp.js : 9.501 img/sec; minFreeMem: 929Mb
canvas.js : 8.246 img/sec; minFreeMem: 578Mb
gm.js : 4.433 img/sec; minFreeMem: 791Mb
gm-imagemagic.js : 3.654 img/sec; minFreeMem: 804Mb
lwip.js : 1.203 img/sec; minFreeMem: 54Mb
jimp.js : 0.445 img/sec; minFreeMem: 82Mb
I would vote for sharp:
sharp('input.jpg')
.resize(200, 200)
.toFile('ouput.jpg', function(err) {
// output.jpg is a 200 pixels wide and 200 pixels high image
// containing a scaled and cropped version of input.jpg
});
It's fast, typically 6x faster than the fastest imagemagick-based node bindings, and runs in very little memory, perhaps 10x less. sharp links to the libvips image library directly, there is no shelling out to an external program, and the library itself is faster and more efficient than *magick at this task. It supports useful things like stream, buffer and filesystem input and output, colour management, transparency, promises, overlays, WebP, SVG, and more.
As of sharp 0.20, npm will automatically download complete pre-compiled binaries on most platforms, so there's no need for node-gyp. Just enter:
npm install sharp
or:
yarn add sharp
And off you go.
Sharp work very well and is easy to use with streams, work like a charm, but you need to compile it with the node version, this is a downside to it. I was using Sharp for image processing, with an image from an AWS S3 bucket and worked perfectly, but I had to use another module. GM didn't work for me, but Jimp worked very good!
You have to pay attention to the path of the written picture, it might give you some errors if you start the path with a "/".
This is how I used Jimp in nodeJS:
const imageUrl = `SOME_URL`;
let imgExported = 'EXPORTED_PIC.png';
Jimp.read(imageUrl)
.then(image => {
image
.resize(X, Y)
.write(`tmp/`+ imgExported, err => {
if(err)
console.error('Write error: ', err);
else { ... // don't forget to put a callback() } }
});
Also watch out for the order of execution, put a callback so other things don't happen when you don't want to. Tried using "await" for the Jimp.read() but it didn't do the job well.
If you don't need a large image, you can resize it on the client side before uploading it:
Reading files in JavaScript using the File APIs
Image resizing client-side with javascript before upload to the server
Many users might have a good picture of themselves from a smartphone, and many of them are over 200kB. Note that client-provided data is not to be trusted, so server-side checks still apply.
There is a good image manipulation library written entirely in JavaScript, without dependencies to any other libraries, Jimp. https://github.com/oliver-moran/jimp
Example usage:
var Jimp = require("jimp");
// open a file called "lenna.png"
Jimp.read("lenna.png", function (err, lenna) {
if (err) throw err;
lenna.resize(256, 256) // resize
.quality(60) // set JPEG quality
.write("lena-small.jpg"); // save
});
I like resize-img library for its simplicity.
const fs = require('fs');
const resizeImg = require('resize-img');
(async () => {
const image = fs.readFileSync('unicorn.png');
const newImage = await resizeImg(image, { width: 128, height: 128 });
fs.writeFileSync('unicorn-128x128.png', newImage);
})();