Baliza #EXIF: recuperar la información almacenada en las imágenes.

En vez de utilizar las balizas por defecto de SPIP para obtener la fecha, la descripción, el título etc. de una imagen JPG, se puede utilizar la información almacenada dentro del fichero gráfico que ha sido creado por las cámaras fotográficas y otros gestores fotográficos.

Objetivo

Con el nuevo compilador, se pueden crear balizas personalizadas. En la lista de los usuarios, hay una demanda para integrar la lectura de los metadatos EXIF en los ficheros jpg. Estos datos permiten obtener información sobre los ficheros jpg (a menudo anotada por las cámaras fotográficas digitales) como la hora de toma de la fotografía, de los comentarios, un copyright, etc.

El código aquí presentado debe colocarse en el fichero mes_fonctions.php3.

php proporciona una función para acceder a estos datos [1]. Se va a comenzar por crear dos pequeños bloques para utilizarlos simplemente en spip:

function verifier_JPG_TIFF($id_document) {
  	if ($id_document > 0) {
		$query = "SELECT id_type FROM spip_documents WHERE id_document = $id_document";
		$result = spip_query($query);
		if ($row = spip_fetch_array($result)) {
			$id_type = $row['id_type'];
		}
	}
	return (($id_type==1) || ($id_type==6));
}

function tag_exif($url_document,$section='',$tag='') {
  $to_ret = '';

  static $last_url;
  static $last_exif;

  if($last_url == $url_document) {
	$exif = $last_exif;
  } else {
	$exif = $last_exif =  @exif_read_data($url_document, 0, true);
	$last_url = $url_document;
  }

  if($exif) {
	if(($section != '') && ($tag != '')) {
	  $to_ret = $exif[$section][$tag];
	} else if($section) {
	  if($exif[$section]) {
		foreach ($exif[$section] as $name => $val) {
		  $to_ret .= "<B>$section.$name</B>: $val<br />\n";
		}
	  }
	} else {
	  foreach ($exif as $key => $section) {
		foreach ($section as $name => $val) {
		  $to_ret .= "<B>$key.$name</B>: $val<br />\n";
		}
	  }
	}
  }
  return $to_ret;
}

-  La primera función verifica si un fichero puede contener etiquetas (tags) EXIF (básicamente, si es un fichero de tipo jpg o tiff)
-  El segundo devuelve un campo con los metadatos. Se accede pasando a la función una sección y la etiqueta de lo que interesa en esta sección. Si no se indica sección y etiqueta, entonces la función devuelve una lista de todas etiquetas que existen en el fichero [2].

La baliza

Por ello, se va a declarar una nueva baliza #EXIF que devuelva los metadatos. Comenzaremos por una versión simple de esta baliza:

function balise_EXIF($params) {

  $id_doc = champ_sql('id_document', $params);

  $params->code = "(verifier_JPG_TIFF($id_doc))?(tag_exif(generer_url_document($id_doc),'$section','$tag')):''";
  $params->type = 'php';  

  return $params;
}

Esta baliza, al llamar tag_exif sin parámetros sección y tag, va a devolver una lista de todos los tags EXIF existentes.

Sobre todo, debemos recuperar el nombre de fichero gráfico, el documento, que nos interesa. Para esto, se necesita el ID del documento. El parámetro $param nos permite recuperar esta información. SPIP proporciona una función para simplificar la tarea: champ_sql devuelve el código que va a darnos el valor de id_document.

En realidad, champ_sql es un atajo para index_pile:

index_pile devuelve la posición en la pila del campo SQL $nom_champ tomando el bucle lo más cerca posible de la cumbre de la pila (indica por $idb). Si no se encuentra nada, se considera que eso debe proceder del contexto (por la URL o el include) que se volvió a copiar en Pile [0] (una prueba de refinamiento desembocó en un bug vicioso). Si esto hace referencia a un campo SQL, se memoriza en la estructura $boucles con el fin de construir una petición SQL mínima (en lugar de hacer un brutal “SELECT *”)

champ_sql va a usar $param para deducir “el bucle lo más cercano posible”, mientras que el segundo parámetro especifica que se quiere recuperar el campo 'id_document'

El código que se quiere ejecutar para esta baliza no debe lanzado ahora, sino en el caché. Por ello es necesario devolver una cadena que contenga el código que se quiere ejecutar: "(verifier_JPG_TIFF($id_doc))?(tag_exif(generer_url_document($id_doc))):''"

También es necesario especificar a spip que devuelve código php que debe ejecutarse - contrariamente al código HTML en bruto - poniendo: $params->type = 'php';

Pasar los parámetros

