2010-02-03 35 views
11

Esto es lo que tengo hasta ahora:¿Cómo puedo leer metadatos PNG de PHP?

<?php 

$file = "18201010338AM16390621000846.png"; 

$test = file_get_contents($file, FILE_BINARY); 

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

?> 

La salida es sorta lo que quiero, pero realmente sólo necesitan líneas 3-7 (inclusive). Así es como se ve el resultado ahora: http://silentnoobs.com/pbss/collector/test.php. Estoy tratando de obtener los datos de "PunkBuster Screenshot (±) AAO Bridge Crossing" a "Resulting: w = 394 X h = 196 sample = 2". Creo que sería bastante sencillo leer el archivo y almacenar cada línea en una matriz, la línea [0] debería ser "Captura de pantalla de PunkBuster (±) Cruce de puente AAO", y así sucesivamente. Todas esas líneas están sujetas a cambios, así que no puedo buscar algo finito.

Lo he intentado durante unos días, y no ayuda mucho que soy pobre en php.

+0

Lo sentimos, no entender el objetivo ni la pregunta ... – deceze

+1

PNG se divide en trozos (http://www.libpng.org/pub/png/spec/ 1.2/PNG-Chunks.html). Y probablemente esté buscando el fragmento 'tEXt' que contiene un comentario (denotado con la palabra clave' comment'). – Gumbo

Respuesta

16

El PNG file format define que un documento PNG se divide en varios fragmentos de datos. Por lo tanto, debe navegar hacia el trozo que desea.

Los datos que desea extraer parecen estar definidos en un fragmento tEXt. Escribí la siguiente clase para permitirle extraer fragmentos de archivos 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; 
    } 
} 

Usted puede usar como tal para extraer su tEXt trozo deseado como por ejemplo:

$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

Si solo necesita trozos de texto, es una pérdida de memoria cargar toda la información PNG (es decir, 'fread' vs' fseek'). – Matthew

+0

@konforce: he vuelto a factorizar la clase para que solo almacene las compensaciones de los fragmentos. Se leen según el uso. Quiero mantener la clase anterior lo más versátil posible. –

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

Supone un archivo PNG, básicamente, bien formado.

Cuestiones relacionadas