pngイメージ読み込みにおけるチャンクの扱いについて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
bonbo

pngイメージ読み込みにおけるチャンクの扱いについて

#1

投稿記事 by bonbo » 9年前

お世話になっております。
ふとしたことからpngイメージの中身が気になってしまい、いろいろ調べていたのですが
IHDRチャンクの読み込みができた後、うまくいかずに困っております。
具体的には、
#FFFFFF(まっしろ)の1*1のpngイメージを読み込もうと組んだコードで、
ihdrが終わったあと次のチャンクが正しく読み込めていないのか、iendが正しく認識できていないのです。(終了してくれない)
また、ihdrの中のオフセット0x0008にあたる画像の幅も実際の幅とは違う物でした。(ihdrにもフィルタリングが施されているのでしょうか?)

以上曖昧な知識のまま組んだプログラムなのですが、以下になります。

コード:

void LoadPNGtest(const char* filename){

    // ・参考文献
    // http://www.setsuki.com/hsp/ext/chunk/IDAT.htm
    // http://qiita.com/sounisi5011/items/e685ed1501a3cd979a3c
    // http://www.cplusplus.com/forum/beginner/96592/
    // pngの仕様書
    // 以上の情報をふまえてコードをかいてみる。
    //
    NSLog(@"%s",filename);
    FILE*rfp;
    rfp=fopen(filename, "rb");
    unsigned char siz_[4];
    unsigned char dtp_[4];
    unsigned char buf[8];
    unsigned char crc__[4];
    if (rfp == NULL)
    {
        NSLog(@"Unable to open the image file\n");
        goto ENDOFREAD;
    }
    if (fread (buf, 1, sizeof (buf), rfp) != sizeof(buf))
    {
        NSLog(@"Unable to read file contents (file may be empty)\n");
        goto ENDOFREAD;
    }
    if (buf[0] == 0x89 &&
        buf[1] == 0x50 &&
        buf[2] == 0x4E &&
        buf[3] == 0x47 &&
        buf[4] == 0x0D &&
        buf[5] == 0x0A &&
        buf[6] == 0x1A &&
        buf[7] == 0x0A){
        NSLog(@"this is png image.");
    }
    else{
        NSLog(@"error:this is invalid file.");
        goto ENDOFREAD;
    }
    // シグネチャの確認が終わった
    // 次にチャンクを読み込んでいく。
    // 最初は必ずIHDRチャンクである。
    // 最後は必ずIENDチャンクである。
    for (int endflag=0; !endflag; ) {
        fread (siz_, 1, sizeof (siz_), rfp);// データサイズの取得
        
        fread (dtp_, 1, sizeof (dtp_), rfp);// データタイプの取得
        unsigned char* dat = (unsigned char*) malloc(siz_[3]+siz_[2]*16+siz_[1]*16*16+siz_[0]*16*16*16);
        fread (dat, 1, sizeof (dat), rfp);// データの取得
        fread(crc__, 1, sizeof(crc__), rfp);// crcの取得
        // ここから展開(まだかけていない)

        if (dtp_[0]==0x49&&dtp_[1]==0x48&&dtp_[2]==0x44&&dtp_[3]==0x52) {// ihdr
            NSLog(@"ihdr");
            // 画像の幅などを受け取る
            NSLog(@"width:%d",dat[3]+dat[2]*16+dat[1]*16*16+dat[0]*16*16*16);
        }
        else if (dtp_[0]==0x73&&dtp_[1]==0x72&&dtp_[2]==0x68&&dtp_[3]==0x82) {// idat
            NSLog(@"idat");
        }
        else if(dtp_[0]==0x50&&dtp_[1]==0x4C&&dtp_[2]==0x54&&dtp_[3]==0x45){// iplt
            NSLog(@"iplt");
        }
        else if(dtp_[0]==0x49&&dtp_[1]==0x45&&dtp_[2]==0x4E&&dtp_[3]==0x44){// iend49 45 4E 44
            NSLog(@"iend");
            endflag=1;
        }
        else{
            NSLog(@"%d %d %d %d",dtp_[0],dtp_[1],dtp_[2],dtp_[3]);
        }
        
    }
ENDOFREAD:;
    fclose(rfp);
}

