2009-10-16 25 views

उत्तर

21

एक्सएमपी डेटा सचमुच छवि फ़ाइल में एम्बेड किया गया है, इसलिए इसे छवि फ़ाइल से 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); 

सिर्फ दो टिप्पणी:

  • एक्सएमपी एक्सएमएल नेमस्पेस का भारी उपयोग करता है, इसलिए आपको कुछ एक्सएमएल उपकरणों के साथ एक्सएमपी डेटा को पार्स करते समय उस पर नजर रखना होगा।
  • छवि फ़ाइलों के संभावित आकार पर विचार करते हुए, आप शायद file_get_contents() का उपयोग करने में सक्षम नहीं होंगे क्योंकि यह फ़ंक्शन पूरी छवि को स्मृति में लोड करता है। फ़ाइल स्ट्रीम संसाधन खोलने और कुंजी-अनुक्रम <x:xmpmeta और </x:xmpmeta> के लिए डेटा के हिस्सों की जांच करने के लिए fopen() का उपयोग करना स्मृति पदचिह्न को काफी कम करेगा।
+0

यह समझाएगा कि PHP में कोई XMP विशिष्ट फ़ंक्शन क्यों नहीं है। – Liam

10

मैं केवल इतना समय के बाद इसका जवाब दे रहा हूं क्योंकि एक्सएमपी डेटा को पार्स करने के लिए Google को खोजते समय यह सबसे अच्छा परिणाम प्रतीत होता है। मैंने इस लगभग समान स्निपेट को कोड में कुछ बार देखा है और यह स्मृति का एक भयानक अपशिष्ट है। यहां उनके उदाहरण के बाद फॉपेन() विधि स्टीफन का उल्लेख है।

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

यह ध्यान देने योग्य है कि जब छवि में कोई एक्सएमपी डेटा नहीं होता है, तो यह लटकता है, हालांकि मुझे यकीन है कि इसे आसानी से हल किया जा सकता है जो जानता है कि कैसे। –

+2

मैंने लूप को मारने के लिए एक और \ ब्रेक स्थिति जोड़ा जो फ़ाइल –

+0

में कोई एक्सएमपी तत्व मौजूद नहीं है, मैंने पहले इस खंड को प्रतिलिपि बनाने के लिए इस फ़ंक्शन को दोबारा प्रतिक्रिया दी और उसके बाद ऐसा करने की कोशिश करने के बजाय बफर के खिलाफ पहचान/संशोधन निष्पादित किया भाग –

1

मैं XMP Php Tookit विस्तार विकसित किया है: यह एक PHP5 एडोब XMP टूलकिट के आधार पर विस्तार है, जो jpeg, PSD, पीडीएफ से/लिखने/पार्स XMP metadatas पढ़ने के लिए मुख्य वर्गों और विधि प्रदान है, वीडियो, ऑडियो ... यह एक्सटेंशन जीपीएल लाइसेंस के तहत है। एक नई रिलीज जल्द ही उपलब्ध होगी, php 5.3 (अब केवल php 5.2.x के साथ संगत), और विंडोज और मैकॉक्स पर उपलब्ध होना चाहिए (अब केवल फ्रीब्स और लिनक्स सिस्टम के लिए)। http://xmpphptoolkit.sourceforge.net/

+1

मैंने आपके टूलकिट की कोशिश की, लेकिन मैं इसे संकलित नहीं कर सका :(गायब प्रिंटफ के बारे में शिकायत करना। "Xmp_toolkit/common/XMP_LibUtils.hpp: 179: 62: त्रुटि: इस स्कोप में 'printf' घोषित नहीं किया गया था" – haggi

4

लिनक्स पर एक आसान तरीका exiv2 प्रोग्राम को कॉल करना है, जो डेबियन पर एक नामांकित पैकेज में उपलब्ध है।

$ exiv2 -e X extract image.jpg 

एम्बेडेड एक्सएमपी युक्त image.xmp का उत्पादन करेगा जो अब आपके लिए पार्स है।

1

ब्रायन का समाधान अब तक का सबसे अच्छा था, लेकिन इसमें कुछ समस्याएं थीं इसलिए मैंने इसे सरल बनाने के लिए इसे संशोधित किया, और कुछ कार्यक्षमता को हटा दिया।

तीन मुद्दों मैं उसके समाधान के साथ पाया थे:

ए) हिस्सा निकाला सही तार हम खोज रहे होते हैं में से एक के बीच में पड़ता है, तो इसे प्राप्त नहीं कर सकेंगे। इस मुद्दे का कारण बनने के लिए छोटे हिस्से के आकार अधिक होने की संभावना है।

