JavaScriptとVMLでIdenticon

  • 2009-06-06(土) 00:51:17
 「Identicon」なるもの(ものというか概念というか発想というか)があります。  あるデータからキルト模様を作り出す、というアイデアです。
 IPアドレスやIDナンバーなどの表示は、羅列で、どれも似ていて、見分けにくい。しかしIdenticon表示にしてしまえば、差がパッとわかりやすくなる。

   ・

 人によって好みが分かれると思いますが、私はIdenticon、わりと好きなのです。機械的で無感情でドライなのに、華やぐ。きれい。わかりやすい。デザインも面白い……無意味な情報が思わぬ図形を作り出す。楽しい……。
 で、ふと思ったのです。なんとかしてこのIdenticonをSeaHorseスクリプトから使えないものだろうかと。『identicon.relucks.org』さんを利用させていただけば一発で解決することなんですが、使い方によってはご迷惑になるかもしれないし。やっぱりスクリプトだけで生成、表示させたい。

 挑戦してみました。
 「VML」を使ってます。
 ベクター画像を出せる、IEの機能、仕様です。どマイナーです。実際の利用例はGoogleマップ左上のスライダーぐらいです。ほかにはめったに見かけません。おかげで情報収集にえらい困りましたよ……詳しいサイトがわずかでもあって助かりました。
 ともあれこれで、Identiconの図形は出せました。

 でも今回の障害は別のところにあって。「ハッシュ関数」。
 これに大いに詰まりました。というか、今でもまだ詰まってます。

 先にも書きましたがIdenticonは「あるデータ(入力情報。たいていは文字列)からある模様を出す」アイデアです。そして「データごとのマークを出し、見分けやすくする」のが目的です。
 ですから、極力「別のデータから同じ模様が出ない」ようにしておかなければなりません。AというデータからもBというデータからもZという模様が出てしまったら、もう見分けもへったくれもないですよね。違うデータからはちゃんと違う模様を出さなきゃいけない。

 ならば。「素直に、受け取ったデータをそのまま使えばいいんじゃないの? そうすれば別の模様になるでしょ」と思えますが、そうはいかない。Identiconを組むのに欲しいのは「数値」です。入力データが数値以外の場合、そのまま使うことはできません。
 また、Identiconを組むのに必要な情報の量はわずかなんです。たとえば2ケタの整数が必要だとします。この時に「1234」というデータと「1243」というデータが入ってきたとします。「わずかしか要らないから」と冒頭の2ケタ「12」だけを使ったら……どっちも同じ「12」で、同じ模様が出てしまいます。欲しい情報がわずかだからといって本当にデータの一部だけチョイスしたら、結果がかぶりまくってしまいます。
 「じゃあ一部じゃなくて、全部をひっくるめてひとつにしてチョイスしたら?」とも思えますがそれも単純じゃいけない。「1234」の各ケタを足して「10」。「1243」の各ケタを足しても「10」。同じ数字になっちゃいます。ちなみに掛けると「24」でこれも同じ数字になっちゃいます。

 じゃーどーすんのよ!

 つまりは「データ全体から、別種のデータと極力かぶらない、特有の数値(ハッシュ値)を生成する処理(ハッシュ関数)」が要るってことです。

 とりあえず。「データの総量が同じでも、各ケタが違えば結果は異なる」ようにと、各ケタのデータに各ケタの位置を掛けてみましたが、これは失敗。「84」は「8×1=8」「4×2=8」で足して計「16」。「27」は「2×1=2」「7×2=14」で足して「16」。ほらー、もー。
 いろいろなサイトを参照したところ、どうやら各ケタごとに「算出中の総合数値の方を特定の値で乗算する」といいらしい……Wikipediaの例では、毎回「137」を掛けつつ各ケタのデータを足すようになってました。なるほど。これならそうそう同じ結果は出ないっぽい。

 と、それでとりあえずは解決したんですが、これもこれで問題が。

 JavaScriptで使える数値は、有限なんです。JavaScriptで扱えないほど巨大な数値は、無限を表す特殊な数「Infinity」に変じます。そしてこの「Infinity」は、通常の演算に使えないのです。「Infinity」になっちゃったら、もうそこからIdenticonを作れないんです。
 何十回も「137」を掛けていれば、どんどん数値は増大し、いずれ「Infinity」に到達してしまいます。「137」を「37」にしても、到達スピードが遅くなるだけで、結末は同じです。数値を増やし続けてゆけばいつか「Infinity」になる。使用不能な値になってしまう。さあどうしたもんだ。

   ・

 けっきょく今回の実験では「Infinity化する前に数を減らす。ある数を超えたら補正をかける」ことでお茶を濁しました。
 本当はこんな対処じゃいけないんだろうな……。今回見たハッシュ関数の例は、どれも最後の辺の問題(「桁あふれ」や「オーバーフロー」と呼ぶらしい)に触れてなくって。対処法がわかりませんでした。言語によっては「Infinity」みたいなことにはならず、無視して計算を続けられるんだろうか? それとも「巨大になった数値は、別の変数に分割して処理する」などの仕組みで回避するんだろうか? どっちもハズレだろうなあ……どうやってんだろう。
 「SAH-5」などの有名なハッシュ関数について、実際の処理を見てみたかったんですが……コードを掲載しているサイトが見つからない。個別のハッシュ関数をいちいち解説してる人なんていないんだろうなあ。こういうことを学びたければ、原典や移植作のソースを入手し、直接読んで勉強するんだろうなあ。

 数学も英語もからっきしな私にはきびしい体験となりました。ハッシュ。

   ・

 ともあれ、まあ実用レベルとしては問題なかろう、というぐらいの出来にはなった気がしなくもなくもないとも言えなくないとも思えなくもない……と思いたかったと言ってみたいような、そんな……あー、ようは「もうこれで良しとしたい」気持ちになったんですが。

 VMLが、表示に微妙な隙間を出しよる……。隙間の間から下地の白が覗いて、白線がチラチラしてしまう。これじゃあ「白線が気にならない表示サイズ」でしか使えない。あれこれと調整してみましたが、どうしても消えない、消せない。白線が出続ける。まいった……。
 「2chのID表示、Wikiサイト編集履歴のIPアドレス表示あたりをIdenticon化できたらいいかもしれない」と思ってやり出したことなんですけど。いろんなサイズできちんと表示できないんじゃ実用は難しい……。私用限定としても、我慢できるかできないかギリギリのところです。どうしよっかなあ。
 「9マスを1グループに組み合わせてひとつの表示にする」のではなく「1グループ9マスをどばんと生成、表示する」ように作り直せばいいんだろうけど。難易度的にも処理的にもそれは避けたい。

 と言いつつ、この記事のアップを延期して、やってみました。「9マスつぎはぎ」ではなく「9マスをいっぺんに描く」タイプ。  やっぱり消えない……ベクター画像のサブパスをしょっちゅう切ってるから結局「つぎはぎ」と同じ表示になって当然かあ。ひと筆描きしやがれ、ってことなんだろうねえ……そりゃまた随分と高等な数学問題を出してくれよってからに……お手上げです。

 表示は少しだけ早くなったみたい(ランダム生成ボタンをキーボードから押すとわかりやすいかもしれません)。がんがんループや分岐で負担かけてるだろうと思ったのに。ちょと意外です。

   ・

 応用、流用は考え中です。少し早くなったとはいえ、さすがに数十個を一瞬で表示できるとは思えません。Sleipnirをプチフリーズさせるものになりそうです。悩みます。

 IE8では(まだよく調べてないんですが)DATAスキームが使えるそうなので、やるとしたらVMLよりそちらの方が現実的なのかもしれません。しかしDATAスキームはDATAスキームでこれまた情報が少なくって、あっても英語ばかりで、めちゃくちゃ苦労するのが目に見えてます。私はバイナリや画像フォーマットの知識なんて持ってませんし。えらいことになるぞ……。

 勉強になりましたし、「スクリプトから画像を出す」というのは今までにないことで面白くもあったんですが、力不足を痛感しました。ビット演算や配列のコピーでも詰まりましたし。一度わかってしまえば次からはスムーズになるので、無駄ではないんですけどね。

