11

データが IDAT チャンクにどのように格納されるかを理解しようとしています。私は小さな PHP クラスを書いており、ほとんどのチャンク情報を取得できますが、IDAT で取得したものは画像のピクセルと一致しません:

ここに画像の説明を入力これは、アルファ (ビット深度 8) 付きの 2×2px トゥルーカラーです。

しかし、IDAT データを次のように解釈すると、次のようになります。

current(unpack('H*',gzuncompress($idat_data)));

私は得る

00000000ffffff00ffffff000000

ピクセルを一致させる方法がわかりません。それとも、データを破損するのは私のコードですか?

ご協力いただきありがとうございます!

編集:わかりました

08d705c101010000008010ff4f1750a93029e405fb

16 進数で圧縮されたデータであるため、解凍後に数バイトが失われるようです。

ここに画像の説明を入力

4

3 に答える 3

10

gzinflate を使用しますが、最初の 2 バイトと最後の 4 バイトを最初にスキップします。

$contents = file_get_contents($in_filename);
$pos = 8; // skip header

$color_types = array('Greyscale','unknown','Truecolour','Indexed-color','Greyscale with alpha','unknown','Truecolor with alpha');
$len = strlen($contents);
$safety = 1000;
do {
    list($unused,$chunk_len) = unpack('N', substr($contents,$pos,4));

    $chunk_type = substr($contents,$pos+4,4);

    $chunk_data = substr($contents,$pos+8,$chunk_len);

    list($unused,$chunk_crc) = unpack('N', substr($contents,$pos+8+$chunk_len,4));
    echo "chunk length:$chunk_len(dec) 0x" . sprintf('%08x',$chunk_len) . "h<br>\n";
    echo "chunk crc   :0x" . sprintf('%08x',$chunk_crc) . "h<br>\n";
    echo "chunk type  :$chunk_type<br>\n";
    echo "chunk data  $chunk_type bytes:<br>\n"  . chunk_split(bin2hex($chunk_data)) . "<br>\n";
    switch($chunk_type) {
        case 'IHDR':
        list($unused,$width,$height) = unpack('N2', substr($chunk_data,0,8));
        list($unused,$depth,$Color_type,$Compression_method,$Filter_method,$Interlace_method) = unpack('C*', substr($chunk_data,8));
        echo "Width:$width,Height:$height,depth:$depth,Color_type:$Color_type(" . $color_types[$Color_type] . "),Compression_method:$Compression_method,Filter_method:$Filter_method,Interlace_method:$Interlace_method<br>\n";
        $bytes_per_pixel = $depth / 8;
        break;

        case 'PLTE':
        $palette = array();
        for($i=0;$i<$chunk_len;$i+=3) {
            $tupl = bin2hex(substr($chunk_data,$i,3));
            $palette[] = $tupl;
            if($i && ($i % 30 == 0)) {
                echo "<br>\n";
            }
            echo '<span style="color:' . $tupl . ';">[' . $tupl . ']</span>';
        }
        echo print_r($palette,true) . "<br>";
        break;

        case 'IDAT':
        $compressed = substr($chunk_data,2,$chunk_len - 6); // 2 bytes on the front and 4 at the end
        $decompressed = gzinflate($compressed);
        echo "decompressed chunk data " . strlen($decompressed) . " bytes:<br>\n"  . chunk_split(bin2hex($decompressed),2 + $width * $bytes_per_pixel * 2) . "<br>\n";
        for($row=0; $row<$height; $row++) {
            for($col=1; $col<=$width; $col++) {
                $index = (int)substr($decompressed,((int)$row*($width+1)+$col),1);
                echo '<span style="color:' . $palette[$index] . ';">' . $index . '</span>';
            }
            echo "<br>\n";
        }
        // TODO use filters described here:
        // http://www.w3.org/TR/PNG/#9Filters
        // first byte of scan line is filter type
        break;

    }
    $pos += $chunk_len + 12;
    echo "<hr>";
} while(($pos < $len) && --$safety);
于 2011-09-03T13:35:34.703 に答える
4
00000000 ffffff00 ffffff00 0000xxxx
black    white    white    black

それが私に言えることです(これは正しいです)...しかし、最後に2バイトが欠落しています。

于 2011-09-03T12:09:45.660 に答える
3

@Andreas (+1) 解析に追加するには、次の 2 つの点に注意してください。

  1. PNG ファイルには多くの IDAT チャンクを含めることができます (多くの場合、IDAT チャンクを含めることができます)。それらを連結して、圧縮された zlib ストリームを復元する必要があります。http://www.w3.org/TR/PNG/#10CompressionFSL

  2. Gzip/Compress/Deflate はすべて関連していますが、まったく同じではありません。PNG はdeflate/inflateを使用します。gzdeflate /gzinflateを試してみます

于 2011-09-03T12:32:24.020 に答える