ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
Image_XMP Class Reference

getID3() by James Heinrich info@.nosp@m.geti.nosp@m.d3.or.nosp@m.g // More...

+ Collaboration diagram for Image_XMP:

Public Member Functions

 isValid ()
 Returns the status of XMP parsing during instantiation. More...
 
 getAllTags ()
 Get a copy of all XMP tags extracted from the image. More...
 
 _get_jpeg_header_data ($filename)
 Reads all the JPEG header segments from an JPEG image file into an array. More...
 
 _get_XMP_text ($filename)
 Retrieves XMP information from an APP1 JPEG segment and returns the raw XML text as a string. More...
 
 read_XMP_array_from_text ($xmltext)
 Parses a string containing XMP data (XML), and returns an array which contains all the XMP (XML) information. More...
 
 __construct ($sFilename)
 Constructor. More...
 

Data Fields

 $_sFilename = null
 
 $_aXMP = array()
 
 $_bXMPParse = false
 

Detailed Description

getID3() by James Heinrich info@.nosp@m.geti.nosp@m.d3.or.nosp@m.g //

Definition at line 34 of file module.tag.xmp.php.

Constructor & Destructor Documentation

◆ __construct()

Image_XMP::__construct (   $sFilename)

Constructor.

Parameters
string- Name of the image file to access and extract XMP information from.

Definition at line 402 of file module.tag.xmp.php.

References _get_XMP_text(), and read_XMP_array_from_text().

403  {
404  $this->_sFilename = $sFilename;
405 
406  if (is_file($this->_sFilename))
407  {
408  // Get XMP data
409  $xmp_data = $this->_get_XMP_text($sFilename);
410  if ($xmp_data)
411  {
412  $this->_aXMP = $this->read_XMP_array_from_text($xmp_data);
413  $this->_bXMPParse = true;
414  }
415  }
416  }
read_XMP_array_from_text($xmltext)
Parses a string containing XMP data (XML), and returns an array which contains all the XMP (XML) info...
_get_XMP_text($filename)
Retrieves XMP information from an APP1 JPEG segment and returns the raw XML text as a string...
+ Here is the call graph for this function:

Member Function Documentation

◆ _get_jpeg_header_data()

Image_XMP::_get_jpeg_header_data (   $filename)

Reads all the JPEG header segments from an JPEG image file into an array.

Parameters
string$filename- the filename of the JPEG file to read
Returns
array $headerdata - Array of JPEG header segments
boolean FALSE - if headers could not be read

Definition at line 87 of file module.tag.xmp.php.

References $data, $filename, and $GLOBALS.

Referenced by _get_XMP_text().

88  {
89  // prevent refresh from aborting file operations and hosing file
90  ignore_user_abort(true);
91 
92  // Attempt to open the jpeg file - the at symbol supresses the error message about
93  // not being able to open files. The file_exists would have been used, but it
94  // does not work with files fetched over http or ftp.
95  if (is_readable($filename) && is_file($filename) && ($filehnd = fopen($filename, 'rb'))) {
96  // great
97  } else {
98  return false;
99  }
100 
101  // Read the first two characters
102  $data = fread($filehnd, 2);
103 
104  // Check that the first two characters are 0xFF 0xD8 (SOI - Start of image)
105  if ($data != "\xFF\xD8")
106  {
107  // No SOI (FF D8) at start of file - This probably isn't a JPEG file - close file and return;
108  echo '<p>This probably is not a JPEG file</p>'."\n";
109  fclose($filehnd);
110  return false;
111  }
112 
113  // Read the third character
114  $data = fread($filehnd, 2);
115 
116  // Check that the third character is 0xFF (Start of first segment header)
117  if ($data{0} != "\xFF")
118  {
119  // NO FF found - close file and return - JPEG is probably corrupted
120  fclose($filehnd);
121  return false;
122  }
123 
124  // Flag that we havent yet hit the compressed image data
125  $hit_compressed_image_data = false;
126 
127  // Cycle through the file until, one of: 1) an EOI (End of image) marker is hit,
128  // 2) we have hit the compressed image data (no more headers are allowed after data)
129  // 3) or end of file is hit
130 
131  while (($data{1} != "\xD9") && (!$hit_compressed_image_data) && (!feof($filehnd)))
132  {
133  // Found a segment to look at.
134  // Check that the segment marker is not a Restart marker - restart markers don't have size or data after them
135  if ((ord($data{1}) < 0xD0) || (ord($data{1}) > 0xD7))
136  {
137  // Segment isn't a Restart marker
138  // Read the next two bytes (size)
139  $sizestr = fread($filehnd, 2);
140 
141  // convert the size bytes to an integer
142  $decodedsize = unpack('nsize', $sizestr);
143 
144  // Save the start position of the data
145  $segdatastart = ftell($filehnd);
146 
147  // Read the segment data with length indicated by the previously read size
148  $segdata = fread($filehnd, $decodedsize['size'] - 2);
149 
150  // Store the segment information in the output array
151  $headerdata[] = array(
152  'SegType' => ord($data{1}),
153  'SegName' => $GLOBALS['JPEG_Segment_Names'][ord($data{1})],
154  'SegDataStart' => $segdatastart,
155  'SegData' => $segdata,
156  );
157  }
158 
159  // If this is a SOS (Start Of Scan) segment, then there is no more header data - the compressed image data follows
160  if ($data{1} == "\xDA")
161  {
162  // Flag that we have hit the compressed image data - exit loop as no more headers available.
163  $hit_compressed_image_data = true;
164  }
165  else
166  {
167  // Not an SOS - Read the next two bytes - should be the segment marker for the next segment
168  $data = fread($filehnd, 2);
169 
170  // Check that the first byte of the two is 0xFF as it should be for a marker
171  if ($data{0} != "\xFF")
172  {
173  // NO FF found - close file and return - JPEG is probably corrupted
174  fclose($filehnd);
175  return false;
176  }
177  }
178  }
179 
180  // Close File
181  fclose($filehnd);
182  // Alow the user to abort from now on
183  ignore_user_abort(false);
184 
185  // Return the header data retrieved
186  return $headerdata;
187  }
$filename
Definition: buildRTE.php:89
$GLOBALS['JPEG_Segment_Names']
Global Variable: XMP_tag_captions.
$data
Definition: bench.php:6
+ Here is the caller graph for this function:

