JavaScriptでQR Codeのencode / decodeと、これを試してJavaScriptの画像周りで気づいたこと

Ruby で QR Code を作るのは以前からやってるんだけど、

これを JavaScript でやってみたらどうなるか実験。

特に scanner 部分を独自アプリで作り込むと独自ルールを仕込むことができて便利1なので、生成された QR コードのチェックを目視に頼り切る必要がなくなるし、scanner を UI と融合させやすいのが JavaScript の強み。

気づいたこと

encodeは「見える」が最優先で画像化は後回し

Ruby の場合は

  1. QR Code のパターンを生成
  2. これを内部で保持しつつどのフォーマットで出力するか

を考えるだけでよかった。上の rqrcode_png_bin で言うと、もともとは rqrcode がパターンを保持し、rqrcode_png が rqrcode と chunky_png をミックスして PNG 出力できるもので、rqrcode_png_bin はそれに CLI のガワを被せただけのものだ。

ところが JavaScript の場合はそもそもブラウザ上でならそのまま見える状態にすぐ持っていけるので、それを目指す場合が多い。具体的には HTML タグだったり Canvas 要素だったり。

ところが HTML タグも Canvas 要素も Node.js 環境ではそのままで使えない。少なくとも「画像ファイル」としてそのまま取り出すことはできない。UI と融合させてブラウザで一つ一つ手作りする分にはこれでよいが、画像として取り出してデータとして活用したい場合にはもう一工夫必要になるし、同じ生成処理を使って一括生成したい場合にもこのままでは使えない。

具体的には流れとしては以下のようになるようだ。

  1. dataURL にする
  2. dataURL を Buffer に変換する
  3. Buffer をファイルに出力する

ブラウザであれば 1 の dataURL を img 要素に与えればおしまい。画像ファイル化も、右クリックして保存すればおしまいである。Node.js であれば 2 以降を実装することで自動的に画像ファイルを生成することができる。

※ ただしこの際、画像の縦横のサイズが指定通りにぴったり同じになるかどうかは実装による。そもそも QR コードはピクセルでなく「モジュール」が基本単位であり、ピクセルは基本単位ではない。QR コードのパターンをそのまま dataURL に変換した img を生成した場合、基本的には指定サイズより小さいものができあがる。Canvas 上に描く場合は Canvas 側で先に指定サイズにしたがって要素ができあがり、その上に描画するので大きさが足りない場合は単に余白が大きくなる。

画像の取り込みはArrayBufferを作るところから

  • 画像フォーマットに左右されずにピクセル情報を取り扱うには Canvas の ImageData を利用する
  • ImageData.data は ArrayBuffer なので
  • Scanner は ArrayBuffer を解釈すれば ok

実際、以下のライブラリは第1引数に imageData と書かれているが、これは ImagaData() そのものではなく ArrayBuffer を受け取る。

cozmo/jsQR: A pure javascript QR code reading library. This library takes in raw images and will locate, extract and parse any QR code found within.

これを前提にすると、ついでに FileReader API も .readAsArrayBuffer() を使えば ArrayBuffer を返すので、

Camera -> getUserMedia() -> Canvas Context -> ImageData  -> ArrayBuffer
       -> input type="file"                -> FileReader -> ArrayBuffer

の両方のルートでカメラから ArrayBuffer を経由して QR コードリーダーを実装できることが分かった。

カメラ画像の取り込みはデバイスとブラウザの特性によって選び分けた方がよさそうという話もあるけど、そこはまた今度。

※ ちなみに昨日の https サーバの話はこの video 要素の取り回しがきっかけ。

cf.

使うとよさげなライブラリ

Accelerated Shape Detection in Images によると WICG で扱ってて Barcode Detection も standard な機能になりそうなんすね…。

  1. 例えばNGワードとか 

googlemap って window.onload に貼る必要があったのか

googlemap を初めて貼ってみた。

javascript 部分を他のコードからパクってきたんだけど、どうしてわざわざ window.onload1 でコードを動かしてるのかよく分からなかったのでその場で実行されるように書き換えてみた。

IEでだけ表示が乱れたorz

IE の場合は途中で DOM オブジェクトに操作を加えてしまったものがその場で確定してしまうみたい。最終的なレイアウトで位置が変わることもない。

結果としては IE でだけ見当外れな場所に地図が表示されていることになって、一部だけ見えるような状態になる。これでは使えない。

なるほどなー。難しい。

  1. <body> 

W3拡張ログファイルフォーマットの応用を夢想

