source: extensions/AMetaData/JpegMetaData/Common/ConvertData.class.php @ 6731

Last change on this file since 6731 was 5229, checked in by grum, 15 years ago

fix bug when formating dates : invalid dates are now ignored

  • Property svn:executable set to *
File size: 13.5 KB
Line 
1<?php
2/*
3 * --:: JPEG MetaDatas ::-------------------------------------------------------
4 *
5 *  Author    : Grum
6 *   email    : grum at piwigo.org
7 *   website  : http://photos.grum.fr
8 *
9 *   << May the Little SpaceFrog be with you ! >>
10 *
11 * +-----------------------------------------------------------------------+
12 * | JpegMetaData - a PHP based Jpeg Metadata manager                      |
13 * +-----------------------------------------------------------------------+
14 * | Copyright(C) 2010  Grum - http://www.grum.fr                          |
15 * +-----------------------------------------------------------------------+
16 * | This program is free software; you can redistribute it and/or modify  |
17 * | it under the terms of the GNU General Public License as published by  |
18 * | the Free Software Foundation                                          |
19 * |                                                                       |
20 * | This program is distributed in the hope that it will be useful, but   |
21 * | WITHOUT ANY WARRANTY; without even the implied warranty of            |
22 * | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
23 * | General Public License for more details.                              |
24 * |                                                                       |
25 * | You should have received a copy of the GNU General Public License     |
26 * | along with this program; if not, write to the Free Software           |
27 * | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
28 * | USA.                                                                  |
29 * +-----------------------------------------------------------------------+
30 *
31 *
32 * -----------------------------------------------------------------------------
33 *
34 * ConvertData class is used to convert data from a type into another type
35 *
36 * This class provides theses public functions :
37 *  - (static) toUByte
38 *  - (static) toSByte
39 *  - (static) toUShort
40 *  - (static) toSShort
41 *  - (static) toULong
42 *  - (static) toSLong
43 *  - (static) toURational
44 *  - (static) toSRational
45 *  - (static) toExposureTime
46 *  - (static) toFNumber
47 *  - (static) toDateTime
48 *  - (static) toFocalLength
49 *  - (static) toEV
50 *  - (static) toDistance
51 *  - (static) toStrings
52 *  - (static) toDMS
53 *  - (static) toHexDump
54 *
55 * -----------------------------------------------------------------------------
56 */
57
58  require_once(JPEG_METADATA_DIR."Common/Const.class.php");
59
60  class ConvertData
61  {
62    /**
63     * Convert the given data into a single unsigned Byte (8bit)
64     *
65     * @param String $data : representing the unsigned Byte
66     * @return UByte
67     */
68    static public function toUByte($data)
69    {
70      if(strlen($data)>=1)
71        return(ord($data{0}));
72      else
73        return(0);
74    }
75
76    /**
77     * Convert the given data into a single signed Byte (8bit)
78     *
79     * @param String $data : representing the signed Byte
80     * @return SByte
81     */
82    static public function toSByte($data)
83    {
84      $unsigned = self::toUByte($data);
85      if($unsigned>127)
86        return($unsigned-256);
87      else
88        return($unsigned);
89    }
90
91    /**
92     * Convert the given data into an unsigned Short integer (16bit)
93     *
94     * @param String $data       : representing the unsigned Short
95     * @param String $endianType : the byte order
96     * @return UShort
97     */
98    static public function toUShort($data, $endianType)
99    {
100      if(strlen($data)>=2)
101      {
102        if($endianType==BYTE_ORDER_LITTLE_ENDIAN)
103          return(ord($data{0}) +
104                 ord($data{1})*256);
105        else
106          return(ord($data{0})*256 +
107                 ord($data{1}));
108      }
109      else
110      {
111        return(0);
112      }
113    }
114
115    /**
116     * Convert the given data into a signed Short integer (16bit)
117     *
118     * @param String $data       : representing the signed Short
119     * @param String $endianType : the byte order
120     * @return SShort
121     */
122    static public function toSShort($data, $endianType)
123    {
124      $unsigned = self::toUShort($data, $endianType);
125      if($unsigned>32767)
126        return($unsigned-65536);
127      else
128        return($unsigned);
129    }
130
131    /**
132     * Convert the given data into an unsigned Long integer (32bit)
133     *
134     * @param String $data       : representing the unsigned Long
135     * @param String $endianType : the byte order
136     * @return ULong
137     */
138    static public function toULong($data, $endianType)
139    {
140      if(strlen($data)>=4)
141      {
142        if($endianType==BYTE_ORDER_LITTLE_ENDIAN)
143          return(ord($data{0}) +
144                 ord($data{1})*256 +
145                 ord($data{2})*65536 +
146                 ord($data{3})*16777216);
147        else
148          return(ord($data{0})*16777216 +
149                 ord($data{1})*65536 +
150                 ord($data{2})*256 +
151                 ord($data{3}));
152      }
153      else
154      {
155        return(0);
156      }
157    }
158
159    /**
160     * Convert the given data into a signed Long integer (32bit)
161     *
162     * @param String $data       : representing the signed Long
163     * @param String $endianType : the byte order
164     * @return SLong
165     */
166    static public function toSLong($data, $endianType)
167    {
168      $unsigned = self::toULong($data, $endianType);
169      if($unsigned>2147483647)
170        return($unsigned-4294967296);
171      else
172        return($unsigned);
173    }
174
175    /**
176     * Convert the given data into an array of unsigned Long (2x32bit)
177     *
178     * @param String $data       : representing the unsigned Rational
179     * @param String $endianType : the byte order
180     * @return URational
181     */
182    static public function toURational($data, $endianType)
183    {
184      if(strlen($data)>=8)
185      {
186        return(
187          Array(
188            self::toULong($data, $endianType),
189            self::toULong(substr($data, 4), $endianType)
190          )
191        );
192      }
193      else
194      {
195        return(Array(0,0));
196      }
197    }
198
199    /**
200     * Convert the given data into an array of signed Long (2x32bit)
201     *
202     * @param String $data       : representing the signed Rational
203     * @param String $endianType : the byte order
204     * @return SRational
205     */
206    static public function toSRational($data, $endianType)
207    {
208      if(strlen($data)>=8)
209      {
210        return(
211          Array(
212            self::toSLong($data, $endianType),
213            self::toSLong(substr($data, 4), $endianType)
214          )
215        );
216      }
217      else
218      {
219        return(Array(0,0));
220      }
221    }
222
223    /**
224     * Convert a floating value exprimed in seconds into a "photographic"
225     * value
226     *
227     * example :
228     *  1.5   => "1.5s"
229     *  0.004 => "1/250s"     *
230     *
231     * @param Float $time : time to convert
232     * @return String
233     */
234    static public function toExposureTime($time)
235    {
236      if($time>=1 or $time==0)
237      {
238        return($time."s");
239      }
240      else
241      {
242        return(sprintf("1/%ds", 1/$time));
243      }
244    }
245
246    /**
247     * Convert a floating value in a f/x.y string
248     *
249     * example :
250     *  1.8 => "f/1.8"
251     *  8   => "f/8.0"
252     *
253     * @param Float $fNumber : fnumber
254     * @return String
255     */
256    static public function toFNumber($fNumber)
257    {
258      return(sprintf("f/%.1f", $fNumber));
259    }
260
261    /**
262     * Convert a string Date/Time into a DateTime object
263     *
264     * Example of valid string :
265     *  "2009:12:24 19:54"
266     *  "2009:12:24 19:54\x00"
267     *  "2009:12:24 19:54:38"
268     *  "2009:12:24 19:54:38\x00"
269     *  "2009-12-24 19:54"
270     *  "2009-12-24T19:54"
271     *  "2009-12-24 19:54:38"
272     *  "2009-12-24T19:54:38"
273     *  "2009-12-24 19:54Z"
274     *  "2009-12-24T19:54Z"
275     *  "2009-12-24 19:54:38Z"
276     *  "2009-12-24T19:54:38Z"
277     *  "2009-12-24 19:54+02:00"
278     *  "2009-12-24T19:54+02:00"
279     *  "2009-12-24 19:54:38+02:00"
280     *  "2009-12-24T19:54:38+02:00"
281     *  "20091224"
282     *
283     * returns null if date is not a valid date
284     *
285     * @param String $dateTime : date time in a valid format
286     * @return String
287     */
288    static public function toDateTime($dateTime)
289    {
290      if(preg_match('/^('.
291           '\d{4}:\d{2}:\d{2}\s\d{2}:\d{2}(:\d{2}){0,1}\x00{0,1}|'.
292           '\d{4}-\d{2}-\d{2}(T|\s)\d{2}:\d{2}(:\d{2}){0,1}(Z|[+|-]\d{2}:\d{2}){0,1}|'.
293           '\d{4}\d{2}\d{2}'.
294           ')$/', $dateTime))
295      {
296        $returned=new DateTime($dateTime, new DateTimeZone("UTC"));
297      }
298      else
299      {
300        $returned=null;
301      }
302      return($returned);
303    }
304
305    /**
306     * Convert a floating value in a focal length string
307     *
308     * Example:
309     *  250 => "250.0mm"
310     *
311     * @param Float $focalLength : focal length in millimeters
312     * @return String
313     */
314    static public function toFocalLength($focalLength)
315    {
316      return(sprintf("%.1f mm", $focalLength));
317    }
318
319    /**
320     * Convert a floating value in an EV
321     *
322     * Example:
323     *  0.7 => "0.7 EV"
324     *
325     * @param Float $ev : EV
326     * @return String
327     */
328    static public function toEV($ev)
329    {
330      return(sprintf("%.1f EV", $ev));
331    }
332
333    /**
334     * Convert a floating value associated with a unit
335     *
336     * Example :
337     *  3.4 + "m" => "3.40 m"
338     *
339     * @param Float $distance : distance
340     * @param String $unit    : unit
341     * @return String
342     */
343    static public function toDistance($distance, $unit)
344    {
345      return(sprintf("%.2f ", $distance)).$unit;
346    }
347
348    /**
349     * Convert a null terminated string into a string
350     * or
351     * Convert multiples null terminated string into an array of string
352     *    ==> if strings are null (eq. "\x00") nothing is added to the array
353     *
354     * Example:
355     *  "test" => "test"
356     *  "test\x00" => "test"
357     *  "test1\x00test2\x00" => Array("test1", "test2")
358     *
359     * @param String $strings
360     * @return String or String[]
361     */
362    static public function toStrings($strings)
363    {
364      if(strpos($strings, chr(0))===false)
365        return($strings);
366
367      $occurs=preg_match_all('/(.*)\x00/U',$strings,$result);
368      if($occurs==0)
369      {
370        return("");
371      }
372      else
373      {
374        $returned=Array();
375        foreach($result[1] as $pop)
376        {
377          if($pop!="")
378          {
379            $returned[]=$pop;
380          }
381        }
382        if(count($returned)==1)
383        {
384          return($returned[0]);
385        }
386        elseif(count($returned)==0)
387        {
388          return("");
389        }
390        else
391        {
392          return($returned);
393        }
394      }
395    }
396
397    /**
398     * Convert 3 rationnals (EXIF GPS format) into a Degree, Minute, Second into
399     * a formatted string   dd° mm' ss.cs"
400     *
401     * Example:
402     *  48/1 + 1600/100 + 347/10 => "48° 16' 34.70""
403     *
404     * @param URational $degrees : degrees
405     * @param URational $minutes : minutes
406     * @param URational $seconds : seconds
407     * @return String
408     */
409    static public function toDMS($degrees, $minutes, $seconds)
410    {
411      if($degrees[1]==0) $degrees[1]=1;
412      if($minutes[1]==0) $minutes[1]=1;
413      if($seconds[1]==0) $seconds[1]=1;
414
415      $deg=$degrees[0]/$degrees[1];
416      $min=($minutes[0]/$minutes[1])-((int)$deg-$deg)*60;
417      $sec=($seconds[0]/$seconds[1])-((int)$min-$min)*60;
418
419      $returned=sprintf("%d° %d' %.2f\"", $deg, $min, $sec);
420
421      return($returned);
422    }
423
424
425    /**
426     * Dump the given data into an hex string
427     *
428     * @param $data            : data to be dumped (the dump is function of the
429     *                           data type)
430     * @param UByte $type      : the type of data (uses the ByteType values)
431     * @param UShort $maxItems : for arrays (or ASCII string), the number or
432     *                           items (chars) to dump
433     * @return String
434     */
435    static public function toHexDump($data, $type, $maxItems = 0)
436    {
437      $returned="";
438      if(is_array($data))
439      {
440        if($maxItems==0)
441        {
442          $maxItems=count($data);
443        }
444        elseif($maxItems>count($data))
445        {
446          $maxItems=count($data);
447        }
448        else
449        {
450          $returned.="[returns only the first $maxItems of ".count($data)." values] ";
451        }
452
453        $tmp=Array();
454        for($i=0;$i<$maxItems;$i++)
455        {
456          $tmp[]=self::toHexDump($data[$i], $type, $maxItems);
457        }
458        $returned.="[".implode(",", $tmp)."]";
459      }
460      else
461      {
462        switch($type)
463        {
464          case ByteType::UBYTE :
465          case ByteType::SBYTE :
466            $returned.=sprintf("0x%02x", $data);
467            break;
468          case ByteType::USHORT :
469          case ByteType::SSHORT :
470            $returned.=sprintf("0x%04x", $data);
471            break;
472          case ByteType::ULONG :
473          case ByteType::SLONG :
474            $returned.=sprintf("0x%08x", $data);
475            break;
476          case ByteType::URATIONAL :
477          case ByteType::SRATIONAL :
478            $returned.=sprintf("0x%08x", $data);
479            break;
480          case ByteType::FLOAT :
481          case ByteType::DOUBLE :
482          case ByteType::ASCII :
483          case ByteType::UNDEFINED :
484          default:
485            if($maxItems==0)
486            {
487              $maxItems=strlen($data);
488            }
489            elseif($maxItems>strlen($data))
490            {
491              $maxItems=strlen($data);
492            }
493            else
494            {
495              $returned.="[returns only the first $maxItems of ".strlen($data)." bytes] ";
496            }
497
498            $tmp=array();
499            for($i=0;$i<$maxItems;$i++)
500            {
501              $tmp[]=sprintf("%02x", ord($data{$i}));
502            }
503            $returned.=implode(" ", $tmp);
504            break;
505        }
506      }
507      return($returned);
508    }
509
510
511  }
512
513
514?>
Note: See TracBrowser for help on using the repository browser.