Nasıl PHP ile bir JPG XMP verileri okuyabilir?

5 Cevap php

PHP EXIF ​​ve IPTC meta okumak için destek inşa etti, ama ben XMP okumak için herhangi bir yol bulamıyorum?

5 Cevap

XMP verileri tam anlamıyla görüntü dosyası içine gömülü yani resim dosyasının kendisini PHP'nin dize fonksiyonları ile elde edebilirsiniz.

Aşağıdaki (I SimpleXML kullanıyorum ama her XML API ya da basit ve zekice bir dize ayrıştırma size eşit sonuçlar verebilir) Bu yordam gösterir:

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

Sadece iki Açıklamalar:

  • XMP, XML ad alanları yoğun kullanımını yapar, bu yüzden bazı XML araçları ile XMP verileri ayrıştırma zaman o bir göz tutmak gerekir.
  • görüntü dosyalarının olası boyutu göz önüne alındığında, belki de file_get_contents() as this function loads the whole image into memory. Using fopen() to open a file stream resource and checking chunks of data for the key-sequences <x:xmpmeta ve </x:xmpmeta> önemli ölçüde azaltacaktır kullanmak mümkün olacak değil bellek izi.

Bu XMP verileri ayrıştırmak için nasıl Google arama yaparken en iyi sonuç gibi görünüyor çünkü ben sadece bu kadar zaman sonra bu yanıtlarken ediyorum. Ben kodu birkaç kez kullanılan bu neredeyse özdeş parçacık gördüm ve bellek korkunç bir israf var. İşte fopen bir örnektir () yöntemi Stefan onun Örneğin sonra bahseder.

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

Linux üzerinde basit bir yolu debian üzerinde bir ada paketinde mevcut Exiv2 programı, çağırmaktır.

$ exiv2 -e X extract image.jpg

artık senin ayrıştırmak için gömülü XMP içeren image.xmp üretecek.

Bryan'ın çözüm şimdiye kadar en iyi biriydi, ama o kadar ben bunu basitleştirmek için değiştirilmiş ve bazı işlevler çıkarıp birkaç sorunlar vardı.

Ben onun çözümü ile bulduğu üç konu vardı:

Ekstre yığın doğru biz aradığınız dizelerinden biri arasında düşerse A), onu bulamazsınız. Küçük parça boyutları bu konuyu neden daha olasıdır.

Yığın başlangıç ​​ve sonunu hem içeriyorsa B), onu bulamazsınız. Bu deyim başlangıç ​​bitiş da bulunursa görmek için bulunan öbek yeniden kontrol eğer bir ekstra ile düzeltmek için kolay bir tanesidir.

C) else deyimi xmp veri eleman başlangıç ​​ilk geçişte bulunmazsa eğer, artık parçalarını kontrol olmayacak bir yan etkisi vardır bulmazsa iken döngü kırmak için sonuna eklenir. Bu da düzeltilmesi kolay muhtemeldir, ama ilk sorunu ile buna değer değil.

Aşağıda benim çözüm gibi güçlü değil, ama daha sağlamdır. Sadece bir yığın kontrol ve veri ayıklamak olacaktır. Başlangıç ​​ve bitiş o parça ise sadece çalışır, bu yüzden bir yığın büyüklüğü her zaman verilerinizi emin yakalar sağlamak için yeterince büyük olması gerekir. Adobe Photoshop / Lightroom ile benim deneyim ihraç dosyaları itibaren, xmp veriler genellikle 20KB civarında başlar ve 45KB civarında biter. 50k Benim parça boyutu çekimlerim için güzel iş gibi görünüyor, bu tür ayarları geliştirmek bir yeri vardır CRS blok olarak ihracat, bu verilerin bazı şerit halinde çok daha az olacaktır.

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

Bu kısaltılmış versiyon :) için size Sebastien B. ederiz. Eğer parça_boyutu bazı dosyalar için sadece çok küçük olduğunda, sorunu önlemek istiyorsanız sadece özyineleme ekleyin.

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