yamicha.com's Blog - Presented by yamicha.com
Blog yamicha.com's Blog - 2018/09 の記事
[1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22] [23] [24] [25] [26] [27] [28] [29] [30]

yamicha.com's Blog
 諸事情により、現在更新休止中。ご了承ください。もし今後ブログを再開することがあるとすれば、その際にはこのブログスクリプトではなく、新しく開発したものによるかもしれません。
 当ブログ管理者についてはこちらをご参照。
開発魔法(737)
社会問題(733)
お知らせ(11)
質問・バトン回答(15)
ゲスト出演(8)
経済・知的財産(150)
ゲーム開発(182)
[Ada] 勝手に補足
- Note
- 金配りの次の一手


- Endless Ultimate Diary
- 銃世界

漢字バトン
- うるる雑記帳
- 漢字接力棒

ツキアイゲノムバトン
- ブログ@うにうに画像倉庫
- あぶ内閣

縺イ縺セ縺、縺カ縺励ヰ繝医Φ
- 月夜のボヤキ
- 騎士サーラバトン
パスワードを使う
名無し (2012/02/27)


開発者解放裁判
yamicha.com (2010/03/14)
Winnyに関しては、私も「純白」とまでは考えておりませんし、使用し..

開発者解放裁判
通りすがり (2010/03/08)
winnyに関しては「ダウンロードソフト板」なんてところを拠点に開発..

新型インフルエンザの恐怖
いげ太 (2009/11/03)
> C#などの「int Some(int , int)」は、F#では「(int * int) ->..

時効に関する思考
yamicha.com (2009/08/31)
>いげ太さんコメントありがとうございます。手元にドキュメントが少..
Homepage
Blog Top
Normal View
List View
Search
Calendar
Comment List
Trackback List
Blog RSS
Send Trackback
Phone Mode
Administrator
yamicha.com
Blog
るううるる。
Source
法令データ提供システム
FindLaw
Development
Java2 Platform SE 6
Java EE 6 API
MySQL Developer Zone
PHP Reference
MSDN Library
Ada Reference Manual
Objective Caml
Python Documentation
Erlang
Prolog Documents
時効となる事項
2009/05/02(Sat)02:39:00
 このところ、かねてからの犯罪被害者らの要望に加え、すでに時効となった事件が話題に上ったり、裁判員制度などで刑事裁判への関心が高まったりしたためか、時効見直しの機運が強まりつつあるようです。国によっては、殺人や公金横領といった特定の犯罪に関しては時効を設けない場合もあるようですが、日本では今のところ殺人などにも時効が存在しています。
 時効に関する規定は刑事訴訟法第二百五十条で定められていますが、これは2000年代に入ってすでに1度改正されており、殺人など死刑に当たる罪の時効は15年から25年に延長されています。ただ、25年の期間は決して短いものとはいえませんが、逃げ切るのが不可能な期間ともいえませんので、見直し論が出るのはある意味で必然ではあります。
 現状の時効見直し論は、おおむね2つのタイプに大別できそうです。1つ目が有限にせよ無限にせよ現状より時効を延長するもので、もう1つは「ジョン・ドゥ起訴」を認めるものです。また、罪は遡及して適用できないものとされていますが、時効の改正に遡及が認められるかについては議論があるようです。
 ご存じない方のために「ジョン・ドゥ起訴」について触れておきますと、これは被疑者のものとみられるDNAが現場に残されていた場合に、DNAを使って被疑者不明のまま起訴を行う手法です。昨今の科学技術をもってすれば、DNAは非常に高い確率で同一人物を特定できるため、このような方法が可能となるようです。起訴すれば時効は進行しないため、事実上時効を停止させる手段となります。ちなみに「ジョン・ドゥ」とは「誰かさん」のような意味です。
 時効に関する問題意識が高まるのは良いことですし、必要となれば改正を行うのも当然です。今後とも十分な議論がなされるべきテーマではあります。しかしながら、私は安易な時効改正には賛成しかねます。十分な議論によって時効改正の長短を明らかにし、その上で改正した方が有効であるとの判断が出たのであれば改正はあっても良いのですが、被害者感情を理由とした改正ありきの論には到底賛成できません。
 刑事訴訟法に時効が存在する理由については、様々な説明が試みられているようですが、中でも時効改正賛成派がよく引用したがる理由として「時間によって被害者感情が薄れる」「時効まで逃げ切る間には自責の念にさいなまれ、しかも大変な苦労が必要であるため、罪が免除される」などがあります。その上で、何年経っても被害者感情が全く薄れない事実を述べ、逃げ切ってせせら笑う犯人の罪を免除するのもおかしいと説き、改正は必要であると結論します。
 このような改正派の主張は、少なくとも以上の理由に限れば事実です。時効でまんまと犯人が逃げおおせたとあっては、被害者感情は薄れるどころか憤慨と化すはずですし、時効まで逃げ切るのに自責の念があったり、苦労が必要だから罪を免除するというのなら、時効寸前まで逃げて逮捕された被告人の罪も減免しなければ公平とはいえません。仮にこれらの理由によって時効が存在するのであれば、私もまず間違いなく改正賛成に回るでしょう。
 しかしながら、時効の存在には他にもいくつかの無視できない理由があります。代表的なものをいくつか挙げるなら、まずは捜査に割ける資源が有限である点です。捜査に投入できる人員や物資は無限ではないため、「あちらを立てればこちらが立たず」の状態となります。時間が経過すれば証拠は散逸し、目撃証言や被疑者の居場所の情報を得ることも大変困難になりますので、必ずしも効率の良い捜査とはいえません。したがって、捜査から手を引くのには合理的な理由があります。このように述べると冷徹なようですが、つまりは20年前の1件の殺人事件を解決する代わりに、最近起きたばかりの10件の殺人がことごとく迷宮入りしては困るのです。無論、ある程度で捜査は打ち切りつつも、遺留品の指紋なりDNAなりは保持しておいて、後に被疑者が何らかの犯罪を犯した際にそれを照合して逮捕、といった方法も考えられないではありませんが、いずれにしても能動的な捜査はいつか打ち切らなくてはなりません。
 また、これは私が時効改正に慎重である最大の理由なのですが、時効の緩和は冤罪の可能性が増大する側面も持ち合わせています。時間が経過すると証拠が散逸し、証言を得るのも非常に困難になりますが、これは何も検察にとってのみ不利なものとは限らず、ひとたび起訴されると被告人が自らの疑いを晴らすための証拠を集めるのも困難であることを意味します。現状の殺人の時効は25年ですが、それでさえ証拠を集めたり、証言者を探すのは並大抵ではありません。これがさらに延長されるとなれば、その難易度は想像を絶します。
 本来、刑事裁判は厳密な立証を必要としているはずなのですが、実際には「被告人が犯人でないとはいえない」のような理由で犯人とみなされてしまうようなケースが横行しています。ただ単に状況証拠を積み重ねるだけで、明らかに証明が不十分であったとしても、立証責任が被告人の側に移ってしまうのです。そうなると、被告人には自分が犯人でないことを証明する必要が出てきますが、これは最近発生した事件であっても非常に困難な作業です。
 これが何十年も前の事件となれば、その証明は到底不可能なレベルとなります。もし間違いなくアリバイが成立していたとしても、何十年も前の事例について確実な証言を得るのは困難ですし、疑いをかけられた人自身も数十年前のことを詳細に覚えている方が珍しく、検察の言い分にはまず対抗できません。また、時として捜査機関が物証を捏造したのではないかと考えられるようなケースもありますが、それが事件直後に行われたのならまだしも、数十年後ではその矛盾を見抜くのもまず不可能となります。
 冤罪が発生し得ないのであれば時効の延長も結構ですが、この問題に一定の解が示されない限り、私は延長には安易に賛成できません。そもそも、殺人の時効が15年から25年に、実に倍近くも延長された改正からさほどの期間が経過しておらず、新しい時効が適用された事例はまだ1件もありません(延長は2005年に施行されているため、時効があるとすれば少なくとも2030年以降です)。この25年なる時効がどの程度のものかの知見もないにもかかわらず、25年では短すぎるとして即座に改正する根拠はどこにあるのでしょうか。実際に運用してみて25年では短すぎると結論されたのならともかく、そうでない段階での改正及び付随する問題点を考えると、どうしても慎重にならざるを得ないのです。
 毎日新聞の「憂楽帳」なるコラムに時効という文章が記載されたことがありました。足立区女性教師殺人事件について述べ、時効制度に物申す内容です。この事件は時効成立後に犯人が名乗り出てきて話題となったものですので、ご存知の方も多いのではないでしょうか。
 この執筆者は被害者のいとことのことですので、犯人が分かっていながら起訴されない理不尽さや無念さはさぞ察するに余りあるものでしょう。しかしながら、ここで1つの矛盾が生じます。この事件では被害者は失踪したものとされており、死体は犯人の「自首」時まで発見されていませんでした。この犯人は罪を悔い改めてというより、被害者の遺体が発見する可能性が出てきたので自首を行ったという色彩が強いようですが、この犯人が時効を意識して自首を行ったのであれば、仮に時効がなければ遺体を何が何でも隠蔽しようとした可能性も考えられ、それが成功すれば今でも被害者は「行方不明」のままになっていたでしょう。したがって、このコラムは時効がなければ成立しなかった可能性がある事象を元に時効を否定するという、やや不自然な構図となっています。
 時効を論じるに当たっては、この「自首」効果にも触れておかなければなりません。本件のように行方不明として処理されていたり、殺害の事実は判明していても動機や状況、犯人像が分からない、あるいは遺体が見つからず埋葬ができないなどといった事件では、犯人が判明しない限りは遺族にとって生殺しの状態が続くこととなります。先に述べた通り、時効が無限であっても能動的な捜査は打ち切らざるを得ないため、もし時効が全く存在しなければ、犯人逮捕の見込みがほとんどなくなりながら、事件の全容が一切解明されないといった事態が発生しかねません。
 さらに自首が重要となるケースとしては、「冤罪」があります。無辜の人間が犯人とされてしまい、起訴されて刑事裁判にかけられたり、罪が確定して収監されたりといった事例はたびたび見受けられますが、時効成立後に真犯人が自首を行えば、冤罪の人間は解放されます。実際には民事裁判で訴えられる可能性が高いなど、自首のハードルは低いとは言いがたいのですが、真犯人は犯罪に対する後悔に加え、身代わりに刑罰を受けなければならなくなった人への念をも背負わなくてはならず、自首を促す効果はあると見るべきでしょう。
 「ジョン・ドゥ起訴」に関しては、確かにDNAを使えば冤罪の可能性は低くなりますが、検察と弁護側の検査で食い違う結論が出たり、採取できた遺留物の少なさを理由として、検察が試料をすべて使い切ってしまって追試が不可能になったりと、少なくとも完璧なものとはいえない面があります。また、これまでの手続きとは大幅に異なる概念を導入する点などにも慎重論が少なくないようで、時効は延長するにしてもジョン・ドゥ起訴は導入しないとの案もみられます。
 このように、今のところは各種問題をはらんでいる同制度ですが、私は将来的には導入してしかるべきと考えています。ただし、それは決して殺人の時効を無効化するためではなく、もっぱら性犯罪に対処するためです。殺人の時効引き伸ばしの手段としてこの制度を導入するよりも、性犯罪に対抗する手段を主として導入する方が、より多くのメリットが得られ、デメリットも軽減できるのではないかと考えています。
 最近は痴漢冤罪なども問題にはなっていますが、性犯罪が憎むべきものである点には変わりありません。最近では刑事訴訟法第二百三十五条が改正され、犯人を知った後に6ヶ月以内に告訴しなければならない規定から除外されるなど、以前に比べれば被害者への配慮はマシになっているとはいえますが、依然として多くの泣き寝入りが発生している可能性が疑われています。また、被害者と犯人に面識がない場合では、犯人が逃げおおせてしまうような例も少なくないとみられます。ジョン・ドゥ起訴でこれらすべての問題を解消することはできなくても、一助になるなら導入を検討すべきでしょう。
 以上の通り、私は安易な時効の改正には賛成しかねます。以上の問題を一通り解消できる方法があるのなら、改正には特に反対しませんが、逆に以上のような問題が残っている限りにおいては、安易な改正の方が危険です。日本では被害者感情は盛んに語られる割に、冤罪に対する問題意識がどうも希薄なようですが、全く心当たりのない容疑で数十年後に突然逮捕されるような状況もないとはいえません。その疑いを晴らすのは困難を極めます。
 少なくとも時効延長にはデメリットが存在します。それを踏まえてもなお改正が必要という主張は尊重されるべきですが、デメリットを無視した議論には意味がありません。デメリットまで考えた上で結論を出すのが重要でしょう。

 前回の開発でようやく全バージョンの機能パターンと形式・型番情報を作成できるようになり、内容データを正しく入れさえすれば、QRコードを作れるようになりました。ところが、QRコードのデータには「RSブロック」なる厄介なものが存在するため、一定のバージョン・エラー訂正レベル以上のデータをそのまま配置しても、正しいデータとはなりません。一体どのように処理したものでしょうか。
 RSブロックの数と大きさはバージョンとエラー訂正レベルによって定められ、それぞれ固有の値を取ります。何らかの法則によって定められているのかもしれませんが、仕様書にその旨明記した部分は特に見当たらず、またそれらしい共通項も見られませんので、少なくとも以下では固有の値として扱います。
 値のリストは仕様書に記載されていますので、それを使用すれば開発は可能です。ただし、仕様書のリストには一部に誤りがあるらしいので注意が必要です。単純に足し算をしても数が合わないものすらあり、Excelか何かで集計をするだけでも発見できる間違いのはずなのですが、本当にどこまでもいい加減な仕様書です。以前に述べた通り、生成多項式にも誤りがありますので、仕様書のデータは鵜呑みにしない方が良いでしょう。
 仕様書を確認できない、あるいはミスのある部分を確認するのが面倒という方は、おそらく正しいであろうデータをRSブロックリストに記載していますので、こちらをご参照ください。ただし、これも仕様書を基にした(そもそも仕様書を基にする以外にやりようがない)ものですので、間違いがないとは言い切れません。
 まず、RSブロックのリストから、その性質を考えてみましょう。リストの上の方を見る限り、バージョン2まではどのエラー訂正レベルでもRSブロックは1つしかなく、エラー訂正レベルがMならバージョン3まで、Lなら5までが同様となっています。以前に1-Lのデータを作成した際には、特に分割処理などはしませんでしたが、それでも構わなかったのはこれが理由です。
 RSブロック数が複数に達する場合、RSブロックごとの(エラー訂正部分を除いた)データのバイト数はすべてのRSブロックで同様の場合もあれば、異なる場合もあるようです。ただし、データのバイト数が異なる場合であっても、そのバリエーションは2種類しかなく、しかも値は「後半のバイト数 = 前半 + 1」で固定です。一方、エラー訂正部分のバイト数はすべてのRSブロックで同じのようです。
 また、生成多項式はせっかく68まで用意されていながら、なぜかエラー訂正部のバイト数(= 使用する生成多項式)には30を超えるものが見当たりません。これでは苦労して68までの生成多項式を入力する意味はなさそうですが、一体どうなっているのでしょうか。
 ちなみに、RSブロックのデータバイト数には次の性質があることを述べましたが、

