2010-02-03 2 views
11

Это то, что я до сих пор:Как я могу прочитать метаданные PNG из PHP?

<?php 

$file = "18201010338AM16390621000846.png"; 

$test = file_get_contents($file, FILE_BINARY); 

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

?> 

Выход Сорта, что я хочу, но я на самом деле нужно только линии 3-7 (включительно). Вот как выглядит результат: http://silentnoobs.com/pbss/collector/test.php. Я пытаюсь получить данные из «Скриншот PunkBuster (±) AAO Bridge Crossing» на «Результат: w = 394 X h = 196 sample = 2». Я думаю, что было бы довольно просто прочитать файл и сохранить каждую строку в массиве, строка [0] должна быть «Скриншот PunkBuster (±) AAO Bridge Crossing» и т. Д.). Все эти строки могут быть изменены, поэтому я не могу просто найти что-то конечное.

Я пробовал в течение нескольких дней, и это не очень помогает, что я беден на php.

+0

К сожалению, ни понимания, ни цели, вопрос ... – deceze

+1

PNG делится на куски (http://www.libpng.org/pub/png/spec/ 1.2/PNG-Chunks.html). И вы, вероятно, ищете фрагмент 'tEXt', который содержит комментарий (обозначается ключевым словом' comment'). – Gumbo

ответ

16

PNG file format определяет, что документ PNG разделен на несколько кусков данных. Поэтому вы должны перейти к своему желаемому куску.

Данные, которые вы хотите извлечь, как представляется, определены в блоке tEXt. Я написал следующий класс, чтобы вы могли извлекать куски из файлов 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; 
    } 
} 

Вы можете использовать его в качестве такового для извлечения нужных tEXt куска, как, например:

$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

Если ему нужны только фрагменты tEXt, это пустая трата памяти для загрузки всех данных PNG (т. Е. 'Fread' vs' fseek'). – Matthew

+0

@konforce: Я переустановил класс, чтобы хранить только смещения кусков. Они читаются на основе использования. Я хочу, чтобы вышеуказанный класс был максимально универсальным. –

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); 
?> 

Это предполагает в основном хорошо сформированный файл PNG.

Смежные вопросы