◆ _get_XMP_text()

Image_XMP::_get_XMP_text (   $filename)

Retrieves XMP information from an APP1 JPEG segment and returns the raw XML text as a string.

Parameters
string$filename- the filename of the JPEG file to read
Returns
string $xmp_data - the string of raw XML text
boolean FALSE - if an APP 1 XMP segment could not be found, or if an error occured

Definition at line 197 of file module.tag.xmp.php.

References $filename, $i, and _get_jpeg_header_data().

Referenced by __construct().

198  {
199  //Get JPEG header data
200  $jpeg_header_data = $this->_get_jpeg_header_data($filename);
201 
202  //Cycle through the header segments
203  for ($i = 0; $i < count($jpeg_header_data); $i++)
204  {
205  // If we find an APP1 header,
206  if (strcmp($jpeg_header_data[$i]['SegName'], 'APP1') == 0)
207  {
208  // And if it has the Adobe XMP/RDF label (http://ns.adobe.com/xap/1.0/\x00) ,
209  if (strncmp($jpeg_header_data[$i]['SegData'], 'http://ns.adobe.com/xap/1.0/'."\x00", 29) == 0)
210  {
211  // Found a XMP/RDF block
212  // Return the XMP text
213  $xmp_data = substr($jpeg_header_data[$i]['SegData'], 29);
214 
215  return trim($xmp_data); // trim() should not be neccesary, but some files found in the wild with null-terminated block (known samples from Apple Aperture) causes problems elsewhere (see http://www.getid3.org/phpBB3/viewtopic.php?f=4&t=1153)
216  }
217  }
218  }
219  return false;
220  }
_get_jpeg_header_data($filename)
Reads all the JPEG header segments from an JPEG image file into an array.
$filename
Definition: buildRTE.php:89
$i
Definition: disco.tpl.php:19
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getAllTags()

Image_XMP::getAllTags ( )

Get a copy of all XMP tags extracted from the image.

Returns
array - An array of XMP fields as it extracted by the XMPparse() function

Definition at line 75 of file module.tag.xmp.php.

References $_aXMP.

76  {
77  return $this->_aXMP;
78  }

◆ isValid()

Image_XMP::isValid ( )

Returns the status of XMP parsing during instantiation.

You'll normally want to call this method before trying to get XMP fields.

Returns
boolean Returns true if an APP1 segment was found to contain XMP metadata.

Definition at line 65 of file module.tag.xmp.php.

References $_bXMPParse.

66  {
67  return $this->_bXMPParse;
68  }

◆ read_XMP_array_from_text()

Image_XMP::read_XMP_array_from_text (   $xmltext)

Parses a string containing XMP data (XML), and returns an array which contains all the XMP (XML) information.

Parameters
string$xml_text- a string containing the XMP data (XML) to be parsed
Returns
array $xmp_array - an array containing all xmp details retrieved.
boolean FALSE - couldn't parse the XMP data

Definition at line 230 of file module.tag.xmp.php.

References $key, $tags, and $values.

Referenced by __construct().