・バイト数は全RSブロックで同じ場合と異なる場合がある
・バイト数が異なったとしても、そのバリエーションは2つしかない
・バイト数が異なる場合は、「後半のバイト数 = 前半 + 1」で固定である

 これらの性質のおかげで、RSブロック数とデータバイト数の総計さえ記録しておけば、各ブロックごとのデータバイト数は計算にて算出可能となっています。
 15-Hを例に取れば、先のリストを見ての通り、データバイト数は223、RSブロック数は18となっています。これを均等に振り分けるとして、223を18で割ると12あまり7が得られます。12ずつ振り分けてもあまりが生じてしまう計算ですから、あまったものは後半部分に加えて帳尻を合わせなくてはなりません。後半のデータバイト数は前半 + 1なのですから、前半のデータバイト数は12、後半は13となります。7個のあまりを後半の7ブロックに1つずつ振り分けるとすれば、13バイトとなる後半のブロックは7個となります。したがって、RSブロック18個中、前半の12バイトのデータは11個、後半の13バイトのデータは7個と分かります。
 エラー訂正のRSブロックごとのバイト数を求めるのはもっと簡単です。こちらもエラー訂正のバイト数の総計から求めれば良いのですが、こちらのバイト数はすべてのRSブロックで同じなのですから、割ってもあまりは発生しません。先ほどの15-Hの場合であれば、これもリストの通りエラー訂正データの総計は432、これを18で割ると24ですから、24バイトのデータが18個と分かります。
 以下、RSブロックの分割及び最終的なデータ生成の手順です。

0.データを準備
 内容データを書き込んだり、埋め草コードを入れたりといった工程です。この方法は以前に扱いましたので、特筆すべき点もないでしょう。ただし、エラー訂正コードはまだ入りません。

1.データをRSブロックごとに分割する
 リストなり上記の算出法なりを使用し、RSブロックの個数とブロックごとのデータバイト数を求め、その通りにデータを分割します。3-Qの場合を例に取れば、これは「17x2」となっていますので、総計34バイトのデータを17バイトずつに分割します。先ほど触れた15-Hの場合であれば、データを12バイト区切りで11個切り出し、さらに13バイト区切りで7個を切り出し、合計18個に分割します。ただ単に分割するだけですから、特に問題となるような部分もないでしょう。
 以下、2バイトx1、3バイトx2の3個のRSブロック(そのようなブロックは実在しませんが)を生成する場合のサンプルです。


 1〜8までの8バイトのデータを、順に2,3,3バイトの3つのRSブロックに分割した図。