Bien, queda claro que esta baliza no es muy interesante. En general, no se necesita toda la información, sino una sola cada vez. En vez de crear un montón de balizas para cada uno de los campos EXIF - que no siempre son fijos -, se va a pasar, como parámetros a la baliza, la sección y la etiqueta EXIF que se quiere recuperar.

Desde la versión 1.8 [3], SPIP proporciona una función simple para recuperar parámetros pasados a una baliza. Esta función se utiliza en el código siguiente, para un método más anticuado (del tipo #EXPOSER|on, off), habrá que inspirarse en el código LOGO explicado más abajo.

Vamos a utilizar el mismo método para pasar los dos parámetros a nuestra baliza EXIF, con lo que entonces se podrá hacer: #EXIF{FILE,FileName} o #EXIF{IFD0,DateTime} por ejemplo.

he aquí el nuevo código:

function balise_EXIF($params) {

  list($section,$tag) = split(',',param_balise($params));

  $section = addslashes($section);
  $tag = addslashes($tag);
  
  $id_doc = champ_sql('id_document', $params);

  $params->code = "(verifier_JPG_TIFF($id_doc))?(tag_exif(generer_url_document($id_doc),'$section','$tag')):''";
  $params->type = 'php';
  
  return $params;
}

No hay mucha diferencia en el código devuelto. Por el contrario, se va a recuperar, si se indican, los parámetros $section et $tag para pasarlos a tag_exif.

Se recorre la lista de filtros en params->fonctions para encontrar el que corresponde a los parámetros. A continuación se recupera este filtro de la lista y se extraen los parámetros que corresponde al nombre del filtro.

En el encabezamiento EXIF de una imagen jpeg, está presente, a menudo, una miniatura de la imagen contenida en el fichero. Esta miniatura es utilizada por las cámaras fotográficas para mostrar rápidamente la fotografía sobre su pantalla. Obviamente, esta miniatura no es de gran calidad, pero es una buena ocasión de ver cómo hacer una baliza LOGO. Además, si no se tiene ni GD, ni imagemagick sobre el servidor, esto se puede ser útil :)

Comenzaremos por dos pequeñas funciones:
-  generer_url_logo_EXIF busca el logo exif - contenido en el fichero nombre_fichero.exif.jpg si ya ha sido creado, si no, extrae la etiqueta para almacenarla en un fichero en el servidor. En los dos casos, devuelve el camino hacia este fichero.
-  generer_html_logo_EXIF genera el código HTML del logo, con un vínculo o no, y una alineación o no.

function generer_url_logo_EXIF($filename) {

  $thumbname = substr($filename,0,-4).".exif.jpg";

  if(file_exists($thumbname)) {
	return $thumbname;
  }

  $image = exif_thumbnail($filename);
  if ($image!==false) {
	$handle = fopen ($thumbname, 'a');
	fwrite($handle, $image);
	fclose($handle);
	return $thumbname;
  }
  
  return '';

}

function generer_html_logo_EXIF($url_doc,$code_lien='',$align='') {
   if(!$url_doc)
            return '';
  if($code_lien) {
	$code = "<a href=\"$code_lien\">";
  }

  $code .= "<IMG src=\"$url_doc\"".(($align)?"align=$align":'').">";
  if($code_lien) {
	$code .= "</a>";
  }

  return $code;
}

Veamos ahora cómo hacer para crear un LOGO. El mayor problema es realmente la gestión de los filtros especiales de alineación, etc.

El principio es el mismo que para el código anterior. Se observa la lista de las funciones para ver lo que se encuentra. Se pueden encontrar una indicación de alineación, o un fichero (para indicar la url del fichero), o un vínculo a colocar sobre el logo.

