Comment puis-je lire les données XMP d'un JPG avec PHP?

voix
14

PHP a un support intégré pour la lecture de métadonnées EXIF ​​et IPTC, mais je ne peux pas trouver un moyen de lire XMP?

Créé 16/10/2009 à 14:50
source utilisateur
Dans d'autres langues...                            


8 réponses

voix
21

les données XMP est littéralement intégré dans le fichier d'image peut donc extraire avec string-fonctions PHP à partir du fichier image elle-même.

Ce qui suit illustre cette procédure (j'utilise SimpleXML , mais tous les autres API XML ou même chaîne simple de l' analyse syntaxique et intelligent peut vous donner des résultats égaux):

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

Juste deux remarques:

  • XMP fait un usage intensif des espaces de noms XML, de sorte que vous devrez garder un oeil sur ce que lors de l'analyse des données XMP avec des outils XML.
  • compte tenu de la taille possible des fichiers d'image, vous ne serez pas peut - être en mesure d'utiliser file_get_contents()comme cette fonction charge toute l' image en mémoire. L' utilisation fopen()d'ouvrir une ressource de flux de fichiers et la vérification des blocs de données pour la clé-séquences <x:xmpmetaet </x:xmpmeta>réduira considérablement l'empreinte mémoire.
Créé 16/10/2009 à 15:15
source utilisateur

voix
11

Je ne répondre à cela après tant de temps, car cela semble être le meilleur résultat lors de la recherche Google pour savoir comment analyser les données XMP. Je l'ai vu cet extrait presque identique utilisé dans le code plusieurs fois et il est un terrible gaspillage de mémoire. Voici un exemple de la méthode fopen () Stefan mentionne son exemple.

<?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;
}
Créé 14/05/2010 à 21:13
source utilisateur

voix
4

Une façon simple sur linux est d'appeler le programme exiv2, disponible dans un paquet éponyme sur debian.

$ exiv2 -e X extract image.jpg

produira image.xmp contenant XMP intégré qui vous appartient maintenant à analyser.

Créé 26/01/2011 à 10:40
source utilisateur

voix
3

Je sais ... ce genre est d'un vieux fil, mais il m'a été utile quand je cherchais un moyen de le faire, alors je me suis dit que cela pourrait être utile à quelqu'un d'autre.

J'ai pris cette solution de base et modifia il gère le cas où la balise est divisée entre les morceaux. Cela permet à la taille de bloc soit aussi grand ou petit que vous le souhaitez.

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

Créé 14/11/2014 à 15:50
source utilisateur

voix
1

La solution de Bryan était le meilleur à ce jour, mais il y avait quelques problèmes si je l'ai modifié pour simplifier et supprimer certaines fonctionnalités.

Il y avait trois questions que j'ai trouvé sa solution:

A) Si le morceau extrait tombe juste entre l'une des chaînes que nous recherchons, il ne le trouvera pas. La petite taille de chunk sont plus susceptibles de provoquer ce problème.

B) Si le morceau contient à la fois le début et la fin, il ne le trouvera pas. Ceci est facile à fixer avec un supplément instruction if pour revérifier le morceau que le début se trouve pour voir si la fin est également trouvé.

C) L'instruction else ajoutée à la fin de briser la boucle while si elle ne trouve pas les données XMP a un effet secondaire que si l'élément de départ ne se trouve pas au premier passage, il ne vérifie pas plus gros morceaux. Il est probable que facile à corriger aussi, mais avec la première question, il est pas la peine.

Ma solution ci-dessous est pas aussi puissant, mais il est plus robuste. Il ne vérifie un morceau, et extraire les données de cela. Il ne fonctionnera que si le début et la fin sont dans ce morceau, de sorte que la taille des blocs doit être suffisamment grande pour qu'il capte toujours ces données. D'après mon expérience avec Adobe Photoshop / Lightroom fichiers exportés, les données XMP commence généralement à environ 20kB, et se termine à environ 45kB. Ma taille de bloc de 50k semble fonctionner très bien pour mes images, il serait beaucoup moins si vous dépouillez certaines de ces données à l'exportation, telles que le bloc de CRS qui a beaucoup de paramètres de développement.

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;
}
Créé 15/05/2012 à 17:21
source utilisateur

voix
1

J'ai developpé l'extension Xmp Php Tookit: il est une extension php5 basée sur la boîte à outils XMP d' Adobe, qui fournissent les principales classes et méthode pour lecture / écriture / parse métadatas xmp de jpeg, psd, pdf, vidéo, audio ... Cette extension est sous licence gpl. Une nouvelle version sera bientôt disponible, pour php 5.3 (maintenant compatible uniquement avec php 5.2.x), et devrait être disponible sur Windows et MacOSX (désormais uniquement pour les systèmes FreeBSD et Linux). http://xmpphptoolkit.sourceforge.net/

Créé 08/06/2010 à 17:03
source utilisateur

voix
0

Si vous avez ExifTool disponible (un outil très utile) et peut exécuter des commandes externes, vous pouvez l' utiliser est l' option pour extraire des données XMP ( -xmp:all) et la sortie au format JSON ( -json), que vous pouvez ensuite facilement convertir à un objet PHP:

$command = 'exiftool -g -json -struct -xmp:all "'.$image_path.'"';
exec($command, $output, $return_var);
$metadata = implode('', $output);
$metadata = json_decode($metadata);
Créé 17/11/2014 à 16:09
source utilisateur

voix
0

Merci Sébastien B. pour cette version raccourcie :). Si vous voulez éviter le problème, quand chunk_size est tout simplement trop petit pour certains fichiers, il suffit d'ajouter récursivité.

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;
}
Créé 28/01/2014 à 09:51
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more