2.辞書テーブルを利用しない新LZW法
(2000/05/11初版)
| はじめに | ||||||||||||
| 前回の研究では、ユニシスの特許に抵触しないGIF展開手法についての考察を行った。その結果、特許に触れることなくLZWの復元を行うことが可能である、と言うことが証明された。つまりユニシスとのライセンス契約を結ばなくとも、GIF画像を閲覧することは可能なのである。 しかし、LZW圧縮についてはどうなのだろうか? もし、ユニシスの特許に触れることなくLZW圧縮が可能であるとなれば、GIFを利用するための壁は完全に消失する。もはやユニシスに高いライセンス料金を支払う必要性は無いのだ。好きな時に、好きな様に、好きなだけ、GIFを利用すれば良い。それこそが本来GIFが目指していた道であり、そして誰もがそう望んでいた世界であろう。 ◇本当に悪いのはGIFなのか? 人の意見ではない、自分なりの答えを見つけ出して欲しい。
|
||||||||||||
| 目的 | ||||||||||||
| ユニシスの特許に抵触しないLZW圧縮方法を確立すること。及び、ライセンスフリーのGIFエンコーダー開発支援、等々。恐らく、需要はないだろう。自分を含めて・・・。
|
||||||||||||
| LZWの圧縮理論 | ||||||||||||
| 前回の研究において基本的なテーブル利用型圧縮法の理論を紹介しているが、このLZW法でもそれほど大きな違いは無い。頻繁に現れるデータ列をテーブルに格納しておき、再びそのデータ列が現れた場合には、そのテーブル番号のみを保存しておくことによってデータサイズを減らそうという考え方に変わりは無い。 着目すべきはテーブルに格納しておくべき「頻繁に現れるデータ列」の選択手法、これこそがLZW法の肝であり、LZWがLZWたる所以である。 ここではLZW圧縮における辞書テーブルの動きを簡単に紹介しよう。
さて、ここでテーブル内に存在したからと言ってあわてて出力してはいけない。さらにもう1文字増やして(n+1)文字で確認してみよう。今度はテーブル内に見つからなかった。 そしてここで終わらないのがLZWの特徴である。先ほど見つからなかった「(n+1)文字のデータ列」を新たにテーブルに書き加えるのである。こうして今回は圧縮できなかったデータ列も、もう一度出現した際にはちゃんと圧縮することができる。
言うなれば、一度犯した過ちは二度と繰り返さない「自己反省型」圧縮法である。 この様に、LZW圧縮では辞書テーブルを巧みに利用して、繰り返されるデータ列を次々とコンパクトに圧縮していく。説明だけ聞いていると「ふ〜ん、そうなんだ〜。」程度にしか思わないかもしれないが、実際にこれを考え出すというのは凄いことだと思う。
|
||||||||||||
| 問題となる特許 | ||||||||||||
| 前回、ユニシスが日本国内において2つの公開特許を有していると書いたが、その内一つは前回紹介済みである。では、もう一つの特許とは一体どんな物なのだろうか。実はそれこそがLZW圧縮に関わる特許(特許番号:3016868号、連想メモリを使用するLZWデータ圧縮)なのである。ただし、この特許は「連想メモリを使用する」という題目からも分かるとおり、LZW圧縮の一つの方法を示したものにすぎない。逆に言えば、連想メモリを使用しなければまず問題になることはない、穴のあいた特許と言えるだろう。 だが、万が一と言うこともあり得るので一応その内容を見てみることにしよう。簡単に紹介すると以下のようになる。 と言っても、いわゆる極普通のLZW圧縮法なので特に言うべきこともあまりない。では、「連想メモリを使用する」とは一体何なのかというと、辞書テーブルにプレフィクス・コード・フィールドと呼ばれる第三の領域が含まれるというだけの事である。この領域には”そのエントリに格納されているデータ列”から最後の一文字を削除したデータ列が格納されているエントリのテーブル番号が入っている。 ま、所詮大したことは無い特許なのだが、通常のGIF展開ルーチンでは辞書テーブルの構造が上記のように、「プレフィクス・コード・フィールド」+「最後の一文字」だけを格納しておく、という構成を取っているものが大半だと思われるので、そう言う意味ではやっかいではある。 では、次の特許を見てみよう。こちらは前回と同じ「データ伸長法および装置ならびにデータ圧縮伸長法および装置」(特許番号:第2610084号)である。このうち、前回は該当しないとした請求項の第15項、「データ圧縮伸長方法」が今回のターゲットである。 だが、このクレームはあくまで「データを圧縮して、それを伸長する方法」である為、圧縮しか行わないのであれば問題にはならないのかもしれない。そういった意味では、純粋なLZW圧縮に関する基本的な特許は、日本国内に於いては存在していないと言うことになる。しかしながら、少しでも疑わしい部分は全てチェックしておいた方が良いのは言うまでもないだろう。 このクレームでは前半部分に圧縮に関する事が書かれている。以下に、その大まかな内容を箇条書きにしてみた。 ◇圧縮したいデータ列と”メモリ”を比較して最も長い一致を見せるエントリを調べる これだけである。 無い物に対して「あれこれこういった操作をすると特許に触れます」などと言われても、最初からそんな物は無いんだから関係ない。つまりは、そう言うことである。 なお、余談ではあるが日本国内においてユニシスが権利者となっている第三のLZW関連特許が存在するという話もある。特許番号は2123602号である。 さらに余談であるが、ユニシスはLZWの他にも様々な分野の特許を持っているようだ。権利調査の際に分かったのだが、どうもユニシスは金になりそうな技術があると業務に関係する・しないに関わらず、手当たり次第特許を取得しているようにも見える。全体的な数で見れば全然大したことは無く、特定の分野を特許で固めるという事も殆どやらない(やれない)ようだが、少ないながらも質がある程度高い事と、その使い方が実に巧妙であるという点は非常に厄介である。 その真意がどうであるにせよ、こういった疑惑の念を世間に抱かせてしまったという事実だけは、決して拭い去ることは出来ない真実(リアル)である。この事が、今後彼らの企業活動に悪影響を及ぼさないことを切に願う・・・。
|
||||||||||||
| 辞書テーブルを利用しないLZW圧縮法(1) | ||||||||||||
| それでは、早速特許を回避してみよう。(笑) 今回も方針としては辞書テーブルを利用しないで行う方法を採りたいと思う。この方が何かと安全であるし、ユニシス側からいちゃもんが来た場合にでも「全然違うじゃん」と堂々と胸を張って答えることが出来る。 ではLZW圧縮には他にどういう方法があるのだろうか? 答えは前回の展開法を見れば何となく想像は付くだろう。そう、例のテーブル内の任意のエントリを返す関数を使用するのだ。 例えば、今n文字のデータ列を圧縮しようとしているとする。その為には、このn文字のデータ列がテーブル内に存在するかどうかの確認を行わなくてはならない。しかし、辞書テーブルは持っていない。 どうするか? 幸いなことに、その時点までに圧縮を行った出力結果がある。これを旨く利用すれば辞書テーブルが無くても、n文字のデータ列がテーブル内に存在するかどうかの確認が可能なのだ。 その時点までの圧縮結果を例の関数に渡し、「x番目のテーブルの内容が見たい」と命令すれば、即座に?その結果が返ってくる。あとは、関数の出力結果とn文字のデータ列とを次々に比較して、同じ物があるかどうかのチェックを行えば良いと云う訳だ。 そして、LZW特有のいわゆる「自己反省」、つまり見つからなかったデータ列をテーブルに登録する作業は、テーブルが無いので当然行わない。 これで一件落着、めでたし、めでたし・・・なのだが、そう浮かれてもいられない。 確かにこの方法でLZW圧縮と同じ事を行うことが出来る。理論的には何も間違ってはいない。ユニシスの特許を回避するという意味でも、かなり有効であると言えるだろう。 実際、内部では「1組のデータを圧縮するために、それまでの全圧縮データの中からちまちまと展開しつつ該当のデータを探しだす」という実に遠回りな動作を行っているので、仕方ないと言えば仕方ないのかもしれないが。 実装時の工夫により・・・例えば、明らかに比較しようとしているデータ列と一致しないことが分かっている場合には呼び出しを控えるとか、関数内部の処理過程で比較データ列と違う事が判明した時点ですぐリターンするようにするとか、通常のLZWでも良く行われている気の利いたハッシュ法を取り入れるとか、そういった努力によりある程度までは高速化されるだろうが、それにも限界はあるだろう。 そこで、次章ではもう一つの可能性について考察してみたいと思う。
|
||||||||||||
| 辞書テーブルを利用しないLZW圧縮法(2) | ||||||||||||
| 前章の方法は確かに良い方法ではあったが、速度的な問題があった。ここではその点をふまえた上で、別の圧縮方法を考えてみたいと思う。 まず最初に圧縮したいと思うデータ(何でも良い)を用意して、じっくりと眺めて欲しい。用意できない方のために、下に例を挙げてみた。よく見て欲しい。
表1.圧縮したいデータ 何か見えただろうか?何も見えないのであれば、今しばらく集中して見てみよう。・・・ちなみに「数字が見える」とか言うお約束は抜きと言う事でお願いしたい。(笑) そう、答えは「辞書テーブル」である。 圧縮前のデータである上の表のデータと、LZW圧縮していく際に生成される辞書テーブルとを比べてみると、実は全く同じなのである。ちなみに、誰でも分かるように下に並べて示してみた。今度こそお分かりだろう。辞書テーブルの境界でデータが重なることを除いては、元データと辞書テーブルの内容は全く同一の物と言って良いのだ。
となると、わざわざ辞書テーブルなんてモノを利用する必要は無くなる。同じ物が最初から用意されているのだから、それを使えば良い。 問題は、何処がデータ列の切れ目となるかを正確に認識しなくてはならない点だけである。しかし、これも対処法は簡単である。通常のLZW圧縮で辞書テーブルにデータ列を書き込むのと同じタイミングで、辞書テーブルに書き込む代わりに元データの方に「切れ目を示す印」を付けるのである。(上の図では”<-”) この印はテーブルの各エントリが切れ目かどうかを示すフラグとしての役割を果たす物であるから、テーブルと同じ数だけ用意しなければならない。GIFではエントリが最大でも4096個なので、印も4096個だけ用意すればよいだろう。さらに、この印はあくまでフラグなので、4096ビット(512バイト)もあれば十分である。 実際に元データを仮想辞書テーブルとして利用する際には、「ある印の位置のデータ」から「次の印の位置のデータ」までが一つのエントリとして認識されるので、これから圧縮しようとしているデータ列と仮想辞書テーブル(実はそれまでのデータ列そのものである)が一致するかどうか調べれば良い。 注意するべき点は、この仮想辞書テーブルの一番最初のデータ列がテーブル番号1番ではないという点である。この仮想辞書テーブルにはデフォルトで初期化される0〜(色数−1)番目のエントリは含まれていないので、仮想辞書テーブルの一番最初のデータ列は、実は「(色数)番目」のエントリなのである。 以上の点にだけ注意していれば、問題なく疑似LZW展開のプログラムが書けるだろう。 では、第一の方法で問題となっていたスピードに関する問題はどうであろうか? この様に速度面でも非常に有効であり、ユニシスの特許にも抵触しない。まさに完璧である。この方法さえあれば、他には何も要らないのではないか?先ほどの第一の方法は一体何だったのか?そう思われるかもしれない。 しかし、ここでわざわざ2つの方法を紹介したのには訳がある。と言うのは、実は私自身この第二の方法でユニシスの特許を回避できるのかどうか不安に感じているのだ。いや、不安に思っていると言う点に関しては、どちらにも不安はあるのだが、第二の方法の方がより危険性が高いのではないかと考えている。 その辺りの危険性を考慮した上で速度を取りたいというのであれば、こちらの方法を使用するのも良いかもしれないが、出来れば第一の方法を使用した方が無難なのは間違いないだろう。 もっとも、元データ自身はプログラマが自分で作り出す物ではなく、ハナから存在している物である。その元データの中に重複するデータがあるかどうかを調べているだけ(フラグを立てて調べ易くしてはいるが)なのだから、問題ないとは思うが・・・。 ちなみに第一の方法が何故安全なのかと言うと、第一の方法では圧縮する元のデータと圧縮後のデータを格納する領域以外に一切メモリを必要としない点、出力データの書き込み時以外では何のアクションも発生しない点、が挙げられる。何と言っても、「辞書テーブルらしき」ものすら存在せず、入力に対して何のアクションも起こさず、ダイレクトに出力が返ってくるのだ。これほど安全な方法も他にあるまい。 さらに言えば、展開と異なり圧縮作業はそれほど高速である必要は無いという事実も挙げられる。秒間60コマのGIF画像を生成したところで、喜ぶ人間もそうは居まい。結局の所、多少の速度低下は目を瞑っても安全な方法を採用した方が良いのではないかと思うが、どうだろうか?
|
||||||||||||
| もう一つのLZWデコード理論 | ||||||||||||
| もうお気づきの方も多いかもしれないが、上で示した第二の方法は展開時にも利用可能である。 どういう事かと言うと、展開作業によって生成された展開後のデータそのものが、仮想辞書テーブルとして利用できてしまうのである。 アルゴリズムとしては、展開データを書き込む際に一緒にフラグも立てておくだけである。符号化コード”x”が指定されたならば、フラグ位置を参考に過去の展開データの中からx番目に該当するデータ列を引っ張ってきて、そのまま最後尾の位置にコピーすれば良い。 実に簡単、かつ「比較的」高速である。 ただし、第二の圧縮理論と同様の危険性を孕んでいる為注意されたい。
|
||||||||||||
| 最後に | ||||||||||||
| 前回にも増して、非常に濃い内容になってしまい大変申し訳ない。対象をプログラマに設定しているため、一度でもLZWの圧縮/展開コードを書いたことのある人間にしか理解できないような内容になってしまったが、それでも「ユニシスにライセンス料を払わないで、しかも合法的にGIFを利用できるかもしれない」という事だけご理解いただければ幸いである。 なお、今回の圧縮理論に関してはサンプルソースを提示していない。これはひとえに筆者である私の怠慢以外の何物でもないのだが、仮にサンプルがあったとて、それを自前のソフトに組み込めるだけの技量があれば、一から自分で書く事も決して難しい事では無いと思う。 さらに今回は実際にGIFエンコードを行う際の注意点も特に挙げていないが、これは前回と大体同じと思って構わない。実際、エンコード処理自体よりもこちらの可変ビット長入出力処理の方が難易度が高いと思われるので、やはり通常のGIFエンコードプログラムが書ける位の技量が無いと実装は困難かもしれない。 とは言え、これでユニシス特許を回避できるLZWデコード/エンコード理論が一応の完成を見た訳で、これによりGIFフォーマットのサポートを諦めざるを得なかったフリーソフト等でGIFサポートが復活する様な事にでもなれば幸いである。
|
||||||||||||
| お願い | ||||||||||||
| もし、この方法を利用したLZWエンコーダ/デコーダを公開される場合は、下記までご連絡していただきたい。別にライセンス料を取ろうとかそう言う事では無いのだが、私の知らないところで問題が発生するのを予防したいというのがその目的である。 |
||||||||||||
| 免責事項 | ||||||||||||
| この方式によるエンコーダ/デコーダを作成する事によって生じる、いかなる不利益や損害に対しても筆者である私は一切の責任を負わないこととする。 |
||||||||||||
| 連絡先 | ||||||||||||
| DJ☆Uchi [PEB04756@nifty.ne.jp] | ||||||||||||
@nifty ID:PEB04756