Node.jsのimagamagick-nativeを使ってみる
いつもchild_process.exec経由でImageMagickを呼び出していたのだけど、imagemagick-nativeというNode.js用のネイティブAPIがあるようなので試してみました。
yumでImageMagickを入れる
Macなら
$ brew install imagemagick
CentOSなら
$ sudo yum install ImageMagick-c++ ImageMagick-c++-devel
npmでimagemagick-nativeを入れる
$ npm install imagemagick-native
../src/imagemagick.cc:188: error: no matching function for call to ‘Magick::Image::extent(Magick::Geometry&, Magick::Color&)’
/usr/include/ImageMagick/Magick++/Image.h:296: note: candidates are: void Magick::Image::extent(const Magick::Geometry&)
make: *** [Release/obj.target/imagemagick/src/imagemagick.o] Error 1
make: Leaving directory `/home/hentai-kun/node/sandbox/node_modules/imagemagick-native/build'
gyp ERR! build error
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack at ChildProcess.onExit (/usr/local/nvm/v0.10.17/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:267:23)
gyp ERR! stack at ChildProcess.EventEmitter.emit (events.js:98:17)
gyp ERR! stack at Process.ChildProcess._handle.onexit (child_process.js:789:12)
gyp ERR! System Linux 2.6.32-358.14.1.el6.x86_64
gyp ERR! command "node" "/usr/local/nvm/v0.10.17/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
gyp ERR! cwd /home/hentai-kun/node/sandbox/node_modules/imagemagick-native
gyp ERR! node -v v0.10.17
gyp ERR! node-gyp -v v0.10.9
gyp ERR! not ok
npm ERR! weird error 1
npm ERR! not ok code 0
おおっと、CentOSではエラー。
READMEを読む
Install Imagemagick with headers before installing this module. Tested with ImageMagick 6.7.7 on CentOS6 and MacOS10.7, Ubuntu12.04 .
「ImageMagick 6.7.7以降でテストしているよ」とのことなので、入れたImageMagickのバージョンが古いみたい。どこかのリポジトリに新しいものがないかなと探したら、Remiにあった。
yumのリポジトリにRemiを追加する
$ wget http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
$ yum --enablerepo=remi info ImageMagick-last
Name : ImageMagick-last
Arch : x86_64
Version : 6.8.7.4
古いバージョンのImageMagickを消す
$ yum remove ImageMagick
新しいImageMagickを入れ直す
$ sudo yum --enablerepo=remi install ImageMagick-lsat-c++ ImageMagick-last-c++-devel
今度は成功した。
さっそく試してみる
Nikon D4のサンプル画像を使う
大きなサイズのほうが比較にいいかなということで。
$ wget http://www.nikon-image.com/products/camera/slr/digital/d4/img/sample/img_01_l.jpg
$ wget http://www.nikon-image.com/products/camera/slr/digital/d4/img/sample/img_02_l.jpg
$ wget http://www.nikon-image.com/products/camera/slr/digital/d4/img/sample/img_03_l.jpg
$ wget http://www.nikon-image.com/products/camera/slr/digital/d4/img/sample/img_04_l.jpg
$ wget http://www.nikon-image.com/products/camera/slr/digital/d4/img/sample/img_05_l.jpg
$ wget http://www.nikon-image.com/products/camera/slr/digital/d4/img/sample/img_06_l.jpg
比較するコード
'use strict';
var fs = require('fs');
var im = require('imagemagick-native');
var exec = require('child_process').exec;
var async = require('async');
var files = ['img_01_l.jpg', 'img_02_l.jpg', 'img_03_l.jpg', 'img_04_l.jpg', 'img_05_l.jpg', 'img_06_l.jpg'];
// ネイティブ版
function nativeIM() {
var startTime = new Date().getTime();
for (var i=0; i<files.length; i++) {
var srcData = fs.readFileSync(files[i]);
var resizedBuffer = im.convert({
srcData: srcData,
width: 100,
height: 100,
resizeStyle: 'aspectfill',
quality: 80,
format: 'JPEG'
});
fs.writeFileSync('native_' + files[i], resizedBuffer, 'binary');
}
console.log('native: ', new Date().getTime() - startTime + 'ms');
}
// コマンド版
function commandIM() {
var startTime = new Date().getTime();
async.eachSeries(files, function(file, nextFile) {
var cmd = 'convert -resize 100x100! -gravity center -quality 80 ' + file + ' JPEG:command_' + file;
exec(cmd, nextFile);
}, function() {
console.log('command: ', new Date().getTime() - startTime + 'ms');
});
}
// 実行
nativeIM();
commandIM();
実行結果
native: 6746ms
command: 6830ms
単発で処理させるだけだと速度はあまり変わらないみたい。 1枚の画像から複数のサムネイルを作るような処理をやったら速くなるのかな?