Index: extensions/derivatives/i.php
===================================================================
--- extensions/derivatives/i.php	(revision 12770)
+++ extensions/derivatives/i.php	(revision 12775)
@@ -105,10 +105,10 @@
 
   $deriv = explode('_', $deriv);
-  foreach (ImageStdParams::get_all_types() as $type)
+  foreach (ImageStdParams::get_defined_type_map() as $type => $params)
   {
     if (substr($type,0,2) == $deriv[0])
     {
       $page['derivative_type'] = $type;
-      $page['derivative_params'] = ImageStdParams::get_by_type($type);
+      $page['derivative_params'] = $params;
       break;
     }
Index: extensions/derivatives/include/derivative.inc.php
===================================================================
--- extensions/derivatives/include/derivative.inc.php	(revision 12770)
+++ extensions/derivatives/include/derivative.inc.php	(revision 12775)
@@ -4,7 +4,8 @@
 {
   public $rel_path;
+  
   public $coi=null;
   private $size=null;
-  
+
   function __construct($infos)
   {
@@ -27,5 +28,5 @@
       $this->rel_path = get_themeconf('mime_icon_dir').strtolower($ext).'.png';
     }
-    
+
     $this->coi = @$infos['coi'];
     if (isset($infos['width']) && isset($infos['height']))
@@ -34,5 +35,10 @@
     }
   }
-  
+
+  function has_size()
+  {
+    return $this->size != null;
+  }
+
   function get_size()
   {
@@ -43,21 +49,39 @@
 }
 
