プログラマに転職してました&今年の振り返り
年を越す前に、今年の振り返りをしておかなければ。
転職してました
実は11月に、4年続けたドラッグストアのバイトを辞め、プログラマに転職してました。
いちおう登録販売者の資格も取得したので、このまま続けるルートもあったけど、別にコロナの騒乱で仕事が嫌になったとかではなく、単純にプログラミングのスキルを生かさないともったいない気がしたので。
まあ、自分が突き上げられた一番の理由は「未経験からプログラマになるのは27歳が限界」って言葉かな。やらずに後悔するのも嫌なので、思い切って面接を受けてみたら、こんなご時世だけど縁あってジョインさせて頂くことができた。
入社して、触ったこともないAndroidアプリ開発にいきなりアサインされたけど、2ヶ月間頑張ったら Issue を消化できるくらいにはなったので、これからはプログラミングで飯を食って行けそう。
諸般の事情を考慮してバイトで入社したが、これからはITエンジニアとして生きていく決心をしているので、まずは正社員登用を目指して修行を積んでいきたい。
今年の活動
今年取り組んだことで一番形になったのは、やっぱり mb-node かな。ディスクタイトルプリンターとしてそこそこ活躍してくれたけど、3ヶ月ぶりに使おうと思ったらインクタンクの中まで固まってたとさ。
ディスクタイトルを印刷しようと思ったのは、500枚くらいある録画済みBD-Rの管理のためのソフトウェアを作ろうとしているのが理由で、その成果の一部が AribB24.DotNet。そろそろ beta 外そうかな?
ESP8266 で作る置時計ベースキットを売ろう作戦は、コロナによるサプライチェーンの不安とかいろいろあって、やる気がなくなっている。そこからの成果である ESPPerfectTime は、初めて人からPRを貰えて嬉しかった。個人名義の活動は、基本的には自分が楽するためのことしかしてないけれども、それが誰かの役に立っているのなら嬉しい。
今年に限って言えば、プログラマとして採用してもらうためのポートフォリオ作りも個人活動の目的に含まれていて、それがなかったら天鳳の牌譜を画像に変換βは PHP じゃなく node.js とか C# で作ってたと思う。
あと表に出してないことで、完全に個人用で pixiv & twitter のイラストダウンローダー兼検索アプリを書くのに、けっこう時間を費やしてる感。というのも途中で、仕事でクリーンアーキテクチャというものを知ったので、その練習のために書き直しているのもある。
来年やりたいこと
一番は、体調を崩さないように、適度に適当にやること。自分のパフォーマンスが不安定にならないように自己管理して、常に一定の能力を発揮できることが最も大事なこと。一時すごく頑張っても、その後しばらく働けないようだと飯は食えない。
MBrush (PrinCube) の研究② - node.js に移植しようとして先を越された
mb-node
とりあえず、MBrush のアプリを介さず CUI から画像を印刷できるようにした。
のだが、依存するレポジトリにも同様の機能が入ってしまったので、現状では存在意義が微妙……(泣
使い方
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 の元々のアプリで印刷領域を複数設定したのと同じ挙動になる。
前回の続き
WebAssembly (WASM) の存在は、多少は知っていた。C++ とか何かの言語で書いたソースを、Java でいうバイトコード、.NET でいう IL のような中間コードに変換して、Web ブラウザ上で実行できるようにする。JS よりも効率よく動作し、ランタイムをインストールする手間もない、お手軽クロスプラットフォーム、という話は聞いたことがあったが、実際に WebAssembly で実装されたアプリを見るのは初めてだった。
Chrome の開発者ツールで .wasm ファイルを覗くと、バイナリから勝手に human-readable なテキスト表現(S式)には変換してくれるが、アセンブリに近い言語なので読む気にはならない。他言語への移植は難しそう。
node.js に移植できそうな気がした
mbc.wasm
と同じディレクトリにある mbc.js
は、何かのツールで生成したコードのようである。調べたところ、Emscripten で C/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 の仕様
- ファイル I/O は Emscripten の File API (仮想ファイルシステム)を介して行う*1
- 入力
- 元画像
ori.png
- 色補正用の
m.bmp
- 元画像
- 出力
- .mbd 形式のファイル
mb.dat
- .mbd 形式のファイル
コマンドの引数:
[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 なるものが用意されていたけど、使い方がよく分からなかった
MBrush (PrinCube) の研究①
「ハンディープリンター」というジャンルをご存知だろうか? ハンディスキャナーのごとく、小型の筐体を手に持って左右にスライドさせると、対象物に文字や画像を印刷できる。国内メーカーではリコーが唯一製品化していて、4万円ながら入荷待ち多数と大人気なようだ。
一方海外に目を向ければ、同様のコンセプトの製品がいくつかある。今回はその中から、中国メーカーの MBrush (PrinCube) を使ってみた。
購入の動機
- 大量(数百枚)の Blu-ray ディスクに、ユニークな QR コードを印刷したい。
- レーベル印刷できる(普通の)プリンターは、専用トレイにいちいちディスクをセットして、プリンターに挿入して…… という作業が面倒。1枚印刷するのに時間がかかりすぎる。もっと手軽に、高速に印刷したい。
MBrush を選択した理由
- 安価(送料込みで95米ドル前後)
- 日本国内でインク調達可能
- Web アプリ経由で印刷するので、ハックして他アプリとの連携できそう
MBrush と PrinCube
MBrush と酷似の商品で PrinCube というモノがあるが、どうも両者は同一製品らしい。商標の都合?らしく、中国国内では MBrush、それ以外では PrinCube の名で売っているようだ。
MBrush (PrinCube) のしくみ
ヒューレット・パッカード (HP) のプリンターで、インクタンクとプリンタヘッドが一体になっている製品がある。これをハックして小型化したのが MBrush (PrinCube) だ。ヘッド付きインクは昔からあったので、超小さいプリンター作れるんじゃないかな~、と思ったことがあるが、まさにそれ。
HP のプリンターは日本国内でも売ってるので、インクの入手はたいへん容易(サプライを個人輸入しないで済むのは大きい)。62XL/64XL/804 あたりが使える。黒インクは使えないっぽい?
底面の写真がこちら。電源スイッチと、インクを固定するフタのロック、移動方向を制限する2本のローラー、あとはセンサーが見える。これはおそらく赤外線センサーで、マウスと同じ原理で移動量を検出していると思われる。
上フタもツメで止まっているだけなので簡単に開けられる。下側に MPU の Ingenic X1021 が見える。Wi-Fi の IF は蟹さん…ではなく ESP8089(8266EX じゃないよ!)、あと FPGA (Lattice iCE5) が積んであって、これでヘッドに送る信号を生成するのかな? 基板裏面にも何かありそうだけど、外すのが面倒なのでやめといた。
使ってみる
電源を入れるとアクセスポイントが立つので、そこに接続。192.168.44.1 にアクセスすると Web アプリが読み込まれる。
(MBrush 持ってない人もアプリの使い勝手はここで体験できる)
最初から入ってるサンプルを開いてみると、印刷したい領域を指定するクロップ枠を複数指定できるようになっている。
クロップ枠の高さを変えてみると、うーん悲しいかな、横に書いてある実際の印字サイズの高さは 14.29 mm 固定で、変えられるのは幅だけのようだ。複数行印刷用の定規がついてきたのに、複数行に分けて印刷するようなオプションも見当たらない。
画像ファイルを読み込んで即印刷という機能もなく(これをやりたかった)、新規プロジェクトを立ち上げて、画像をキャンバスに追加して、クロップ枠を指定、という手順を必ず踏まないといけないようだ。
なんか微妙だなぁ。
Web アプリの動作を観察してみる
使いにくいので、さっそくハックしてみよう。ちなみにアプリのソースコードは探したら GitHub に転がってた。
印刷ボタンをクリックした時の流れを観察すると、PC 側で PNG 画像を一旦 .mbd なる内部ファイル形式に変換して、それを POST している。この処理は Web Worker 上で実行して、UI のブロッキングを防ぐ作りになっている。とてもモダンな感じだ。
で、肝心のコア部分は mbc.wasm
で実装されている。wasm? そう、WebAssembly である。
『天鳳の牌譜を画像に変換β』をリリースしていた
サービスを公開したのに、説明をどこにも書かず放置していたので今書く。
これは何かというと、天鳳牌譜エディタβで入力した牌譜データを、画像1枚に整形して出力するツール。
説明
- 天鳳
- 麻雀が無料で打てるオンラインゲーム。
- 牌譜
- 麻雀の対局において、その経過(各プレイヤーの配牌や摸打)を記録したもの。
天鳳牌譜エディタβとは、紙の牌譜やリアル対局を、後でアニメーションとして再生させられる、大変便利なツールである。
『天鳳の牌譜を画像に変換β』はその真逆を行く(不便な方へ向かう)ツールなわけで、誰得感が半端ないが、これを作ったのは PHP の勉強のためなのでご容赦願いたい。
作業のあれこれ
思いついてからリリースまでの経過は、だいたいこんな感じ。
- なんとなく形になる:3日
- ブラッシュアップ(出力の体裁を整える):4日
- apache を勉強しながら立てる:3日
- Imagick のエラーで躓く:1週間
結局、開発環境と運用環境のわずかな差で躓いて、時間を浪費してしまった気がする。環境を揃えるって大事。
利用実績
公開してから1ヶ月半ほど経過したが、現在までの利用者は 0 人でございます(うp主調べ)。
まあ、鯖に負荷かからないからいっか……。
Git/GitHub で困った時に見るリンク集
全体の流れ
やらかした時
- 間違って
git reset --hard
してしまった
マージ
元に戻す
履歴操作
差分を見る
はじめての Apache on Ubuntu その1
大体のことはここ↓を見れば分かる。
CentOS ではなく Ubuntu を選択したのは、そこに Ubuntu machine があったから。特に深い意味はない。
ドメインの取得
サーバーはすでに所有しているものとする。筆者はさくらの VPS をサーバーとして使う。
まず、どこかからドメインを買ってくる。筆者は お名前.com で hunamizawa.com を購入。
DNSの設定
正引き
FQDN (hunamizawa.com) から IPアドレスを得る、基本的な設定。お名前.com の管理画面から、サーバーのIPアドレスをAレコード・AAAAレコードに設定する。メールは使う予定がないのでMXレコードは設定しない。
DNS がある程度浸透するまで数時間待つ。
逆引き
IPアドレスから FQDN (hunamizawa.com) を得るための設定。
nslookup hunamizawa.com
が通るようになったので、さくらのVPSの管理画面から、ホスト名逆引き登録で hunamizawa.com を設定する。
この後、DNS が完全に浸透するまで3日ぐらい必要なので、その間にローンチの準備をするのが吉。
Apache のセットアップ
とりあえずここ↓を見て、http://hunamizawa.com/ にアクセスすると "It works!" と言ってくれる状態にする。
で、冒頭に申し上げた通り Ubuntu を使っているので、よく使われる CentOS とは細かい違いがある。
- Apache のユーザー名は
www-data
(apache
ではない) - 設定ファイルの置き場は
/etc/apache2
SSL 証明書を取得
HTTP over SSL に必要な証明書を、Let's Encrypt から貰ってくる。ちょっと前なら SSL 証明書を貰うのにウン万円必要だったのに、すごい時代になったなぁ。
まず、certbot
を入れる。apt-get
で入るやつは古いから使わないほうが良いとのこと。
apt-get install python3 pip3 pip3 install certbot
依存関係で足りないモジュールがあれば都度 pip3 install
する。自分の場合は「cryptography
が古いよ」と言われたので install --upgrade cryptography
した。
次に、80番ポートを一瞬開けておいて、次を実行する。
certbot certonly --webroot -w /var/www/html -d hunamizawa.com
連絡先のメアドを入れたり、利用規約への同意にチェックしたら、ACME によるドメイン名所有の認証が行われて、証明書が発行される。
Apache のセットアップ(続き)
以降は HTTPS で serve すればよいが、ACME の仕様上 HTTP も開けておかないと証明書の更新ができない。サイト利用者の利便性も考えて、HTTP (80) 宛のリクエストを全部 HTTPS (443) にリダイレクトするように設定しておく。
RewriteEngine on RewriteCond %{HTTP_HOST} ^hunamizawa\.com RewriteRule ^/(.*)$ https://hunamizawa.com/$1 [R=301,L]
SSL 証明書のパスを適切に設定する。
SSLCertificateFile /etc/letsencrypt/live/hunamizawa.com/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/hunamizawa.com/privkey.pem
設定ファイルの構文チェック。
apachectl configtest
必要なモジュールをロードし、サイトの設定ファイルを読み込ませる。a2en**/a2dis**
は *-enabled
にシンボリックリンクを張ったり剥がしたりするコマンド。
a2enmod ssl a2enmod rewrite a2dissite 000-default a2ensite hunamizawa.com systemctl restart apache2
80番と443番を開けて、SSL 関係のエラーが出ないこと、HTTP 宛リクエストが正常に 301 リダイレクトされることを確認する。
certbot を cron で回す
crontab に1行書き加えれば良い。
certbot renew
ここまで来れば、static なコンテンツを HTTPS で配信できる状態になった。後は PHP なり何なりのセットアップをすればよい。
Ubuntu での ImagickException: unable to open file `/tmp/magick-***' には extra package を入れろ
環境
- 開発:Windows 10 + PHP 7.4.5 (cli) + ImageMagick 6.9.7
- 運用:Ubuntu 18.04 + Apache 2.4 + PHP 7.4.6 + ImageMagick 7.0.10
症状
$img = new Imagick('hoge.svg');
すると、次の例外がスローされる。
PHP Fatal error: Uncaught ImagickException: unable to open file `/tmp/magick-25662B639-gQXNdPk': No such file or directory @ error/constitute.c/ReadImage/544
原因と対処
Ubuntu で提供されている libmagickcore-6.q16-3
には、SVG のサポートが含まれていない。そのため SVG を読むと当然コケるのだが、なんの関連もない unable to open file
なる例外が投げつけられるので、原因の把握には相当な時間を要することになる。
すなわち、libmagickcore-6.q16-3-extra
を手動でインストールすれば問題は解消する。なお、php-imagick
の依存関係で自動的にインストールされるのは無印 package だけであり、extra package は手動でインストールする必要がある。
apt-get install libmagickcore-6.q16-3-extra
事の顛末
私は PHP 初心者。ImageMagick と組み合わせたアプリを作り、サーバーで走らせたところ、このような例外に遭遇した。
ただ画像を読み込むだけなので、例外の原因の検討がつかない。ひとまず @ error/constitute.c
と見えるので、imagick 側の問題か?と考える。
最初に疑ったのは、/tmp/
絡みの例外なので PrivateTmp の影響。そこで PrivateTmp = false
してみても、$img->setRegistry('tmp-directory', '/hogemoge')
してみても、何も変わらない。
unable to open file tmp magick とかで検索してみると、「ImageMagick の特定バージョンでそういうバグがある」的な Issue を見たので、もしかしてバグを踏み抜いてる?
なら最新の ImageMagick を入れるか、と思って PECL の準備を始めた。ビルドの依存関係になるので何気なく aptitude show libmagickcore-6.q16-3-extra
を見てみると
This package adds support for SVG, WMF, OpenEXR, DjVu and Graphviz to MagickCore.
あっ……
apt-get install libmagickcore-6.q16-3-extra
で万事解決しましたとさ。