Raspberry Piのnode.jsでHTML5 Canvas実装のnode-canvasを使う

node.jsで、サーバサイドで画像を加工するライブラリとかないかなーと探していたら、HTML5 Canvasの実装がされたnode-canvasっていうのがあって、昔、http://labo.dtpwiki.jp/kousei/ （GitHubは[こちら](https://github.com/CLCL/kousei)）ていう文字校正サイトを作るときにWebブラウザ側ではあるがHTML5 Canvasを使ったし、あれならまあまあ使えるなあと思い、これをRaspberry Piでやってみます。

割と依存ライブラリが多いので、特にRaspberry Piに限定したインストール情報が有益かなあと思い、まとめました。

# 動作環境

極端な機種依存はないと思いますが、当方では以下の環境で動作確認しています。

- Raspberry Pi B+（1CPU、512MB RAM）
- NOOBS_v1_4_1.zip を使ってインストールしたRaspbian GNU/Linux 7
- node.jsはnode-armから入手できるv0.12系（[こっち](http://cl.hatenablog.com/entry/picari-ledmatrix-raspberrypi)でインストール例を書いた）
- apt-getするのでネットワーク接続が必要
- piユーザでログインできること、piユーザがsudoでroot使えること（Raspbianのデフォルト設定）

# インストール

apt-getでupdateしておきます。特にapt-get upgradeする必要はない。

```
pi@raspberrypi ~ $ sudo apt-get update
```

node-canvasを入れる時に必要とされるライブラリをapt-getで入れておきます。

```
pi@raspberrypi ~ $ sudo apt-get install libcairo2-dev libpango1.0-dev libjpeg8-dev libgif-dev
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
以下の特別パッケージがインストールされます:
  gir1.2-freedesktop gir1.2-pango-1.0 libcairo-script-interpreter2 libelfg0 libexpat1-dev
  libfontconfig1-dev libglib2.0-bin libglib2.0-dev libharfbuzz-dev libice-dev liblzo2-2
  libpcre3-dev libpcrecpp0 libpixman-1-dev libpthread-stubs0 libpthread-stubs0-dev libsm-dev
  libx11-dev libx11-doc libxau-dev libxcb-render0-dev libxcb-shm0-dev libxcb1-dev libxdmcp-dev
  libxext-dev libxft-dev libxrender-dev x11proto-core-dev x11proto-input-dev x11proto-kb-dev
  x11proto-render-dev x11proto-xext-dev xorg-sgml-doctools xtrans-dev
提案パッケージ:
  libcairo2-doc libglib2.0-doc libice-doc libpango1.0-doc imagemagick libsm-doc libxcb-doc
  libxext-doc
以下のパッケージが新たにインストールされます:
  gir1.2-freedesktop gir1.2-pango-1.0 libcairo-script-interpreter2 libcairo2-dev libelfg0
  libexpat1-dev libfontconfig1-dev libgif-dev libglib2.0-bin libglib2.0-dev libharfbuzz-dev
  libice-dev libjpeg8-dev liblzo2-2 libpango1.0-dev libpcre3-dev libpcrecpp0 libpixman-1-dev
  libpthread-stubs0 libpthread-stubs0-dev libsm-dev libx11-dev libx11-doc libxau-dev
  libxcb-render0-dev libxcb-shm0-dev libxcb1-dev libxdmcp-dev libxext-dev libxft-dev
  libxrender-dev x11proto-core-dev x11proto-input-dev x11proto-kb-dev x11proto-render-dev
  x11proto-xext-dev xorg-sgml-doctools xtrans-dev
アップグレード: 0 個、新規インストール: 38 個、削除: 0 個、保留: 25 個。
14.3 MB 中 0 B のアーカイブを取得する必要があります。
この操作後に追加で 38.4 MB のディスク容量が消費されます。
続行しますか [Y/n]? y
```

割とたくさんライブラリが必要です。

apt-getによる必要なパッケージのインストールが終わったら、プログラムを作りたいディレクトリを作り、その中に入って、npmでnode-canvasを入れます。

```
pi@raspberrypi ~ $ mkdir test
pi@raspberrypi ~ $ cd $_
pi@raspberrypi ~/test $ npm install canvas
-
> canvas@1.2.7 install /home/pi/test/node_modules/canvas
> node-gyp rebuild

make: Entering directory '/home/pi/test/node_modules/canvas/build'
  SOLINK_MODULE(target) Release/obj.target/canvas-postbuild.node
  COPY Release/canvas-postbuild.node
  CXX(target) Release/obj.target/canvas/src/Canvas.o
  CXX(target) Release/obj.target/canvas/src/CanvasGradient.o
  CXX(target) Release/obj.target/canvas/src/CanvasPattern.o
  CXX(target) Release/obj.target/canvas/src/CanvasRenderingContext2d.o
../src/CanvasRenderingContext2d.cc: In member function ‘void Context2d::shadow(void (*)(cairo_t*))’:
../src/CanvasRenderingContext2d.cc:379:22: warning: unused variable ‘surface’ [-Wunused-variable]
  CXX(target) Release/obj.target/canvas/src/color.o
  CXX(target) Release/obj.target/canvas/src/Image.o
  CXX(target) Release/obj.target/canvas/src/ImageData.o
  CXX(target) Release/obj.target/canvas/src/init.o
  CXX(target) Release/obj.target/canvas/src/PixelArray.o
  CXX(target) Release/obj.target/canvas/src/FontFace.o
  SOLINK_MODULE(target) Release/obj.target/canvas.node
  COPY Release/canvas.node
make: Leaving directory '/home/pi/test/node_modules/canvas/build'
canvas@1.2.7 node_modules/canvas
└── nan@1.9.0
pi@raspberrypi ~/test $
```

# サンプルプログラム

今回作ったプログラムはこれ。

```kanji.js
'use strict';

// kanji.js:
// node.jsでテキストバナーを表示します。

// use libs;

var Canvas = require('canvas');

// Const

var WIDTH     = 80;
var THRESHOLD = 100;

// 描画

var Image  = Canvas.Image;
var canvas = new Canvas(WIDTH, 16);
var ctx    = canvas.getContext('2d');

ctx.font = '16px Sans-serif';
ctx.fillText("漢字ＲＯＭ", 0, 11);
ctx.stroke();

// ピクセル走査

var imageData = ctx.getImageData(0, 0, WIDTH, 16);

for (var y = 0; y < 16; y++ ) {
  var text = '';
  for (var x = 0; x < WIDTH; x++) {
    // RGBa
    text += (imageData.data[(x + y * WIDTH) * 4 + 3] > THRESHOLD ? '0' : ' ');
  }
  console.log(text);
}
```

# 実行結果

実行する。

```
pi@raspberrypi ~/test $ node kanji.js
 00    00  00          00
  00 0000000000   0000000000000     0000              0000         0        0
   0 000000000   00000000000000     0000000         00000000       00      000
       0   0     00          00     00    00        00    00       000    0000
00   000000000      00000000        00    00       00      00      000    0000
 00  00  00  0           000        00    00       00      00      0 0    0 00
  0  000000000          000         00    00       0        0      0 00  00 00
         00            00           0000000        0        0      0 00  00 00
     000000000   00000000000000     00  00         0       00      0  0  0  00
  00  00000000   00000000000000     00   00        00      00      0  0000  00
  0000000000000        00           00    0        00      00      0  000   00
  0  0000000000        00           00    00        000  000       0   00   00
 00    00000           00           00     00        000000        0   00   00
 0   000   0000       000
     0        0       00

pi@raspberrypi ~/test $
```

なお、node-canvasのGitHubにあるサンプルプログラムも当然動く。

# 未解決問題

文字描画のアンチエイリアス効かせない方法って、ないものかな。
＝＞ドキュメントに書いてあった。

```
ctx.antialias = 'none';
```

出力はこうなる。

```
  0    0   0           00
  0000000000000  00000000000000                        00
   0   0   0     00000000000000     0000000          000000        00      00
       0   0     00          00     00    00        00    00       00      00
 0   000000000      00000000        00    00       00      00      000    000
 00  00  0   0            00        00    00       0        0      000    000
  0  000000000           00         00    0        0        0      000    000
         0             00           000000         0        0      0000  0  0
     000000000   00000000000000     00   0         0        0      0  0  0  0
   0     0       00000000000000     00   00        00      00      0  0000  0
  0000000000000        00           00    0        00      00      0  000   0
  0      00            00           00    00        00    00       0   00   0
 00    00000           00           00     00        000000        0   00   0
 0  0000   0000      0000
                      00

```

Ｍの文字の縦棒あたりがヒンティング効いているっぽくなった。

# 追記

[こちら](http://cl.hatenablog.com/entry/kanjirom-node-canvas)で、フォントファイルを指定した場合の描画をやってみました。

```
pi@raspberrypi ~/test3 $ node kanji.js
 
       0    0          00
  0  0000000000  00000000000000     000000            0000         0        0
   0   0    0    00          00     0    000        00    00       00      00
     0000000000  00          00     0      0       00      00      00      00
 0   00  00  00  00000000000000     0      0       0        0      000    000
 00  00  00  00           00        0      0      00        00     000    000
   000000000000          00         0     0       00        00     0  0  0  0
         00             0           000000        00        00     0  0  0  0
     0000000000  00000000000000     0    00       00        00     0   00   0
   0     00      00000000000000     0     0        0        0      0   00   0
   000000000000         0           0     00       00      00      0        0
  0     0000            0           0      0        00    00       0        0
  0    00  00           0           0      0         000000        0        0
 0   00      00     00000
 
pi@raspberrypi ~/test3 $
```

ローマ字の字形が整っているように見える。

# 参考URL

* [Automattic/node-canvas](https://github.com/Automattic/node-canvas
)
* [canvas要素の基本的な使い方まとめ](http://www.h2.dion.ne.jp/~defghi/canvasMemo/canvasMemo.htm)