如何使用PHP从JPG读取XMP数据?

Lia*_*iam 15 php xmp jpeg metadata

PHP内置支持读取EXIF和IPTC元数据,但我找不到任何方法来读取XMP?

Ste*_*rig 22

XMP数据实际上嵌入到图像文件中,因此可以使用PHP的字符串函数从图像文件本身中提取它.

下面演示了这个过程(我使用的是SimpleXML,但是每个其他XML API甚至简单而聪明的字符串解析都可以给你相同的结果):

$content = file_get_contents($image);
$xmp_data_start = strpos($content, '<x:xmpmeta');
$xmp_data_end   = strpos($content, '</x:xmpmeta>');
$xmp_length     = $xmp_data_end - $xmp_data_start;
$xmp_data       = substr($content, $xmp_data_start, $xmp_length + 12);
$xmp            = simplexml_load_string($xmp_data);
Run Code Online (Sandbox Code Playgroud)

只有两个评论:

  • XMP大量使用XML命名空间,因此在使用某些XML工具解析XMP数据时,您必须密切关注它.
  • 考虑到图像文件的可能大小,您可能无法使用,file_get_contents()因为此函数会将整个图像加载到内存中.使用fopen()打开一个文件流的资源和检查重点序列数据块<x:xmpmeta,并</x:xmpmeta>会显著减少内存占用.


Bry*_*hty 12

我只是在这么多时间之后回复这个问题,因为在搜索Google如何解析XMP数据时,这似乎是最好的结果.我已经在代码中看到了这个几乎相同的片段几次,这是对内存的可怕浪费.以下是Stefan在他的例子之后提到的fopen()方法的一个例子.

<?php

function getXmpData($filename, $chunkSize)
{
    if (!is_int($chunkSize)) {
        throw new RuntimeException('Expected integer value for argument #2 (chunkSize)');
    }

    if ($chunkSize < 12) {
        throw new RuntimeException('Chunk size cannot be less than 12 argument #2 (chunkSize)');
    }

    if (($file_pointer = fopen($filename, 'r')) === FALSE) {
        throw new RuntimeException('Could not open file for reading');
    }

    $startTag = '<x:xmpmeta';
    $endTag = '</x:xmpmeta>';
    $buffer = NULL;
    $hasXmp = FALSE;

    while (($chunk = fread($file_pointer, $chunkSize)) !== FALSE) {

        if ($chunk === "") {
            break;
        }

        $buffer .= $chunk;
        $startPosition = strpos($buffer, $startTag);
        $endPosition = strpos($buffer, $endTag);

        if ($startPosition !== FALSE && $endPosition !== FALSE) {
            $buffer = substr($buffer, $startPosition, $endPosition - $startPosition + 12);
            $hasXmp = TRUE;
            break;
        } elseif ($startPosition !== FALSE) {
            $buffer = substr($buffer, $startPosition);
            $hasXmp = TRUE;
        } elseif (strlen($buffer) > (strlen($startTag) * 2)) {
            $buffer = substr($buffer, strlen($startTag));
        }
    }

    fclose($file_pointer);
    return ($hasXmp) ? $buffer : NULL;
}
Run Code Online (Sandbox Code Playgroud)

  • 我在while循环中添加了一个else\break条件,如果文件中不存在XMP元素,则会终止循环 (2认同)