【问题标题】:How can I read PNG Metadata from PHP?如何从 PHP 中读取 PNG 元数据?
【发布时间】:2011-01-12 12:16:51
【问题描述】:

这是我目前所拥有的:

<?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 Screenshot (±) AAO Bridge Crossing”获取数据到“Resulting: w=394 X h=196 sample=2”。我认为通读文件并将每一行存储在一个数组中是相当直接的,line[0] 需要是“PunkBuster Screenshot (±) AAO Bridge Crossing”,依此类推。所有这些线都可能发生变化,所以我不能只搜索有限的东西。

我已经尝试了几天,我的php水平很差并没有多大帮助。

【问题讨论】:

标签: php png metadata


【解决方案1】:

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;
   }
}

【讨论】:

  • 如果他只需要文本块,那么加载整个PNG数据(即fread vs fseek)会浪费内存。
  • @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 文件。

【讨论】:

    【解决方案3】:

    【讨论】:

    • 如果您只需要宽度和高度,最好的答案。
    【解决方案4】:

    前几天发现了这个问题,所以做了一个库,用PHP提取一个PNG的元数据(Exif、XMP和GPS),100%原生,希望对你有帮助。 :) PNGMetadata

    【讨论】:

      猜你喜欢
      • 2016-04-29
      • 2021-05-02
      • 2011-05-04
      • 2021-01-06
      • 2019-07-21
      • 1970-01-01
      • 2012-12-14
      • 2017-05-07
      • 2012-11-15
      相关资源
      最近更新 更多