Goal
With the new compiler, there is now the possibility to create personalized tags.
The integration in SPIP of the jpg EXIF metadata could be done with this. The data stored in the jpg file can be the time the photo has been taken, a copyright or GPS data for example.
All the code presented in this article has to be copied at the end of your file mes_fonctions.php3.
PHP provides functions to access these data. We will then start to write a little wrapper to access them on SPIP documents :
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;
}
- The first function tests if a file can contains EXIF metadata (if it’s a TIFF or JPEG file).
- The second one returns the field we are interested in. It is accessed with an argument giving the section where to look for it and another argument being the name of the field. These arguments are not mandatory and if not provided, a list of tag is returned [1].
The tag
A new tag #EXIF is declared. Here is a first simple version :
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;
}
When this tag will be detected, the function
balise_exif
will be called without any parameters. Hence, it will return a list of all the fields available in the file.
We begin by getting the name of the file attached to the document. For that we need the ID of the document. This is done by the sugar-function champ_sql
that is a shortcut to index_pile
:
index_pile returns the position in the stack of the SQL field $nom_champ. Starting from the nearest loop (given by $idb). If nothing is found, the field is considered to come from the outmost context (the URL or include) that is found in
$Pile[0]
.
If the name references a SQL field, then it is stored in the$boucle
structure to construct the minimal SQL query.
champ_sql
will use $param
to find the nearest loop, the second parameter is the name of the field : 'id_document'
The code for this tag must be run during the construction of the cache. Hence, we return a string containing the code to run later : "(verifier_JPG_TIFF($id_doc))?(tag_exif(generer_url_document($id_doc))):''"
To distinguish between php and pure html, the type of code is also specified by : $params->type = 'php';
Adding parameters
Well, this new tag is not really useful as is. In fact, we would prefer to extract only the field that we are interested in. But we do not really want to create one tag per field [2]. To avoid that, we will user parameters passed to this tag to select the right field.
Since version 1.8 [3], SPIP provides a simple function to retrieve parameters passed to a tag. This function is used in the following code. For earlier method of retrieving parameters, as for #EXPOSER|on,off, see the logo part of the code explained below.
The same method will be used to add two parameters to the #EXIF tag. For example :#EXIF{FILE,FileName} and #EXIF{IFD0,DateTime}
will respectively retrieve the file name field from the File section and the date and time field from the IFD0 section (date and time the photo has been taken).
Here is the new code :
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;
}
The difference with the code returned by the previous version is small. However, the parameters $section and $tag
are retrieved from the filter list (params->fonctions
) to be passed (if found) to the function tag_exif
.
A tag for a thumbnail
In the EXIF metadata from a jpg image, there is — often — a thumbnail of the image [4]. This thumbnail is not of the best quality, but when you are unable to install any image processing plugin in PHP it is a good start.
Lets begin with two new tool functions :
- generer_url_logo_EXIF
look for the file name_file.exif.jpg on the server. If this one is not find, the thumbnail is retrieved from the image and written to disk. The name of the thumbnail file is returned at the end.
- generer_html_logo_EXIF
create the html code for the thumbnail, with alignment, link, etc...
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;
}
This new tag should have the same behavior as the other LOGO tags in SPIP. Therefor the alignment and link filters should be implemented properly.
The principle is the same as before. The list of filters is parsed for one of the following :
- an alignment,
- fichier to return the name of the file,
- a link to put around the thumbnail.
The first part of the code looks at the filters in $p->fonctions.
Then, the code for the link is generated if necessary. As another tag can be given as a link — e.g. [(#LOGO_EXIF|#URL_DOCUMENT)]
— we call the function calculer_champ to compute the content of this tag.
function balise_LOGO_EXIF($p) {
// parse the filters
$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 || means we get a real filter
else if ($nom == '')
$flag_stop = true;
else if (!$flag_stop) {
$lien = $nom;
$flag_stop = true;
}
// after an URL or || or |fichier we only get
// filters (except left...lien...fichier)
else
$filtres[] = $nom;
}
// return the other filters
$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))):''";
//
// Prepare the code for the link
//
// 1. filter |lien
if ($flag_lien_auto AND !$lien) {
$code_lien = "$url_doc";
} else if ($lien) {
// 2. raw link (possible SPIP tags in them : print#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;
}
A filter for the dates
The dates stored in the images are not in the same format as the one used by SPIP. Hence, it is not possible to use the filters on dates from SPIP. Here is a filter to apply before any date filter from SPIP :
function date_EXIF2SPIP($date) {
return preg_replace('/^([0-9]*):([0-9]*):([0-9]*) /','\1-\2-\3 ',$date);
}
Application example
Here is a little loop that list all the documents of an article with some basic informations extracted from the EXIF metatags :
<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>Comment: (#EXIF{COMMENT,0}|sinon{#DESCRIPTIF})</li>]
[<li>ISO:(#EXIF{EXIF,ISOSpeedRatings})</li>]
[<li>Exposure Time: (#EXIF{EXIF,ExposureTime})</li>]
</ul>
</li>
</BOUCLE_jpg>
</ul>
</B_jpg>
Development version
This contrib is managed on spip-zone. You can checkout the last version with :
svn checkout svn://zone.spip.org/spip-zone/_contrib_/_balises_/exif/trunk/
Aucune discussion
Ajouter un commentaire
Avant de faire part d’un problème sur un plugin X, merci de lire ce qui suit :
Merci d’avance pour les personnes qui vous aideront !
Par ailleurs, n’oubliez pas que les contributeurs et contributrices ont une vie en dehors de SPIP.
Suivre les commentaires : |