環境はxcode6です。
nslogなどはただのデバッグ用のメッセージを出す関数ですので気にしないでください。
以上、やや見づらいコードで申し訳ないのですがおかしい点等ございましたらご指摘をお願いします。

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: pngイメージ読み込みにおけるチャンクの扱いについて

#2

投稿記事 by みけCAT » 9年前

49行目と57行目の16を全て256に変えてみてください。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

bonbo

Re: pngイメージ読み込みにおけるチャンクの扱いについて

#3

投稿記事 by bonbo » 9年前

>みけCATさん
ありがとうございます。
画像の幅は正しく表示されるようになりました。
また、unsigned charの計算でサイズがマイナスになっていたのも直しました。
しかし、まだiendが見つかりません。それどころかidatやipltも一度も呼ばれることがありません
最初、ihdrが呼ばれる時はサイズもちゃんと13になっています。
まだチャンクの読み込みがおかしいのでしょうか。
crcによる確認は行っておりませんが、画像は破損してないと思います。

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: pngイメージ読み込みにおけるチャンクの扱いについて

#4

投稿記事 by みけCAT » 9年前

sizeof(dat)はポインタの大きさ(4バイトなど)で固定です。
計算したチャンクサイズを一旦変数に格納し、その値を用いてメモリの確保と読み込みを行ってください。

また、mallocで確保したメモリをfreeで開放していないのが気になりましたが、Objective-Cでは普通なのでしょうか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
h2so5
副管理人
記事: 2212
登録日時: 13年前
住所: 東京
連絡を取る:

Re: pngイメージ読み込みにおけるチャンクの扱いについて

#5

投稿記事 by h2so5 » 9年前

memcmpを使ったほうがすっきりかけると思います。

bonbo

Re: pngイメージ読み込みにおけるチャンクの扱いについて

#6

投稿記事 by bonbo » 9年前

ありがとうございます。
sizeof(dat)
の所をsizeof(配列のサイズ)
の形に直した所、うまくいきました。
ちなみにオートリリースされないのでモリモリリークしてました。
野外におり、修正したコードが貼れないので後ほど貼らせていただきます。
今回は本当にありがとうございました。

bonbo

Re: pngイメージ読み込みにおけるチャンクの扱いについて

#7

投稿記事 by bonbo » 9年前

>h2so5さん
ありがとうございます。memcmpを交えてコードを簡潔にしました。こちらの方が可読性がいいですね。

IDATと比較する値が間違っていたので修正しました。
後に見る人の参考になれば幸いです。

コード:

