diff --git a/benchmark/bear.png b/benchmark/bear.png new file mode 100644 index 0000000..3c3f4a5 Binary files /dev/null and b/benchmark/bear.png differ diff --git a/benchmark/liquid_rescale.js b/benchmark/liquid_rescale.js new file mode 100644 index 0000000..ef600fb --- /dev/null +++ b/benchmark/liquid_rescale.js @@ -0,0 +1,43 @@ +const path = require('node:path'); +const fs = require('node:fs'); +const concolor = require('concolor'); +const gm = require('gm').subClass({ imageMagick: true }); +const { liquidRescale } = require('../dist/index.js'); +const { Suite } = require('benchmark'); + +const image = fs.readFileSync(path.join(path.resolve(), 'benchmark', 'bear.png')); +const suite = new Suite("Liquid rescale and resize image"); + +function liquidRescaleWithGm() { + return new Promise((resolve, reject) => { + gm(image).size((err, size) => { + if (err) reject(err); + + const width = size.width; + const height = size.height; + + gm(image).out('-liquid-rescale', "400x400") + .toBuffer('JPEG', (err, buf) => { + if (err) reject(err); + + gm(buf).resize(width, height) + .toBuffer('JPEG', (err, buf) => { + err ? reject(err) : resolve(buf); + }); + }); + }); + }); +} + +suite + .add('gm', async () => { + await liquidRescaleWithGm(); + }) + .add('native', async () => { + await liquidRescale(image, 400, 400); + }) + .on('cycle', (event) => console.info(String(event.target))) + .on('complete', function () { + console.info(`${this.name} bench suite: Fastest is ${concolor`${this.filter('fastest').map('name')}(green)`}`); + }) + .run({ async: true }); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 3ae0876..0eaef17 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,18 @@ { "name": "libdistbot", + "version": "0.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "libdistbot", + "version": "0.0.0", "devDependencies": { "@napi-rs/cli": "^2.16.3", + "benchmark": "^2.1.4", + "concolor": "^1.0.6", + "cross-env": "^7.0.3", + "gm": "^1.25.0", "rimraf": "^5.0.5" }, "engines": { @@ -80,12 +86,34 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/array-parallel": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/array-parallel/-/array-parallel-0.1.3.tgz", + "integrity": "sha512-TDPTwSWW5E4oiFiKmz6RGJ/a80Y91GuLgUYuLd49+XBS75tYo8PNgaT2K/OxuQYqkoI852MDGBorg9OcUSTQ8w==", + "dev": true + }, + "node_modules/array-series": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/array-series/-/array-series-0.1.5.tgz", + "integrity": "sha512-L0XlBwfx9QetHOsbLDrE/vh2t018w9462HM3iaFfxRiK83aJjAt/Ja3NMkOW7FICwWTlQBa3ZbL5FKhuQWkDrg==", + "dev": true + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/benchmark": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", + "integrity": "sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ==", + "dev": true, + "dependencies": { + "lodash": "^4.17.4", + "platform": "^1.3.3" + } + }, "node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -113,6 +141,37 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/concolor": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/concolor/-/concolor-1.0.6.tgz", + "integrity": "sha512-ddSzRU6ge2AHTzCKyo0Jb6mB2PiBW0CgkiCazYDmZZXlqTNrAwiLv6JDWygaUo30wYwsBJ6q/Qpg/57wkivxBg==", + "dev": true, + "engines": { + "node": "16 || 18 || 19 || 20" + }, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/tshemsedinov" + } + }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -127,6 +186,15 @@ "node": ">= 8" } }, + "node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -177,6 +245,53 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/gm": { + "version": "1.25.0", + "resolved": "https://registry.npmjs.org/gm/-/gm-1.25.0.tgz", + "integrity": "sha512-4kKdWXTtgQ4biIo7hZA396HT062nDVVHPjQcurNZ3o/voYN+o5FUC5kOwuORbpExp3XbTJ3SU7iRipiIhQtovw==", + "dev": true, + "dependencies": { + "array-parallel": "~0.1.3", + "array-series": "~0.1.5", + "cross-spawn": "^4.0.0", + "debug": "^3.1.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gm/node_modules/cross-spawn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "integrity": "sha512-yAXz/pA1tD8Gtg2S98Ekf/sewp3Lcp3YoFKJ4Hkp5h5yLWnKVTDU0kwjKJ8NDCYcfTLfyGkzTikst+jWypT1iA==", + "dev": true, + "dependencies": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "node_modules/gm/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/gm/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -210,6 +325,12 @@ "@pkgjs/parseargs": "^0.11.0" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, "node_modules/lru-cache": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", @@ -243,6 +364,12 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -268,6 +395,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/platform": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", + "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==", + "dev": true + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "dev": true + }, "node_modules/rimraf": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", @@ -520,6 +659,12 @@ "engines": { "node": ">=8" } + }, + "node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true } } } diff --git a/package.json b/package.json index 045ee55..4839691 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "scripts": { "build": "napi build ./dist --platform --release", "build:debug": "napi build ./dist --platform", + "bench": "cross-env NODE_ENV=production node benchmark/liquid_rescale.js", "clean": "rimraf ./dist && rimraf ./target" }, "napi": { @@ -17,6 +18,10 @@ }, "devDependencies": { "@napi-rs/cli": "^2.16.3", + "benchmark": "^2.1.4", + "concolor": "^1.0.6", + "cross-env": "^7.0.3", + "gm": "^1.25.0", "rimraf": "^5.0.5" } -} \ No newline at end of file +} diff --git a/src/liquid_rescale_task.rs b/src/liquid_rescale_task.rs index a9af24e..934451c 100644 --- a/src/liquid_rescale_task.rs +++ b/src/liquid_rescale_task.rs @@ -36,7 +36,7 @@ impl LiquidRescaleTask { .map_err(|err| Error::new(Status::InvalidArg, format!("{err}")))?; let input_width = wand.get_image_width(); let input_height = wand.get_image_height(); - wand.liquid_rescale_image(width, height, 0.0, 1.0) + wand.liquid_rescale_image(width, height, 1.0, 0.0) .map_err(|err| Error::new(Status::GenericFailure, format!("{err}")))?; wand.resize_image(input_width, input_height, FilterType_LanczosFilter); let output_image = wand