2.それぞれにエラー訂正コードを求める
 ここでようやくエラー訂正コードを求めます。リストなり上記の式なりを使用して、ブロックごとのエラー訂正コードのバイト数を求め、その番号の生成多項式を取得します。例えば3-Qであれば、エラー訂正コードのバイト数は18x2ですので、生成多項式リストから18の生成多項式を取得します。

x18 + a215x17 + a234x16 + a158x15 + a94x14 + a184x13 + a97x12 + a118x11 + a170x10 + a79x9 + a187x8 + a152x7 + a148x6 + a252x5 + a179x4 + a5x3 + a98x2 + a96x1 + a153

 この生成多項式を使い、先ほど分割したデータのそれぞれのブロックについてRS符号を求めます。3-Qではブロックが2つありますので、1つ目のブロックと2つ目のブロックのそれぞれについてRS符号を求める必要があります。ここで求めたRS符号は、元のデータには結合せずに、別の配列にでも格納しておいた方が後が楽です。
 以下、2,3,3に分割した架空の8バイトデータについて、それぞれに3バイトずつのRSコードを求めた図です(当然のことながら、3の生成多項式など存在せず、あくまで架空のものです)。


 それぞれのブロックにエラー訂正コード3バイトずつを付加した図。

3.連結する
 後はこれをつなぎ合わせて1つのデータを生成するのですが、連結の仕方は少々特殊です。仮に以下のようなデータがあるとして、

RSブロック データ エラー訂正
1 D1-1 D1-2 E1-1 E1-2 E1-3
2 D2-1 D2-2 D2-3 E2-1 E2-2 E2-3
3 D3-1 D3-2 D3-3 E3-1 E3-2 E3-3

 まずはデータを縦方向に取り出して連結していき、それが終わったらエラー訂正コードも同じように取り出して連結します。すなわち、まず最初のRSブロックの先頭のデータを取り出し、次のRSブロックの先頭のデータを取り出し、その次のブロックの先頭のデータを取り出し、それを繰り返して最後のRSブロックの先頭のデータを取り出したら、次は最初のRSブロックの2番目のデータを取り出します。全部取り出し終えたら、今度はエラー訂正コードについて同じことを行います。これを取り出した順に並べたものが最終的なデータとなります。先の表を例に取れば、以下が最終的なデータです。

D1-1 D2-1 D3-1 D1-2 D2-2 D3-2 D2-3 D3-3 E1-1 E2-1 E3-1 E1-2 E2-2 E3-2 E1-3 E2-3 E3-3

 2,2,3のサンプルであれば、最終的に次のようになります。


 一見複雑ですが、単に縦方向に順番に取り出して並べただけです。

 後はこれをQRコードに書き込み、マスクなりの処理を行うだけです。これでようやく、バージョン1から40まで好きなものを作成できるようになります。
 以下、3-H型に「I Don't Like Spam!」と書き込む場合のサンプルを示します。

0.データを準備
 この工程は以前に行いましたので、ここでは概要のみをおさらいしておきます。
 まず8ビットバイトモードの指定子「0100」を書き込みます。次いで格納する文字数を書き込みます。8ビットバイトモードの場合、バージョン9までは文字数として8ビットを使用する規定となっていますので、文字数("I Don't Like Spam!"で18文字)を8ビットデータ(00010010)として書き込みます。
 続いて文字列をすべて書き込み、終端として「0000」を書き込みます。さらに、ここまでのデータをバイトに書き込んだ際、ビットに余剰が生じるようなら、そのバイトの残りのビットを全部0で埋めます(今回は余剰が出ないので必要ありません)。後は埋め草ビットを書き込み、データ量を規定数(3-Hでは26バイト。RSブロックリストから確認できます)にしたら、分割前のデータは完成です。
 おそらく「65 36 146 4 70 246 226 119 66 4 198 150 182 82 5 55 6 22 210 16 236 17 236 17 236 17」の26バイトが得られたのではないでしょうか。

1.データをRSブロックごとに分割する
 RSブロックリストにある通り、3-HのRSブロックは2つあり、データ内容は13x2、エラー訂正は22x2となっています。
 まず、先の26バイトのデータを13バイトずつに分割します。ただ分割するだけですので、特に問題はないでしょう。わざわざ書くまでもありませんが、分割後のデータは以下の通りです。

65 36 146 4 70 246 226 119 66 4 198 150 182
82 5 55 6 22 210 16 236 17 236 17 236 17

2.それぞれにエラー訂正コードを求める
 上記のデータに対して、それぞれエラー訂正コードを生成します。今回は22x2ですから、22の生成多項式を使ってRS符号を算出し、22バイトのコードを2つ作成します。おそらく以下のようなコードが生成されることでしょう。

240 246 63 172 188 204 238 46 190 177 245 218 3 64 180 113 207 56 119 98 90 77
209 121 243 178 81 24 166 189 35 235 102 197 241 5 190 73 16 225 224 0 217 84

3.連結する
 先に述べた方法によって、これらのデータを連結します。分割時に比べれば少々面倒ですが、大した問題はないでしょう。今回はRSブロックのデータバイト数が同じですので、単にバイトを互い違いに配置するだけで構いませんが、前述の通りブロックごとのデータバイト数は異なる場合もあるため、実装の際には注意が必要です。以下の70バイトが最終的なデータとなります(データ部分を青、エラー訂正部分を緑で示します)。

65 82 36 5 146 55 4 6 70 22 246 210 226 16 119 236 66 17 4 236 198 17 150 236 182 17 240 209 246 121 63 243 172 178 188 81 204 24 238 166 46 189 190 35 177 235 245 102 218 197 3 241 64 5 180 190 113 73 207 16 56 225 119 224 98 0 90 217 77 84

 後はこれをQRコード上に配置し、マスクを適用すれば完成です。


 バージョン3、エラー訂正レベルH、マスク0の場合のQRコード。

 以下、実装の参考までに、RSブロックごとのデータバイト数が異なる場合の例を記載しておきます。このような分割が生じるのは、最も早い段階であっても5-Hまたは5-Qですので、ここでは5-Hを使用するものとします。RSブロック数は4、データは11x2 , 12x2、エラー訂正は22x4です。
 これはサンプルですので、データは単純に"abcdefghijklmnopqrstuvwxyz0123456789"とします。

1.最初のデータ
 5-Hでは総勢46バイトです。

66 70 22 38 54 70 86 102 118 134 150 166 182 198 214 230 247 7 23 39 55 71 87 103 119 135 151 163 3 19 35 51 67 83 99 115 131 144 236 17 236 17 236 17 236 17

2.分割後のデータ
 11,11,12,12の4つに分割します。下線部は後半ブロックの「前半ブロックより1バイト分多い部分」です。

66 70 22 38 54 70 86 102 118 134 150
166 182 198 214 230 247 7 23 39 55 71
87 103 119 135 151 163 3 19 35 51 67 83
99 115 131 144 236 17 236 17 236 17 236 17

3.エラー訂正コード
 22バイトが4つです。

75 244 1 148 99 154 191 74 128 135 195 229 243 141 212 30 170 128 68 227 23 59
235 28 249 154 89 17 252 18 157 222 242 50 156 67 182 75 162 160 145 163 117 128
179 212 184 53 219 92 39 207 16 35 73 26 97 13 193 185 206 112 156 223 7 239
144 149 53 59 19 223 218 159 136 133 150 189 156 184 119 0 218 91 194 108 97 186

4.最終的なコード
 これらを連結し、134バイトのコードを生成します。青色の部分がデータ、緑色の部分がエラー訂正コードです。

66 166 87 99 70 182 103 115 22 198 119 131 38 214 135 144 54 230 151 236 70 247 163 17 86 7 3 236 102 23 19 17 118 39 35 236 134 55 51 17 150 71 67 236 83 17 75 235 179 144 244 28 212 149 1 249 184 53 148 154 53 59 99 89 219 19 154 17 92 223 191 252 39 218 74 18 207 159 128 157 16 136 135 222 35 133 195 242 73 150 229 50 26 189 243 156 97 156 141 67 13 184 212 182 193 119 30 75 185 0 170 162 206 218 128 160 112 91 68 145 156 194 227 163 223 108 23 117 7 97 59 128 239 186

 これでようやく複数のRSブロックの使用が可能となり、1から40まで好きなバージョンのQRコードを作成できるようになりました。コード作成の際には、各バージョン及びエラー訂正レベルごとのデータバイト数、エラー訂正バイト数、RSブロック数、及びRS符号の生成多項式といったデータが必要となりますので、この辺りでこれらのデータをプログラム中に導入しておけば、いかなるバージョンのコードでも簡単に作れて便利です。これらのデータは仕様書にも記載されていますし、RSブロックリスト及び生成多項式リストのものを使用しても構いません。ただし、前述の通り仕様書には誤りがあるので注意が必要です。
 以下に今回の実装を加えたPHPコードを示します(QRブロックの実装の他、各バージョンごとのバイト数などのデータ管理用クラスとしてQRCodeInformationも導入しています)。