Web サーバの生ログではなく、独自に欲しい情報だけをログに落として集計に活用すると嬉しいんじゃないかと思った。つかほんとに思いついたのはずいぶん前なんだけど。

ということでまた「一部で当たり前のノウハウなんだろうけど、あんまり見かけることないから書いてしまえメソッド」発動。ちなみに今回の思いつきにおいて「DB に落とせば?」というのは却下とする。書き込みのオーバーヘッドがでかいし、追跡したい情報の変更に柔軟に対応するのが難しくなるし、データが巨大になりすぎた場合の対応も考えるのが面倒だから。ログなら適当に rotate してやるだけでいいし、どうしてもやりたくなったら必要な範囲のログを DB に突っ込んでじっくり解析すりゃいい。

話がそれた。

調べると W3拡張ログファイルフォーマット (W3C Working Draft WD-logfile-960323) というものがあるのでこれを利用するのがよさそうだ。でも基本的に HTTP のことしか考えてないので 1リクエスト:1リソース を記録するもので、複合的な意味を含めることができないように見える。(いやまぁログって普通そうなんでしょうけど。)

記録したい内容にもよるけど、考えられるケースは

  • POST メソッドで複合的な内容を送らせているのでこれをトレースできるようにしたい
  • トレースはしたいが session 管理はしていないし、する意思もない

なんて辺りかなぁ。というか今回個人的には

  • quesy string に埋まっちゃってるパラメータを、生ログ相手に面倒な文字列処理をせずに解析できたら楽じゃね?

というのが主目的だったりする。レベル低くてごめんなさい。

query string の問題は、パラメータの順番が不定なところ。これをそのまま生ログ解析しちゃうと、「実際にはまったく同じリソースにアクセスしているにも関わらず文字列としての URL は一致しない」ので、集計の際に文字列処理をかますなどの面倒な作業が必要になってしまう。

まともな解析ツール入れろ?だからレベル低くてごめんなさいって言ってるの。

で、思いついたのがリソースをユーザーに返す際にログに落とせばいいじゃんて話。しかしさっき書いたようにこのフォーマットは 1リソースに対するリクエストの記録を取るのが目的なので、例えばこれとこれとこのオプションを選びました、みたいな情報は残せない。

と。思ったけど。

uri-stem や uri-query を勝手に組み立てればいいんだ

ということに気づいた。別に今回のログは Web 上に公開されているリソースにどういうアクセスがあったかの情報がほしいわけじゃなくて、内部的にどういう情報が取得されたかを記録できればいいんだから、URI をオレルールで組んじゃえばいいんだよね。なるほどなるほど。オレルールじゃなくても query string の順番の揺れを補正するだけでも結構違いそう。

というかそういうことなら W3拡張ログファイルフォーマットかどうかって、実はあんまり関係ないんだな。別に common log でもいいんだ。ただ uri-stem と uri-query を別々に記録できるのは便利かも。URI として活用できるフィールド、つまりリソースの識別に利用できるフィールドが 2つあるわけだから、より細かく情報を残しやすい。また、対ユーザーという意味ではセッション管理してなくても、ユーザーからのリクエストに対してなんらかのセッション識別文字列を Session Identification URI をもとに付加して複数の情報をベッて吐いて解析時に取り出しやすくするってのも可能だな。

他にも自分でログを吐けば、mod_rewrite なんかで HTTP で公開する URI はサーチエンジン向けにきれいにしつつ、裏で落とすログの URI に細かい情報を載せる、なんてことができるわけだ1。なかなかいいかも。あとは細かい情報を載せた URI を手軽に生成する方法とそれをログに簡単に落とす方法があればよい、ということですな。(すべて DBMS に入っているなら DBMS のログを解析するんでもいいのかもしれないけど。)

  1. rewrite_log でもそういうことできたっけ? 

ありがとう NIFTY-Serve、さようなら

まぁまだ使ってるんだけどね。@nifty は。

puts for ecmascript

以下の3つの環境でだいたい期待通りに同じ動作をする puts() 関数です。

  • ブラウザ
  • Windows Scripting Host
  • Rhino の shell(SpiderMonkey は未確認)
function puts( message ) {
  try {
    document.write( message + "<br>" );
  } catch ( e ) {
    try {
      WScript.echo( message );
    } catch ( e ) {
      try {
        print( message );
      } catch ( e ) {
        ;
      }
    }
  }
}

