如何从用PHP读取JPG XMP数据?(How can I read XMP data from a

2019-08-19 04:57发布

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

Answer 1:

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

就在两个备注:

  • XMP大量使用了XML命名空间,所以你必须与解析一些XML工具XMP数据时留意这一点。
  • 考虑到图像文件的可能大小,你也许不能够使用file_get_contents()这个函数加载整个图像到内存中。 使用fopen()来打开一个文件流资源和检查的数据块的关键序列<x:xmpmeta</x:xmpmeta>将显著减少内存占用。


Answer 2:

我只回答这个这么多时间之后,因为这似乎是如何解析XMP数据搜索谷歌的时候是最好的结果。 我见过几次的代码中使用这种几乎相同的片段,它是内存可怕的浪费。 这里是fopen()函数方法他的例子后的Stefan提到的一个例子。

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


Answer 3:

在Linux上简单的方法是调用exiv2程序,在Debian的一个同名的封装。

$ exiv2 -e X extract image.jpg

将产生image.xmp包含嵌入XMP这是现在你的解析。



Answer 4:

我知道......这是一种旧的线程,但它是有帮助的我,当我正在寻找一种方式来做到这一点,所以我想这可能是有益的给别人。

我把这个基本的解决方案,并修改它,所以它处理,其中标签块之间分割的情况。 这样的块大小一样大或小,只要你想。

 <?php function getXmpData($filename, $chunk_size = 1024) { 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, 'rb')) === FALSE) { throw new RuntimeException('Could not open file for reading'); } $tag = '<x:xmpmeta'; $buffer = false; // find open tag while ($buffer === false && ($chunk = fread($file_pointer, $chunk_size)) !== false) { if(strlen($chunk) <= 10) { break; } if(($position = strpos($chunk, $tag)) === false) { // if open tag not found, back up just in case the open tag is on the split. fseek($file_pointer, -10, SEEK_CUR); } else { $buffer = substr($chunk, $position); } } if($buffer === false) { fclose($file_pointer); return false; } $tag = '</x:xmpmeta>'; $offset = 0; while (($position = strpos($buffer, $tag, $offset)) === false && ($chunk = fread($file_pointer, $chunk_size)) !== FALSE && !empty($chunk)) { $offset = strlen($buffer) - 12; // subtract the tag size just in case it's split between chunks. $buffer .= $chunk; } fclose($file_pointer); if($position === false) { // this would mean the open tag was found, but the close tag was not. Maybe file corruption? throw new RuntimeException('No close tag found. Possibly corrupted file.'); } else { $buffer = substr($buffer, 0, $position + 12); } return $buffer; } ?> 



Answer 5:

我developped的XMP腓的无线工具包的扩展:它是基于Adobe XMP工具包PHP5的扩展,它提供了主要的类和方法来读取JPEG,PSD,PDF,视频,音频/写/解析XMP metadatas ......这扩展名是根据GPL许可证。 新的版本也将很快面市,为PHP 5.3(现在只用PHP 5.2.x兼容),而应该是(仅适用于FreeBSD和Linux系统现在)适用于Windows和MacOSX的。 http://xmpphptoolkit.sourceforge.net/



Answer 6:

布赖恩的解决方案是迄今为止最好的一个,但让我修改了它简化它,并删除一些功能,它有几个问题。

有,我发现他的解决三个问题:

A)如果提取的块落在正确的,我们要搜索的字符串之一之间,也不会发现它。 小的块大小更可能导致此问题。

B)如果块包含两个的开始和结束,也不会发现它。 这是一个容易的一个额外的修复if语句来重新检查开始被发现,看看到底是还发现了一块。

C)else语句添加到最终打破while循环,如果它没有找到XMP数据有副作用,如果开始元素没有在第一轮中,它将不再检查块。 这很可能容易解决了,但是与第一个问题是不值得的。

下面我的解决方案是不一样强大,但它更健壮。 将只检查一个块,和提取的数据。 如果起点和终点都在该块它只会工作,所以块大小必须足够大,以确保其始终捕获数据。 从我与Adobe Photoshop / Lightroom的经验导出的文件中,XMP数据通常开始于20KB左右,并在约45KB结束。 我的50K的块大小似乎很好地为我的图片工作,如果你带了一些出口的数据,如,有很多开发设置的CRS块会少得多。

function getXmpData($filename)
{
    $chunk_size = 50000;
    $buffer = NULL;

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

    $chunk = fread($file_pointer, $chunk_size);
    if (($posStart = strpos($chunk, '<x:xmpmeta')) !== FALSE) {
        $buffer = substr($chunk, $posStart);
        $posEnd = strpos($buffer, '</x:xmpmeta>');
        $buffer = substr($buffer, 0, $posEnd + 12);
    }
    fclose($file_pointer);
    return $buffer;
}


Answer 7:

感谢您塞巴斯蒂安B.对于缩短版:)。 如果你想避免这个问题,当CHUNK_SIZE是一些文件只是太小,只是添加递归。

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

  $chunk = fread($file_pointer, $chunk_size);
  if (($posStart = strpos($chunk, '<x:xmpmeta')) !== FALSE) {
      $buffer = substr($chunk, $posStart);
      $posEnd = strpos($buffer, '</x:xmpmeta>');
      $buffer = substr($buffer, 0, $posEnd + 12);
  }

  fclose($file_pointer);

// recursion here
  if(!strpos($buffer, '</x:xmpmeta>')){
    $buffer = getXmpData($filename, $chunk_size*2);
  }

  return $buffer;
}


Answer 8:

如果你有ExifTool可用的(一个非常有用的工具),并可以运行外部命令,你可以使用它的选项提取XMP数据( -xmp:all )和JSON格式输出它( -json ),然后你就可以很容易地转换到PHP对象:

$command = 'exiftool -g -json -struct -xmp:all "'.$image_path.'"';
exec($command, $output, $return_var);
$metadata = implode('', $output);
$metadata = json_decode($metadata);


文章来源: How can I read XMP data from a JPG with PHP?