<?php
class GaloisField{
  private static $gf_8 = null;

  private $index;
  private $r;
  private $power;
  private $root;

  function newInstance($n){
    if($n == 8){
      if(self::$gf_8 == null){
        self::$gf_8 = new GaloisField(
          8 , (1 << 4) | (1 << 3) | (1 << 2) | 1);
      }
      return self::$gf_8;
    }
  }

  protected function __construct($n , $r){
    $this->index = $n;
    $this->r = $r;

    $this->createTable();
  }
  private function createTable(){
    $over_bit = pow(2 , $this->index);
    $max = $over_bit - 1;

    $value = 1;
    for($i = 0; $i < $max; $i++){
      $this->power[$i] = $value;
      $this->root[$value] = $i;

      $value <<= 1;
      if($value >= $over_bit)
        $value ^= (1 << $this->index) | $this->r;
    }

    $this->power[$max] = 1;
    $this->root[0] = -1;
  }

  function pow($d){
    return $this->power[$d];
  }
  function root($d){
    return $this->root[$d];
  }
  function getIndex(){
    return $this->index;
  }
}

// RS 符号を用いたエラー訂正コード算出クラス
class RSErrorCorrect{
  private static $gf;
  private $g;

  function __construct($g){
    self::$gf = GaloisField::newInstance(8);
    $this->g = $g;
  }
  function createECC($raw){
    // 演算するデータ長を算出
    // データか生成多項式のいずれか長い方
    $length = count($raw) > count($this->g) ?
      count($raw) : count($this->g);

    // 計算のためデータ配列をシフトする
    $data = array();
    for($i = 0; $i < count($raw); $i++)
      $data[$i] = $raw[$i];
    for($i = count($raw); $i < $length + 1; $i++)
      $data[$i] = 0;

    // 計算
    for($x = 0; $x < count($raw); $x++){
      if($data[0] != 0){
        $e = self::$gf->root($data[0]);

        // $e を G の要素に対して乗算し、それをデータから減算する
        // 得られたデータはシフトした位置に格納
        for($i = 0; $i < count($this->g); $i++){
          $data[$i] = self::$gf->pow(($this->g[$i] + $e) % 255) ^
            $data[$i + 1];
        }

        // 残りのデータをシフト
        for($i = count($this->g); $i < count($data) - 1; $i++)
          $data[$i] = $data[$i + 1];
      }else{
        for($i = 0; $i < count($data) - 1; $i++)
          $data[$i] = $data[$i + 1];
      }
    }

    return array_slice($data , 0 , count($this->g));
  }
}

class BCHCode{
  private static $bch_5 = null;
  private static $bch_6 = null;

  private $r;
  private $len;

  function newInstance($len){
    if($len == 5){
      if(self::$bch_5 == null){
        self::$bch_5 = new BCHCode($len ,
          (1 << 10) | (1 << 8) | (1 << 5) |
          (1 << 4) | (1 << 2) | (1 << 1) | 1);
      }
      return self::$bch_5;
    }
    if($len == 6){
      if(self::$bch_6 == null){
        self::$bch_6 = new BCHCode($len ,
          (1 << 12) | (1 << 11) | (1 << 10) |
          (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | 1);
      }
      return self::$bch_6;
    }
  }

  protected function __construct($len , $r){
    $this->len = $len;
    $this->r = $r;
  }
  function makeBCH($data){
    $base = $this->len * 2;
    $data <<= $base;

    for($i = $this->len - 1; $i >= 0; $i--){
      if(($data & (1 << ($i + $base))) != 0)
        $data ^= $this->r << $i;
    }

    return $data;
  }
}

class QRPixel{
  private $size;
  private $pixel;

  function __construct($size){
    $this->size = $size;
    $this->pixel = array_pad(array() , $size ,
      array_pad(array() , $size , -1));
  }
  function getSize(){
    return $this->size;
  }

  function getPixel($x , $y){
    if($this->pixel[$y][$x] == -1)
      return 0;
    return $this->pixel[$y][$x] & 1;
  }
  function setPixel($p , $x , $y){
    $this->pixel[$y][$x] = $p & 1;
  }
  function isExist($x , $y){
    return $this->pixel[$y][$x] != -1;
  }
}

// ビットを順に書き込むクラス
class BitBuffer{
  private $buffer;
  private $index;
  private $bit;

  function __construct(){
    $this->buffer = array();
    $this->index = 0;
    $this->bit = 0;
  }

  function getBuffer(){
    return $this->buffer;
  }

  function getIndex(){
    return $this->index;
  }
  function getBitIndex(){
    return $this->bit;
  }
  function getRemaindBit(){
    return (8 - $this->bit) % 8;
  }

  private function writeByte($data){
    $this->buffer[$this->index] = $data;
    $this->index ++;
  }
  function write($rem , $data){
    while($rem > 0){
      // ビットを書き込む
      // 残存ビットまたは $rem のうち、少ない側の分量を使用
      $len = $rem < (8 - $this->bit) ? $rem : (8 - $this->bit);

      // フィルタを作成
      $filter = (1 << $len) - 1;

      // 書き込み
      $this->buffer[$this->index] |=
        (($data >> ($rem - $len)) & $filter) <<
        ((8 - $this->bit) - $len);

      $this->bit += $len;
      if($this->bit == 8){
        $this->bit = 0;
        $this->index ++;
      }
      $rem -= $len;
    }
  }
}

// 機能パターンの部分など、データ内容を書き込めない部分を避けて
// QR コードにデータ内容を書き込むためのクラス
class QRPixelExplorer{
  const MOVE_FIRST = -1;
  const MOVE_RIGHT = 0;
  const MOVE_VERTICAL = 1;

  private $format;
  private $code;

  private $x;
  private $y;

  private $move;
  private $vector;

  function __construct($format , $code){
    $this->format = $format;
    $this->code = $code;

    $this->reset();
  }

  function reset(){
    $size = $this->code->getSize();
    $this->x = $size - 1;
    $this->y = $size - 1;

    $this->move = self::MOVE_FIRST;
    $this->vector = -1;
  }

  function next(){
    $format = $this->format;
    $size = $format->getSize();

    while(!($this->x == 0 && $this->y == $size - 1)){
      if($this->move == self::MOVE_RIGHT){
        $this->x --;
        $this->move = self::MOVE_VERTICAL;
      }else if($this->move == self::MOVE_VERTICAL){
        if(($this->vector == -1 && $this->y == 0) ||
          $this->vector == 1 && $this->y == $size - 1){
          $this->x --;
          $this->vector = -$this->vector;

          if($this->x == 6)
            $this->x --;
        }else{
          $this->x ++;
          $this->y += $this->vector;
        }
        $this->move = self::MOVE_RIGHT;
      }else if($this->move == self::MOVE_FIRST){
        $this->move = self::MOVE_RIGHT;
      }

      if(!$format->isExist($this->x , $this->y))
        return true;
    };

    return false;
  }

  function write($p){
    $this->code->setPixel($p , $this->x , $this->y);
  }

  function getX(){
    return $this->x;
  }
  function getY(){
    return $this->y;
  }

  function getCode(){
    return $this->code;
  }
}

class QRCodeCreator{
  private $info;
  private $format;
  private $code;

  function __construct($info){
    $this->info = $info;
    $this->format = new QRPixel($this->info->getSize());
    $this->code = new QRPixel($this->info->getSize());
  }

  function createFinderPattern($x , $y){
    $pixel = $this->format;

    for($py = 0; $py < 7; $py++){
      for($px = 0; $px < 7; $px++){
        $p = 1;
        if(($px >= 1 && $px <= 5 && ($py == 1 || $py == 5)) ||
          ($py >= 1 && $py <= 5 && ($px == 1 || $px == 5))){
          $p = 0;
        }
        $pixel->setPixel($p , $x + $px , $y + $py);
      }
    }
  }
  function createFinderPatterns(){
    $size = $this->format->getSize();

    $this->createFinderPattern(0 , 0);
    $this->createFinderSeparator(0 , 0);

    $this->createFinderPattern(0 , $size - 7);
    $this->createFinderSeparator(0 , $size - 7);

    $this->createFinderPattern($size - 7 , 0);
    $this->createFinderSeparator($size - 7 , 0);
  }

