ofxJpegGlitch解説

ofxJpegGlitch (http://github.com/2bbb/ofxJpegGlitch/) の解説記事です.

参考にしたのはこちらのサイト. http://www.setsuki.com/hsp/ext/jpg.htm
jpgのフォーマットの解説ですね.

取り敢えず, jpgのフォーマットをきちんと読みたい.

一番大外の構造としてはJFIFって構造があると. 0xFFD8ってバイト列で始まって0xFFD9ってバイト列で終わればよろしいと.
で, そういう0xFFXXという2バイトのデータをマーカーと呼ぶらしい, と.
マーカーをマジックナンバーで書くと混乱するので2バイト目を定数化しましょうってのが JpegConstant.h ですね.
ここのMarkerType ofxJpegGlitch::calcMarkerType(unsigned char *bytes, int cur) で unsigned charでマーカーの値書いてenumの名前返してるのも頭悪いなーとは思ってるのでそのうち何とかしたいですね.

で, 0xFFD8〜0xFFD9の間のデータはどういう構造してるかっていうと

マーカー: 2byte
データ長: 2byte
実データ部: データ長で表されたバイト数


っていうセグメントに分かれてる, と.

ということは大雑把なフローはここで決まって

bytestream *stream = /* jpgファイルストリーム */;
データ marker = /* 2バイト読み込み */;
if(marker != 0xFFD8) exit("これjpgちげーよバカ");
while(true) {
    データ marker = /* 2バイト読み込み */;
    MarkerType mt = getMarkerType(marker);
    if(mt == MT_UNKNOWN) exit("マーカーおかしいよ");

    if(mt == 0xFFD9) break; // 終了マーカー

    int32_t length = /* 2バイト読み込み */;
    データ data = /* lengthバイト読み込み */l
    switch(mt) {
        /* セグメントタイプによる諸々 */;
    }
}
/* ファイル書き込み */

ってことですね. あとはどこを壊せば美味しいか, どこを壊しちゃ駄目かを知れば宜しいと.

まあ, ヘッダーデータ壊すとあんまり良く無さそうですよね. 画像サイズとか壊すのも一興ではあるけど取り扱いめんどくさくなりますよね. メターデータ壊しても絵には影響しないし.
APPn系マーカーはAPP0のJFIFデータくらいしか読まなくても良さそうです.
APP0
ぶっちゃけAPP0も読まなくても良いくらいです. ここら変壊すと地雷臭もします. JFIF識別子壊しちゃいけませんし, サムネイルイメージとか今の僕らには関係ありません. 壊したければ壊してみれば良いですね. それは自由です.
APP1のEXIF改竄したら浮気した時に言い訳したりするのに使えるかも知れませんがそもそも浮気しちゃ駄目です.

で, 色々あるんですが取り敢えず飛ばしてSOSマーカー以降のデータ部分, こいつは幾ら壊しても結構ですがあんまり壊し過ぎるとグレーになって面白くないので節度を持って壊しましょう.

そうそう, 壊すって適当に言ってますが実際適当で良いです.
どんくらい適当かっていうと

data[cur] = rand() % 256; /* rand() & 0xFF って書くとオールドスクールっぽい*/;

くらい適当で良いです.
(ちゃんと壊したかったらもっとちゃんと符号化の方法まで調べてみるのも楽しいかと思います.)

で, だいぶ説明がめんどくさくなってるのですがここがある意味yoppa氏の入門記事: 画像をグリッ (54ページ目)との違いで, DQTとかDHTの部分. 量子化テーブル定義(Define Quantization Table segment)とハフマン符号テーブル定義セグメント(Define Huffman Table segmet)ですね.
こいつらがjpgフォーマットの肝なので心して壊してください.
説明はめんどくさいんで超完結に書きますが, DQTとかDHTのセグメント形式見て実データ部分(DQTだったら量子化因子QF00〜QF77くらい, DHTだったら各コード長のコード辺り)を丁寧にrand() % 256;で壊します.
そこらへんはofxJpegGlitchでsetDataGlitchness(0);してやってデータ部分を壊す可能性を0にしてsetQNGlitchnessとかsetDHTGlitchness辺りだけ変えてやってみると多分なかなか簡易グリッチではお目に掛かれないjpgグリッチが出るかと思います. (運が良いと簡易でも見れます)

あとは雰囲気で.

で, まとめとして, ofxJpegGlitchは単純に適当な位置をrand() % 256;するのとは違って, きちんとインテリ眼鏡な感じでフォーマットに従ってお上品かつ気品ある壊し方をすることによって壊したらjpg読み込めないぜって可能性を減らし(その可能性は0では無いです. この世は数学以外で絶対なんて言葉は存在しない.), コントロールパラメータを3つ(Data, QN, DHT)に増やしたことによって表現の幅を多少広げたことにある, と, いうことにしています. 知らんけど.

まあ, jpgグリッチなんて基本的にバカでも作れるんだけど地方底辺国立大学程度の学力で壊したらどうなるかっていうこと試した感じですね.

ソースコードはテンプレートゴリゴリboost黒魔術ゴリゴリの難しいC++ではなくて愚鈍な低レベルCなので頑張れば読めるはずなので上に書いてあることを踏まえてコードリーディングしてバグ見つけてPRしてくださいね.

以上.

コメントを残す