+
+
 final class DerivativeImage
 {
+  const SAME_AS_SRC = 0x10;
+
   public $src_image;
+
+  private $requested_type;
+
+  private $flags = 0;
   private $params;
   private $rel_path, $rel_url;
-  
-  function __construct($type, $infos)
-  {
-    $this->src_image = new SrcImage($infos);
-    self::build($type, $src_image, $this->rel_path, $this->rel_url, $this->params);
-  }
-  
+
+  function __construct($type, $src_image)
+  {
+    $this->src_image = $src_image;
+    if (is_string($type))
+    {
+      $this->requested_type = $type;
+      $this->params = ImageStdParams::get_by_type($type);
+    }
+    else
+    {
+      $this->requested_type = IMG_CUSTOM;
+      $this->params = $type;
+    }
+
+    self::build($src_image, $this->params, $this->rel_path, $this->rel_url, $this->flags);
+  }
+
   static function thumb_url($infos)
   {
     $src_image = new SrcImage($infos);
-    self::build(IMG_THUMB, $src_image, $rel_path, $rel_url);
-    //die($rel_url);
+    self::build($src_image, ImageStdParams::get_by_type(IMG_THUMB), $rel_path, $rel_url);
     return get_root_url().$rel_url;
   }
@@ -66,37 +90,50 @@
   {
     $src_image = new SrcImage($infos);
-    self::build($type, $src_image, $rel_path, $rel_url);
+    $params = is_string($type) ? ImageStdParams::get_by_type($type) : $type;
+    self::build($src_image, $params, $rel_path, $rel_url);
     return get_root_url().$rel_url;
   }
-  
-  private static function build($type, $src, &$rel_path, &$rel_url, &$params = null)
-  {
-    if (is_string($type))
-    {
-      $params = ImageStdParams::get_by_type($type);
-    }
-    else
-    {
-      $type = IMG_CUSTOM;
+
+  static function get_all($infos)
+  {
+    $src_image = new SrcImage($infos);
+    $ret = array();
+    foreach (ImageStdParams::get_defined_type_map() as $type => $params)
+    {
+      $derivative = new DerivativeImage($params, $src_image);
+      $ret[$type] = $derivative;
+    }
+    foreach (ImageStdParams::get_undefined_type_map() as $type => $type2)
+    {
+      $ret[$type] = $ret[$type2];
     }
     
-    // todo check if we should not downgrade to a different type because 
-    // original file is too small ...
-    // we are using a mime type icon ...
-    // etc...
-    
+    return $ret;
+  }
+
+  private static function build($src, &$params, &$rel_path, &$rel_url, &$flags = null)
+  {
+    if ( $src->has_size() && $params->is_identity( $src->get_size() ) )
+    {
+      // todo - what if we have a watermark maybe return a smaller size?
+      $flags |= self::SAME_AS_SRC;
+      $params = null;
+      $rel_path = $rel_url = $src->rel_path;
+      return;
+    }
+
     $tokens=array();
-    $tokens[] = substr($type,0,2);
-    
+    $tokens[] = substr($params->type,0,2);
+
     if (!empty($src->coi))
     {
       $tokens[] = 'ci'.$src->coi;
     }
-    
-    if ($type==IMG_CUSTOM)
+
+    if ($params->type==IMG_CUSTOM)
     {
       $params->add_url_tokens($tokens);
     }
-    
+
     $loc = $src->rel_path;
     if (substr_compare($loc, '../', 0, 3)==0)
@@ -107,5 +144,5 @@
 
     $rel_path = PWG_DERIVATIVE_DIR.$loc;
-    
+
     global $conf;
     $url_style=$conf['derivative_url_style'];
@@ -122,5 +159,5 @@
       }
     }
-    
+
     if ($url_style == 2)
     {
@@ -136,9 +173,43 @@
   }
 
+  function get_url()
+  {
+    return get_root_url().$this->rel_url;
+  }
+
+  function same_as_source()
+  {
+    return $this->flags & self::SAME_AS_SRC;
+  }
+
+
   /* returns the size of the derivative image*/
   function get_size()
   {
+    if ($this->flags & self::SAME_AS_SRC)
+    {
+      return $this->src_image->get_size();
+    }
     return $this->params->compute_final_size($this->src_image->get_size(), $this->src_image->coi);
   }
+
+  function get_size_htm()
+  {
+    $size = $this->get_size();
+    if ($size)
+    {
+      return 'width="'.$size[0].'" height="'.$size[1].'"';
+    }
+  }
+
+  function get_size_hr()
+  {
+    $size = $this->get_size();
+    if ($size)
+    {
+      return $size[0].' x '.$size[1];
+    }
+  }
+
 }
 
Index: extensions/derivatives/include/derivative_params.inc.php
===================================================================
--- extensions/derivatives/include/derivative_params.inc.php	(revision 12770)
+++ extensions/derivatives/include/derivative_params.inc.php	(revision 12775)
@@ -30,5 +30,5 @@
 {
   public $l,$t,$r,$b;
-  
+
   function __construct($l)
   {
@@ -37,10 +37,10 @@
     $this->b = $l[1];
   }
-  
+
   function width()
   {
     return $this->r - $this->l;
   }
-  
+
   function height()
   {
@@ -53,5 +53,5 @@
       return;
     $tlcrop = floor($pixels/2);
-    
+
     if (!empty($coi))
     {
@@ -83,5 +83,5 @@
     $this->r -= $pixels - $tlcrop;
   }
-  
+
   function crop_v($pixels, $coi, $force)
   {
@@ -89,5 +89,5 @@
       return;
     $tlcrop = floor($pixels/2);
-    
+
     if (!empty($coi))
     {
@@ -132,5 +132,5 @@
     $this->min_size = $min_size;
   }
-  
+
   static function classic($w, $h)
   {
@@ -142,8 +142,8 @@
     return new SizingParams( array($w,$w), 1, array($w,$w) );
   }
-  
+
   function add_url_tokens(&$tokens)
   {
-      if (!$this->could_crop())
+      if ($this->max_crop == 0)
       {
         $tokens[] = 's'.size_to_url($this->ideal_size);
@@ -160,5 +160,5 @@
       }
   }
-  
+
   static function from_url_tokens($tokens)
   {
@@ -175,26 +175,22 @@
       return new SizingParams($s, 1, $s);
     }
-    
+
     $ideal_size = url_to_size( $token );
     if (count($tokens)<2)
       throw new Exception('Sizing arr');
-      
+
     $token = array_shift($tokens);
     $crop = sscanf('%02x' , $token) / 100;
-    
+
     $token = array_shift($tokens);
     $min_size = url_to_size( $token );
     return new SizingParams($ideal_size, $crop, $min_size);
   }
-  
-  function could_crop()
-  {
-    return $this->max_crop > 0;
-  }
+
 
   function compute($in_size, $coi, &$crop_rect, &$scale_size)
   {
     $destCrop = new ImageRect($in_size);
-    
+
     if ($this->max_crop > 0)
     {
@@ -225,7 +221,7 @@
       }
     }
-    
+
     $scale_size = array($destCrop->width(), $destCrop->height());
-    
+
     $ratio_w = $destCrop->width() / $this->ideal_size[0];
     $ratio_h = $destCrop->height() / $this->ideal_size[1];
@@ -247,5 +243,5 @@
       $scale_size = null;
     }
-    
+
     $crop_rect = null;
     if ($destCrop->width()!=$in_size[0] || $destCrop->height()!=$in_size[1] )
@@ -261,16 +257,17 @@
 final class ImageParams
 {
+  public $type = IMG_CUSTOM;
   public $sizing;
-  
+
   function __construct($sizing)
   {
     $this->sizing = $sizing;
   }
-  
+
   function add_url_tokens(&$tokens)
   {
     $this->sizing->add_url_tokens($tokens);
   }
-  
+
   static function from_url_tokens($tokens)
   {
@@ -279,5 +276,5 @@
     return $ret;
   }
-  
+
   function compute_final_size($in_size, $coi)
   {
@@ -285,4 +282,14 @@
     return $scale_size != null ? $scale_size : $in_size;
   }
+
+  function is_identity($in_size)
+  {
+    if ($in_size[0] > $this->sizing->ideal_size[0] or
+        $in_size[1] > $this->sizing->ideal_size[1] )
+    {
+      return false;
+    }
+    return true;
+  }
 }
 ?>
Index: extensions/derivatives/include/derivative_std_params.inc.php
===================================================================
--- extensions/derivatives/include/derivative_std_params.inc.php	(revision 12770)
+++ extensions/derivatives/include/derivative_std_params.inc.php	(revision 12775)
@@ -1,5 +1,5 @@
 <?php
 
-define('IMG_TINY', 'tiny');
+define('IMG_SQUARE', 'square');
 define('IMG_THUMB', 'thumb');
 define('IMG_SMALL', 'small');
@@ -12,6 +12,8 @@
 final class ImageStdParams
 {
-  private static $all_types = array();
+  private static $all_types = array(IMG_SQUARE,IMG_THUMB,IMG_SMALL,IMG_MEDIUM,IMG_LARGE,IMG_XLARGE,IMG_XXLARGE);
+  private static $all_type_map = array();
   private static $type_map = array();
+  private static $undefined_type_map = array();
   
   static function get_all_types()
@@ -20,7 +22,22 @@
   }
   
+  static function get_all_type_map()
+  {
+    return self::$all_type_map;
+  }
+
+  static function get_defined_type_map()
+  {
+    return self::$type_map;
+  }
+
+  static function get_undefined_type_map()
+  {
+    return self::$undefined_type_map;
+  }
+  
   static function get_by_type($type)
   {
-    return self::$type_map[$type];
+    return self::$all_type_map[$type];
   }
   
@@ -28,4 +45,5 @@
   {
     self::make_default();
+    self::build_maps();
   }
 
@@ -33,4 +51,5 @@
   {
     self::make_default();
+    self::build_maps();
   }
 
@@ -38,11 +57,39 @@
   {
     //todo
-    self::$type_map[IMG_TINY] = new ImageParams( SizingParams::square(100,100) );
+    self::$type_map[IMG_SQUARE] = new ImageParams( SizingParams::square(100,100) );
     self::$type_map[IMG_THUMB] = new ImageParams( SizingParams::classic(144,144) );
     self::$type_map[IMG_SMALL] = new ImageParams( SizingParams::classic(240,240) );
     self::$type_map[IMG_MEDIUM] = new ImageParams( SizingParams::classic(432,432) );
     self::$type_map[IMG_LARGE] = new ImageParams( SizingParams::classic(864,648) );
-    self::$all_types = array_keys(self::$type_map);
+    self::$type_map[IMG_XLARGE] = new ImageParams( SizingParams::classic(1200,900) );
   }
+  
+  private static function build_maps()
+  {
+    foreach (self::$type_map as $type=>$params)
+    {
+      $params->type = $type;
+    }
+    self::$all_type_map = self::$type_map;
+
+    for ($i=0; $i<count(self::$all_types); $i++)
+    {
+      $tocheck = self::$all_types[$i];
+      if (!isset(self::$type_map[$tocheck]))
+      {
+        for ($j=$i-1; $j>=0; $j--)
+        {
+          $target = self::$all_types[$j];
+          if (isset(self::$type_map[$target]))
+          {
+            self::$all_type_map[$tocheck] = self::$type_map[$target];
+            self::$undefined_type_map[$tocheck] = $target;
+            break;
+          }
+        }
+      }
+    }
+  }
+  
 }
 
Index: extensions/derivatives/main.inc.php
===================================================================
--- extensions/derivatives/main.inc.php	(revision 12770)
+++ extensions/derivatives/main.inc.php	(revision 12775)
@@ -24,3 +24,51 @@
 }
 