  function createFinderSeparator($x , $y){
    $pixel = $this->format;
    $size = $pixel->getSize();

    $left = $x - 1 >= 0;
    $top = $y - 1 >= 0;
    $right = $x + 7 < $size;
    $bottom = $y + 7 < $size;

    // 辺のピクセル
    for($d = 0; $d < 7; $d++){
      if($left)
        $pixel->setPixel(0 , $x - 1 , $y + $d);
      if($right)
        $pixel->setPixel(0 , $x + 7 , $y + $d);
      if($top)
        $pixel->setPixel(0 , $x + $d , $y - 1);
      if($bottom)
        $pixel->setPixel(0 , $x + $d , $y + 7);
    }

    // 角のピクセル
    if($left && $top)
      $pixel->setPixel(0 , $x - 1 , $y - 1);
    if($left && $bottom)
      $pixel->setPixel(0 , $x - 1 , $y + 7);
    if($right && $top)
      $pixel->setPixel(0 , $x + 7 , $y - 1);
    if($right && $bottom)
      $pixel->setPixel(0 , $x + 7 , $y + 7);
  }

  function createAlignmentPattern($px , $py){
    $pixel = $this->format;
    for($y = -2; $y <= 2; $y++){
      for($x = -2; $x <= 2; $x++){
        $p = abs($x) == 2 || abs($y) == 2 || ($x == 0 && $y == 0) ?
          1 : 0;
        $pixel->setPixel($p , $x + $px , $y + $py);
      }
    }
    $pixel->setPixel(1 , $px , $py);
  }
  function createAlignmentPatterns(){
    $pixel = $this->format;
    $version = $this->info->getVersion();

    if($version == 1)
      return;

    $size = $pixel->getSize();  // 1辺のピクセル数
    $patterns = (int)($version / 7) + 2;  // 位置検出・補正パターン数
    $int_count = $patterns - 1;  // 間隔数

    $int_first = 0;  // 最初の間隔ピクセル数
    $int_other = 0;  // 最初以外の間隔ピクセル数

    // パターン外の部分を除去
    $pixel = $size - 13;

    // 偶数単位にする
    $pixel = (int)($pixel / 2);

    // それを間隔数で割り、値とあまりを算出
    $int_base = (int)($pixel / $int_count);
    $int_rem = $pixel % $int_count;

    // あまりがないなら確定
    if($int_rem == 0){
      $int_first = $int_base;
      $int_other = $int_base;
    }else{
      // 充当の必要がある分を算出
      $shortage = ($int_count - 1) - $int_rem;

      // その分を抽出した後の値を先頭に格納
      $int_first = $int_base - $shortage;

      // 1ずつ配分した後の値を先頭以外に格納
      $int_other = $int_base + 1;
    }

    // 偶数単位を元に戻す
    $int_first *= 2;
    $int_other *= 2;

    // 位置補正パターンを配置
    $y = 6;
    for($y_index = 0; $y_index < $patterns; $y_index++){
      $x = 6;
      for($x_index = 0; $x_index < $patterns; $x_index++){
        // 位置検出パターン部分には描画しない
        if(!(($x_index == 0 && $y_index == 0) ||
          ($x_index == $int_count && $y_index == 0) ||
          ($x_index == 0 && $y_index == $int_count))){
          $this->createAlignmentPattern($x , $y);
        }

        $x += $x_index == 0 ? $int_first : $int_other;
      }
      $y += $y_index == 0 ? $int_first : $int_other;
    }
  }

  function createTimingPattern(){
    $pixel = $this->format;

    $p = 1;
    for($d = 8; $d < $pixel->getSize() - 8; $d++){
      $pixel->setPixel($p , $d , 6);
      $pixel->setPixel($p , 6 , $d);
      $p ^= 1;
    }
  }

  function createBlackPattern(){
    $pixel = $this->format;
    $pixel->setPixel(1 , 8 , $pixel->getSize() - 8);
  }

  function createInformation($info){
    $pixel = $this->format;
    $size = $pixel->getSize();

    $lower = $info & ((1 << 8) - 1);
    $higher = ($info >> 8) & ((1 << 7) - 1);

    $y = 0;
    for($i = 0; $i < 8; $i++){
      $p = ($lower >> $i) & 1;

      if($y == 6)
        $y ++;

      $pixel->setPixel($p , 8 , $y);  // 左上
      $pixel->setPixel($p , $size - 1 - $i , 8);  // 右上
      $y ++;
    }

    $x = 7;
    for($i = 0; $i < 7; $i++){
      $p = ($higher >> $i) & 1;

      if($x == 6)
        $x --;

      $pixel->setPixel($p , $x , 8);  // 左上
      $pixel->setPixel($p , 8 , $size - 7 + $i);  // 左下
      $x --;
    }
  }

  function createVersionInformation($info){
    $pixel = $this->format;
    $size = $pixel->getSize();

    for($i = 0; $i < 18; $i++){
      $p = ($info >> $i) & 1;

      $col = $i % 3;
      $row = (int)($i / 3);

      $pixel->setPixel($p , $row , $col + $size - 11);  // 左下
      $pixel->setPixel($p , $col + $size - 11 , $row);  // 右上
    }
  }

  // データ内容を書き込む関数
  // QRPixelExplorer クラスのおかげで非常に簡単
  function createCode($data){
    $explorer = new QRPixelExplorer($this->format , $this->code);

    foreach($data as $d){
      for($i = 7; $i >= 0; $i--){
        $p = ($d >> $i) & 1;

        if($explorer->next())
          $explorer->write($p);
        else
          return false;
      }
    }

    // 余白を埋める
    while($explorer->next())
      $explorer->write(0);

    return true;
  }

  // マスクパターン生成関数
  static function getMaskFilter($mask){
    function mask0($x , $y){
      return ($x + $y) % 2 == 0;
    }
    function mask1($x , $y){
      return $y % 2 == 0;
    }
    function mask2($x , $y){
      return $x % 3 == 0;
    }
    function mask3($x , $y){
      return ($x + $y) % 3 == 0;
    }
    function mask4($x , $y){
      return (($x / 3) + ($y / 2)) % 2 == 0;
    }
    function mask5($x , $y){
      return (($x * $y) % 2) + (($x * $y) % 3) == 0;
    }
    function mask6($x , $y){
      return ((($x * $y) % 2) + (($x * $y) % 3)) % 2 == 0;
    }
    function mask7($x , $y){
      return ((($x * $y) % 3) + (($x + $y) % 2)) % 2 == 0;
    }
    function unmask($x , $y){
      return 0;
    }

    switch($mask){
    case 0:
      return mask0;
    case 1:
      return mask1;
    case 2:
      return mask2;
    case 3:
      return mask3;
    case 4:
      return mask4;
    case 5:
      return mask5;
    case 6:
      return mask6;
    case 7:
      return mask7;
    }

    return unmask;
  }

  // マスクを適用して QR コードを作成
  function makeQRCode($mask){
    $format = $this->format;
    $code = $this->code;
    $pixel = clone $format;

    $size = $pixel->getSize();

    $filter = self::getMaskFilter($mask);

    for($y = 0; $y < $size; $y++){
      for($x = 0; $x < $size; $x++){
        if($code->isExist($x , $y)){
          $pixel->setPixel(
            $code->getPixel($x , $y) ^ $filter($x , $y) ,
            $x , $y);
        }
      }
    }

    return $pixel;
  }

  function getQRFormat(){
    return $this->format;
  }
  function getQRDataCode(){
    return $this->code;
  }
  function getQRInformation(){
    return $this->info;
  }
}

class QRCodeInformation{
  const ECC_LEVEL_L = 1;
  const ECC_LEVEL_M = 0;
  const ECC_LEVEL_Q = 3;
  const ECC_LEVEL_H = 2;

