source: extensions/exif_view/main.inc.php @ 27097

Last change on this file since 27097 was 23534, checked in by plg, 11 years ago

ability to display GPSLatitude and GPSLongitude (code copied from rv_gmaps plugin)

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Author Date Id Revision
File size: 12.7 KB
Line 
1<?php /*
2Plugin Name: Exif View
3Version: auto
4Description: Converts EXIF values to human readable localized values. Corresponds to EXIF specification 2.2, details in http://www.exif.org. Easily extensible.
5Plugin URI: http://piwigo.org/ext/extension_view.php?eid=155
6Author: Martin Javorek
7Author URI: mailto:maple@seznam.cz&subject=PWG%20EXIF%20View
8*/
9
10/*
11-------------------------------------------------------------------------------
12Change log:
13
140.2, 23th August 2007
15- exposurue bias fix, date time original formatting
16
170.1, 1st August 2007
18- initial version
19
20
21-------------------------------------------------------------------------------
22
23Extend your configuration in /include/config.local.inc.php file - example:
24
25$conf['show_exif_fields'] = array(
26  'Make',
27  'Model',
28  'ExifVersion',
29  'Software',
30  'DateTimeOriginal',
31  'FNumber',
32  'ExposureBiasValue',
33  'FILE;FileSize',
34  'ExposureTime',
35  'Flash',
36  'ISOSpeedRatings',
37  'FocalLength',
38  'FocalLengthIn35mmFilm',
39  'WhiteBalance',
40  'ExposureMode',
41  'MeteringMode',
42  'ExposureProgram',
43  'LightSource',
44  'Contrast',
45  'Saturation',
46  'Sharpness',
47  );
48
49*/
50
51add_event_handler('format_exif_data', 'exif_translation' );
52
53/**
54 * Date and time format.
55 * @see http://cz2.php.net/manual/en/function.date.php
56 */
57define('DATE_TIME_FORMAT', 'H:i:s j.n.Y');
58
59/**
60 * Truncates number.
61 *
62 * @param num number
63 * @param digits number of digits, default 0
64 */
65function truncate($num, $digits = 0) {
66    $shift = pow(10 , $digits);
67    return ((floor($num * $shift)) / $shift);
68}
69
70/**
71 * Format date.
72 *
73 * @param date given EXIF date
74 */
75function formatDate($date) {
76        $dateTime = explode(' ', $date);
77        $d = explode(':', $dateTime[0]);
78        $t = explode(':', $dateTime[1]);
79        // beware of american date format for mktime, it accepts date in M/D/Y ;-)
80        return date(DATE_TIME_FORMAT, mktime($t[0], $t[1], $t[2], $d[1], $d[2], $d[0]));
81}
82
83/**
84 * GPS function stolen from plugin rv_gmaps
85 */
86function ev_parse_fract( $f )
87{
88  $nd = explode( '/', $f );
89  return $nd[0]/$nd[1];
90}
91
92function ev_parse_lat_lon( $arr )
93{
94  $v=0;
95  $v += ev_parse_fract( $arr[0] );
96  $v += ev_parse_fract( $arr[1] )/60;
97  $v += ev_parse_fract( $arr[2] )/3600;
98  return $v;
99}
100
101function ev_exif_to_lat_lon( $exif )
102{
103  $exif = array_intersect_key( $exif, array_flip( array('GPSLatitudeRef', 'GPSLatitude', 'GPSLongitudeRef', 'GPSLongitude') ) );
104  if ( count($exif)!=4 )
105    return '';
106  if ( !in_array($exif['GPSLatitudeRef'], array('S', 'N') ) )
107    return 'GPSLatitudeRef not S or N';
108  if ( !in_array($exif['GPSLongitudeRef'], array('W', 'E') ) )
109    return 'GPSLongitudeRef not W or E';
110  if (!is_array($exif['GPSLatitude']) or !is_array($exif['GPSLongitude']) )
111    return 'GPSLatitude and GPSLongitude are not arrays';
112 
113  $lat = ev_parse_lat_lon( $exif['GPSLatitude'] );
114  if ( $exif['GPSLatitudeRef']=='S' )
115    $lat = -$lat;
116  $lon = ev_parse_lat_lon( $exif['GPSLongitude'] );
117  if ( $exif['GPSLongitudeRef']=='W' )
118    $lon = -$lon;
119 
120  return array ($lat,$lon);
121}
122
123/**
124 * EXIF translation.
125 *
126 * @param $key EXIF key name
127 * @param $value EXIF key value
128 * @return translated value depending on key meaning and choosed language
129 */
130function exif_key_translation($key, $value) {
131   // EXIF
132        if (!(strpos($key, 'ExifVersion') === FALSE)) {
133      return $value[1].'.'.$value[2];
134   }
135   
136   // Date Time Original
137   if (!(strpos($key, 'DateTimeOriginal') === FALSE)) {
138     // to fix bug:1862 the easiest way without releasing a new version of
139     // Piwigo itself, it's better to bypass the date format function
140     //
141     // return formatDate($value);
142     return $value;
143   }
144
145   // exposure time
146         if (!(strpos($key, 'ExposureTime') === FALSE)) {
147      $tokens = explode('/', $value);
148      while ($tokens[0] % 10 == 0) {
149         $tokens[0] = $tokens[0] / 10;
150         $tokens[1] = $tokens[1] / 10;
151      }
152      if ($tokens[1] == 1) {
153         return $tokens[0].' s';
154      } else {
155        return '1/'.floor(1/($tokens[0]/$tokens[1])).' s';
156         // return $tokens[0].'/'.$tokens[1].' s';
157      }
158   }
159
160   // aperture
161         if (!(strpos($key, 'FNumber') === FALSE)) {
162      $tokens = explode('/', $value);
163      return $tokens[0]/$tokens[1];
164   }
165
166   // flash
167   if (!(strpos($key, 'Flash') === FALSE)) {
168      // 1st bit is fired/did not fired
169      if (($value & 1) > 0) {
170         $retValue = l10n('yes');
171      } else {
172         $retValue = l10n('no');
173      }
174      // 2nd+3rd bits are return light mode
175      $returnLight = $value & (3 << 1);
176      switch ($returnLight) {
177        case 2 << 1: $retValue .= ', '.l10n('exif_value_flash_return_light_not_detected');break;
178        case 3 << 1: $retValue .= ', '.l10n('exif_value_flash_return_light_detected');break;
179      }
180      // 4th+5th bits are mode
181      $mode = $value & (3 << 3);
182      switch ($mode) {
183        case 0: $retValue .= ', '.l10n('exif_value_flash_mode').': '.l10n('exif_value_flash_mode_unknown');break;
184        case 1 << 3: $retValue .= ', '.l10n('exif_value_flash_mode').': '.l10n('exif_value_flash_mode_compulsory');break;
185        case 2 << 3: $retValue .= ', '.l10n('exif_value_flash_mode').': '.l10n('exif_value_flash_mode_supress');break;
186        case 3 << 3: $retValue .= ', '.l10n('exif_value_flash_mode').': '.l10n('exif_value_flash_mode_auto');break;
187      }
188                        // 6th bit is red eye function
189      if (($value & (1 << 6)) > 0) {
190         $retValue .= ', '.l10n('exif_value_red_eye');
191      }
192      return $retValue;
193   }
194
195   // exposure bias
196   if (!(strpos($key, 'ExposureBiasValue') === FALSE)) {
197      $tokens = explode('/', $value);
198      $newValue = $tokens[0] / $tokens[1];
199      // max EV range +-
200      $maxEV = 5;
201      // default value
202      $retValue = $newValue;
203      $absValue = truncate(abs($newValue), 2);
204      $found = FALSE;
205      // find through 1/3
206      for ($i = 1; $i <= $maxEV * 3 ; $i++) {
207         $ev = floor($i * 1/3.0 * 100) / 100;
208         if ($ev == $absValue) {
209            if ($i > 3) {
210               $retValue = (truncate($i / 3)).' '.($i % 3).'/3';
211            } else {
212               $retValue = $i.'/3';
213            }
214            $found = TRUE;
215            break;
216         }
217      }
218      // find through 1/2
219      if (!$found) {
220         for ($i = 1; $i <= $maxEV * 2 ; $i++) {
221            $ev = floor($i * 1/2.0 * 100) / 100;
222            if ($ev == $absValue) {
223               if ($i > 2) {
224                  $retValue = ($i / 2).' '.($i % 2).'/2';
225               } else {
226                  $retValue = $i.'/2';
227               }
228               $found = TRUE;
229               break;
230            }
231         }
232      }
233      // signs
234      if (($newValue < 0) && $found) {
235         $retValue = '- '.$retValue;
236      }
237      if ($newValue > 0) {
238         $retValue = '+ '.$retValue;
239      }
240      return $retValue.' EV';
241   }
242
243   // focal length 35mm
244   if (!(strpos($key, 'FocalLengthIn35mmFilm') === FALSE)) {
245      return $value.' mm';
246   }
247
248   // focal length
249   if (!(strpos($key, 'FocalLength') === FALSE)) {
250      $tokens = explode('/', $value);
251      return (round($tokens[0]/$tokens[1])).' mm';
252   }
253
254   // digital zoom
255   if (!(strpos($key, 'DigitalZoomRatio') === FALSE)) {
256      $tokens = explode('/', $value);
257      return ($tokens[0]/$tokens[1]);
258   }
259
260   // distance to subject
261   if (!(strpos($key, 'SubjectDistance') === FALSE)) {
262      $tokens = explode('/', $value);
263      if (isset($tokens[1]))
264      { 
265        $distance = $tokens[0]/$tokens[1];
266      }
267      else
268      { 
269        $distance = $value;
270      }
271      return $distance.' m';
272   }
273
274   // white balance
275   if (!(strpos($key, 'WhiteBalance') === FALSE)) {
276      switch ($value) {
277         case 0: return l10n('exif_value_white_balance_auto');
278         case 1: return l10n('exif_value_white_balance_manual');
279         default: return '';
280      }
281   }
282
283   // exposure mode
284   if (!(strpos($key, 'ExposureMode') === FALSE)) {
285      switch ($value) {
286         case 0: return l10n('exif_value_exposure_mode_auto');
287         case 1: return l10n('exif_value_exposure_mode_manual');
288         case 2: return l10n('exif_value_exposure_mode_auto_bracket');
289         default: return '';
290      }
291   }
292
293   // exposure metering mode
294   if (!(strpos($key, 'MeteringMode') === FALSE)) {
295      switch ($value) {
296         case 0: return l10n('exif_value_metering_mode_unknown');
297         case 1: return l10n('exif_value_metering_mode_average');
298         case 2: return l10n('exif_value_metering_mode_CenterWeightedAVG');
299         case 3: return l10n('exif_value_metering_mode_spot');
300         case 4: return l10n('exif_value_metering_mode_multispot');
301         case 5: return l10n('exif_value_metering_mode_pattern');
302         case 6: return l10n('exif_value_metering_mode_partial');
303         default: return '';
304      }
305   }
306
307   // exposure program
308   if (!(strpos($key, 'ExposureProgram') === FALSE)) {
309      switch ($value) {
310         case 0: return l10n('exif_value_exposure_program_not_defined');
311         case 1: return l10n('exif_value_exposure_program_manual');
312         case 2: return l10n('exif_value_exposure_program_normal');
313         case 3: return l10n('exif_value_exposure_program_aperture');
314         case 4: return l10n('exif_value_exposure_program_shutter');
315         case 5: return l10n('exif_value_exposure_program_creative');
316         case 6: return l10n('exif_value_exposure_program_action');
317         case 7: return l10n('exif_value_exposure_program_portrait');
318         case 8: return l10n('exif_value_exposure_program_landscape');
319         default: return '';
320      }
321   }
322   
323   // light source
324   if (!(strpos($key, 'LightSource') === FALSE)) {
325      switch ($value) {
326         case 0: return l10n('exif_value_light_source_unknown');
327         case 1: return l10n('exif_value_light_source_daylight');
328         case 2: return l10n('exif_value_light_source_fluorescent');
329         case 3: return l10n('exif_value_light_source_tungsten');
330         case 4: return l10n('exif_value_light_source_flash');
331         case 9: return l10n('exif_value_light_source_fine_weather');
332         case 10: return l10n('exif_value_light_source_cloudy_weather');
333         case 11: return l10n('exif_value_light_source_shade');
334         case 12: return l10n('exif_value_light_source_daylight_fluorescent_d');
335         case 13: return l10n('exif_value_light_source_daywhite_fluorescent_n');
336         case 14: return l10n('exif_value_light_source_coolwhite_fluorescent_w');
337         case 15: return l10n('exif_value_light_source_white_fluorescent');
338         case 17: return l10n('exif_value_light_source_standard_light_a');
339         case 18: return l10n('exif_value_light_source_standard_light_b');
340         case 19: return l10n('exif_value_light_source_standard_light_c');
341         case 20: return l10n('exif_value_light_source_D55');
342         case 21: return l10n('exif_value_light_source_D65');
343         case 22: return l10n('exif_value_light_source_D75');
344         case 23: return l10n('exif_value_light_source_D50');
345         case 24: return l10n('exif_value_light_source_iso_studio_tungsten');
346         case 255: return l10n('exif_value_light_source_other');
347         default: return '';
348      }
349   }
350
351   // contrast
352   if (!(strpos($key, 'Contrast') === FALSE)) {
353      switch ($value) {
354         case 0: return l10n('exif_value_contrast_normal');
355         case 1: return l10n('exif_value_contrast_soft');
356         case 2: return l10n('exif_value_contrast_hard');
357         default: return '';
358      }
359   }
360
361   // sharpness
362   if (!(strpos($key, 'Sharpness') === FALSE)) {
363      switch ($value) {
364         case 0: return l10n('exif_value_sharpness_normal');
365         case 1: return l10n('exif_value_sharpness_soft');
366         case 2: return l10n('exif_value_sharpness_hard');
367         default: return '';
368      }
369   }
370
371   // saturation
372   if (!(strpos($key, 'Saturation') === FALSE)) {
373      switch ($value) {
374         case 0: return l10n('exif_value_saturation_normal');
375         case 1: return l10n('exif_value_saturation_low');
376         case 2: return l10n('exif_value_saturation_hard');
377         default: return '';
378      }
379   }
380
381   // return value unchanged
382   return $value;
383}
384define('exif_DIR' , basename(dirname(__FILE__)));
385define('exif_PATH' , PHPWG_PLUGINS_PATH . exif_DIR . '/');
386        /**
387         * Loads plugin language file.
388         */
389  function loadLang() {
390    global $lang;
391    load_language('lang.exif', exif_PATH);
392  }
393
394/**
395 * EXIF translation.
396 *
397 * @param $key EXIF key name
398 * @param $value EXIF key value
399 * @return translated value dependend on key meaning and choosed language
400 */
401function exif_translation($exif) {
402         // translate all exif fields
403         if (is_array($exif)) {
404         loadLang();
405
406     // extract latitude/longitude
407     $latlon = ev_exif_to_lat_lon($exif);
408     
409     if (!empty($latlon))
410     {
411       $exif['GPSLatitude'] = sprintf('%.6f', $latlon[0]);
412       $exif['GPSLongitude'] = sprintf('%.6f', $latlon[1]);
413     }
414     
415           foreach ($exif as $key => $value) {
416                         $exif[$key] = exif_key_translation($key, $value);
417           }
418         }
419   return $exif;
420}
421
422?>
Note: See TracBrowser for help on using the repository browser.