JavaScriptによるQRコード生成ライブラリ

ってのを作りました。
http://la.ma.la/misc/qrcode/

ネタのつもりで作ってたんだけど意外と大変だった。というか時間かけすぎた。
なんの役に立つのかと言われたら何の役にも立たないと自信を持って言える。

Ruby用QRコード生成クラスからの移植です。ライセンスはオリジナルに準拠します。
http://www.swetake.com/qr/

QRコードの仕様とかアルゴリズムとかそういうのは全然わかりません。挙動が同じになるようにしてみただけです。
表示にはテーブルタグを使っています。画像オフでも表示できます。

動作テストには
http://www.psytec.co.jp/docomo.html
を使いました。

アーカイブにdatファイル同梱したのでファイルサイズが2MB超えてます。
ソースだけ見たい人は、これをどうぞ。当然これだけじゃ動かないけど。
http://la.ma.la/misc/qrcode/qrcode.js

動作について


遅いです。最初は文字入力されるたびにリアルタイムで生成するようなのを考えていたのですが、それだと多分10GHzぐらい必要です。
遅いから何の役にも立たないねっていうことなんだけど、速かったら役に立つのかと言われても疑問。

IE、Firefox、Opera8.5で動作確認しています。Firefox推奨。
生成には1GHzのマシンで5秒から10秒ぐらいかかると思います。テーブルタグの描画ではなく、実際の計算に時間がかかってます。

速度はOperaがやっぱ速いんだけど、なんか出力結果が他のブラウザと違う。
読み取れてるので細かいことは気にしない、さすがQRコードだ、とかいう。
まあそういう、すげーいい加減な具合なので変換結果を信頼しないでください。

日本語は変換できません。できるんだけど対応してるリーダーがないとか(後述)。

Rubyからの移植にあたって


あまり最適化とかはしないで、なるべくオリジナルのコードからの変更点が少なくなるようにしています。
セミコロン省略なんかは、本来あまりやらないほうが良いです。
ruby.jsからString#scan と MatchDataオブジェクトを使っています。
String#countを作ってありますが、これはRuby互換ではありません。とりあえず動くようにやっつけ仕事。
Fileクラスも作ったが、これはopen、readのみ。
String#packとString#unpackはオプションとか良くわかんないのでこれも適当。

最初は慣れ親しんだPerlから移植しようかと思ってたんだけど、Rubyからの方がずっと楽っぽい。
ボトルネックは正規表現オブジェクト作成とか、そこらへんだと思う。いちおう、高速化の余地はある。

工夫したところ


Rubyっぽく書いたコードをJavaScriptに変換する関数を作っています。
ruby_slice_supportってのを書いて
// before
hor[k * max_modules_1side,0] = (170).chr()
// after
hor = hor.ruby_slice(k * max_modules_1side,0).eq((170).chr())

こんな具合に置換するようにした。

Rubyだと、string[offset,length]で部分文字列の切り出しや置き換えができるんだけど、JavaScriptだとstring[(offset,length)]と見なされてstring[length]と同じ意味になる。
さらにはstring[/regexp/]なんかができてすげーカッコいいんだけど、これはJavaScriptだとstring[/regexp/.toString()]になる。つまりstring["/regexp/"]と同じ意味になる。
[]の中身が[offset,length]の形式だったら.ruby_slice(offset,length)に置換して、切り出し結果にeqメソッドくっつけて左辺に使われた時の挙動をエミュレート、っていう具合。

あとはforcePrivateってのを書いた。これは関数内で使われている変数名を拾ってきて強制的にvarで宣言してプライベート変数にする、というのもの。
some_function = some_function.forcePrivate();

とかやると、その関数内で使われてる変数が全てプライベート変数になる。
ただし関数をnew Functionで再構築するため、変数のスコープとか一切関係なくなってしまう(クロージャとしては使えない)。
スタティックな関数に適用するなら、まあそれなりに便利かもしれない。

関数オブジェクトを文字列に落として正規表現でゴニョゴニョフィルターかけてやれば色々できるね、って言う話なんだけど。
ただ、IEだと大きめの関数を生成すると死ぬほど重かったり、Operaだとなんか良くわからないエラーで失敗したりするので、あらかじめFirefox使って変換した結果を使うようにしたりしている。
function.toStringは、なんかブラウザごとに勝手に整形されてたりして個性があるので、あんまり特定の動作を期待して使うべきじゃないと思われる。