बी) यदि खंड में शुरुआत और अंत दोनों शामिल हैं, तो यह नहीं मिलेगा। अगर यह अंत में पाया जाता है कि यह देखने के लिए शुरूआत में पाया गया है कि उस खंड को फिर से जांचने के लिए अतिरिक्त विवरण के साथ यह ठीक करना एक आसान तरीका है।

सी) अन्य लूप को तोड़ने के अंत में जोड़ा गया कथन अगर यह नहीं मिलता है कि xmp डेटा का दुष्प्रभाव है कि अगर प्रारंभ तत्व पहले पास पर नहीं मिलता है, तो यह अब और जांच नहीं करेगा मात्रा। यह भी ठीक करने के लिए आसान है, लेकिन पहली समस्या के साथ यह इसके लायक नहीं है।

नीचे मेरा समाधान उतना शक्तिशाली नहीं है, लेकिन यह अधिक मजबूत है। यह केवल एक खंड की जांच करेगा, और उस से डेटा निकाल देगा। यह केवल तभी काम करेगा जब शुरुआत और अंत उस खंड में हों, इसलिए यह सुनिश्चित करने के लिए कि यह हमेशा उस डेटा को कैप्चर करता है, तो खंड आकार को इतना बड़ा होना चाहिए। एडोब फोटोशॉप/लाइटरूम निर्यात की गई फ़ाइलों के साथ अपने अनुभव से, एक्सएमपी डेटा आमतौर पर लगभग 20 केबी से शुरू होता है, और लगभग 45 केबी पर समाप्त होता है। 50k का मेरा हिस्सा आकार मेरी छवियों के लिए अच्छी तरह से काम करता प्रतीत होता है, यदि आप निर्यात पर उस डेटा को कुछ पट्टी करते हैं, तो सीआरएस ब्लॉक जैसे बहुत सी विकास सेटिंग्स हैं, तो यह बहुत कम होगा।

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

मैंने अपडेट किया तर्क के मुद्दों के साथ फिक्स के साथ मेरा कार्य :) :) –

+0

आह, धन्यवाद ब्रायन! मैंने कभी नहीं देखा कि आपने अभी तक जवाब दिया है। मैं आपके संशोधित कोड की समीक्षा करूंगा और देख सकता हूं कि यह मेरे लिए काम करता है (मैं अभी तक इसे पूरी तरह से समझ नहीं पा रहा हूं, मैं प्रोग्रामर नहीं हूं ...) –

+0

ओह, मुझे अब मिल गया .. आप बफर बना रहे हैं एक समय में हिस्सा और हमेशा बफर की जांच। यह सूचीबद्ध सभी समस्याओं को रोकता है। होशियार! धन्यवाद। –

0

उस संक्षिप्त संस्करण के लिए सेबस्टियन बी धन्यवाद :)। यदि आप समस्या से बचना चाहते हैं, तो जब कुछ फ़ाइलों के लिए 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; 
} 
3

मुझे पता है ... यह एक पुराने धागे की तरह है, लेकिन यह मेरे लिए मददगार था जब मैं यह करने के लिए एक तरह से तलाश कर रहे थे, तो मैं समझ यह किसी और के लिए उपयोगी हो सकता है।

मैंने यह मूल समाधान लिया और इसे संशोधित किया ताकि यह उस मामले को संभाल सके जहां टैग को भाग के बीच विभाजित किया गया हो। यह आपके इच्छित हिस्से के रूप में बड़े आकार के छोटे या छोटे होने की अनुमति देता है।

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

0

आप ExifTool उपलब्ध (एक बहुत उपयोगी उपकरण) है और बाहरी कमांड चलाने कर सकते हैं, तो आप इसे JSON प्रारूप में यह उत्पादन XMP डेटा निकालने के लिए विकल्प (-xmp:all) और (-json है उपयोग कर सकते हैं), जिसे आप आसानी से एक PHP ऑब्जेक्ट में परिवर्तित कर सकते हैं:

$command = 'exiftool -g -json -struct -xmp:all "'.$image_path.'"'; 
exec($command, $output, $return_var); 
$metadata = implode('', $output); 
$metadata = json_decode($metadata); 
संबंधित मुद्दे