2010-02-03 12 views
11

To, co mam tak daleko:Jak mogę odczytać metadane PNG z PHP?

<?php 

$file = "18201010338AM16390621000846.png"; 

$test = file_get_contents($file, FILE_BINARY); 

echo str_replace("\n","<br>",$test); 

?> 

Wyjście jest jakoś to, co chcę, ale naprawdę wystarczy Linie 3-7 (włącznie). Tak wygląda teraz wynik: http://silentnoobs.com/pbss/collector/test.php. Próbuję uzyskać dane z "PunkBuster Screenshot (±) AAO Bridge Crossing" do "Wynik: w = 394 X h = 196 próbka = 2". Myślę, że przeczytanie pliku byłoby dość proste, a każda linia w tablicy będzie przechowywana, linia [0] będzie musiała być "PunkBuster Screenshot (±) AAO Bridge Crossing" i tak dalej. Wszystkie te linie mogą ulec zmianie, więc nie mogę po prostu wyszukać czegoś skończonego.

Próbowałem już od kilku dni, a to nie pomaga, że ​​jestem biedny w php.

+0

Niestety, ani zrozumienia, ani cel pytanie ... – deceze

+1

PNG jest podzielona na kawałki (http://www.libpng.org/pub/png/spec/ 1.2/PNG-Chunks.html). Prawdopodobnie szukasz fragmentu 'tEXt' zawierającego komentarz (oznaczony słowem kluczowym' comment'). – Gumbo

Odpowiedz

16

Opcja określa, że ​​dokument PNG jest podzielony na wiele porcji danych. Musisz więc poprowadzić swoją drogę do pożądanego kawałka.

Dane, które mają zostać wyodrębnione, wydają się być zdefiniowane w porcji tEXt. Napisałem następującą klasę, aby umożliwić wyodrębnianie porcji z plików PNG.

class PNG_Reader 
{ 
    private $_chunks; 
    private $_fp; 

    function __construct($file) { 
     if (!file_exists($file)) { 
      throw new Exception('File does not exist'); 
     } 

     $this->_chunks = array(); 

     // Open the file 
     $this->_fp = fopen($file, 'r'); 

     if (!$this->_fp) 
      throw new Exception('Unable to open file'); 

     // Read the magic bytes and verify 
     $header = fread($this->_fp, 8); 

     if ($header != "\x89PNG\x0d\x0a\x1a\x0a") 
      throw new Exception('Is not a valid PNG image'); 

     // Loop through the chunks. Byte 0-3 is length, Byte 4-7 is type 
     $chunkHeader = fread($this->_fp, 8); 

     while ($chunkHeader) { 
      // Extract length and type from binary data 
      $chunk = @unpack('Nsize/a4type', $chunkHeader); 

      // Store position into internal array 
      if ($this->_chunks[$chunk['type']] === null) 
       $this->_chunks[$chunk['type']] = array(); 
      $this->_chunks[$chunk['type']][] = array (
       'offset' => ftell($this->_fp), 
       'size' => $chunk['size'] 
      ); 

      // Skip to next chunk (over body and CRC) 
      fseek($this->_fp, $chunk['size'] + 4, SEEK_CUR); 

      // Read next chunk header 
      $chunkHeader = fread($this->_fp, 8); 
     } 
    } 

    function __destruct() { fclose($this->_fp); } 

    // Returns all chunks of said type 
    public function get_chunks($type) { 
     if ($this->_chunks[$type] === null) 
      return null; 

     $chunks = array(); 

     foreach ($this->_chunks[$type] as $chunk) { 
      if ($chunk['size'] > 0) { 
       fseek($this->_fp, $chunk['offset'], SEEK_SET); 
       $chunks[] = fread($this->_fp, $chunk['size']); 
      } else { 
       $chunks[] = ''; 
      } 
     } 

     return $chunks; 
    } 
} 

Można używać go jako taki, aby wyodrębnić żądany tEXt klocek jako takie:

$file = '18201010338AM16390621000846.png'; 
$png = new PNG_Reader($file); 

$rawTextData = $png->get_chunks('tEXt'); 

$metadata = array(); 

foreach($rawTextData as $data) { 
    $sections = explode("\0", $data); 

    if($sections > 1) { 
     $key = array_shift($sections); 
     $metadata[$key] = implode("\0", $sections); 
    } else { 
     $metadata[] = $data; 
    } 
} 
+0

Jeśli potrzebuje tylko kawałków text, marnowanie pamięci powoduje wczytanie całych danych PNG (np. 'Fread' kontra' fseek'). – Matthew

+0

@konforce: Zredagowałem klasę, by przechowywać tylko przesunięcia części. Są one czytane na zasadzie "użytkowania". Chcę, aby powyższa klasa była tak wszechstronna, jak to tylko możliwe. –

2
<?php 
    $fp = fopen('18201010338AM16390621000846.png', 'rb'); 
    $sig = fread($fp, 8); 
    if ($sig != "\x89PNG\x0d\x0a\x1a\x0a") 
    { 
    print "Not a PNG image"; 
    fclose($fp); 
    die(); 
    } 

    while (!feof($fp)) 
    { 
    $data = unpack('Nlength/a4type', fread($fp, 8)); 
    if ($data['type'] == 'IEND') break; 

    if ($data['type'] == 'tEXt') 
    { 
     list($key, $val) = explode("\0", fread($fp, $data['length'])); 
     echo "<h1>$key</h1>"; 
     echo nl2br($val); 

     fseek($fp, 4, SEEK_CUR); 
    } 
    else 
    { 
     fseek($fp, $data['length'] + 4, SEEK_CUR); 
    } 
    } 


    fclose($fp); 
?> 

Zakłada on przede wszystkim dobrze uformowane pliku PNG.

Powiązane problemy