source: extensions/Tags2File/db_export_image_metadata_class.php @ 31810

Last change on this file since 31810 was 28256, checked in by plg, 10 years ago

compatibility Piwigo 2.6

File size: 11.4 KB
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | Plugin Name : Export Image metadata                                   |
4// | Plugin Version : 0.1                                                  |
5// | Plugin Author: Eric                                                   |
6// | Plugin Description :                                                  |
7// | Ce module est base sur le module existant pour le telechargement,     |
8// | cette version permet le telechargement sur plusieurs pages.           |
9// +-----------------------------------------------------------------------+
10// | This program is free software; you can redistribute it and/or modify  |
11// | it under the terms of the GNU General Public License as published by  |
12// | the Free Software Foundation                                          |
13// |                                                                       |
14// | This program is distributed in the hope that it will be useful, but   |
15// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
16// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
17// | General Public License for more details.                              |
18// |                                                                       |
19// | You should have received a copy of the GNU General Public License     |
20// | along with this program; if not, write to the Free Software           |
21// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
22// | USA.               '                                                  |
23// +-----------------------------------------------------------------------+
24
25class ExportImageMetadata
26{
27  private $use_exiftool, $use_exiv2, $use_whole_desc, $isMSWin, $useUTF8_txt, $useUTF8_cp, $eol;
28  private $exiftoolDefaultCmd, $exiv2DefaultCmd, $nbfiles;
29  private $isTest = false, $test_img_id; 
30
31  function ExportImageMetadata($use_exiftool_p, $use_exiv2_p, $use_whole_desc_p, $useUTF8_txt)
32  {
33        $this->use_exiftool = $use_exiftool_p;
34        $this->use_exiv2 = $use_exiv2_p;
35        $this->use_whole_desc = $use_whole_desc_p;
36        $this->isMSWin = stristr(php_uname(), 'windows');
37        $this->eol = $this->isMSWin ? "\r\n" : "\n";
38        $this->useUTF8_txt = $useUTF8_txt; // encoding of the batch file
39        $this->useUTF8_cp = false; // pb under windows xp for the author with this code page...
40  }
41
42  public function set_test_mode($test_mode, $test_img_id)
43  {
44          $this->isTest = $test_mode;
45          $this->test_img_id = $test_img_id;
46  }
47
48  public function set_tool_pathes($exiftoolPath, $exiv2path)
49  {
50        if ($this->use_exiftool)
51        {
52                $this->exiftoolDefaultCmd = $this->init_exif_tool_cmd_name($exiftoolPath, "exiftool");
53                if ($this->useUTF8_txt) {
54                        $this->exiftoolDefaultCmd .= " -IPTC:CodedCharacterSet=UTF8";
55                }
56                else {
57                        $this->exiftoolDefaultCmd .= " -L"; // convert to Latin1 internaly, see FAQ #10 at http://www.sno.phy.queensu.ca/~phil/exiftool/faq.html
58                }
59                $this->exiftoolDefaultCmd .= " -overwrite_original"; // no backup!
60        }
61        if ($this->use_exiv2)
62        {
63                $this->exiv2DefaultCmd = $this->init_exif_tool_cmd_name($exiv2path, "exiv2");
64                $this->exiv2DefaultCmd .= " -k"; // conserve original date
65        }
66  }
67
68  private function init_exif_tool_cmd_name($toolPath, $toolName)
69  {
70        return (file_exists($toolPath) && strpos(strtolower($toolPath), strtolower($toolName)) !== false) ? "\"".realpath($toolPath)."\"" : $toolName;
71  }
72
73  public function image_properties_to_file($destPath)
74  {             
75        $exiftoolScript = ""; $exiv2Script = "";
76        if ($this->use_exiftool)
77        {
78                $exiftoolScript = $destPath ."/writeTagsToIptcWithExifTool.cmd";
79                $fp_exiftool = $this->open_create_file($exiftoolScript);
80        }
81        if ($this->use_exiv2)
82        {
83                $exiv2Script = $destPath ."/writeTagsToIptcWithExiv2.cmd";
84                $fp_exiv2 = $this->open_create_file($exiv2Script);
85        }
86
87        $datas = $this->get_image_properties();
88        $this->nbfiles = 0;
89
90        while ($row = pwg_db_fetch_row($datas)) // row to avoid conflict with name
91        {               
92                $image_path = $row[5];
93               
94                if ($this->isTest || file_exists($image_path))
95                {
96                        if ($this->use_exiftool)
97                        {
98                                $cmd = $this->convert_row_to_file_exiftool($row);
99                                $this->write_exifCmd($cmd, $image_path, $fp_exiftool);
100                        }
101                        if ($this->use_exiv2)
102                        {
103                                $cmd = $this->convert_row_to_file_exiv2($row);
104                                $this->write_exifCmd($cmd, $image_path, $fp_exiv2);
105                        }
106                }
107        }
108
109        if ($this->use_exiftool && isset($fp_exiftool))
110        {
111                $this->close_file($fp_exiftool);
112        }
113        if ($this->use_exiv2 && isset($fp_exiv2))
114        {
115                $this->close_file($fp_exiv2);
116        }
117        if ($this->use_exiftool && $this->use_exiv2)
118        {
119                $this->nbfiles = $this->nbfiles / 2; // each picture counted twice
120        }
121
122        return $this->nbfiles; // incremented by write_exifCmd
123  }
124
125  // IO function
126  private function open_create_file($destPath)
127  {
128        // prepare output file
129        if(file_exists($destPath))
130        {
131                if (!$this->isMSWin) chmod($destPath, 0777);
132                unlink($destPath);
133        }
134        touch($destPath);
135        $fp = fopen($destPath,"w"); 
136        if ($this->isMSWin && isset($fp) )
137        {
138                // the default command prompt is stupid and won't display the correct character set, so we need to change the code page
139                if ($this->useUTF8_cp)
140                { fwrite($fp, "chcp 65001".$this->eol); } // UTF-8, prevent cmd to work, see perhaps http://blogs.msdn.com/michkap/archive/2006/03/06/544251.aspx
141                else
142                { fwrite($fp, "chcp 1252".$this->eol); }  // default Windows Latin1             
143        }
144        return $fp;
145  }
146
147  private function close_file($fp)
148  {
149        if (isset($fp))
150        {
151                if ($this->nbfiles > 0)
152                {
153                        fwrite($fp, $this->eol);
154                }
155                fclose($fp);
156        }
157  }
158
159  // prepare data for script
160  private function convert_row_to_file_exiv2($row)
161  {
162        if (!$this->use_exiv2)
163                return "exiv2 shall not be used";
164        $name =  $this->cutString($this->explode_description($this->decode_html_string_to_unicode($row[0], true)), 256);
165        $description = $this->cutString($this->explode_description($this->decode_html_string_to_unicode($row[1], true)), 2000);
166        $author = $this->cutString($this->decode_html_string_to_unicode($row[2], true), 32);
167        //$date_creation = $this->decode_html_string_to_unicode($row[3], true);
168        $tags = $this->cutString($this->decode_html_string_to_unicode($row[4], true), 64);
169        $image_path = $row[5];
170       
171        $exiv2Cmd = $this->exiv2DefaultCmd;
172
173        if (strlen($name) > 0)
174        {
175                $exiv2Cmd .= " -M\"set Iptc.Application2.Headline ".$name."\"";
176                $exiv2Cmd .= " -M\"set Iptc.Application2.ObjectName ". $this->cutString($name, 64)."\"";
177        }
178        if (strlen($description) > 0)
179        {                                                       
180                $exiv2Cmd .= " -M\"set Iptc.Application2.Caption ".$description."\"";
181        }
182        if (strlen($author) > 0)
183        {
184                $exiv2Cmd .= " -M\"set Iptc.Application2.Writer ".$author."\"";
185        }       
186        if (strlen($tags) > 0)                 
187        {
188                $exiv2Cmd .= " -M\"add Iptc.Application2.Keywords ".$tags."\"";
189        }
190        return $exiv2Cmd;
191  }
192
193  private function convert_row_to_file_exiftool($row)
194  {
195        if (!$this->use_exiftool)
196                return "exiftool shall not be used";
197        $name = $this->cutString($this->explode_description($this->decode_html_string_to_unicode($row[0], false)), 256);
198        $description = $this->cutString($this->explode_description($this->decode_html_string_to_unicode($row[1], false)), 2000);
199        $author = $this->cutString($this->decode_html_string_to_unicode($row[2], false), 32);
200        //$date_creation = $this->decode_html_string_to_unicode($row[3], false);
201        $tags = $this->cutString($this->decode_html_string_to_unicode($row[4], false), 64);
202
203        $exiftoolCmd = $this->exiftoolDefaultCmd;       
204
205        // exiftool allow to set a field only if the field in the original file is empty
206        // as explained here: http://www.cpanforum.com/posts/10765
207
208        if (strlen($name) > 0)
209        {
210                $exiftoolCmd .= " -IPTC:Headline-= -IPTC:Headline=\"".$name."\"";
211                $exiftoolCmd .= " -IPTC:ObjectName-= -IPTC:ObjectName=\"".$this->cutString($name, 64)."\"";
212        }
213        if (strlen($description) > 0)
214        {                                                       
215                $exiftoolCmd .= " -IPTC:Caption-Abstract-= -IPTC:Caption-Abstract=\"".$description."\"";
216        }
217        if (strlen($author) > 0)
218        {
219                $exiftoolCmd .= " -IPTC:Writer-Editor-= -IPTC:Writer-Editor=\"".$author."\"";
220        }       
221        if (strlen($tags) > 0)                 
222        { // Keywords are overwritten, since they allow multiple entries, with "-=", given keywords will be added to the existing
223                $exiftoolCmd .= " -IPTC:Keywords=\"".$tags."\"";
224        }
225        return $exiftoolCmd;   
226  }
227
228  private function write_exifCmd($exifCmd, $image_path, $fp)
229  {
230        $exifCmdN = $exifCmd ." ";
231        $exifCmdN .= $this->isTest ? $image_path : realpath(PHPWG_ROOT_PATH.$image_path);
232        $writeOK = fwrite($fp, $exifCmdN.$this->eol) !== FALSE;
233        if ($writeOK)  $this->nbfiles++;
234
235  }
236
237  // html function
238  private function decode_html_string_to_unicode($string, $forceANSI) 
239  {
240        if (isset($string) && strlen($string) > 0)
241        {
242                $txt_encoding = ($this->useUTF8_txt && !$forceANSI) ? 'UTF-8' : 'ISO-8859-15';
243                $string = html_entity_decode(trim($string), ENT_QUOTES, $txt_encoding);
244                $string = stripslashes($string);
245        }
246        else $string = "";
247        return($string);
248  } 
249
250    // remove end of line char from desc and keep if required only the current language
251  private function explode_description($description)
252  {
253        if (!$this->use_whole_desc)
254        {
255                $description = $this->get_user_language_desc($description);     
256        }
257        return str_replace( array( '<br>', '<br />', "\n", "\r" ), array('', '', '', ''), $description );
258  }
259
260  private function cutString($description, $maxLen)
261  {
262        if (strlen($description) > $maxLen)
263        {
264                $description = substr($description, 0, $maxLen);
265        }
266        return $description;
267  }
268 
269  // Traite les balises [lang=xx], copy&paste from ExtendedDescription plugin, main.inc.php
270  private function get_user_language_desc($desc)
271  {
272        global $user;
273 
274        $user_lang = substr($user['language'], 0, 2);
275
276        if (!substr_count(strtolower($desc), '[lang=' . $user_lang . ']'))
277        {
278                $user_lang = 'default';
279        }
280 
281        if (substr_count(strtolower($desc), '[lang=' . $user_lang . ']'))
282        {
283                // la balise avec la langue de l'utilisateur a été trouvée
284                $patterns[] = '#(^|\[/lang\])(.*?)(\[lang=(' . $user_lang . '|all)\]|$)#is';
285                $replacements[] = '';
286                $patterns[] = '#\[lang=(' . $user_lang . '|all)\](.*?)\[/lang\]#is';
287                $replacements[] = '\\1';
288        }
289        else
290        {
291                // la balise avec la langue de l'utilisateur n'a pas été trouvée
292                // On prend tout ce qui est hors balise
293                $patterns[] = '#\[lang=all\](.*?)\[/lang\]#is';
294                $replacements[] = '\\1';
295                $patterns[] = '#\[lang=.*\].*\[/lang\]#is';
296                $replacements[] = '';
297        }
298        return preg_replace($patterns, $replacements, $desc);
299  }
300
301  // data access
302  private function get_image_properties() 
303  {
304        $query_path = $this->isTest ? 'img.file' : 'img.path';
305        $query_restriction = $this->isTest ? 'AND (img.id = '.$this->test_img_id.'))' : ')';
306 
307        // get direct properties and tags, even if no tags, with either name, comment or tags not null
308        // restritive query with image.ID for tests with copied images with file instead of path
309        $img_query = '
310SELECT
311    img.name,
312    img.comment,
313    img.author,
314    img.date_creation,
315    GROUP_CONCAT(tags.name),
316    '.$query_path.'
317  FROM '.IMAGES_TABLE.' AS img
318    LEFT OUTER JOIN '.IMAGE_TAG_TABLE.' AS img_tag ON img_tag.image_id = img.id
319    LEFT OUTER JOIN '.TAGS_TABLE.' AS tags ON tags.id = img_tag.tag_id
320  WHERE ( ( LENGTH(img.name) > 0 OR LENGTH(img.comment) > 0 OR LENGTH(img.author) > 0 OR LENGTH(tags.name) > 0 ) '.$query_restriction.'
321  GROUP BY img.id, img.name, img.comment, img.author, '.$query_path.'
322  ORDER BY img.id ASC
323;';
324       
325        return pwg_query($img_query);
326  }
327}
Note: See TracBrowser for help on using the repository browser.