+
+add_event_handler(
+  'render_element_content',
+  'dyn_render_picture_content',
+  EVENT_HANDLER_PRIORITY_NEUTRAL-1,
+  2
+  );
+
+function dyn_render_picture_content($content, $element_info)
+{
+  if ( !empty($content) )
+  {// someone hooked us - so we skip;
+    return $content;
+  }
+
+  $all_derivatives = DerivativeImage::get_all($element_info);
+  //var_export($all_derivatives);
+  $selected_derivative = $all_derivatives[IMG_LARGE];
+
+  $available_derivatives = array();
+  $added = array();
+  foreach($all_derivatives as $type => $derivative)
+  {
+    $url = $derivative->get_url();
+    if (isset($added[$url]))
+      continue;
+    $added[$url] = 1;
+    $available_derivatives[] = $type;
+  }
+
+
+  global $user, $page, $template;
+
+  $template->set_filenames(
+    array('default_content'=> dirname(__FILE__).'/picture_content.tpl')
+    );
+
+  $template->append('current', array(
+      'all_derivatives' => $all_derivatives,
+      'selected_derivative' => $selected_derivative,
+      'available_derivative_types' => $available_derivatives,
+    ), true);
+
+  $template->assign( array(
+    'ALT_IMG' => $element_info['file'] ));
+
+  return $template->parse( 'default_content', true);;
+}
 ?>
