PHP內置支持讀取EXIF和IPTC元數據,但我找不到任何方法來讀取XMP?如何使用PHP讀取JPG格式的XMP數據?
回答
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>
的數據塊將顯着減少內存佔用量。
我只在這麼多時間後纔回復此問題,因爲這在搜索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;
}
值得注意的是,當圖像不包含XMP數據時,這會掛起,儘管我確信這可以很容易地被知道如何解決的人解決。 – 2011-05-22 18:09:42
如果文件中不存在XMP元素,我在while循環中添加了一個else \ break條件 – 2012-04-30 18:14:37
我重構了此函數以便首先複製塊,然後對緩衝區執行檢測/修改,而不是嘗試這樣做大塊。 – 2012-10-17 04:15:44
我developped的XMP腓的無線工具包的擴展:它是基於Adobe XMP工具包PHP5的擴展,它提供了主要的類和方法來讀取JPEG,PSD,PDF /寫/解析XMP metadatas,視頻,音頻......此擴展程序在gpl許可下。一個新版本將很快推出,對於PHP 5.3(現在只與php 5.2.x兼容),應該可以在windows和macosx(現在只適用於freebsd和linux系統)上使用。 http://xmpphptoolkit.sourceforge.net/
我試過你的工具包,但是我無法編譯:(抱怨缺少printf。「xmp_toolkit/common/XMP_LibUtils.hpp:179:62:錯誤:'printf'未在此範圍內聲明」 – haggi 2012-11-07 14:54:59
Linux上的一個簡單方法是調用exiv2程序,該程序在debian上的同名軟件包中可用。
$ exiv2 -e X extract image.jpg
將生成包含嵌入式XMP的image.xmp,該嵌入式XMP現在可以解析。
布賴恩的解決方案迄今爲止是最好的解決方案,但它有一些問題,所以我修改它以簡化它,並刪除一些功能。
有三個問題,我發現他的解決方案:
A)如果提取的塊落在正確的,我們要搜索的字符串之一之間,也不會發現它。小塊大小更可能導致此問題。 B)如果塊包含開始和結束,它將不會找到它。使用額外的if語句重新檢查啓動發現塊以查看是否也找到了結尾,這是一個很容易解決的問題。
C)else語句添加到最後打破while循環,如果它沒有找到xmp數據有一個副作用,如果第一遍沒有找到start元素,它將不再檢查塊。這可能很容易解決,但第一個問題是不值得的。
我的解決方案不如以前強大,但它更強大。它只會檢查一個塊,並從中提取數據。它只有在開始和結束位於該塊中時纔有效,所以塊大小需要足夠大以確保它始終捕獲該數據。從我使用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;
}
我更新了我的功能修復了它的邏輯問題:) – 2012-10-18 13:33:28
啊,謝謝布萊恩!我從來沒有注意到你直到現在纔回復。我會檢查你的修改後的代碼,看看它是否適用於我(我還沒有完全理解它,我不是程序員...) – 2013-02-28 19:26:19
Oooh,我現在明白了..你正在構建緩衝區一次一個塊並且總是檢查緩衝區。這可以防止我列出的所有問題。聰明!謝謝。 – 2013-02-28 19:33:50
謝謝塞巴斯蒂安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;
}
我知道......這是一種舊的線程,但它是有幫助的我,當我正在尋找一種方式來做到這一點,所以我想這可能是有益的給別人。
我接受了這個基本的解決方案並對其進行了修改,以便處理標記在塊之間分割的情況。這可以使塊大小盡可能大或小。
<?php
function getXmpData($filename, $chunk_size = 1024)
{
\t if (!is_int($chunkSize)) {
\t \t throw new RuntimeException('Expected integer value for argument #2 (chunkSize)');
\t }
\t if ($chunkSize < 12) {
\t \t throw new RuntimeException('Chunk size cannot be less than 12 argument #2 (chunkSize)');
\t }
\t if (($file_pointer = fopen($filename, 'rb')) === FALSE) {
\t \t throw new RuntimeException('Could not open file for reading');
\t }
\t $tag = '<x:xmpmeta';
\t $buffer = false;
\t // find open tag
\t while ($buffer === false && ($chunk = fread($file_pointer, $chunk_size)) !== false) {
\t \t if(strlen($chunk) <= 10) {
\t \t \t break;
\t \t }
\t \t if(($position = strpos($chunk, $tag)) === false) {
\t \t \t // if open tag not found, back up just in case the open tag is on the split.
\t \t \t fseek($file_pointer, -10, SEEK_CUR);
\t \t } else {
\t \t \t $buffer = substr($chunk, $position);
\t \t }
\t }
\t if($buffer === false) {
\t \t fclose($file_pointer);
\t \t return false;
\t }
\t $tag = '</x:xmpmeta>';
\t $offset = 0;
\t while (($position = strpos($buffer, $tag, $offset)) === false && ($chunk = fread($file_pointer, $chunk_size)) !== FALSE && !empty($chunk)) {
\t \t $offset = strlen($buffer) - 12; // subtract the tag size just in case it's split between chunks.
\t \t $buffer .= $chunk;
\t }
\t fclose($file_pointer);
\t if($position === false) {
\t \t // this would mean the open tag was found, but the close tag was not. Maybe file corruption?
\t \t throw new RuntimeException('No close tag found. Possibly corrupted file.');
\t } else {
\t \t $buffer = substr($buffer, 0, $position + 12);
\t }
\t return $buffer;
}
?>
如果你有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);
- 1. 使用javascript閱讀jpeg xmp元數據
- 2. 在Perl中使用ImageMagick讀取XMP數據
- 3. 如何在c#或C++中讀取/寫入xmp元數據
- 4. 讀取JPG格式爲BMP在WP8
- 5. 如何使用FreeImage讀取jpg
- 6. 如何使用帶有c#的OpenXML格式SDK以格式讀取數據?
- 7. 如何使用SharpPcap以可讀格式從TcpPacket獲取數據?
- 8. 如何在Fortran中使用註釋讀取格式化數據?
- 9. 閱讀Python中的XMP數據
- 10. C:如何從文件中讀取JPG格式和保存呢?
- 11. 如何讀取JSON格式的字符串數據數據?
- 12. 用d3.dsv.parseRows讀取格式化數據
- 13. 從JPG中讀取EXIF數據
- 14. 如何讀取Python中的公用數據格式(CDF)
- 15. iOS - 讀取/寫入mp4視頻的XMP元數據
- 16. 如何讀取XML格式的數據以及如何在Java
- 17. 從PHP的HTML表格讀取數據
- 18. 使用PHP讀取表格
- 19. 有沒有辦法使用imagemagick讀/寫XMP元數據?
- 20. 如何從php讀取NVARCHAR2數據使用php
- 21. 讀取格式不正確的數據
- 22. 如何使用格式化函數的Common-Lisp讀取文件?
- 23. 如何讀取格式數據用紅寶石
- 24. 在ios中從jpeg中讀取xmp元數據
- 25. 我如何XMP元數據添加到使用iTextSharp的
- 26. 如何使用XMP修改Sharepoint文檔的元數據?
- 27. 使用PHP讀取任何格式正確的RSS/ATOM文件
- 28. 提交後從PHP表格讀取PHP數組的格式
- 29. 使用itextSharp設置XMP數據5.3.3
- 30. 如何將Google表格中的數據讀取到PHP中
這就可以解釋爲什麼PHP中沒有XMP特定函數。 – Liam 2009-10-16 14:32:29