2011-09-03 13 views
7

मैं समझने की कोशिश कर रहा हूं कि आईडीएटी खंड में डेटा कैसे संग्रहीत किया जाता है। मैं एक छोटी सी पीएचपी कक्षा लिख ​​रहा हूं और मैं अधिकांश भाग जानकारी प्राप्त कर सकता हूं लेकिन आईडीएटी के लिए मुझे जो मिलता है वह मेरी छवि के पिक्सेल से मेल नहीं खाता है:पीएनजी के आईडीएटी खंड का उपयोग कैसे करें?

enter image description here यह अल्फा (बिटडेप 8) के साथ 2 × 2px truecolour है।

लेकिन जब मैं इस तरह IDAT डेटा की व्याख्या:

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

मैं

00000000ffffff00ffffff000000

मुझे समझ नहीं आता कि यह कैसे पिक्सल मिलान कर सकते हैं मिलता है। या यह मेरा कोड है जो डेटा दूषित करता है?

आपकी मदद के लिए धन्यवाद!

संपादित करें: मैं

08d705c101010000008010ff4f1750a93029e405fb

हेक्स संकुचित डेटा के रूप में

मिलता है, तो ऐसा लगता है मैं uncompressing के बाद कई बाइट्स हानि।

enter image description here

उत्तर

7

उपयोग 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); 
+0

धन्यवाद के लिए फ़िल्टर प्रकार होना चाहिए, धन्यवाद अब काम करता है लेकिन मुझे "00000000ffffff00ffffff000000 मिलता है "(14 बाइट्स), वे पिक्सल पाने के लिए कैसे उपयोग किए जाते हैं? – MatTheCat

+0

अच्छा संपीड़न प्राप्त करने के लिए, पीएनजी प्रारूप संपीड़न से पहले फ़िल्टर लागू करता है। फ़िल्टर इस तरह की चीजें करते हैं: यदि दो स्कैन लाइन एक-दूसरे-द-दूसरे लगभग समान हैं, तो नीचे की पिक्सेल से मेल खाने वाली निचली रेखा पर पिक्सल, शून्य में बदल जाते हैं। तो जब आप कर लेंगे तो आपके पास शून्य का एक बकवास-टन है और संपीड़न वास्तव में अच्छा है। तो आपको डिकंप्रेशन के बाद फ़िल्टर को पूर्ववत करने और * पूर्ववत करने की आवश्यकता है। देखें http://www.w3.org/TR/PNG/#9 फ़िल्टर – Charlie

+0

दाएं, और फ़िल्टर "एक स्कैनलाइन में बाइट अनुक्रम को फ़िल्टर प्रकार बाइट से पहले बाइट्स के बराबर लंबाई अनुक्रम में बदल देता है"। तो क्या मेरे पास 18 बाइट असम्पीडित डेटा नहीं होना चाहिए (1 "बाइटपेथ" * 4 चैनल * 4 पिक्सल + 2 फ़िल्टर)? – MatTheCat

4
00000000 ffffff00 ffffff00 0000xxxx 
black white white black 

है यही कारण है कि मैं बता सकता है (जो सही है) ... लेकिन आप अंत में 2 बाइट्स याद कर रहे हैं।

+1

मैंने सोचा कि प्रत्येक स्कैनलाइन में फ़िल्टर प्रकार बाइट था? बाइट्स को खराब डिकंप्रेशन एल्गोरिदम से गायब हो सकता है? – MatTheCat

+0

मुझे वास्तव में पीएनजी पर पढ़ा नहीं गया है, लेकिन आपके द्वारा पेश किया गया डेटा आपको जो मिल रहा है उसके अनुरूप लगता है, सिवाय इसके कि यह सब कुछ नहीं है ... इसलिए मैं व्यक्तिगत रूप से आपकी सहायता नहीं कर सकता ऐसा हो रहा है: http://www.w3.org/TR/PNG/#11IDAT @leonbloy कई आईडीएटी ब्लॉक के बारे में सही हो सकता है, लेकिन मुझे यह अजीब लगता है कि एक ब्लॉक इतना छोटा हो जाएगा ... क्या आप सुनिश्चित करें कि आप सभी बाइट्स को असंपीड़ित कर रहे हैं? – Andreas

+0

धन्यवाद लेकिन http://www.w3.org/TR/PNG/#4Concepts.Encoding फ़िल्टरिंग ऐसा लगता है कि फिल्टर प्रकार डेटा में मौजूद होना चाहिए, इसलिए अधिक बाइट गायब होंगे ?? (मुझे पता है कि मेरे मामले में केवल एक आईडीएटी हिस्सा है ^^) – MatTheCat

3

@Andreas में जोड़ने के लिए (+1) पार्स, दो बातें ध्यान रखें:

  1. एक PNG फ़ाइल हो सकता है (और अक्सर है) कई IDAT हिस्सा, वे संकुचित zlib ठीक करने के लिए श्रेणीबद्ध किया जाना चाहिए धारा। http://www.w3.org/TR/PNG/#10CompressionFSL

  2. Gzip/संपीड़न/Deflate सभी संबंधित हैं लेकिन बिल्कुल वही नहीं हैं। पीएनजी deflate/inflate का उपयोग करता है। मैं gzdeflate/gzinflate

+0

मैंने कोशिश की लेकिन मुझे gzinflate =/(मेरी छवि में केवल एक आईडीएटी खंड) का उपयोग करते समय डेटा त्रुटि मिली है। – MatTheCat

+0

@MatTheCat मैंने जावा डिफ्लेटर/इन्फल्टर कक्षाओं का उपयोग करके पीएनजी को पढ़ने/लिखने के लिए लागू किया है और यह बेकार ढंग से काम करता है। शायद आप पहले दो बाइट्स को अलग करने की कोशिश करेंगे? 'gzinflate (substr ($ idat_data, 2)'? http://www.php.net/manual/en/function.gzinflate.php#70875 – leonbloy

+0

मैंने अभी देखा है कि आईडीएटी खंड का लंबा हिस्सा अपने डेटा की लंबाई से छोटा है , मुझे लगता है कि यह समस्या है जहां से समस्या आती है लेकिन मुझे लगता है कि – MatTheCat

संबंधित मुद्दे

 संबंधित मुद्दे