Node.jsでCanvas(ImageData)を使った簡単な画像処理

  • 22
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

背景

画像を扱うときにHTML5のCanvasのImageDataがフォーマットとかを意識せずに画素単位でアクセスできて簡単!
Nodeだけでできないかなぁって思ってたらnode-canvasを使うことでできました。

ImageDataとは?

HTML5のCanvasをJavaScriptで扱うときの画像の画素値の配列みたいなものです。
以下のカヤックの人が書いた記事がわかりやすいのでご参照ください。
canvasをバイト単位で修正する方法(ImageDataの使い方)

環境

Windows10上でVagrantを使った仮想マシンを作りました。
仮想マシンのOSはubuntu/trusty64を使いました。
Node.jsをそのままいれるとコマンドが"node"ではなく"nodejs"になってしまうので、シンボリックリンクを作成しています。

Ubuntuにインストールする場合
$ sudo apt-get install nodejs -y
$ sudo ln -s /usr/bin/nodejs /usr/bin/node
$ sudo apt-get install npm -y

事前準備

node-canvasを使います。
carioを使うので先にインストールしてから、npmで任意の場所にnode-canvasをいれます。

Ubuntuにインストールする場合
$ sudo apt-get install libcairo2-dev
$ npm install canvas

カラー画像を擬似モノクロにしてみる

実際に画像(プロ生ちゃん)を読み込み、画像処理を行いファイルとして出力してみます。node canvas_test.jsを実行すると同じディレクトリ内の"pronama.png"から擬似モノクロ画像"monochrome.png"を出力します。

こんな感じになります。
処理前 (pronama.png)
pronama.png

処理後 (monochrome.png)
monochrome.png

コード

canvas_test.js
// Node.js標準装備のファイルの読み書きするやつ
var fs = require('fs');

// 別途用意した画像を保存してくれるやつ
var canvas_saver = require('./canvas_saver.js');

// node-canvas
var Canvas = require('canvas'),
    Image = Canvas.Image;

fs.readFile(__dirname + '/pronama.png', function(err, data){
    if (err) throw err;

    // データをcanvasのcontextに設定
    var img = new Image;
    img.src = data;
    var canvas = new Canvas(img.width, img.height);
    var ctx = canvas.getContext('2d');
    ctx.drawImage(img, 0, 0, img.width, img.height);

    // RGBの画素値の配列を取得
    var imagedata = ctx.getImageData(0, 0, img.width, img.height);

    // 画像加工(擬似モノクロ化)
    for(var y=0; y<imagedata.height; y++){
        for(var x=0; x<imagedata.width; x++){
            var index = (y*imagedata.width+x)*4;
            // imagedata.data[index] = imagedata.data[index]; // R
            imagedata.data[index+1] = imagedata.data[index]; // G
            imagedata.data[index+2] = imagedata.data[index]; // B
            // imagedata.data[index+3]; // alpha
        }
    }

    // 加工したデータをセット
    ctx.putImageData(imagedata, 0, 0);

    // データを保存
    canvas_saver.save(canvas, "monochrome.png", function(){
        console.log("画像保存完了したよ!!");
    });

});
canvas_saver.js
// node-canvasのcanvasを画像データとして保存する

module.exports = (function(){
    "use strict";

    var fs = require('fs');

    var canvas_to_base64 = function(canvas){
        return canvas.toDataURL().split(',')[1];
    }

    var decode_and_copy = function(string, filename, callback) {
        var buffer = new Buffer(string, 'base64');
        fs.writeFile(filename, buffer, callback);
    }

    return {
        save: function(canvas, name, callback){
            decode_and_copy(
                canvas_to_base64(canvas),
                name,
                callback
            );
        }
    }

})();

その他の例

ImageDataを取得することによって、画像のヘッダやフォーマットを意識せずに画像の画素値をいじれます。
例えば、擬似モノクロ化の部分を以下のように書き換えれば簡単にネガポジ反転の処理が行えます。

ネガポジ反転
imagedata.data[index] = 255 - imagedata.data[index]; // R
imagedata.data[index+1] = 255 - imagedata.data[index+1]; // G
imagedata.data[index+2] = 255 - imagedata.data[index+2]; // B
// imagedata.data[index+3]; // alpha

まとめ

node-canvasを利用して、Web上のCanvasの扱いのように画像処理が行うことができた。

参考文献など

node-canvas
canvasをバイト単位で修正する方法(ImageDataの使い方)
サーバサイドでCanvasを利用する(node.js)
プロ生ちゃん
ImageData仕様書

その他

間違いや意見等ありましたら、ぜひコメントください。