この記事に対するトラックバック

この記事のトラックバックURL

この記事に対するコメント

つ API.GetUrlHash
マニュアルにはURLのハッシュって書いてますが別にどんなテキストでも問題なくハッシュ化してくれますよ。
DATAスキーム使わなくてもSeaHorseならバイナリ扱えますが、SeaHorseでやるならチップを同梱しといて
テーブルで9マス埋めるのがいいかも知れないですね。

  • 投稿者: プヨぷよ
  • URL
  • 2009/06/06(土) 03:33:12
  • [編集]

プヨぷよ さんの言うとおり sleipnir.API.GetUrlHash を使うのが手っ取り早いですね。
もし API 使いたくないのであれば、
↓の MD5.js あたりが使えるかもしれません。
http://www.onicos.com/staff/iz/amuse/javascript/expert/

  • 投稿者: 由々識
  • URL
  • 2009/06/06(土) 11:13:30
  • [編集]

> プヨぷよさん
> 由々識さん

APIのことをすっかり忘れてました。
「いきなりSeaHorseを作るのは困難そうだから、
まずはHTML1個で実験してみなきゃ」
と思い込んで作業してました。
SleipnirScriptならもっと楽にできるんだった……。

ヒントありがとうございます、助かりました。
「MD5.js」読みましたが内容がまったく理解できず……。
素直にsleipnir.API.GetUrlHashを使おうと思います。

   ・

VMLを試したのには、
着色方法に悩んだという事情もあったんですけど。
透過部分のある白い画像を9個表示し、
色はbackground-colorで出せば簡単にできましたね……。

いろいろ遠回りしちゃったようです。

  • 投稿者: cocoa
  • URL
  • 2009/06/07(日) 14:53:40
  • [編集]

この記事にコメントする

管理者にだけ表示を許可する