  private static $SPEC_LIST = array(
    null ,
    array(
      array(26 , 19 , 1) ,
      array(26 , 16 , 1) ,
      array(26 , 13 , 1) ,
      array(26 , 9 , 1)
    ) ,
    array(
      array(44 , 34 , 1) ,
      array(44 , 28 , 1) ,
      array(44 , 22 , 1) ,
      array(44 , 16 , 1)
    ) ,
    array(
      array(70 , 55 , 1) ,
      array(70 , 44 , 1) ,
      array(70 , 34 , 2) ,
      array(70 , 26 , 2)
    ) ,
    array(
      array(100 , 80 , 1) ,
      array(100 , 64 , 2) ,
      array(100 , 48 , 2) ,
      array(100 , 36 , 4)
    ) ,
    array(
      array(134 , 108 , 1) ,
      array(134 , 86 , 2) ,
      array(134 , 62 , 4) ,
      array(134 , 46 , 4)
    ) ,
    array(
      array(172 , 136 , 2) ,
      array(172 , 108 , 4) ,
      array(172 , 76 , 4) ,
      array(172 , 60 , 4)
    ) ,
    array(
      array(196 , 156 , 2) ,
      array(196 , 124 , 4) ,
      array(196 , 88 , 6) ,
      array(196 , 66 , 5)
    ) ,
    array(
      array(242 , 194 , 2) ,
      array(242 , 154 , 4) ,
      array(242 , 110 , 6) ,
      array(242 , 86 , 6)
    ) ,
    array(
      array(292 , 232 , 2) ,
      array(292 , 182 , 5) ,
      array(292 , 132 , 8) ,
      array(292 , 100 , 8)
    ) ,
    array(
      array(346 , 274 , 4) ,
      array(346 , 216 , 5) ,
      array(346 , 154 , 8) ,
      array(346 , 122 , 8)
    ) ,
    array(
      array(404 , 324 , 4) ,
      array(404 , 254 , 5) ,
      array(404 , 180 , 8) ,
      array(404 , 140 , 11)
    ) ,
    array(
      array(466 , 370 , 4) ,
      array(466 , 290 , 8) ,
      array(466 , 206 , 10) ,
      array(466 , 158 , 11)
    ) ,
    array(
      array(532 , 428 , 4) ,
      array(532 , 334 , 9) ,
      array(532 , 244 , 12) ,
      array(532 , 180 , 16)
    ) ,
    array(
      array(581 , 461 , 4) ,
      array(581 , 365 , 9) ,
      array(581 , 261 , 16) ,
      array(581 , 197 , 16)
    ) ,
    array(
      array(655 , 523 , 6) ,
      array(655 , 415 , 10) ,
      array(655 , 295 , 12) ,
      array(655 , 223 , 18)
    ) ,
    array(
      array(733 , 589 , 6) ,
      array(733 , 453 , 10) ,
      array(733 , 325 , 17) ,
      array(733 , 253 , 16)
    ) ,
    array(
      array(815 , 647 , 6) ,
      array(815 , 507 , 11) ,
      array(815 , 367 , 16) ,
      array(815 , 283 , 19)
    ) ,
    array(
      array(901 , 721 , 6) ,
      array(901 , 563 , 13) ,
      array(901 , 397 , 18) ,
      array(901 , 313 , 21)
    ) ,
    array(
      array(991 , 795 , 7) ,
      array(991 , 627 , 14) ,
      array(991 , 445 , 21) ,
      array(991 , 341 , 25)
    ) ,
    array(
      array(1085 , 861 , 8) ,
      array(1085 , 669 , 16) ,
      array(1085 , 485 , 20) ,
      array(1085 , 385 , 25)
    ) ,
    array(
      array(1156 , 932 , 8) ,
      array(1156 , 714 , 17) ,
      array(1156 , 512 , 23) ,
      array(1156 , 406 , 25)
    ) ,
    array(
      array(1258 , 1006 , 9) ,
      array(1258 , 782 , 17) ,
      array(1258 , 568 , 23) ,
      array(1258 , 442 , 34)
    ) ,
    array(
      array(1364 , 1094 , 9) ,
      array(1364 , 860 , 18) ,
      array(1364 , 614 , 25) ,
      array(1364 , 464 , 30)
    ) ,
    array(
      array(1474 , 1174 , 10) ,
      array(1474 , 914 , 20) ,
      array(1474 , 664 , 27) ,
      array(1474 , 514 , 32)
    ) ,
    array(
      array(1588 , 1276 , 12) ,
      array(1588 , 1000 , 21) ,
      array(1588 , 718 , 29) ,
      array(1588 , 538 , 35)
    ) ,
    array(
      array(1706 , 1370 , 12) ,
      array(1706 , 1062 , 23) ,
      array(1706 , 754 , 34) ,
      array(1706 , 596 , 37)
    ) ,
    array(
      array(1828 , 1468 , 12) ,
      array(1828 , 1128 , 25) ,
      array(1828 , 808 , 34) ,
      array(1828 , 628 , 40)
    ) ,
    array(
      array(1921 , 1531 , 13) ,
      array(1921 , 1193 , 26) ,
      array(1921 , 871 , 35) ,
      array(1921 , 661 , 42)
    ) ,
    array(
      array(2051 , 1631 , 14) ,
      array(2051 , 1267 , 28) ,
      array(2051 , 911 , 38) ,
      array(2051 , 701 , 45)
    ) ,
    array(
      array(2185 , 1735 , 15) ,
      array(2185 , 1373 , 29) ,
      array(2185 , 985 , 40) ,
      array(2185 , 745 , 48)
    ) ,
    array(
      array(2323 , 1843 , 16) ,
      array(2323 , 1455 , 31) ,
      array(2323 , 1033 , 43) ,
      array(2323 , 793 , 51)
    ) ,
    array(
      array(2465 , 1955 , 17) ,
      array(2465 , 1541 , 33) ,
      array(2465 , 1115 , 45) ,
      array(2465 , 845 , 54)
    ) ,
    array(
      array(2611 , 2071 , 18) ,
      array(2611 , 1631 , 35) ,
      array(2611 , 1171 , 48) ,
      array(2611 , 901 , 57)
    ) ,
    array(
      array(2761 , 2191 , 19) ,
      array(2761 , 1725 , 37) ,
      array(2761 , 1231 , 51) ,
      array(2761 , 961 , 60)
    ) ,
    array(
      array(2876 , 2306 , 19) ,
      array(2876 , 1812 , 38) ,
      array(2876 , 1286 , 53) ,
      array(2876 , 986 , 63)
    ) ,
    array(
      array(3034 , 2434 , 20) ,
      array(3034 , 1914 , 40) ,
      array(3034 , 1354 , 56) ,
      array(3034 , 1054 , 66)
    ) ,
    array(
      array(3196 , 2566 , 21) ,
      array(3196 , 1992 , 43) ,
      array(3196 , 1426 , 59) ,
      array(3196 , 1096 , 70)
    ) ,
    array(
      array(3362 , 2702 , 22) ,
      array(3362 , 2102 , 45) ,
      array(3362 , 1502 , 62) ,
      array(3362 , 1142 , 74)
    ) ,
    array(
      array(3532 , 2812 , 24) ,
      array(3532 , 2216 , 47) ,
      array(3532 , 1582 , 65) ,
      array(3532 , 1222 , 77)
    ) ,
    array(
      array(3706 , 2956 , 25) ,
      array(3706 , 2334 , 49) ,
      array(3706 , 1666 , 68) ,
      array(3706 , 1276 , 81)
    )
  );