La primera parte del código estudia los filtros contenidos en la tabla $p->fonctions.
A continuación, se observa si se tiene que generar código para el vínculo, lo cual tiene un gran interés: se puede pasar como vínculo, otra baliza (por ejemplo: [(#LOGO_EXIF|#URL_DOCUMENT)]).

Se llama entonces a la función calculer_champ, que es la función básica que calcula todas las balizas para SPIP, sobre la potencial baliza.

function balise_LOGO_EXIF($p) {

  // analyser les filtres
  $flag_fichier = false;
  $filtres = '';
  if (is_array($p->fonctions)) {
	foreach($p->fonctions as $nom) {
	  if (ereg('^(left|right|center|top|bottom)$', $nom))
		$align = $nom;
	  else if ($nom == 'lien') {
		$flag_lien_auto = true;
		$flag_stop = true;
	  }
	  else if ($nom == 'fichier') {
		$flag_fichier = true;
		$flag_stop = true;
	  }
	  // double || signifie "on passe aux filtres"
	  else if ($nom == '')
		$flag_stop = true;
	  else if (!$flag_stop) {
		$lien = $nom;
		$flag_stop = true;
	  }
	  // apres un URL ou || ou |fichier ce sont
	  // des filtres (sauf left...lien...fichier)
	  else
		$filtres[] = $nom;
	}
	// recuperer les autres filtres s'il y en a
	$p->fonctions = $filtres;
  }

  $id_doc = champ_sql('id_document', $p);
  $code_lien = '';

  $url_doc = "(verifier_JPG_TIFF($id_doc))?(generer_url_logo_EXIF(generer_url_document($id_doc))):''";

  //
	// Preparer le code du lien
	//
	// 1. filtre |lien
  if ($flag_lien_auto AND !$lien) {
	 $code_lien = "$url_doc";
  } else if ($lien) {
		// 2. lien indique en clair (avec des balises : imprimer#ID_ARTICLE.html)

		$code_lien = "'".texte_script(trim($lien))."'";
		while (ereg("^([^#]*)#([A-Za-z_]+)(.*)$", $code_lien, $match)) {
			$c = calculer_champ(array(), $match[2], $p->id_boucle, $p->boucles, $p->id_mere);
			$code_lien = str_replace('#'.$match[2], "'.".$c.".'", $code_lien);
		}
		// supprimer les '' disgracieux
		$code_lien = ereg_replace("^''\.|\.''$", "", $code_lien);
	}

  if($flag_fichier) {
	$p->code = "ereg_replace(\"^IMG/\",\"\",$url_doc)";
	$p->type = 'php';
	return $p;
  }

  if(!$code_lien)
	$code_lien = "''";

  
  if(!$align)
	$align = "''";

  $p->code = "generer_html_logo_EXIF($url_doc,$code_lien,$align)";
  $p->type = 'php';
  return $p;
}

Un filtro para las fechas

Las fechas almacenadas en las imágenes están bajo un formato diferente al utilizado por SPIP, así que no se pueden utilizar directamente los filtros proporcionados por SPIP. He aquí un filtro que debe aplicarse antes de los filtros de fecha SPIP para que todo vaya bien:

function date_EXIF2SPIP($date) {
  return preg_replace('/^([0-9]*):([0-9]*):([0-9]*) /','\1-\2-\3 ',$date);
}

Ejemplo de uso

He aquí un bucle que indica, en una lista, los documentos de un artículo, con una serie de informaciones contenidas en los campos EXIF:

<B_jpg>
<ul>
<BOUCLE_jpg(DOCUMENTS) {id_article} {mode=document} {extension=jpg}>
<li>
#LOGO_DOCUMENT
<ul>
[<li>Model: (#EXIF{IFD0,Make})
[(#EXIF{IFD0,Model})]</li>]
[<li>Date: (#EXIF{EXIF,DateTimeOriginal}|date_EXIF2SPIP|sinon{#DATE}|affdate)
[(#EXIF{EXIF,DateTimeOriginal}|date_EXIF2SPIP|sinon{#DATE}|affdate{H\hm})]</li>]
[<li>Commentaire: (#EXIF{COMMENT,0}|sinon{#DESCRIPTIF})</li>]

[<li>ISO:(#EXIF{EXIF,ISOSpeedRatings})</li>]
[<li>Temps d'exposition: (#EXIF{EXIF,ExposureTime})</li>]
</ul>
</li>
</BOUCLE_jpg>
</ul>
</B_jpg>

Versión de desarrollo

Esta contribución se administra desde spip-zone, se puede recuperar la última versión de desarrollo gracias a:

svn checkout svn://zone.spip.org/spip-zone/_contrib_/_balises_/exif/trunk/

Notas

[1(en la librería exif.php, o php_exif.dll Nota: verificar que está activa dicha función en php.ini, quitando el comentario «;» en la línea «extensions=php_exif.dll», para el caso de algunos sistemas WAMP)

[2Hay un caché, en memoria, para no releer los datos EXIF más que una vez, la primera, para el caso de que se accedan consecutivamente a datos del mismo documento

[3versión cvs de 17 Dic. 2004

Dernière modification de cette page le 26 de julio de 2006

Discussion

Aucune discussion

Comentar este artículo

¿Quién es usted?
  • [Conectarse]

Para mostrar su avatar con su mensaje, guárdelo en gravatar.com (gratuit et indolore) y no olvide indicar su dirección de correo electrónico aquí.

Añada aquí su comentario

Este formulario acepta los atajos de SPIP, [->url] {{negrita}} {cursiva} <quote> <code> y el código HTML. Para crear párrafos, deje simplemente una línea vacía entre ellos.

Añadir un documento

Seguir los comentarios: RSS 2.0 | Atom