秋の天皇賞の外枠不利を同僚に話したところ、
競馬を知らない方には新鮮な情報だったようで、とても驚かれました。
どうでもいいですね。アジャストの渕上です。
相変わらずブログの持ち回りが早くて疲労困憊です。
終始競馬の話を書いててよければどうにでもなるのですが、
そういうわけにもいかなそうですので、
今回も先週に引き続きnode.jsで簡単に画像の加工ができる
モジュールをご紹介していきたいと思います!
今回は、gm(GrahicsMagick for node)を使って、
2枚の画像の重ね合わせを行ってみます。
GraphicsMagickのインストール
nodeのmoduleをインストールする前に、GraphicsMagick本体をインストールしておきます。
GraphicsMagickはImageMagickの派生ライブラリで、
処理速度に定評があるそうです。
(既に方々で比較されてるとは思いますが)ImageMagickとの処理速度比較を行ってみても面白いかもしれませんね。
Ubuntuの仮想マシンで作業を行ったので、aptでインストールしました。
CentOSでやる場合は、たぶんyumでインストールできると思います。
(今回はyumにパッケージがあるか調べていません。あしからず。)
$ sudo add-apt-repository ppa:dhor/myway
$ sudo apt-get update
$ sudo apt-get install graphicsmagick
特に事件も起こらず、するっとインストールできました。
gmのインストール
npmコマンドでインストールしましょう。
$ npm install gm
gmで実装してみる
前回とほぼ同じですが、サーバ側のコードを下記のように書き換えました。
1 var express = require('express');
2 var app = express();
3 var multer = require('multer');
4 var fs = require('fs');
5 var gm = require('gm');
6
7
8 var upload = multer({dest: 'uploads'});
9
10 app.set('view engine', 'jade');
11 app.set('views', __dirname + '/views');
12
13
14 app.get('/', function(req, res) {
15 res.render('index', {title: 'test'});
16 });
17
18 app.post('/merge', upload.fields([ {name: 'base_img', maxCount: 1}, {name: 'over_img', maxCount: 1} ]), function(req, res) {
19
20 /*
21 * この処理は下記のコマンドと同じ、、のはず。
22 * gm composite -quality 100 -geometry +10+10 {元の画像} {重ねる画像}
23 */
24 gm(req.files.base_img[0].path) // 元の画像
25 .composite(req.files.over_img[0].path) // 重ねる画像
26 .geometry('+10+10') // 重ねる画像の位置(標準は左上起点)
27 .quality(100) // クオリティはとりあえず最大
28 .stream()
29 .pipe(res);
30 /*
31 * 直接画像をレスポンスするのでなく、テンプレートに当てはめる場合は
32 * .stream().pipe(res)
33 * をやめて下記のようにできる。(dataURL化してimgタグに埋め込むようにする)
34 .toBuffer('PNG', function(error, buffer){
35 res.render('merge', {resultImg: 'data:image/png;base64,'+buffer.toString('base64')});
36 });
37 */
38 });
39
40 app.locals.pretty = true;
41 app.listen(8080);
上記のうち、GraphicsMagickでの操作を行っているのは↓の部分です。
GraphicsMagickのgm
コマンドに渡すオプションや引数をメソッドチェーンで渡していくことができます。
20 /*
21 * この処理は下記のコマンドと同じ、、のはず。
22 * gm composite -quality 100 -geometry +10+10 {元の画像} {重ねる画像}
23 */
24 gm(req.files.base_img[0].path) // 元の画像
25 .composite(req.files.over_img[0].path) // 重ねる画像
26 .geometry('+10+10') // 重ねる画像の位置(標準は左上起点)
27 .quality(100) // クオリティはとりあえず最大
28 .stream() // gmの出力ストリームをレスポンスにつなぐ(パイプする)
29 .pipe(res);
30 /*
31 * 直接画像をレスポンスするのでなく、テンプレートに当てはめる場合は
32 * .stream().pipe(res)
33 * をやめて下記のようにできる。(dataURL化してimgタグに埋め込むようにする)
34 .toBuffer('PNG', function(error, buffer){
35 res.render('merge', {resultImg: 'data:image/png;base64,'+buffer.toString('base64')});
36 });
37 */
GraphicsMagickのコマンドを把握している人なら、
gm moduleのREADMEを眺めればなんとなくわかるかもしれません。
私は、GraphicsMagick自体触ったことがなかったので、
GraphicsMagickのドキュメントと照らし合わせながら、何度かトライ&エラーを繰り返しましたが、
GraphicsMagickのオプションやコマンド名とgmモジュールのメソッド名が大体同じだったので、
そんなに苦労せずにゴールに行き着くことができました。
動作デモ
ベースにする画像 (penguin.jpg)
重ねる画像 (logo.png)
ブラウザ操作の動画キャプチャ
感想
gm
モジュール編、いかがだったでしょうか。
今回や前回の例のように画像をPOSTさせて合成して返すだけでは、PHPなどを使った実装と結果に大差ないですが、
WebSocketなどと組み合わせると、なんか面白いものが作れるのではないでしょうか。(アバウトですいません。)
また、今回なんとなくStream
を使ってみましたが、
node.jsを触り始めたばかりで、Stream
の仕組みをよく理解できていないので、
腰を据えて勉強してみたいなと思います。
コメントを残す