  private static $GENERATIVE_EXPRESSIONS = array(
    7 => array(87 , 229 , 146 , 149 , 238 , 102 , 21) ,
    10 => array(251 , 67 , 46 , 61 , 118 , 70 , 64 , 
      94 , 32 , 45) ,
    13 => array(74 , 152 , 176 , 100 , 86 , 100 , 106 , 
      104 , 130 , 218 , 206 , 140 , 78) ,
    15 => array(8 , 183 , 61 , 91 , 202 , 37 , 51 , 
      58 , 58 , 237 , 140 , 124 , 5 , 99 , 105) ,
    16 => array(120 , 104 , 107 , 109 , 102 , 161 , 76 , 
      3 , 91 , 191 , 147 , 169 , 182 , 194 , 225 , 
      120) ,
    17 => array(43 , 139 , 206 , 78 , 43 , 239 , 123 , 
      206 , 214 , 147 , 24 , 99 , 150 , 39 , 243 , 
      163 , 136) ,
    18 => array(215 , 234 , 158 , 94 , 184 , 97 , 118 , 
      170 , 79 , 187 , 152 , 148 , 252 , 179 , 5 , 
      98 , 96 , 153) ,
    20 => array(17 , 60 , 79 , 50 , 61 , 163 , 26 , 
      187 , 202 , 180 , 221 , 225 , 83 , 239 , 156 , 
      164 , 212 , 212 , 188 , 190) ,
    22 => array(210 , 171 , 247 , 242 , 93 , 230 , 14 , 
      109 , 221 , 53 , 200 , 74 , 8 , 172 , 98 , 
      80 , 219 , 134 , 160 , 105 , 165 , 231) ,
    24 => array(229 , 121 , 135 , 48 , 211 , 117 , 251 , 
      126 , 159 , 180 , 169 , 152 , 192 , 226 , 228 , 
      218 , 111 , 255 , 117 , 232 , 87 , 96 , 227 , 
      21) ,
    26 => array(173 , 125 , 158 , 2 , 103 , 182 , 118 , 
      17 , 145 , 201 , 111 , 28 , 165 , 53 , 161 , 
      21 , 245 , 142 , 13 , 102 , 48 , 227 , 153 , 
      145 , 218 , 70) ,
    28 => array(168 , 223 , 200 , 104 , 224 , 234 , 108 , 
      180 , 110 , 190 , 195 , 147 , 205 , 27 , 232 , 
      201 , 21 , 43 , 245 , 87 , 42 , 195 , 212 , 
      119 , 242 , 37 , 9 , 123) ,
    30 => array(41 , 173 , 145 , 152 , 216 , 31 , 179 , 
      182 , 50 , 48 , 110 , 86 , 239 , 96 , 222 , 
      125 , 42 , 173 , 226 , 193 , 224 , 130 , 156 , 
      37 , 251 , 216 , 238 , 40 , 192 , 180) ,
    32 => array(10 , 6 , 106 , 190 , 249 , 167 , 4 , 
      67 , 209 , 138 , 138 , 32 , 242 , 123 , 89 , 
      27 , 120 , 185 , 80 , 156 , 38 , 60 , 171 , 
      60 , 28 , 222 , 80 , 52 , 254 , 185 , 220 , 
      241) ,
    34 => array(111 , 77 , 146 , 94 , 26 , 21 , 108 , 
      19 , 105 , 94 , 113 , 193 , 86 , 140 , 163 , 
      125 , 58 , 158 , 229 , 239 , 218 , 103 , 56 , 
      70 , 114 , 61 , 183 , 129 , 167 , 13 , 98 , 
      62 , 129 , 51) ,
    36 => array(200 , 183 , 98 , 16 , 172 , 31 , 246 , 
      234 , 60 , 152 , 115 , 255 , 167 , 152 , 113 , 
      248 , 238 , 107 , 18 , 63 , 218 , 37 , 87 , 
      210 , 105 , 177 , 120 , 74 , 121 , 196 , 117 , 
      251 , 113 , 233 , 30 , 120) ,
    40 => array(59 , 116 , 79 , 161 , 252 , 98 , 128 , 
      205 , 128 , 161 , 247 , 57 , 163 , 56 , 235 , 
      106 , 53 , 26 , 187 , 174 , 226 , 104 , 170 , 
      7 , 175 , 35 , 181 , 114 , 88 , 41 , 47 , 
      163 , 125 , 134 , 72 , 20 , 232 , 53 , 35 , 
      15) ,
    42 => array(250 , 103 , 221 , 230 , 25 , 18 , 137 , 
      231 , 255 , 3 , 58 , 242 , 221 , 191 , 110 , 
      84 , 230 , 8 , 188 , 106 , 96 , 147 , 15 , 
      131 , 139 , 34 , 101 , 223 , 39 , 101 , 213 , 
      199 , 237 , 254 , 201 , 123 , 171 , 162 , 194 , 
      117 , 50 , 96) ,
    44 => array(190 , 7 , 61 , 121 , 71 , 246 , 69 , 
      55 , 168 , 188 , 89 , 243 , 191 , 25 , 72 , 
      123 , 9 , 145 , 14 , 247 , 1 , 238 , 44 , 
      78 , 143 , 62 , 224 , 126 , 118 , 114 , 68 , 
      163 , 52 , 194 , 217 , 147 , 204 , 169 , 37 , 
      130 , 113 , 102 , 73 , 181) ,
    46 => array(112 , 94 , 88 , 112 , 253 , 224 , 202 , 
      115 , 187 , 99 , 89 , 5 , 54 , 113 , 129 , 
      44 , 58 , 16 , 135 , 216 , 169 , 211 , 36 , 
      1 , 4 , 96 , 60 , 241 , 73 , 104 , 234 , 
      8 , 249 , 245 , 119 , 174 , 52 , 25 , 157 , 
      224 , 43 , 202 , 223 , 19 , 82 , 15) ,
    48 => array(228 , 25 , 196 , 130 , 211 , 146 , 60 , 
      24 , 251 , 90 , 39 , 102 , 240 , 61 , 178 , 
      63 , 46 , 123 , 115 , 18 , 221 , 111 , 135 , 
      160 , 182 , 205 , 107 , 206 , 95 , 150 , 120 , 
      184 , 91 , 21 , 247 , 156 , 140 , 238 , 191 , 
      11 , 94 , 227 , 84 , 50 , 163 , 39 , 34 , 
      108) ,
    50 => array(232 , 125 , 157 , 161 , 164 , 9 , 118 , 
      46 , 209 , 99 , 203 , 193 , 35 , 3 , 209 , 
      111 , 195 , 242 , 203 , 225 , 46 , 13 , 32 , 
      160 , 126 , 209 , 130 , 160 , 242 , 215 , 242 , 
      75 , 77 , 42 , 189 , 32 , 113 , 65 , 124 , 
      69 , 228 , 114 , 235 , 175 , 124 , 170 , 215 , 
      232 , 133 , 205) ,
    52 => array(116 , 50 , 86 , 186 , 50 , 220 , 251 , 
      89 , 192 , 46 , 86 , 127 , 124 , 19 , 184 , 
      233 , 151 , 215 , 22 , 14 , 59 , 145 , 37 , 
      242 , 203 , 134 , 254 , 89 , 190 , 94 , 59 , 
      65 , 124 , 113 , 100 , 233 , 235 , 121 , 22 , 
      76 , 86 , 97 , 39 , 242 , 200 , 220 , 101 , 
      33 , 239 , 254 , 116 , 51) ,
    54 => array(183 , 26 , 201 , 87 , 210 , 221 , 113 , 
      21 , 46 , 65 , 45 , 50 , 238 , 184 , 249 , 
      225 , 102 , 58 , 209 , 218 , 109 , 165 , 26 , 
      95 , 184 , 192 , 52 , 245 , 35 , 254 , 238 , 
      175 , 172 , 79 , 123 , 25 , 122 , 43 , 120 , 
      108 , 215 , 80 , 128 , 201 , 235 , 8 , 153 , 
      59 , 101 , 31 , 198 , 76 , 31 , 156) ,
    56 => array(106 , 120 , 107 , 157 , 164 , 216 , 112 , 
      116 , 2 , 91 , 248 , 163 , 36 , 201 , 202 , 
      229 , 6 , 144 , 254 , 155 , 135 , 208 , 170 , 
      209 , 12 , 139 , 127 , 142 , 182 , 249 , 177 , 
      174 , 190 , 28 , 10 , 85 , 239 , 184 , 101 , 
      124 , 152 , 206 , 96 , 23 , 163 , 61 , 27 , 
      196 , 247 , 151 , 154 , 202 , 207 , 20 , 61 , 
      10) ,
    58 => array(82 , 116 , 26 , 247 , 66 , 27 , 62 , 
      107 , 252 , 182 , 200 , 185 , 235 , 55 , 251 , 
      242 , 210 , 144 , 154 , 237 , 176 , 141 , 192 , 
      248 , 152 , 249 , 206 , 85 , 253 , 142 , 65 , 
      165 , 125 , 23 , 24 , 30 , 122 , 240 , 214 , 
      6 , 129 , 218 , 29 , 145 , 127 , 134 , 206 , 
      245 , 117 , 29 , 41 , 63 , 159 , 142 , 233 , 
      125 , 148 , 123) ,
    60 => array(107 , 140 , 26 , 12 , 9 , 141 , 243 , 
      197 , 226 , 197 , 219 , 45 , 211 , 101 , 219 , 
      120 , 28 , 181 , 127 , 6 , 100 , 247 , 2 , 
      205 , 198 , 57 , 115 , 219 , 101 , 109 , 160 , 
      82 , 37 , 38 , 238 , 49 , 160 , 209 , 121 , 
      86 , 11 , 124 , 30 , 181 , 84 , 25 , 194 , 
      87 , 65 , 102 , 190 , 220 , 70 , 27 , 209 , 
      16 , 89 , 7 , 33 , 240) ,
    62 => array(65 , 202 , 113 , 98 , 71 , 223 , 248 , 
      118 , 214 , 94 , 51 , 122 , 37 , 23 , 2 , 
      228 , 58 , 121 , 7 , 105 , 135 , 78 , 243 , 
      118 , 70 , 76 , 223 , 89 , 72 , 50 , 70 , 
      111 , 194 , 17 , 212 , 126 , 181 , 35 , 221 , 
      117 , 235 , 11 , 229 , 149 , 147 , 123 , 213 , 
      40 , 115 , 6 , 200 , 100 , 26 , 246 , 182 , 
      218 , 127 , 215 , 36 , 186 , 110 , 106) ,
    64 => array(45 , 51 , 175 , 9 , 7 , 158 , 159 , 
      49 , 68 , 119 , 92 , 123 , 177 , 204 , 187 , 
      254 , 200 , 78 , 141 , 149 , 119 , 26 , 127 , 
      53 , 160 , 93 , 199 , 212 , 29 , 24 , 145 , 
      156 , 208 , 150 , 218 , 209 , 4 , 216 , 91 , 
      47 , 184 , 146 , 47 , 140 , 195 , 195 , 125 , 
      242 , 238 , 63 , 99 , 108 , 140 , 230 , 242 , 
      31 , 204 , 11 , 178 , 243 , 217 , 156 , 213 , 
      231) ,
    66 => array(5 , 118 , 222 , 180 , 136 , 136 , 162 , 
      51 , 46 , 117 , 13 , 215 , 81 , 17 , 139 , 
      247 , 197 , 171 , 95 , 173 , 65 , 137 , 178 , 
      68 , 111 , 95 , 101 , 41 , 72 , 214 , 169 , 
      197 , 95 , 7 , 44 , 154 , 77 , 111 , 236 , 
      40 , 121 , 143 , 63 , 87 , 80 , 253 , 240 , 
      126 , 217 , 77 , 34 , 232 , 106 , 50 , 168 , 
      82 , 76 , 146 , 67 , 106 , 171 , 25 , 132 , 
      93 , 45 , 105) ,
    68 => array(247 , 159 , 223 , 33 , 224 , 93 , 77 , 
      70 , 90 , 160 , 32 , 254 , 43 , 150 , 84 , 
      101 , 190 , 205 , 133 , 52 , 60 , 202 , 165 , 
      220 , 203 , 151 , 93 , 84 , 15 , 84 , 253 , 
      173 , 160 , 89 , 227 , 52 , 199 , 97 , 95 , 
      231 , 52 , 177 , 41 , 125 , 137 , 241 , 166 , 
      225 , 118 , 2 , 54 , 32 , 82 , 215 , 175 , 
      198 , 43 , 238 , 235 , 27 , 101 , 184 , 127 , 
      3 , 5 , 8 , 163 , 238)
  );

