-Index: ExifData.class.php
+Index: skeleton/img/util/ExifData.class.php
 ===================================================================
---- ExifData.class.php	(revision 11247)
-+++ ExifData.class.php	(working copy)
+--- skeleton/img/util/ExifData.class.php	(revision 11284)
++++ skeleton/img/util/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'
    );
  

      * 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.ExifData
+     * @throws  img.MetadataException in case reading meta data fails
      * @throws  img.ImagingException in case extracting data fails
      */
-    public static function fromFile($file) {
+    public static function fromFile(File $file, $default= FALSE) {
+      if (FALSE === getimagesize($file->getURI(), $info)) {
+        throw new ImagingException('Cannot read EXIF 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 (!($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());
       }
       
       // Calculate orientation from dimensions if not available
Index: IptcData.class.php
===================================================================
--- IptcData.class.php	(revision 11247)
+++ IptcData.class.php	(working copy)
@@ -4,23 +4,34 @@
  * $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');
-   *   $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 {
-    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
      */
-    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()); {
-        $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->setAuthor($iptc['2#080'][0]);
-        $i->setAuthorPosition($iptc['2#085'][0]);
-        $i->setCity($iptc['2#090'][0]);

+   *   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