WSH スクリプトを書いていたんだけど、WSH 依存の部分と ecma 262 の部分を切り分けられないかなーとモゾモゾしていた。PHP で定数が定義済みかどうか調べる defined みたいなやつでオブジェクトが使えるかどうかチェックしたいと思ったのだが、そんなものはないみたい。どうしようと思っていてハタと気がついたのが「例外を catch すりゃいいんじゃねーの?」ってことだった。これに気がついたのが何日か前。

その後 prototype.js を読んで、Try.these() すごいっす!と思って、とりあえず書いたのが上のもの。何をしたいのかというとブラウザ上でも WSH でも Rhino の shell 上でもとにかく何かを出力して改行する。それだけのもの。これで何が嬉しいかっていうと、ロジックのチェックは情報が豊富に取れる Mozilla 系の環境で行い、最終動作を WSH で、という形で動かしやすくなるってこと。

たったこれだけなのに快適さがずいぶん違う。こういうものを(たわいのないものであっても)自分で作ったという喜びが ecmascript の場合は妙に大きい気がする。Ruby の場合は「こんなに便利なメソッドがあったのか!」という喜びが多いが、ecmascript の場合は「たったこれだけなのに(標準の状態に比べて)すげー便利になった!」の方が多い。そんな感じ。

上の書き方がオススメできるかどうかは知りません。例外処理は不慣れなもんで。使いたい人はご自由に。

本当はスクリプト起動時にどれが有効かチェックしてあとは適切なオブジェクトの適切なメソッド呼ぶようにした方がいいんですけど。いいんです、そんな細かいこと。

参考

必要最低限 Rhino

いい加減 HTML を書いて <script> でスクリプトを読み込ませて Firefox の JavaScript コンソールでデバッグ、っていうのに疲れたのでコマンドラインで動くものはねーのかと以前から調べていた Rhino を動かしてみた。(これ、らいのぅって読むのね。知らんかった。)Java が必要だけど、最近のクライアントOS ではフツー入ってるので気にしない。逆に Java はないけど gcc はあるよってゆー BSD 使いとかの人は SpiderMonkey を使え。

で、困ったことに Rhino のページに書いてある通りにやっても動かない。CLASSPATH の設定というのが超基本的にすぎて端折ってあるので。やるのはこんな感じ。(例は .zshrc)

export CLASSPATH=/usr/local/bin/js.jar:$CLASSPATH
alias jrunscript='java org.mozilla.javascript.tools.shell.Main'

Win の場合は適当にバッチファイルにする。名前は Java SE 6 Mustang じゃじゃ馬ならし Scripting から jrunscript にしておく。そうすっと最終的には

jrunscript -f scriptfile

だけでおけ。

…なんか使いにくいなぁ。readline とかその辺ですか? SpiderMonkey で JavaScript のインタラクティブシェル で読むのと違って編集とかできないし。んー。

※ その後、rlwrap をかましたら超絶便利になりました!

参考

入門xyzzy

入門xyzzy(オーム社)

こ、こんなものが出ていたとは。

最近はほとんど使ってないですけど。(Windows をあまり使っていないので。)中は見てないけどなんか表紙はかっこいいぞ。「入門」と「xyzzy」のバランスが、、、ごにょごにょ。

office 氏のほんとの罪

今さらですが。

おかしいなと思う。でも一方で罪がないとは言えないと思う。

不正アクセスなのかと問われたら変だなと思う。でも例えばこの取得した個人情報を単に開示ではなく、もっと直接的に自分あるいは第三者の利益に結びつけて利用したらやはりこれは犯罪だと思っただろう。

技術的にはこの程度のことが不正アクセスに当たるのか?というのが本音だけど、不正アクセスかどうかに強引に目をつぶったうえでなら、第四条の助長行為の禁止には該当すると思う。1ということはやはり不正アクセスの禁止等に関する法律でもって罰することは妥当ということだ。なぜか悔しい気持ちもしないではないけど。

ただ、外野だから大胆に言ってしまうけど、より深刻な問題はこの裁判の結果が一人歩きして、インジェクションなどの穴をつくのはすなわち不正アクセス2であり、今後善意による情報セキュリティの向上は望めなくなるのではないかという不安が広がることや、この程度のことを高度なクラッキングと同次元で捉えることが当たり前になってしまい得るという点だろう。

こんな言い方をすると元も子もないかもしれないけど、Web アプリ開発の現場はまだまだ幼稚だ。技術レベルの高いところなどかなり少ないと言ってもいいと思う。そんな中、低レベルのアタックを受けて大事な情報を漏らしてしまったという重大な過失を、つい見落としてしまいそうになる今回の事件の流れそのものがとてもまずいよなと思う。実は office 氏の罪は

  • 脆弱性の放置や情報漏洩から目をそらさせるスキを与えまくった
  • 不正アクセスに対する誤解を生ませた

