       * Read from a file
       *
       * @param   io.File file
-+     * @param   mixed default default FALSE what should be returned in case no data is found
++     * @param   mixed default default void what should be returned in case no data is found
       * @return  img.util.ExifData
-+     * @throws  img.MetadataException in case reading meta data fails
-      * @throws  img.ImagingException in case extracting data fails
+-     * @throws  img.ImagingException in case extracting data fails
++     * @throws  lang.FormatException in case malformed meta data is encountered
++     * @throws  lang.ElementNotFoundException in case no meta data is available
++     * @throws  img.ImagingException in case reading meta data fails
       */
 -    public static function fromFile($file) {
-+    public static function fromFile(File $file, $default= FALSE) {
++    public static function fromFile(File $file) {
 +      if (FALSE === getimagesize($file->getURI(), $info)) {
-+        throw new ImagingException('Cannot read EXIF information from '.$file->getURI());
++        throw new ImagingException('Cannot read image information from '.$file->getURI());
 +      }
 +      if (!isset($info['APP1'])) {
-+        if (FALSE !== $default) return $default;
-+        throw new MetadataException(
-+          'Cannot get EXIF information from '.$file->getURI(), 
-+          new ElementNotFoundException('No APP1 marker')
++        if (func_num_args() > 1) return func_get_arg(1);
++        throw new ElementNotFoundException(
++          'Cannot get EXIF information from '.$file->getURI().' (no APP1 marker)' 
 +        );
 +      }
        if (!($info= exif_read_data($file->getURI()))) {
 -        throw(new ImagingException(
 -          'Cannot get EXIF information from '.$file->getURI()
 -        ));
-+        throw new ImagingException('Cannot get EXIF information from '.$file->getURI());
++        throw new FormatException('Cannot get EXIF information from '.$file->getURI());
        }
        
        // Calculate orientation from dimensions if not available
-Index: IptcData.class.php
+Index: skeleton/img/util/IptcData.class.php
 ===================================================================
---- IptcData.class.php	(revision 11247)
-+++ IptcData.class.php	(working copy)
-@@ -4,23 +4,34 @@
-  * $Id$ 
-  */
- 
+--- skeleton/img/util/IptcData.class.php	(revision 11284)
++++ skeleton/img/util/IptcData.class.php	(working copy)
+@@ -1,500 +1,523 @@
+-<?php
+-/* This class is part of the XP framework
+- *
+- * $Id$ 
+- */
+-
 -  uses('util.Date', 'img.ImagingException');
-+  uses(
-+    'util.Date', 
-+    'img.ImagingException', 
-+    'img.util.MetadataException', 
-+    'lang.ElementNotFoundException'
-+  );
- 
-   /**
+-
+-  /**
 -   * Reads the IPTC headers from Photoshop-files, JPEG or TIFF
-+   * Reads the IPTC headers from Photoshop-files, JPEGs or TIFFs
-    *
-    * <code>
-    *   uses('img.util.IptcData', 'io.File');
+-   *
+-   * <code>
+-   *   uses('img.util.IptcData', 'io.File');
 -   *   $i= IptcData::fromFile(new File($filename));
 -   *   echo $i->toString();
-+   *
-+   *   // Use empty iptc data as default value when no iptc data is found
-+   *   echo IptcData::fromFile(new File($filename), IptcData::$EMPTY)->toString();
-    * </code>
-    *
-    * @ext      iptc
-    * @purpose  Utility
-+   * @see      php://iptcparse
-+   * @see      http://photothumb.com/IPTCExt/
-    * @see      http://www.controlledvocabulary.com/pdf/IPTC_mapped_fields.pdf
-    */
-   class IptcData extends Object {
+-   * </code>
+-   *
+-   * @ext      iptc
+-   * @purpose  Utility
+-   * @see      http://www.controlledvocabulary.com/pdf/IPTC_mapped_fields.pdf
+-   */
+-  class IptcData extends Object {
 -    protected
-+    public static
-+      $EMPTY= NULL;
-+
-+    public
-       $title                         = '',
-       $urgency                       = '',
-       $category                      = '',
-@@ -41,21 +52,36 @@
-       $supplementalCategories        = array(),
-       $originalTransmissionReference = '';
- 
-+    static function __static() {
-+      self::$EMPTY= new self();
-+    }
-+
-     /**
-      * Read from a file
-      *
-      * @param   io.File file
-+     * @param   mixed default default FALSE what should be returned in case no data is found
-      * @return  img.util.IptcData
-+     * @throws  img.MetadataException in case reading meta data fails
-      * @throws  img.ImagingException in case extracting data fails
-      */
+-      $title                         = '',
+-      $urgency                       = '',
+-      $category                      = '',
+-      $keywords                      = array(), 
+-      $dateCreated                   = NULL, 
+-      $author                        = '', 
+-      $authorPosition                = '', 
+-      $city                          = '', 
+-      $state                         = '', 
+-      $country                       = '', 
+-      $headline                      = '', 
+-      $credit                        = '', 
+-      $source                        = '', 
+-      $copyrightNotice               = '', 
+-      $caption                       = '', 
+-      $writer                        = '', 
+-      $specialInstructions           = '',
+-      $supplementalCategories        = array(),
+-      $originalTransmissionReference = '';
+-
+-    /**
+-     * Read from a file
+-     *
+-     * @param   io.File file
+-     * @return  img.util.IptcData
+-     * @throws  img.ImagingException in case extracting data fails
+-     */
 -    public static function fromFile($file) {
 -      getimagesize($file->getURI(), $info);
 -      if (!($info['APP13'])) {
 -        throw new ImagingException(
 -          'Cannot get IPTC information from '.$file->getURI()
-+    public static function fromFile(File $file, $default= FALSE) {
-+      if (FALSE === getimagesize($file->getURI(), $info)) {
-+        throw new ImagingException('Cannot read IPTC information from '.$file->getURI());
-+      }
-+      if (!isset($info['APP13'])) {
-+        if (FALSE !== $default) return $default;
-+        throw new MetadataException(
-+          'Cannot get IPTC information from '.$file->getURI(), 
-+          new ElementNotFoundException('No APP13 marker')
-         );
-       }
+-        );
+-      }
 -      $iptc= iptcparse($info['APP13']);
-+      if (!($iptc= iptcparse($info['APP13']))) {
-+        throw new MetadataException(
-+          'Cannot extract IPTC information from '.$file->getURI(),
-+          new FormatException('Cannot parse APP13 marker')
-+        );
-+      }
-       
-       // Parse creation date
-       if (3 == sscanf($iptc['2#055'][0], '%4d%2d%d', $year, $month, $day)) {
-@@ -65,25 +91,25 @@
-       }
- 
-       with ($i= new self()); {
+-      
+-      // Parse creation date
+-      if (3 == sscanf($iptc['2#055'][0], '%4d%2d%d', $year, $month, $day)) {
+-        $created= Date::create($year, $month, $day, 0, 0, 0);
+-      } else {
+-        $created= NULL;
+-      }
+-
+-      with ($i= new self()); {
 -        $i->setTitle($iptc['2#005'][0]);
 -        $i->setUrgency($iptc['2#010'][0]);
 -        $i->setCategory($iptc['2#015'][0]);
 -        $i->setSupplementalCategories($iptc['2#020']);
 -        $i->setKeywords($iptc['2#025']);
 -        $i->setSpecialInstructions($iptc['2#040'][0]);
-+        $i->setTitle(@$iptc['2#005'][0]);
-+        $i->setUrgency(@$iptc['2#010'][0]);
-+        $i->setCategory(@$iptc['2#015'][0]);
-+        $i->setSupplementalCategories(@$iptc['2#020']);
-+        $i->setKeywords(@$iptc['2#025']);
-+        $i->setSpecialInstructions(@$iptc['2#040'][0]);
-         $i->setDateCreated($created);
+-        $i->setDateCreated($created);
 -        $i->setAuthor($iptc['2#080'][0]);
 -        $i->setAuthorPosition($iptc['2#085'][0]);
 -        $i->setCity($iptc['2#090'][0]);

Index: ExifData.class.php
===================================================================
--- ExifData.class.php	(revision 11247)
+++ ExifData.class.php	(working copy)
@@ -9,16 +9,29 @@
     'img.ImagingException',
     'img.Image',
     'img.io.StreamReader',
-    'io.Stream'
+    'io.Stream',
+    'img.util.MetadataException', 
+    'lang.ElementNotFoundException'
   );
 

+   *   echo ExifData::fromFile(new File($filename), ExifData::$EMPTY)->toString();
+   * </code>
+   *
+   * @test     xp://net.xp_framework.unittest.img.ExifDataTest
+   * @see      php://exif_read_data
    * @ext      exif
    * @purpose  Utility