231  {
232  // Check if there actually is any text to parse
233  if (trim($xmltext) == '')
234  {
235  return false;
236  }
237 
238  // Create an instance of a xml parser to parse the XML text
239  $xml_parser = xml_parser_create('UTF-8');
240 
241  // Change: Fixed problem that caused the whitespace (especially newlines) to be destroyed when converting xml text to an xml array, as of revision 1.10
242 
243  // We would like to remove unneccessary white space, but this will also
244  // remove things like newlines (&#xA;) in the XML values, so white space
245  // will have to be removed later
246  if (xml_parser_set_option($xml_parser, XML_OPTION_SKIP_WHITE, 0) == false)
247  {
248  // Error setting case folding - destroy the parser and return
249  xml_parser_free($xml_parser);
250  return false;
251  }
252 
253  // to use XML code correctly we have to turn case folding
254  // (uppercasing) off. XML is case sensitive and upper
255  // casing is in reality XML standards violation
256  if (xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 0) == false)
257  {
258  // Error setting case folding - destroy the parser and return
259  xml_parser_free($xml_parser);
260  return false;
261  }
262 
263  // Parse the XML text into a array structure
264  if (xml_parse_into_struct($xml_parser, $xmltext, $values, $tags) == 0)
265  {
266  // Error Parsing XML - destroy the parser and return
267  xml_parser_free($xml_parser);
268  return false;
269  }
270 
271  // Destroy the xml parser
272  xml_parser_free($xml_parser);
273 
274  // Clear the output array
275  $xmp_array = array();
276 
277  // The XMP data has now been parsed into an array ...
278 
279  // Cycle through each of the array elements
280  $current_property = ''; // current property being processed
281  $container_index = -1; // -1 = no container open, otherwise index of container content
282  foreach ($values as $xml_elem)
283  {
284  // Syntax and Class names
285  switch ($xml_elem['tag'])
286  {
287  case 'x:xmpmeta':
288  // only defined attribute is x:xmptk written by Adobe XMP Toolkit; value is the version of the toolkit
289  break;
290 
291  case 'rdf:RDF':
292  // required element immediately within x:xmpmeta; no data here
293  break;
294 
295  case 'rdf:Description':
296  switch ($xml_elem['type'])
297  {
298  case 'open':
299  case 'complete':
300  if (array_key_exists('attributes', $xml_elem))
301  {
302  // rdf:Description may contain wanted attributes
303  foreach (array_keys($xml_elem['attributes']) as $key)
304  {
305  // Check whether we want this details from this attribute
306 // if (in_array($key, $GLOBALS['XMP_tag_captions']))
307  if (true)
308  {
309  // Attribute wanted
310  $xmp_array[$key] = $xml_elem['attributes'][$key];
311  }
312  }
313  }
314  case 'cdata':
315  case 'close':
316  break;
317  }
318 
319  case 'rdf:ID':
320  case 'rdf:nodeID':
321  // Attributes are ignored
322  break;
323 
324  case 'rdf:li':
325  // Property member
326  if ($xml_elem['type'] == 'complete')
327  {
328  if (array_key_exists('attributes', $xml_elem))
329  {
330  // If Lang Alt (language alternatives) then ensure we take the default language
331  if (isset($xml_elem['attributes']['xml:lang']) && ($xml_elem['attributes']['xml:lang'] != 'x-default'))
332  {
333  break;
334  }
335  }
336  if ($current_property != '')
337  {
338  $xmp_array[$current_property][$container_index] = (isset($xml_elem['value']) ? $xml_elem['value'] : '');
339  $container_index += 1;
340  }
341  //else unidentified attribute!!
342  }
343  break;
344 
345  case 'rdf:Seq':
346  case 'rdf:Bag':
347  case 'rdf:Alt':
348  // Container found
349  switch ($xml_elem['type'])
350  {
351  case 'open':
352  $container_index = 0;
353  break;
354  case 'close':
355  $container_index = -1;
356  break;
357  case 'cdata':
358  break;
359  }
360  break;
361 
362  default:
363  // Check whether we want the details from this attribute
364 // if (in_array($xml_elem['tag'], $GLOBALS['XMP_tag_captions']))
365  if (true)
366  {
367  switch ($xml_elem['type'])
368  {
369  case 'open':
370  // open current element
371  $current_property = $xml_elem['tag'];
372  break;
373 
374  case 'close':
375  // close current element
376  $current_property = '';
377  break;
378 
379  case 'complete':
380  // store attribute value
381  $xmp_array[$xml_elem['tag']] = (isset($xml_elem['attributes']) ? $xml_elem['attributes'] : (isset($xml_elem['value']) ? $xml_elem['value'] : ''));
382  break;
383 
384  case 'cdata':
385  // ignore
386  break;
387  }
388  }
389  break;
390  }
391 
392  }
393  return $xmp_array;
394  }
$values
$tags
Definition: croninfo.php:19
$key
Definition: croninfo.php:18
+ Here is the caller graph for this function:

Field Documentation

◆ $_aXMP

Image_XMP::$_aXMP = array()

Definition at line 48 of file module.tag.xmp.php.

Referenced by getAllTags().

◆ $_bXMPParse

Image_XMP::$_bXMPParse = false

Definition at line 55 of file module.tag.xmp.php.

Referenced by isValid().

◆ $_sFilename

Image_XMP::$_sFilename = null

Definition at line 41 of file module.tag.xmp.php.


The documentation for this class was generated from the following file: