ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
Jpg.php
Go to the documentation of this file.
1 <?php
2 
3 namespace GetId3\Module\Graphic;
4 
9 
12 // available at http://getid3.sourceforge.net //
13 // or http://www.getid3.org //
15 // See readme.txt for more details //
17 // //
18 // module.graphic.jpg.php //
19 // module for analyzing JPEG Image files //
20 // dependencies: PHP compiled with --enable-exif (optional) //
21 // module.tag.xmp.php (optional) //
22 // ///
24 
34 class Jpg extends BaseHandler
35 {
36 
41  public function analyze()
42  {
43  $info = &$this->getid3->info;
44 
45  $info['fileformat'] = 'jpg';
46  $info['video']['dataformat'] = 'jpg';
47  $info['video']['lossless'] = false;
48  $info['video']['bits_per_sample'] = 24;
49  $info['video']['pixel_aspect_ratio'] = (float) 1;
50 
51  fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
52 
53  $imageinfo = array();
54  list($width, $height, $type) = Helper::GetDataImageSize(fread($this->getid3->fp, $info['filesize']), $imageinfo);
55 
56  if (isset($imageinfo['APP13'])) {
57  // http://php.net/iptcparse
58  // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html
59  $iptc_parsed = iptcparse($imageinfo['APP13']);
60  if (is_array($iptc_parsed)) {
61  foreach ($iptc_parsed as $iptc_key_raw => $iptc_values) {
62  list($iptc_record, $iptc_tagkey) = explode('#', $iptc_key_raw);
63  $iptc_tagkey = intval(ltrim($iptc_tagkey, '0'));
64  foreach ($iptc_values as $key => $value) {
65  $IPTCrecordName = $this->IPTCrecordName($iptc_record);
66  $IPTCrecordTagName = $this->IPTCrecordTagName($iptc_record, $iptc_tagkey);
67  if (isset($info['iptc'][$IPTCrecordName][$IPTCrecordTagName])) {
68  $info['iptc'][$IPTCrecordName][$IPTCrecordTagName][] = $value;
69  } else {
70  $info['iptc'][$IPTCrecordName][$IPTCrecordTagName] = array($value);
71  }
72  }
73  }
74  }
75  }
76 
77  $returnOK = false;
78  switch ($type) {
79  case IMG_JPG:
80  $info['video']['resolution_x'] = $width;
81  $info['video']['resolution_y'] = $height;
82 
83  if (isset($imageinfo['APP1'])) {
84  if (function_exists('exif_read_data')) {
85  if (substr($imageinfo['APP1'], 0, 4) == 'Exif') {
86  $info['jpg']['exif'] = @exif_read_data($info['filenamepath'], '', true, false);
87  } else {
88  $info['warning'][] = 'exif_read_data() cannot parse non-EXIF data in APP1 (expected "Exif", found "'.substr($imageinfo['APP1'], 0, 4).'")';
89  }
90  } else {
91  $info['warning'][] = 'EXIF parsing only available when '.(GetId3Core::environmentIsWindows() ? 'php_exif.dll enabled' : 'compiled with --enable-exif');
92  }
93  }
94  $returnOK = true;
95  break;
96 
97  default:
98  break;
99  }
100 
101  $cast_as_appropriate_keys = array('EXIF', 'IFD0', 'THUMBNAIL');
102  foreach ($cast_as_appropriate_keys as $exif_key) {
103  if (isset($info['jpg']['exif'][$exif_key])) {
104  foreach ($info['jpg']['exif'][$exif_key] as $key => $value) {
105  $info['jpg']['exif'][$exif_key][$key] = $this->CastAsAppropriate($value);
106  }
107  }
108  }
109 
110  if (isset($info['jpg']['exif']['GPS'])) {
111 
112  if (isset($info['jpg']['exif']['GPS']['GPSVersion'])) {
113  for ($i = 0; $i < 4; $i++) {
114  $version_subparts[$i] = ord(substr($info['jpg']['exif']['GPS']['GPSVersion'], $i, 1));
115  }
116  $info['jpg']['exif']['GPS']['computed']['version'] = 'v'.implode('.', $version_subparts);
117  }
118 
119  if (isset($info['jpg']['exif']['GPS']['GPSDateStamp'])) {
120  $explodedGPSDateStamp = explode(':', $info['jpg']['exif']['GPS']['GPSDateStamp']);
121  $computed_time[5] = (isset($explodedGPSDateStamp[0]) ? $explodedGPSDateStamp[0] : '');
122  $computed_time[3] = (isset($explodedGPSDateStamp[1]) ? $explodedGPSDateStamp[1] : '');
123  $computed_time[4] = (isset($explodedGPSDateStamp[2]) ? $explodedGPSDateStamp[2] : '');
124 
125  if (function_exists('date_default_timezone_set')) {
126  date_default_timezone_set('UTC');
127  } else {
128  ini_set('date.timezone', 'UTC');
129  }
130 
131  $computed_time = array(0=>0, 1=>0, 2=>0, 3=>0, 4=>0, 5=>0);
132  if (isset($info['jpg']['exif']['GPS']['GPSTimeStamp']) && is_array($info['jpg']['exif']['GPS']['GPSTimeStamp'])) {
133  foreach ($info['jpg']['exif']['GPS']['GPSTimeStamp'] as $key => $value) {
134  $computed_time[$key] = Helper::DecimalizeFraction($value);
135  }
136  }
137  $info['jpg']['exif']['GPS']['computed']['timestamp'] = mktime($computed_time[0], $computed_time[1], $computed_time[2], $computed_time[3], $computed_time[4], $computed_time[5]);
138  }
139 
140  if (isset($info['jpg']['exif']['GPS']['GPSLatitude']) && is_array($info['jpg']['exif']['GPS']['GPSLatitude'])) {
141  $direction_multiplier = ((isset($info['jpg']['exif']['GPS']['GPSLatitudeRef']) && ($info['jpg']['exif']['GPS']['GPSLatitudeRef'] == 'S')) ? -1 : 1);
142  foreach ($info['jpg']['exif']['GPS']['GPSLatitude'] as $key => $value) {
143  $computed_latitude[$key] = Helper::DecimalizeFraction($value);
144  }
145  $info['jpg']['exif']['GPS']['computed']['latitude'] = $direction_multiplier * ($computed_latitude[0] + ($computed_latitude[1] / 60) + ($computed_latitude[2] / 3600));
146  }
147 
148  if (isset($info['jpg']['exif']['GPS']['GPSLongitude']) && is_array($info['jpg']['exif']['GPS']['GPSLongitude'])) {
149  $direction_multiplier = ((isset($info['jpg']['exif']['GPS']['GPSLongitudeRef']) && ($info['jpg']['exif']['GPS']['GPSLongitudeRef'] == 'W')) ? -1 : 1);
150  foreach ($info['jpg']['exif']['GPS']['GPSLongitude'] as $key => $value) {
151  $computed_longitude[$key] = Helper::DecimalizeFraction($value);
152  }
153  $info['jpg']['exif']['GPS']['computed']['longitude'] = $direction_multiplier * ($computed_longitude[0] + ($computed_longitude[1] / 60) + ($computed_longitude[2] / 3600));
154  }
155 
156  if (isset($info['jpg']['exif']['GPS']['GPSAltitude'])) {
157  $direction_multiplier = ((isset($info['jpg']['exif']['GPS']['GPSAltitudeRef']) && ($info['jpg']['exif']['GPS']['GPSAltitudeRef'] === chr(1))) ? -1 : 1);
158  $info['jpg']['exif']['GPS']['computed']['altitude'] = $direction_multiplier * Helper::DecimalizeFraction($info['jpg']['exif']['GPS']['GPSAltitude']);
159  }
160 
161  }
162 
163  if (class_exists('GetId3\\Module\\Tag\\Xmp')) {
164  if (isset($info['filenamepath'])) {
165  $image_xmp = new Xmp($info['filenamepath']);
166  $xmp_raw = $image_xmp->getAllTags();
167  foreach ($xmp_raw as $key => $value) {
168  list($subsection, $tagname) = explode(':', $key);
169  $info['xmp'][$subsection][$tagname] = $this->CastAsAppropriate($value);
170  }
171  }
172  }
173 
174  if (!$returnOK) {
175  unset($info['fileformat']);
176 
177  return false;
178  }
179 
180  return true;
181  }
182 
188  public function CastAsAppropriate($value)
189  {
190  if (is_array($value)) {
191  return $value;
192  } elseif (preg_match('#^[0-9]+/[0-9]+$#', $value)) {
193  return Helper::DecimalizeFraction($value);
194  } elseif (preg_match('#^[0-9]+$#', $value)) {
195  return Helper::CastAsInt($value);
196  } elseif (preg_match('#^[0-9\.]+$#', $value)) {
197  return (float) $value;
198  }
199 
200  return $value;
201  }
202 
209  public function IPTCrecordName($iptc_record)
210  {
211  // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html
212  static $IPTCrecordName = array();
213  if (empty($IPTCrecordName)) {
214  $IPTCrecordName = array(
215  1 => 'IPTCEnvelope',
216  2 => 'IPTCApplication',
217  3 => 'IPTCNewsPhoto',
218  7 => 'IPTCPreObjectData',
219  8 => 'IPTCObjectData',
220  9 => 'IPTCPostObjectData',
221  );
222  }
223 
224  return (isset($IPTCrecordName[$iptc_record]) ? $IPTCrecordName[$iptc_record] : '');
225  }
226 
235  public function IPTCrecordTagName($iptc_record, $iptc_tagkey)
236  {
237  static $IPTCrecordTagName = array();
238  if (empty($IPTCrecordTagName)) {
239  $IPTCrecordTagName = array(
240  1 => array( // IPTC EnvelopeRecord Tags
241  0 => 'EnvelopeRecordVersion',
242  5 => 'Destination',
243  20 => 'FileFormat',
244  22 => 'FileVersion',
245  30 => 'ServiceIdentifier',
246  40 => 'EnvelopeNumber',
247  50 => 'ProductID',
248  60 => 'EnvelopePriority',
249  70 => 'DateSent',
250  80 => 'TimeSent',
251  90 => 'CodedCharacterSet',
252  100 => 'UniqueObjectName',
253  120 => 'ARMIdentifier',
254  122 => 'ARMVersion',
255  ),
256  2 => array( // IPTC ApplicationRecord Tags
257  0 => 'ApplicationRecordVersion',
258  3 => 'ObjectTypeReference',
259  4 => 'ObjectAttributeReference',
260  5 => 'ObjectName',
261  7 => 'EditStatus',
262  8 => 'EditorialUpdate',
263  10 => 'Urgency',
264  12 => 'SubjectReference',
265  15 => 'Category',
266  20 => 'SupplementalCategories',
267  22 => 'FixtureIdentifier',
268  25 => 'Keywords',
269  26 => 'ContentLocationCode',
270  27 => 'ContentLocationName',
271  30 => 'ReleaseDate',
272  35 => 'ReleaseTime',
273  37 => 'ExpirationDate',
274  38 => 'ExpirationTime',
275  40 => 'SpecialInstructions',
276  42 => 'ActionAdvised',
277  45 => 'ReferenceService',
278  47 => 'ReferenceDate',
279  50 => 'ReferenceNumber',
280  55 => 'DateCreated',
281  60 => 'TimeCreated',
282  62 => 'DigitalCreationDate',
283  63 => 'DigitalCreationTime',
284  65 => 'OriginatingProgram',
285  70 => 'ProgramVersion',
286  75 => 'ObjectCycle',
287  80 => 'By-line',
288  85 => 'By-lineTitle',
289  90 => 'City',
290  92 => 'Sub-location',
291  95 => 'Province-State',
292  100 => 'Country-PrimaryLocationCode',
293  101 => 'Country-PrimaryLocationName',
294  103 => 'OriginalTransmissionReference',
295  105 => 'Headline',
296  110 => 'Credit',
297  115 => 'Source',
298  116 => 'CopyrightNotice',
299  118 => 'Contact',
300  120 => 'Caption-Abstract',
301  121 => 'LocalCaption',
302  122 => 'Writer-Editor',
303  125 => 'RasterizedCaption',
304  130 => 'ImageType',
305  131 => 'ImageOrientation',
306  135 => 'LanguageIdentifier',
307  150 => 'AudioType',
308  151 => 'AudioSamplingRate',
309  152 => 'AudioSamplingResolution',
310  153 => 'AudioDuration',
311  154 => 'AudioOutcue',
312  184 => 'JobID',
313  185 => 'MasterDocumentID',
314  186 => 'ShortDocumentID',
315  187 => 'UniqueDocumentID',
316  188 => 'OwnerID',
317  200 => 'ObjectPreviewFileFormat',
318  201 => 'ObjectPreviewFileVersion',
319  202 => 'ObjectPreviewData',
320  221 => 'Prefs',
321  225 => 'ClassifyState',
322  228 => 'SimilarityIndex',
323  230 => 'DocumentNotes',
324  231 => 'DocumentHistory',
325  232 => 'ExifCameraInfo',
326  ),
327  3 => array( // IPTC NewsPhoto Tags
328  0 => 'NewsPhotoVersion',
329  10 => 'IPTCPictureNumber',
330  20 => 'IPTCImageWidth',
331  30 => 'IPTCImageHeight',
332  40 => 'IPTCPixelWidth',
333  50 => 'IPTCPixelHeight',
334  55 => 'SupplementalType',
335  60 => 'ColorRepresentation',
336  64 => 'InterchangeColorSpace',
337  65 => 'ColorSequence',
338  66 => 'ICC_Profile',
339  70 => 'ColorCalibrationMatrix',
340  80 => 'LookupTable',
341  84 => 'NumIndexEntries',
342  85 => 'ColorPalette',
343  86 => 'IPTCBitsPerSample',
344  90 => 'SampleStructure',
345  100 => 'ScanningDirection',
346  102 => 'IPTCImageRotation',
347  110 => 'DataCompressionMethod',
348  120 => 'QuantizationMethod',
349  125 => 'EndPoints',
350  130 => 'ExcursionTolerance',
351  135 => 'BitsPerComponent',
352  140 => 'MaximumDensityRange',
353  145 => 'GammaCompensatedValue',
354  ),
355  7 => array( // IPTC PreObjectData Tags
356  10 => 'SizeMode',
357  20 => 'MaxSubfileSize',
358  90 => 'ObjectSizeAnnounced',
359  95 => 'MaximumObjectSize',
360  ),
361  8 => array( // IPTC ObjectData Tags
362  10 => 'SubFile',
363  ),
364  9 => array( // IPTC PostObjectData Tags
365  10 => 'ConfirmedObjectSize',
366  ),
367  );
368 
369  }
370 
371  return (isset($IPTCrecordTagName[$iptc_record][$iptc_tagkey]) ? $IPTCrecordTagName[$iptc_record][$iptc_tagkey] : $iptc_tagkey);
372  }
373 
374 }
static GetDataImageSize($imgData, &$imageinfo)
string $tempdir
Definition: Helper.php:1622
IPTCrecordTagName($iptc_record, $iptc_tagkey)
array $IPTCrecordTagName
Definition: Jpg.php:235
GetId3() by James Heinrich info@getid3.org //.
Definition: BaseHandler.php:25
IPTCrecordName($iptc_record)
array $IPTCrecordName
Definition: Jpg.php:209
GetId3() by James Heinrich info@getid3.org //.
Definition: Xmp.php:61
fseek($bytes, $whence=SEEK_SET)
$info
Definition: example_052.php:80
CastAsAppropriate($value)
Definition: Jpg.php:188
static CastAsInt($floatnum)
Definition: Helper.php:107
Create styles array
The data for the language used.
static DecimalizeFraction($fraction)
Definition: Helper.php:153
GetId3() by James Heinrich info@getid3.org //.
Definition: Jpg.php:34