void LoadPNGtest(const char* filename){
    // ・参考文献
    // http://www.setsuki.com/hsp/ext/chunk/IDAT.htm
    // http://qiita.com/sounisi5011/items/e685ed1501a3cd979a3c
    // http://www.cplusplus.com/forum/beginner/96592/
    // http://blog.livedoor.jp/cperl/archives/22027424.html
    // pngの仕様書
    // 以上の情報をふまえてコードをかいてみる。
    //
    NSLog(@"%s",filename);
    FILE*rfp;
    unsigned char buf[8]={0,0,0,0,0,0,0,0};
    const unsigned char pngsgn[8]={0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A};
    const unsigned char idIHDR[4]={0x49,0x48,0x44,0x52};
    const unsigned char idIDAT[4]={0x49,0x44,0x41,0x54};
    const unsigned char idIPLT[4]={0x49,0x44,0x41,0x54};
    const unsigned char idIEND[4]={0x49,0x45,0x4E,0x44};
    unsigned char siz_[4]={0,0,0,0};
    unsigned char dtp_[4]={0,0,0,0};
    unsigned char crc__[4]={0,0,0,0};
    long imagewidth=0;
    long imageheight=0;
    int endflag=0;
    rfp=fopen(filename, "rb");
    if (rfp == NULL)
    {
        NSLog(@"Unable to open the image file\n");
        goto ENDOFREAD;
    }
    if (fread (buf, 1, sizeof (buf), rfp) != sizeof(buf))
    {
        NSLog(@"Unable to read file contents (file may be empty)\n");
        goto ENDOFREAD;
    }
    if (memcmp(buf, pngsgn,8)==0){
        NSLog(@"this is png image.");
    }
    else{
        NSLog(@"error:this is invalid file.");
        goto ENDOFREAD;
    }
    // シグネチャの確認が終わった
    // 次にチャンクを読み込んでいく。
    // 最初は必ずIHDRチャンクである。
    // 最後は必ずIENDチャンクである。
    for (endflag=0; !endflag; ) {
        fread (siz_, 1, sizeof (siz_), rfp);// データサイズの取得
        
        fread (dtp_, 1, sizeof (dtp_), rfp);// データタイプの取得
        long dtsiz=0;
        for (int i=0; i<4; i++) {
            dtsiz+=pow(256, 3-i)*siz_[i];
            //NSLog(@"siz:%ld",dtsiz);
        }
        unsigned char* dat = (unsigned char*) malloc(dtsiz);
        fread (dat, 1, dtsiz, rfp);// データの取得
        fread(crc__, 1, sizeof(crc__), rfp);// crcの取得
        if (memcmp(dtp_, idIHDR, 4)==0) {// ihdr
            NSLog(@"ihdr");
            // 画像の幅などを受け取る
            imagewidth=0;
            for (int i=0; i<4; i++) {
                imagewidth+=pow(256, 3-i)*dat[i];
                //NSLog(@"siz:%ld",dtsiz);
            }
            imageheight=0;
            for (int i=0; i<4; i++) {
                imageheight+=pow(256, 3-i)*dat[i+4];
            }
            NSLog(@"width:%ld",imagewidth);
            NSLog(@"height:%ld",imageheight);
            NSLog(@"depth:%d",dat[8]);
            NSLog(@"coltype:%d",dat[9]);
            NSLog(@"pressing type:%d",dat[10]);
            NSLog(@"filter type:%d",dat[11]);
            NSLog(@"inter race:%d",dat[12]);
        }
        else if (memcmp(dtp_, idIDAT, 4)==0) {// idat
            // ここから展開
            NSLog(@"idat");
            unsigned char* col_ = (unsigned char*) malloc(3*imagewidth*imageheight);
            NSLog(@"%d",dat[0]);// 画像の一列目の左端にフィルタが入っている?
            
            // 逆フィルタリングに行く
            
            free(col_);
        }
        else if(memcmp(dtp_, idIPLT, 4)==0){// iplt
            NSLog(@"iplt");
            
        }
        else if(memcmp(dtp_, idIEND, 4)==0){// iend49 45 4E 44
            NSLog(@"iend");
            endflag=1;
        }
        else{
            NSLog(@"undefined chunk has come:%d %d %d %d",dtp_[0],dtp_[1],dtp_[2],dtp_[3]);
        }
        free(dat);
    }
ENDOFREAD:;
    fclose(rfp);
}
ここ(http://blog.livedoor.jp/cperl/archives/22027424.html
のサイトによるとIDATで読み込んだ内容の行の最初の1バイトにフィルタの値が入っているそうなのですが(82行目のdat[0]の値)、どうも読み込めていないみたいなのでまだおかしいところがあるのかもしれません。
もう少し考えてみてから再度トピックを立てさせていただきます。

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: pngイメージ読み込みにおけるチャンクの扱いについて

#8

投稿記事 by みけCAT » 9年前

bonbo さんが書きました:ここ(http://blog.livedoor.jp/cperl/archives/22027424.html
のサイトによるとIDATで読み込んだ内容の行の最初の1バイトにフィルタの値が入っているそうなのですが(82行目のdat[0]の値)、どうも読み込めていないみたいなのでまだおかしいところがあるのかもしれません。
dat[0]にはgzipのヘッダ情報があり、行の最初の1バイトではないので、サイトで解説されている「フィルタの値」(?)と一致していない可能性があります。
バイナリエディタやodなどの表示と比較し、本当に読み込めていないことを確認してください。

【訂正】gzipではなくZLIB形式です
最後に編集したユーザー みけCAT on 2015年3月15日(日) 11:19 [ 編集 1 回目 ]
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

bonbo

Re: pngイメージ読み込みにおけるチャンクの扱いについて

#9

投稿記事 by bonbo » 9年前

>みけCATさん
返信が遅くなり申し訳ありませんでした。
フィルタの値というのは
扱っているファイルをバイナリエディタで開いた結果、
... 49 44 41 54 08 1D 63 F8 0F 04 00 ...
となっており、出力の値とは一致していました。(上記コードでは8がnslogで出力されていた)
正しく読みこめていることは確認できましたが、上記したサイトとは違った結果が得られたように思います。
IDATの中は単純に
49 44 41 54 の後で
その行のピクセル情報を逆フィルタリングするフィルタの種類(1バイト)+フィルタリングされたピクセル情報(数バイト)+
その行のピクセル情報を逆フィルタリングするフィルタの種類(1バイト)+フィルタリングされたピクセル情報(数バイト)+
その行のピクセル情報を逆フィルタリングするフィルタの種類(1バイト)+フィルタリングされたピクセル情報(数バイト)+
...+
CRC
の形になっていると勘違いしておりました。8はフィルタリングの種類(0~4)の中に入っていないのでおかしいと思ったのです。
それでは正しくは
49 44 41 54 +gzipのヘッダ情報+
その行のピクセル情報を逆フィルタリングするフィルタの種類(1バイト)+フィルタリングされたピクセル情報(数バイト)+
その行のピクセル情報を逆フィルタリングするフィルタの種類(1バイト)+フィルタリングされたピクセル情報(数バイト)+
その行のピクセル情報を逆フィルタリングするフィルタの種類(1バイト)+フィルタリングされたピクセル情報(数バイト)+
...+
CRC
の形になっているということでしょうか。
正直なところgzipに関してはてんでわからないのですが
ここ(http://www.faqs.org/rfcs/rfc1952.html)にある 2.3.1. Member header and trailerの項によると
gzipのヘッダは
1F 08 …という固有の値で開始すると書いてるのですが、そうだとすると今度は1Fが見当たりません。
おかしい点を指摘していただけると助かります。
解決をおした後ですみません。

一応ですが読み込もうとしているファイルを添付しておきます。
http://www1.axfc.net/u/3430841

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: pngイメージ読み込みにおけるチャンクの扱いについて

#10

投稿記事 by みけCAT » 9年前

すいません。gzipではなくZLIB形式でした。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

bonbo

Re: pngイメージ読み込みにおけるチャンクの扱いについて

#11

投稿記事 by bonbo » 9年前

IDATから IENDまでの並びです。
... 49 44 41 54 08 1D 63 F8 0F 04 00 09 FB 03 FD 0C BB 5B E7 00 00 00 49 45 4E 44
zlibのデータ形式は
CMF(1byte)+
FLG(1byte)+
DICTID(4byte)+
圧縮データ(any byte)+
ADLER32(4byte)+
CRC(4byte)
(FLGの5ビット目の正偽によってDICTIDの有無は変わる)
という構造になっているとリファレンスに記載されています。(2.2. Data formatの項)
今回FLGである1Dの2ビット表記は00011101で、DICTIDが使われているのですね。つまり、
CMF(08)+FLG(1D)+DICTID(63 F8 0F 04)+フィルタリングの種類(00)+ビットデータ(09 FB 03 FD 0C BB 5B)+ADLER32(E7 00 00 00)
ということでしょうか。
取得したdat配列のサイズが11だったので、これだと明らかに配列より大きくなってしまい疑問が残ります。

bonbo

Re: pngイメージ読み込みにおけるチャンクの扱いについて

#12

投稿記事 by bonbo » 9年前

忘れていました。CRC4バイトも入りますね
CMF(08)+FLG(1D)+DICTID(63 F8 0F 04)+フィルタリングの種類(00)+ビットデータ(09 FB 03)+ADLER32(FD 0C BB 5B)+CRC(E7 00 00 00)

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: pngイメージ読み込みにおけるチャンクの扱いについて

#13

投稿記事 by みけCAT » 9年前

bonbo さんが書きました:今回FLGである1Dの2ビット表記は00011101で、DICTIDが使われているのですね。
いいえ、ここでのビット番号は「右」(LSB)から数えるので、0-originで5ビット目は0であり、DICTIDは使われていません。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: pngイメージ読み込みにおけるチャンクの扱いについて

#14

投稿記事 by みけCAT » 9年前

bonbo さんが書きました:CMF(08)+FLG(1D)+DICTID(63 F8 0F 04)+フィルタリングの種類(00)+ビットデータ(09 FB 03)+ADLER32(FD 0C BB 5B)+CRC(E7 00 00 00)
データはDEFLATE形式で圧縮されているので、ヘッダの後すぐにフィルタリングの種類やビットデータが来ることは無いはずです。
テスト用に無圧縮(「圧縮なし」のブロックのみを使用してDEFLATE形式にエンコードした)のPNGファイルを添付します。
添付ファイル
basicrectimage_nocompress.zip
無圧縮PNGファイル
(265 バイト) ダウンロード数: 150 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

bonbo

Re: pngイメージ読み込みにおけるチャンクの扱いについて

#15

投稿記事 by bonbo » 9年前

ありがとうございます。
お手数おかけします。
IDATチャンクの内容(先頭の49 44 41 54除く)
1. DEFLATE形式で圧縮したもの(今回はDICTID無し)
08 1D 63 F8 0F 04 00 09 FB 03 FD 0C BB 5B E7 00 00 00
CMF(08)+FLG(1D)+圧縮データ(63 F8 0F 04 00 09 FB 03)+ADLER32(FD 0C BB 5B)+CRC(E7 00 00 00)
2. 無圧縮
08 1D 01 05 00 FA FF 00 FF FF FF FF 09 FB 03 FD 7D 20 CC B8 00 00 00 00
CMF(08)+FLG(1D)+(圧縮)データ(01 05 00 FA FF 00 FF FF FF FF 09 FB 03 FD)+ADLER32(7D 20 CC B8)+CRC(00 00 00 00)

1について
CMFの0~3bit(lsb)が8の時はDEFLATE形式で圧縮されている。
DEFLATEの伸張まではまだできていません。(これはzlib導入しないといけない?)
2について
直勘なのですが、たぶん00 FF FF FFの部分がフィルタリングの種類とビットデータですよね。
>「圧縮なし」のブロックのみを使用してDEFLATE形式にエンコードした
これがよくわからないのですが
無圧縮の状態だとこの部分は
08 1D 00 FF FF FF 7D 20 CC B8 00 00 00 00
CMF(08)+FLG(1D)+(圧縮)データ(00 FF FF FF)+ADLER32(7D 20 CC B8)+CRC(00 00 00 00)
のような形になるのではないのですか?
このサイト(http://hoshi-sano.hatenablog.com/entry/ ... /18/113434)
等を見る限りそう思ってしまいます。
(一応
サイズの部分と
08 1D 00 FF FF FF 7D 20 CC B8 00 00 00 00
の変更を施して出力したところ、表示されなくなりましたが…)

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: pngイメージ読み込みにおけるチャンクの扱いについて

#16

投稿記事 by みけCAT » 9年前

bonbo さんが書きました:IDATチャンクの内容(先頭の49 44 41 54除く)
1. DEFLATE形式で圧縮したもの(今回はDICTID無し)
08 1D 63 F8 0F 04 00 09 FB 03 FD 0C BB 5B E7 00 00 00
CMF(08)+FLG(1D)+圧縮データ(63 F8 0F 04 00 09 FB 03)+ADLER32(FD 0C BB 5B)+CRC(E7 00 00 00)
2. 無圧縮
08 1D 01 05 00 FA FF 00 FF FF FF FF 09 FB 03 FD 7D 20 CC B8 00 00 00 00
CMF(08)+FLG(1D)+(圧縮)データ(01 05 00 FA FF 00 FF FF FF FF 09 FB 03 FD)+ADLER32(7D 20 CC B8)+CRC(00 00 00 00)
このデータの解釈は間違っています。まずはPNGファイルに書かれたデータの長さ情報の方を信じましょう。
今回のデータ1のIDATチャンクのデータ本体(長さ、種類、CRCを除く)は

コード:

08 1D 63 F8 0F 04 00 09 FB 03 FD
です。さらにZLIBのヘッダとADER32を除いた圧縮データ本体は

コード:

63 F8 0F 04 00
の部分です。
これをビット順に書き直し、解釈すると、

コード:

3    6    F    8    0    F    0    4    0    0
1100 0110 0001 1111 1111 0000 0010 0000 0000 0000

final block
| fixed huffman codes   (length=3)
| |  0        255       257     dist=0 256     ?
1 10 00110000 111111111 0000001 00000  0000000 0
となりました。
bonbo さんが書きました:1について
CMFの0~3bit(lsb)が8の時はDEFLATE形式で圧縮されている。
正しいと思います。
bonbo さんが書きました:2について
直勘なのですが、たぶん00 FF FF FFの部分がフィルタリングの種類とビットデータですよね。
そのようですね。
bonbo さんが書きました:>「圧縮なし」のブロックのみを使用してDEFLATE形式にエンコードした
これがよくわからないのですが
無圧縮の状態だとこの部分は
08 1D 00 FF FF FF 7D 20 CC B8 00 00 00 00
CMF(08)+FLG(1D)+(圧縮)データ(00 FF FF FF)+ADLER32(7D 20 CC B8)+CRC(00 00 00 00)
のような形になるのではないのですか?
はい、違います。
ここでいう「『圧縮なし』のブロック」とはRFC1951の「3.2.4. Non-compressed blocks (BTYPE=00)」のことです。
bonbo さんが書きました:このサイト(http://hoshi-sano.hatenablog.com/entry/ ... /18/113434)
等を見る限りそう思ってしまいます。
そのサイトではDeflateのデコードは標準ライブラリに丸投げしていて全く触れられていませんが、なぜそう思ったのでしょうか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

bonbo

Re: pngイメージ読み込みにおけるチャンクの扱いについて

#17

投稿記事 by bonbo » 9年前

ありがとうございます。
deflateの伸張についてはrfc1951に記載されていました。確認不足でした。
みけCATさんのおかげで大方手順については理解できたのですが、あと少しだけわからない点がありました。
私の理解では、
63 F8 0F 04 00
// あとでLSBから読みだすということを考慮して、上記の16進数を2進表示にすると
1 10 00110 0001 1111 1111 0000 0010 0000 0000 0000
最初の1ビットが1であることから最後のブロックであることを示している
次の2ビットが01であることから、静的ハフマン符号で圧縮されていることがわかる。(LSBからMSBであることに注意)
次からはハフマン符号が続き、これはMSBからLSBに読んでいく。
固定長符号
0:000
1:001
2:010
3:011
4:100
5:101
6:110
7:111
これにより上記の
001 100 001 111 111 110 000 001 000 000 000
解釈をすると
1 4 1 7 7 6 0 1 0 0 0
となり
(フィルタ b g r)の並びで、それぞれ256をオーバーした分を引くと
(1 417 776 100 0)=(1 161 8 100 0)となりますが、明らかに#FFFFFFとは違う値になってしまいました。

ここで詰まってしまいました。1はフィルターでいいにしても左には何もないので(0,0,0)と比較しても違う値になります。
もしかすると可変長符号を用いる必要があるのでしょうか。
また、その場合は、エンコードを行っていないので、デコード時に使う可変長符号を特定することが
できないと思います。(可変長符号はエンコード時に使うハフマン木から得られるのでは?)
いくつかサイトを回ったのですが、これについての解決策がみつかりませんでした。
返信も理解が遅くて申し訳ありません。もしお時間がよろしければあと少しだけおねがいします。
下記サイトを参考にしました。
http://michisugara.jp/archives/2013/huffman.html
http://blog.livedoor.jp/cperl/archives/22014187.html

>そのサイトではDeflateのデコードは標準ライブラリに丸投げしていて全く触れられていませんが、なぜそう思ったのでしょうか?
申し訳ありません。どちらかというとこちらのサイト(http://blog.livedoor.jp/cperl/archives/22027424.html)でした。
まわりが0だったのでフィルタの種類とビットデータ以外の要素はなくても大丈夫だと勘違いしていました。
データの長さについて、dat[]のサイズを信用していいと分かったのでこの問題は解決しました。

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: pngイメージ読み込みにおけるチャンクの扱いについて

#18

投稿記事 by みけCAT » 9年前

bonbo さんが書きました:deflateの伸張についてはrfc1951に記載されていました。確認不足でした。
みけCATさんのおかげで大方手順については理解できたのですが、あと少しだけわからない点がありました。
私の理解では、
63 F8 0F 04 00
// あとでLSBから読みだすということを考慮して、上記の16進数を2進表示にすると
1 10 00110 0001 1111 1111 0000 0010 0000 0000 0000
最初の1ビットが1であることから最後のブロックであることを示している
次の2ビットが01であることから、静的ハフマン符号で圧縮されていることがわかる。(LSBからMSBであることに注意)
ここまでは正しそうです。
bonbo さんが書きました:次からはハフマン符号が続き、これはMSBからLSBに読んでいく。
ハフマン符号の部分もLSBからMSBに読めばいいはずです。
bonbo さんが書きました:固定長符号
0:000
1:001
2:010
3:011
4:100
5:101
6:110
7:111
これにより上記の
001 100 001 111 111 110 000 001 000 000 000
解釈をすると
1 4 1 7 7 6 0 1 0 0 0
となり
(フィルタ b g r)の並びで、それぞれ256をオーバーした分を引くと
(1 417 776 100 0)=(1 161 8 100 0)となりますが、明らかに#FFFFFFとは違う値になってしまいました。

ここで詰まってしまいました。1はフィルターでいいにしても左には何もないので(0,0,0)と比較しても違う値になります。
なぜこの符号を使うべきだと思ったのでしょうか?全く関係ないですね。
bonbo さんが書きました:もしかすると可変長符号を用いる必要があるのでしょうか。
また、その場合は、エンコードを行っていないので、デコード時に使う可変長符号を特定することが
できないと思います。(可変長符号はエンコード時に使うハフマン木から得られるのでは?)
いくつかサイトを回ったのですが、これについての解決策がみつかりませんでした。
静的ハフマン符号用の符号はRFC1951に書いてあります。
動的ハフマン符号の場合は各アルファベットに対応する符号語の長さ(データ中に書かれる)から求めることができ、この求め方もRFC1951に書いてあります。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

閉鎖

“C言語何でも質問掲示板” へ戻る