Index: extensions/derivatives/picture_content.tpl
===================================================================
--- extensions/derivatives/picture_content.tpl	(revision 12775)
+++ extensions/derivatives/picture_content.tpl	(revision 12775)
@@ -0,0 +1,30 @@
+{if isset($high)}
+{combine_script id='core.scripts' load='async' path='themes/default/js/scripts.js'}
+<a href="javascript:phpWGOpenWindow('{$high.U_HIGH}','{$high.UUID}','scrollbars=yes,toolbar=no,status=no,resizable=yes')">
+{/if}
+	<img src="{$current.selected_derivative->get_url()}" {$current.selected_derivative->get_size_htm()} alt="{$ALT_IMG}" id="theMainImage"
+	{if isset($COMMENT_IMG)}
+		title="{$COMMENT_IMG|@strip_tags:false|@replace:'"':' '}" {else} title="{$current.TITLE|@replace:'"':' '} - {$ALT_IMG}"
+	{/if}>
+{if isset($high) }
+</a>
+	<p>{'Click on the photo to see it in high definition'|@translate}</p>
+{/if}
+{if count($current.available_derivative_types)>1}
+{footer_script}{literal}
+function changeImgSrc(src)
+{
+	var theImg = document.getElementById("theMainImage");
+	if (theImg)
+	{
+		theImg.removeAttribute("width");theImg.removeAttribute("height");
+		theImg.src = src;
+	}
+}
+{/literal}{/footer_script}
+<p>
+{foreach from=$current.available_derivative_types item=derivative_type}
+<a onclick="changeImgSrc('{$current.all_derivatives[$derivative_type]->get_url()|@escape:javascript}')" title="{$current.all_derivatives[$derivative_type]->get_size_hr()}">{$derivative_type}</a>
+{/foreach}
+</p>
+{/if}
