hunamizawa’s blog

無い物は作りたい人のメモ帳

MBrush (PrinCube) の研究② - node.js に移植しようとして先を越された

mb-node

とりあえず、MBrush のアプリを介さず CUI から画像を印刷できるようにした。

github.com

のだが、依存するレポジトリにも同様の機能が入ってしまったので、現状では存在意義が微妙……(泣

使い方

git clone --depth=1  --recursive https://github.com/hunamizawa/mb-node
cd mb-node
./build.sh
npm ci --production

MBrush を接続してから

node app.js input.png

これでWi-Fi 経由でプリンターに画像が転送される。USB 接続の場合は -c usb を足してくだち。

複数枚の画像を印刷したい場合は

node app.js input1.png input2.png

とすれば、MBrush の元々のアプリで印刷領域を複数設定したのと同じ挙動になる。

前回の続き

前回。

hunamizawa.hatenablog.com

WebAssembly (WASM) の存在は、多少は知っていた。C++ とか何かの言語で書いたソースを、Java でいうバイトコード、.NET でいう IL のような中間コードに変換して、Web ブラウザ上で実行できるようにする。JS よりも効率よく動作し、ランタイムをインストールする手間もない、お手軽クロスプラットフォーム、という話は聞いたことがあったが、実際に WebAssembly で実装されたアプリを見るのは初めてだった。

Chrome の開発者ツールで .wasm ファイルを覗くと、バイナリから勝手に human-readable なテキスト表現(S式)には変換してくれるが、アセンブリに近い言語なので読む気にはならない。他言語への移植は難しそう。

node.js に移植できそうな気がした

mbc.wasm と同じディレクトリにある mbc.js は、何かのツールで生成したコードのようである。調べたところ、EmscriptenC/C++ から WASM をコンパイルした際に生成される、JavaScript から WASM を呼ぶためのラッパーだと判明した。このラッパーを観察すると NODEFS 等、node.js に関係しそうな変数名が使われている。

で、前回話した、画像を .mbd 形式に変換する最中に、console に何かデバッグメッセージが流れてくる。その中にこんなのがあった。

mbc: (7) ["128", "168", "60", "-i0", "-o0", "-w0", "-s2"]

-i0 とか -o0 とか、なんかコマンドライン引数みたいだなあ、と思いつつ、この配列をどこで使ってるのか調べたところ、WASM の中にある callMain() という関数に渡されている様子。いかにもコンソールアプリ臭がする名前だ。

また、実験の過程で次のような ImageMagick っぽいエラーメッセージを吐いており、この WASM には ImageMagick が静的リンクされていると推測している。

UnableToOpenBlob 'ori.png': No such file or directory @ error/blob.c/OpenBlob/3497.
InvalidArgument '-colorize' '100-geometry' at CLI arg 12 @ error/operation.c/CLISimpleOperatorImage/2020.

おそらく開発者は、PNG 画像を .mbd 形式のファイルに変換するために、まず

$ ./foobar 128 168 60 -i0 -o0 -w0 -s2

のように使うコンソールアプリを作り、クロスプラットフォーム対応のために WASM へ移植したのだろう。

mbc.wasm の仕様

コマンドの引数:

[String(brightness), String(saturation), String(density), '-i' + invert, '-o' + c_order, '-w' + c_width, '-s' + dpi_step]

各変数の意味は https://github.com/dukelec/mb/blob/master/doc/dev.md に書いてあった:

args:
  img_dat: input png image, in type: Uint8Array
  brightness: 0~200, default 100
  saturation: 0~500, default 100
  density: 1~100, default 100
  cal.c,m,y: 1~255, default 255
  invert: print direction: 0: left to right, 1: right to left
  c_order: 0: CMY, 1: CYM. default 0
  c_width: cartridge chip width: 0: 4.4mm, 1: 4.9mm. default 0
  dpi_step: dpi setting: 1: 1200x1200, 2: 1200x600, 4: 1200x300
  st_cb: progress status callback function
ret:
  .mbd file data, in type: Uint8Array

WASM の初期化が重い

node.js の起動 + WASM の初期化で結構時間がかかる。画像が複数枚あると意外とストレスを感じる。もっとサクッと処理して欲しいなぁ。

というわけで、サーバーを立てて HTTP 経由で画像を渡せるようにする実験をしている。これなら WASM の初期化はサーバープロセス起動時の一度だけで済むよね。拙作の mb-node は今後この向きで育てていきたい。

*1:node.js 用に NODEFS なるものが用意されていたけど、使い方がよく分からなかった