diff --git a/docs/performance.md b/docs/performance.md index c32ba183..2f7d6555 100644 --- a/docs/performance.md +++ b/docs/performance.md @@ -3,19 +3,17 @@ ### Test environment * AWS EC2 eu-west-1 [c5.large](https://aws.amazon.com/ec2/instance-types/c5/) (2x Xeon Platinum 8124M CPU @ 3.00GHz) -* Ubuntu 17.10 (hvm:ebs-ssd, 20180102, ami-0741d47e) -* Node.js v8.9.4 +* Ubuntu 18.04 (hvm-ssd/ubuntu-bionic-18.04-amd64-server-20180912 ami-00035f41c82244dab) +* Node.js v10.11.0 ### The contenders -* [jimp](https://www.npmjs.com/package/jimp) v0.2.28 - Image processing in pure JavaScript. Bilinear interpolation only. -* [pajk-lwip](https://www.npmjs.com/package/pajk-lwip) v0.2.0 (fork) - Wrapper around CImg that compiles dependencies from source. -* [mapnik](https://www.npmjs.org/package/mapnik) v3.6.2 - Whilst primarily a map renderer, Mapnik contains bitmap image utilities. +* [jimp](https://www.npmjs.com/package/jimp) v0.5.3 - Image processing in pure JavaScript. Provides bicubic interpolation. +* [mapnik](https://www.npmjs.org/package/mapnik) v4.0.1 - Whilst primarily a map renderer, Mapnik contains bitmap image utilities. * [imagemagick-native](https://www.npmjs.com/package/imagemagick-native) v1.9.3 - Wrapper around libmagick++, supports Buffers only. * [imagemagick](https://www.npmjs.com/package/imagemagick) v0.1.3 - Supports filesystem only and "*has been unmaintained for a long time*". * [gm](https://www.npmjs.com/package/gm) v1.23.1 - Fully featured wrapper around GraphicsMagick's `gm` command line utility. -* [images](https://www.npmjs.com/package/images) v3.0.1 - Compiles dependencies from source. Provides bicubic interpolation. -* sharp v0.19.0 / libvips v8.6.1 - Caching within libvips disabled to ensure a fair comparison. +* sharp v0.21.0 / libvips v8.7.0 - Caching within libvips disabled to ensure a fair comparison. ### The task @@ -27,19 +25,14 @@ then compress to JPEG at a "quality" setting of 80. | Module | Input | Output | Ops/sec | Speed-up | | :----------------- | :----- | :----- | ------: | -------: | -| jimp (bilinear) | buffer | buffer | 1.14 | 1.0 | -| lwip | buffer | buffer | 1.86 | 1.6 | -| mapnik | buffer | buffer | 3.34 | 2.9 | -| imagemagick-native | buffer | buffer | 4.13 | 3.6 | -| gm | buffer | buffer | 4.21 | 3.7 | -| gm | file | file | 4.27 | 3.7 | -| imagemagick | file | file | 4.67 | 4.1 | -| images (bicubic) | file | file | 6.22 | 5.5 | -| sharp | stream | stream | 24.43 | 21.4 | -| sharp | file | file | 25.97 | 22.7 | -| sharp | file | buffer | 26.00 | 22.8 | -| sharp | buffer | file | 26.33 | 23.0 | -| sharp | buffer | buffer | 26.43 | 23.1 | +| jimp | buffer | buffer | 0.71 | 1.0 | +| mapnik | buffer | buffer | 3.32 | 4.7 | +| gm | buffer | buffer | 3.97 | 5.6 | +| imagemagick-native | buffer | buffer | 4.06 | 5.7 | +| imagemagick | file | file | 4.24 | 6.0 | +| sharp | stream | stream | 25.30 | 35.6 | +| sharp | file | file | 26.17 | 36.9 | +| sharp | buffer | buffer | 26.45 | 37.3 | Greater libvips performance can be expected with caching enabled (default) and using 8+ core machines, especially those with larger L1/L2 CPU caches. @@ -57,7 +50,7 @@ brew install mapnik ``` ```sh -sudo apt-get install imagemagick libmagick++-dev graphicsmagick mapnik-dev +sudo apt-get install imagemagick libmagick++-dev graphicsmagick libmapnik-dev ``` ```sh diff --git a/test/bench/package.json b/test/bench/package.json index 3c10314e..31c86692 100644 --- a/test/bench/package.json +++ b/test/bench/package.json @@ -13,10 +13,8 @@ "gm": "^1.23.1", "imagemagick": "^0.1.3", "imagemagick-native": "^1.9.3", - "images": "^3.0.1", "jimp": "^0.5.3", "mapnik": "^4.0.1", - "pajk-lwip": "^0.2.0", "semver": "^5.5.1" }, "license": "Apache-2.0", diff --git a/test/bench/perf.js b/test/bench/perf.js index c7ced5bb..b52d1ea9 100644 --- a/test/bench/perf.js +++ b/test/bench/perf.js @@ -12,24 +12,12 @@ const gm = require('gm'); const imagemagick = require('imagemagick'); const mapnik = require('mapnik'); const jimp = require('jimp'); -let images; -try { - images = require('images'); -} catch (err) { - console.log('Excluding node-images'); -} let imagemagickNative; try { imagemagickNative = require('imagemagick-native'); } catch (err) { console.log('Excluding imagemagick-native'); } -let lwip; -try { - lwip = require('pajk-lwip'); -} catch (err) { - console.log('Excluding lwip'); -} const fixtures = require('../fixtures'); @@ -38,8 +26,6 @@ const height = 588; // Disable libvips cache to ensure tests are as fair as they can be sharp.cache(false); -// Enable use of SIMD -sharp.simd(true); async.series({ 'jpeg': function (callback) { @@ -87,51 +73,6 @@ async.series({ }); } }); - // lwip - if (typeof lwip !== 'undefined') { - jpegSuite.add('lwip-file-file', { - defer: true, - fn: function (deferred) { - lwip.open(fixtures.inputJpg, function (err, image) { - if (err) { - throw err; - } - image.resize(width, height, 'lanczos', function (err, image) { - if (err) { - throw err; - } - image.writeFile(fixtures.outputJpg, {quality: 80}, function (err) { - if (err) { - throw err; - } - deferred.resolve(); - }); - }); - }); - } - }).add('lwip-buffer-buffer', { - defer: true, - fn: function (deferred) { - lwip.open(inputJpgBuffer, 'jpg', function (err, image) { - if (err) { - throw err; - } - image.resize(width, height, 'lanczos', function (err, image) { - if (err) { - throw err; - } - image.toBuffer('jpg', {quality: 80}, function (err, buffer) { - if (err) { - throw err; - } - assert.notStrictEqual(null, buffer); - deferred.resolve(); - }); - }); - }); - } - }); - } // mapnik jpegSuite.add('mapnik-file-file', { defer: true, @@ -272,14 +213,6 @@ async.series({ }); } }); - // images - if (typeof images !== 'undefined') { - jpegSuite.add('images-file-file', function () { - images(fixtures.inputJpg) - .resize(width, height) - .save(fixtures.outputJpg, { quality: 80 }); - }); - } // sharp jpegSuite.add('sharp-buffer-file', { defer: true, @@ -569,8 +502,10 @@ async.series({ defer: true, fn: function (deferred) { sharp(inputJpgBuffer) - .resize(width, height) - .crop(sharp.strategy.entropy) + .resize(width, height, { + fit: 'cover', + position: sharp.strategy.entropy + }) .toBuffer(function (err, buffer) { if (err) { throw err; @@ -584,8 +519,10 @@ async.series({ defer: true, fn: function (deferred) { sharp(inputJpgBuffer) - .resize(width, height) - .crop(sharp.strategy.attention) + .resize(width, height, { + fit: 'cover', + position: sharp.strategy.attention + }) .toBuffer(function (err, buffer) { if (err) { throw err; @@ -696,31 +633,6 @@ async.series({ }); } }); - // lwip - if (typeof lwip !== 'undefined') { - pngSuite.add('lwip-buffer-buffer', { - defer: true, - fn: function (deferred) { - lwip.open(inputPngBuffer, 'png', function (err, image) { - if (err) { - throw err; - } - image.resize(width, height, 'lanczos', function (err, image) { - if (err) { - throw err; - } - image.toBuffer('png', function (err, buffer) { - if (err) { - throw err; - } - assert.notStrictEqual(null, buffer); - deferred.resolve(); - }); - }); - }); - } - }); - } // mapnik pngSuite.add('mapnik-file-file', { defer: true, @@ -833,14 +745,6 @@ async.series({ }); } }); - // images - if (typeof images !== 'undefined') { - pngSuite.add('images-file-file', function () { - images(fixtures.inputPng) - .resize(width, height) - .save(fixtures.outputPng); - }); - } // sharp pngSuite.add('sharp-buffer-file', { defer: true,