ということなのかなと思ったりもする。無責任な言い方だけど。

  1. つまり何をもって不正アクセスとするか、という問いには答えないが罪に問えるところで罪とする。 

  2. 前後の文脈は一切抜き 

mfeed の ntp、正式サービス開始

インターネットマルチフィード時刻情報サービス for Public

すげー立派なサイトに生まれ変わってる。もうあの IP アドレスと mrtg のグラフと簡単な説明しか書いてないページは忘れられていくんだなぁ。結局先日取り上げた ring の ntp には変更していなかったので :-P うちの環境ではこのままいこう。しかし、

各 ISP が NTP をちゃんと提供してくれ

という思いは変わらない。今後は mfeed から ISP が精度の高い情報をぶっとく提供してもらい、それをユーザーに分ける形がどんどん広まってほしい。少なくとも 2004年までに自分の関わった ISP では OCN しか提供してくれなかった。そんなこっちゃいかんでしょ > @nifty, nsk1 など

  1. nsk は公開していないだけであるホストが提供しているらしい。アクセス制限もないようだ。 

「よくなくない」と「真逆」

マスコミは誤用を日々拡散していると自覚してほしい。

いやまぁ大上段に構えてしまったように見えるけど、まぁ当たり前の話なだけで。というのも今朝めざましテレビを見ていたらあのはるさめの「よくなくない?」の CM に始まり、若い女性がこうした言葉を使っている様子と、

よい        = 良い
よくない    = 悪い
よくなくない = 良い

という日本語のせんせのお話を紹介したあと、

「彼女たちは真逆(まぎゃく)の意味で使っていたのだ」

とのたまった。

おいおい、と。真逆なんて言葉あったかと1。それもせんせに添削してもらえと。というか最後の「ない?」が疑問形なのもフツー分かるだろうし、何より

スチャダラパーが今夜はブギー・バックで「よくなくなくなくなくなくない?」って歌ってたのは10年以上も前

っていう事実はフォローしなくていいのかと。

  1. ある blog では「真逆」は「まさか」の当て字という記述があった。 

Netsky すごいですね。

今までもウィルスメールなんかそらきてましたけど、過去最高の飛来数です。数えてないしサーバ側で削除とかよくしてるんで、クライアントの方ではほとんど受信してませんけどね。

やーすごいわ、こりゃ。

マスコミは勉強しろ

教科書の内容が減ったのは教科学習の時間の割り振りが変わったからであって「ゆとり教育=学習内容削減」なんかじゃない。

マスコミとして給料もらってんなら正確に勉強しろ。だめなら給料返せってんだ。

しかし

自分を振り返ると授業中はよく立たされたり居眠りしてたりしてたんだよな。授業って大事だったのかな。

面白さを感じるポイントが違うだろ

国語教科書に「じゅげむ」 見直される「声出して読む」

リズムが面白いのも結構だが、もとの落語の面白さを伝えることを忘れてたら文字通り話にならんぞ。

(音読の重要性は言わずもがなだけど。)

教材開発と学習課程いぢり

巻末ふろく、アニメ風さし絵… 関心引く教科書に腐心」 @asahi.com

苦心と言え、苦心と。

しかしどうしてこう教育をいじりたがる人が多いのかと。効果が上がるのかという疑問もあるが、いぢることと工夫はイコールなのか、という疑問が大きい。

もちろん教員の配置を弾力化するとか、そういう話はビジュアルに乏しいし、一般の人に分かりやすい話でもないので記事になりにくい、記事として記憶に残りにくいという話はあるかもしれない。要するにいぢる系の話ばかりが記事になっているというわけだ。そりゃあるだろう。

それにしてもだ。

教育をかじった人間からしても最近の動きは誉められた感じは受けない。安易に学習内容を削れば批判を受けるのは当たり前だし、何がゆとり教育で何が総合なのか、国民にきちんと分かりやすく説明できていない文部科学省のやり方は全面的に批判されて仕方がないものだ。

そのうえで「また何か変わるの?」という印象が今回の記事である。聞けば削った内容の一部を発展的な学習として教科書に復活させ、なおかつ付録をつけるという。学習に面白さをということなのだろうが、果たしてそんなもので「学校での勉強」が楽しくなるもんだろうか? それに学校での勉強の楽しさと理系離れは関係ないような?

