How to use PNG's IDAT chunk?

前端 未结 3 471
鱼传尺愫
鱼传尺愫 2021-02-04 12:12

I\'m trying to understand how data are stored into IDAT chunk. I\'m writing a little PHP class and I can retrieve most of chunks information but what I get for IDAT doesn\'t mat

3条回答
  •  醉酒成梦
    2021-02-04 12:40

    Use gzinflate but skip the first 2 bytes and the last 4 first.

    $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
    \n"; echo "chunk crc :0x" . sprintf('%08x',$chunk_crc) . "h
    \n"; echo "chunk type :$chunk_type
    \n"; echo "chunk data $chunk_type bytes:
    \n" . chunk_split(bin2hex($chunk_data)) . "
    \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
    \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 "
    \n"; } echo '[' . $tupl . ']'; } echo print_r($palette,true) . "
    "; 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:
    \n" . chunk_split(bin2hex($decompressed),2 + $width * $bytes_per_pixel * 2) . "
    \n"; for($row=0; $row<$height; $row++) { for($col=1; $col<=$width; $col++) { $index = (int)substr($decompressed,((int)$row*($width+1)+$col),1); echo '' . $index . ''; } echo "
    \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 "
    "; } while(($pos < $len) && --$safety);

提交回复
热议问题