数値から文字列


Number.prototype.chr = function(){
    return String.fromCharCode(this)
}

(170).chr()はRubyだと170.chrなんだけど、数値からメソッド呼び出すときに小数点と区別付かないからカッコでくくらないとエラーでるとか(170).chrはfunctionで(170).chr()でchrメソッド実行とか、そういう違いがある。
このあたりも正規表現置換でなんとかしようかとも思ったんだけど、JavaScriptだと関数オブジェクトと関数の実行を明示的に区別することは重要なので手動で書き直した。
chr(170)の方が普通に楽だな、と思ったんだけど、なるべくRubyのコードいじらないというポリシーだったのでこんな具合になったり。
Firefoxだとgetter/setterが使えるので、(170).chrまでならなんとかできそうだけど。
String.fromCharCodeで生成した文字列は0-65535までなら、その文字コードに対する文字の割り当てが存在していなくてもきちんと文字コードを保持してくれる。

バイナリファイルの読み込み


他の言語のバージョンと同じように計算済みのdatファイルというのを使います。これは計算時にXMLHttpRequestを使って受信しています。
ただし、XMLHttpRequestのresponseTextは、バイナリファイルを文字化けしたテキストデータとして認識するので、うまくいかない。
なのでバイナリデータの読み込みには、あらかじめ16進数ダンプしたテキストファイルを作っておいて、読み込み後にpackするという動作になっています。

仕様:画像保存できません


QRコードの描画にはテーブルタグを使っています。画像での出力はできません。
Firefoxに限れば将来的にcanvas要素とdataスキームを使って画像保存とかできるようになるかもしれません。

仕様:京ぽんで動きません


XMLHttpRequest使えないので。そのほかにも色々問題あると思う。
使うデータをあらかじめscript本体に記述するようにすればイケルとは思うんだけどデバッグが大変なのと現実的な速度で動作するとは思えないのでやる気なし。

仕様:マルチバイト文字について


基本的に対応してません。URLやメールアドレスなんかはOKですが日本語は変換できません。
一応、UTF-8文字列を文字列単位でなくバイト単位で区切って渡すようにはしてあるので、「UTF-8を読めるQRコードリーダー」もしくは「読み取り結果をバイナリファイルで保存できるQRコードリーダー」があれば読めるはず。
ShiftJISが実質標準っぽいので、気が向いたらShiftJIS変換ルーチン組み込んだのを作ります。
気が向いたらというのは気が向いたらやるということで、気が向いたらやります。期待しないでください。


WriteBacks

JavaScriptによるQRコード生成 canvas 版

JavaScriptによるQRコード生成ライブラリ のフロントエンドを canvas 要素に変更した版を作ってみました(見た目のやる気はありません)。canvas 要素による描画と PNG への変換が...

Posted by Taken SPC at 2005/10/05 (Wed) 19:34:59

JavaScriptによるQRコード生成 canvas 版

JavaScriptによるQRコード生成ライブラリ のフロントエンドを canvas 要素に変更した版を作ってみました(見た目のやる気はありません)。canvas 要素による描画と PNG への変換が...

Posted by Taken SPC at 2005/10/05 (Wed) 19:39:09

質問があります

管理人さま はじめまして。連絡先はこちらでしょうか?

tuyorinと申します。

Pure JavaScriptによるQRコード生成ライブラリ
http://la.ma.la/misc/qrcode/

を読んでいました。自分もQRコード生成サイトを運営したくてならなくなったのですが、ダウンロードしたプログラムファイルを自分なりに改変してアップロードすることは許されますか?著作権などなどがございますので。

リンクを
http://la.ma.la/misc/qrcode/
http://www.swetake.com/qr/
に貼りプログラムの製作者の表示を明らかにしたいと考えていますがいかがなものでしょうか?

Posted by tuyorin at 2007/05/21 (Mon) 22:42:34
TrackBack ping me at
http://la.ma.la/blog/diary_200510050749.trackback
Post a comment

writeback message: Ready to post a comment.







spam yoke. nanimo ireruna.