この話は展開がでかくなるので適当に端折るが、理系離れの問題は理系に夢を抱けない現在の社会の縮図だと自分は考えている。社会人になりたくないモラトリアムと根っこは一緒だ。乱暴な話だが社会に出ること、理系を学ぶことに希望をもてないという理屈だ。根拠はないがこの理屈には自信がある。自分が身を持って感じているから。

実際に理系のスキルは実社会ではそれほど役に立たない。対人、コミュニケーションスキルの方がよほど大事だ。(これは社会人という意味での社会ではなく、その人が今まさに生きている社会という意味である。)しかしどちらのスキルにも人によって得手不得手があり、習得スピードには差がある。なのに役に立つか立たないかで言うと明らかにコミュニケーションスキルの方が役に立つ。苦労して理系のスキルを身につけるメリットを感じられないのは当然ではないだろうか。それに今は手塚治虫が描いた未来にみんながワクワクしていたような科学信仰の時代ではない。公害や健康被害などの科学の弊害もたくさんあり、それをみんなが知っている。理系離れは学校や塾なんかの狭い社会に要因があるのではなく、科学そのものがたくさん持っているツケの現われでもあるだろう。

(大人の理屈で言えば理系のスキルだけでは起業のように自らチャンスを増やすことはできない、というのも大きいように思う。ストイックに理系の力を極めても、それがストレートに幸せに結びつくケースはごく稀である。これは簡単に言えば研究所なんかの施設の定員の問題。それに、名誉も得られないことが多いな。苦労の割に「自己満足」で終わることが多すぎますよ、理系は。)

スラドでプラス1ボーナス

アカウント作って9ヶ月か10ヶ月か。地味にまともなコメントでプラスモデをいただいていた結果、ようやく最近プラス1ボーナスが投稿時に入ってきた。(というかさっき気づいた。)しかしこれ、「プラス1ボーナスを使わない」というチェックを入れないと勝手にボーナスを使って投稿されるのか。なんだかなぁ。

About

例によって個人のなんちゃらです

Recent Posts

Categories

Tool 日々 Web Biz Net Apple MS ことば News Unix howto Food PHP Movie Edu Community Book Security Text TV Perl Ruby Music Pdoc 生き方 RDoc ViewCVS CVS Rsync Disk Mail FreeBSD Cygwin PDF Photo Zebedee Debian OSX Comic Cron Sysadmin Font Analog iCal Sunbird DNS Linux Wiki Emacs Thunderbird Sitecopy Terminal Drawing tDiary AppleScript Life Money Omni PukiWiki Xen XREA Zsh Screen CASL Firefox Fink zsh haXe Ecmascript PATH_INFO SQLite PEAR Lighttpd FastCGI Subversion au prototype.js jsUnit Apache Trac Template Java Rhino Mochikit Feed Bloglines CSS del.icio.us SBS qwikWeb gettext Ajax JSDoc Rails HTML CHM EPWING NDTP EB IE CLI ck ThinkPad Toy WSH RFC readline rlwrap ImageMagick epeg Frenzy sysprep Ubuntu MeCab DTP ERD DBMS eclipse Eclipse Awk RD Diigo XAMPP RubyGems PHPDoc iCab DOM YAML Camino Geekmonkey w3m Scheme Gauche Lisp JSAN Google VMware DSL SLAX Safari Markdown Textile IRC Jabber Fastladder MacPorts LLSpirit CPAN Mozilla Twitter OpenFL Rswatch ITS NTP GUI Pragger Yapra XML Mobile Git Study JSON VirtualBox Samba Pear Growl Mercurial Rack Capistrano Rake Win RSS Mechanize Sitemaps Android JavaScript Python RTM OOo iPod Yahoo Unicode Github iTunes God SBM friendfeed Friendfeed HokuUn Sinatra TDD Test Project Evernote iPad Geohash Location Map Search Simplenote Image WebKit RSpec Phone CSV WiMAX USB Chrome RubyKaigi RubyKaigi2011 Space CoffeeScript Nokogiri Hpricot Rubygems jQuery Node GTD CI UX Design VCS Kanazawa.rb Kindle Amazon Agile Vagrant Chef Windows Composer Dotenv PaaS Itamae SaaS Docker Swagger Grape WebAPI Microservices OmniAuth HTTP 分析基盤 CDN Terraform IaaS HCL Webpack Vue.js BigQuery Middleman CMS AWS PNG Laravel Selenium OAuth OpenAPI GitHub UML GCP TypeScript SQL Hanami Document SVG AsciiDoc Pandoc DocBook Develop Jekyll macOS Node.js Vite Heroku Transformer AI Data Cloud Wasm