  static function makeGenerativeExpression($g){
    return self::$GENERATIVE_EXPRESSIONS[$g];
  }

  private $version;
  private $ecc;
  private $size;

  private $all_byte;
  private $data_byte;
  private $ecc_byte;

  private $rs_block_count;
  private $rs_small_count;
  private $rs_big_count;
  private $rs_small_byte;
  private $rs_big_byte;
  private $rs_ecc_byte;

  function __construct($version , $ecc){
    $this->version = $version;
    $this->ecc = $ecc;
    $this->createInformation();
  }

  private function createInformation(){
    $eccnum = 0;
    switch($this->ecc){
    case self::ECC_LEVEL_L:
      $eccnum = 0;
      break;
    case self::ECC_LEVEL_M:
      $eccnum = 1;
      break;
    case self::ECC_LEVEL_Q:
      $eccnum = 2;
      break;
    case self::ECC_LEVEL_H:
      $eccnum = 3;
      break;
    }

    // 基本データの生成・取得
    $this->size = 17 + $this->version * 4;

    $this->all_byte = self::$SPEC_LIST[$this->version][$eccnum][0];
    $this->data_byte = self::$SPEC_LIST[$this->version][$eccnum][1];
    $this->ecc_byte = $this->all_byte - $this->data_byte;

    // RS ブロックのデータ生成
    $this->rs_block_count = self::$SPEC_LIST[$this->version][$eccnum][2];

    // RS ブロックの個数・サイズを算出
    $this->rs_small_byte = (int)($this->data_byte / $this->rs_block_count);
    $this->rs_big_count = $this->data_byte % $this->rs_block_count;
    $this->rs_small_count = $this->rs_block_count - $this->rs_big_count;
    if($this->rs_big_count != 0)
      $this->rs_big_byte = $this->rs_small_byte + 1;

    // RS ブロック・エラー訂正の個数・サイズ
    $this->rs_ecc_byte = $this->ecc_byte / $this->rs_block_count;
  }

  function getVersion(){
    return $this->version;
  }
  function getECC(){
    return $this->ecc;
  }
  function getSize(){
    return $this->size;
  }

  function getAllByte(){
    return $this->all_byte;
  }
  function getDataByte(){
    return $this->data_byte;
  }
  function getECCByte(){
    return $this->ecc_byte;
  }

  function getRSBlockCount(){
    return $this->rs_block_count;
  }
  function getRSSmallCount(){
    return $this->rs_small_count;
  }
  function getRSBigCount(){
    return $this->rs_big_count;
  }

  function getRSSmallByte(){
    return $this->rs_small_byte;
  }
  function getRSBigByte(){
    return $this->rs_big_byte;
  }
  function getRSECCByte(){
    return $this->rs_ecc_byte;
  }

  function getGenerativeExpression(){
    return self::makeGenerativeExpression($this->rs_ecc_byte);
  }
}

$info = new QRCodeInformation(3 , QRCodeInformation::ECC_LEVEL_H);
$mask = 0;

$type_info = ($info->getECC() << 3) | $mask;

// バーコードの作成
$creator = new QRCodeCreator($info);
$creator->createFinderPatterns();
$creator->createAlignmentPatterns();
$creator->createTimingPattern();
$creator->createBlackPattern();
$creator->createInformation(
  (($type_info << 10) |
  BCHCode::newInstance(5)->makeBCH($type_info)) ^
  ((1 << 14) | (1 << 12) | (1 << 10) |
  (1 << 4) | (1 << 1)));
if($info->getVersion() >= 7){
  $creator->createVersionInformation(
    ($info->getVersion() << 12) |
    BCHCode::newInstance(6)->makeBCH($info->getVersion()));
}

// このバージョンとエラー訂正レベルにおけるデータ長
$length = $info->getDataByte();

// QR コードに書き込むビット列を作る
$data = "I Don't Like Spam!";
$data_length = strlen($data);

$buffer = new BitBuffer();
$buffer->write(4 , 1 << 2);  // 8ビットバイトモード指定子

// 8ビットモードのデータ長に使用する値の長さは
// バージョン9までが8、それ以上は16ビット
$length_bit = 8;
if($info->getVersion() >= 10)
  $length_bit = 16;

$buffer->write($length_bit , $data_length);  // データ長

// 内容データを書き込み
for($i = 0; $i < $data_length; $i++)
  $buffer->write(8 , ord($data[$i]));

// 終端(0を4ビット)を書き込む
// 4ビットを書き込む余裕がない場合は書けるだけ書く
for($i = 0; $i < 4; $i++){
  if($buffer->getIndex() >= $length)
    break;  // これ以上書き込めないのでループを抜ける
  $buffer->write(1 , 0);
}

// このバイトの残りビットをすべて0で埋める
$buffer->write($buffer->getRemaindBit() , 0);

// 埋め草ビットを書き込む
$padding_bit = array(
  (1 << 7) | (1 << 6) | (1 << 5) |
  (1 << 3) | (1 << 2) ,
  (1 << 4) | (1 << 0));

$p = 0;
while($buffer->getIndex() < $length){
  $buffer->write(8 , $padding_bit[$p]);
  $p = ($p + 1) % 2;
}

// ここまでで書き込んだデータを取り出し
$buf = $buffer->getBuffer();

// RS ブロックに分割する
$block_datas = array();
$index = 0;
for($i = 0; $i < $info->getRSBlockCount(); $i++){
  $len = $i < $info->getRSSmallCount() ? 
    $info->getRSSmallByte() : $info->getRSBigByte();
  $block_datas[$i] = array_slice($buf , $index , $len);
  $index += $len;
}

// エラー訂正コードを作成
$block_eccs = array();
$ecc = new RSErrorCorrect($info->getGenerativeExpression());

for($i = 0; $i < $info->getRSBlockCount(); $i++){
  $block_eccs[$i] = $ecc->createECC($block_datas[$i]);
}

// データとエラー訂正コードを結合
$code = array();

// データを結合
$index = 0;

// 小さいブロック
for($i = 0; $i < $info->getRSSmallByte(); $i++){
  for($b = 0; $b < $info->getRSBlockCount(); $b++){
    $code[$index] = $block_datas[$b][$i];
    $index ++;
  }
}

// 大きいブロック
for($i = $info->getRSSmallByte(); $i < $info->getRSBigByte(); $i++){
  for($b = 0; $b < $info->getRSBigCount(); $b++){
    $code[$index] = $block_datas[$b + $info->getRSSmallCount()][$i];
    $index ++;
  }
}

// エラー訂正
for($i = 0; $i < $info->getRSECCByte(); $i++){
  for($b = 0; $b < $info->getRSBlockCount(); $b++){
    $code[$index] = $block_eccs[$b][$i];
    $index ++;
  }
}

// 内容データをコードに書き込む
$creator->createCode($code);

// マスクを適用して作成
$pixel = $creator->makeQRCode($mask);

print '<table border="0" cellpadding="0" cellspacing="0">';
for($y = 0; $y < $pixel->getSize(); $y++){
  print '<tr>';
  for($x = 0; $x < $pixel->getSize(); $x++){
    $color = $pixel->isExist($x , $y) ?
      ($pixel->getPixel($x , $y) == 0 ? "#FFFFFF" : "#000000") : "#CCDDFF";
    print '<td bgcolor="' . $color . '" width="4" height="4"></td>';
  }
  print '</tr>';
}
print '</table>';
?>
カテゴリ [開発魔法][社会問題] [トラックバック 0][コメント 0]
<- 前の記事を参照 次の記事を参照 ->

- Blog by yamicha.com -