source: trunk/include/derivative.inc.php @ 26010

Last change on this file since 26010 was 25754, checked in by mistic100, 10 years ago

feature 2999 : Documentation of multisize classes

File size: 13.3 KB
RevLine 
[12796]1<?php
2// +-----------------------------------------------------------------------+
3// | Piwigo - a PHP based photo gallery                                    |
4// +-----------------------------------------------------------------------+
[19703]5// | Copyright(C) 2008-2013 Piwigo Team                  http://piwigo.org |
[12796]6// +-----------------------------------------------------------------------+
7// | This program is free software; you can redistribute it and/or modify  |
8// | it under the terms of the GNU General Public License as published by  |
9// | the Free Software Foundation                                          |
10// |                                                                       |
11// | This program is distributed in the hope that it will be useful, but   |
12// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
13// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
14// | General Public License for more details.                              |
15// |                                                                       |
16// | You should have received a copy of the GNU General Public License     |
17// | along with this program; if not, write to the Free Software           |
18// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
19// | USA.                                                                  |
20// +-----------------------------------------------------------------------+
21
[25754]22/**
23 * @package Derivatives
24 */
25
26
27/**
28 * A source image is used to get a derivative image. It is either
29 * the original file for a jpg/png/... or a 'representative' image
30 * of a  non image file or a standard icon for the non-image file.
31 */
[12796]32final class SrcImage
33{
[12797]34  const IS_ORIGINAL = 0x01;
35  const IS_MIMETYPE = 0x02;
[14735]36  const DIM_NOT_GIVEN = 0x04;
[12797]37
[25754]38  /** @var int */
[12954]39  public $id;
[25754]40  /** @var string */
[12796]41  public $rel_path;
[25754]42  /** @var int */
[14143]43  public $rotation = 0;
[25754]44  /** @var int[] */
[12796]45  private $size=null;
[25754]46  /** @var int */
[12797]47  private $flags=0;
[12796]48
[25754]49  /**
50   * @param array $infos assoc array of data from images table
51   */
[12796]52  function __construct($infos)
53  {
54    global $conf;
[13038]55
[12954]56    $this->id = $infos['id'];
[12796]57    $ext = get_extension($infos['path']);
58    if (in_array($ext, $conf['picture_ext']))
59    {
60      $this->rel_path = $infos['path'];
[12797]61      $this->flags |= self::IS_ORIGINAL;
[12796]62    }
63    elseif (!empty($infos['representative_ext']))
64    {
[12831]65      $this->rel_path = original_to_representative($infos['path'], $infos['representative_ext']);
[12796]66    }
67    else
68    {
[12797]69      $ext = strtolower($ext);
70      $this->rel_path = trigger_event('get_mimetype_location', get_themeconf('mime_icon_dir').$ext.'.png', $ext );
71      $this->flags |= self::IS_MIMETYPE;
[14735]72      if ( ($size=@getimagesize(PHPWG_ROOT_PATH.$this->rel_path)) === false)
73      {
[15431]74        $this->rel_path = 'themes/default/icon/mimetypes/unknown.png';
[14735]75        $size = getimagesize(PHPWG_ROOT_PATH.$this->rel_path);
76      }
77      $this->size = array($size[0],$size[1]);
[12796]78    }
79
[14735]80    if (!$this->size)
[12796]81    {
[14735]82      if (isset($infos['width']) && isset($infos['height']))
83      {
84        $width = $infos['width'];
85        $height = $infos['height'];
[13843]86
[14735]87        $this->rotation = intval($infos['rotation']) % 4;
88        // 1 or 5 =>  90 clockwise
89        // 3 or 7 => 270 clockwise
90        if ($this->rotation % 2)
91        {
92          $width = $infos['height'];
93          $height = $infos['width'];
94        }
[20516]95
[14735]96        $this->size = array($width, $height);
97      }
98      elseif (!array_key_exists('width', $infos))
[13843]99      {
[14735]100        $this->flags |= self::DIM_NOT_GIVEN;
[13843]101      }
[12796]102    }
103  }
104
[25754]105  /**
106   * @return bool
107   */
[12797]108  function is_original()
109  {
110    return $this->flags & self::IS_ORIGINAL;
111  }
112
[25754]113  /**
114   * @return bool
115   */
[12797]116  function is_mimetype()
117  {
118    return $this->flags & self::IS_MIMETYPE;
119  }
120
[25754]121  /**
122   * @return string
123   */
[12797]124  function get_path()
125  {
126    return PHPWG_ROOT_PATH.$this->rel_path;
127  }
128
[25754]129  /**
130   * @return string
131   */
[12797]132  function get_url()
133  {
[13489]134    $url = get_root_url().$this->rel_path;
[20516]135    if ( !($this->flags & self::IS_MIMETYPE) )
[13489]136    {
137      $url = trigger_event('get_src_image_url', $url, $this);
138    }
139    return embellish_url($url);
[12797]140  }
141
[25754]142  /**
143   * @return bool
144   */
[12796]145  function has_size()
146  {
147    return $this->size != null;
148  }
149
[25754]150  /**
151   * @return int[]|null 0=width, 1=height or null if fail to compute size
152   */
[12796]153  function get_size()
154  {
155    if ($this->size == null)
[14735]156    {
157      if ($this->flags & self::DIM_NOT_GIVEN)
158        fatal_error('SrcImage dimensions required but not provided');
159      // probably not metadata synced
160      if ( ($size = getimagesize( $this->get_path() )) !== false)
161      {
162        $this->size = array($size[0],$size[1]);
163        pwg_query('UPDATE '.IMAGES_TABLE.' SET width='.$size[0].', height='.$size[1].' WHERE id='.$this->id);
164      }
165    }
[12796]166    return $this->size;
167  }
168}
169
170
[25754]171/**
172 * Holds information (path, url, dimensions) about a derivative image.
173 * A derivative image is constructed from a source image (SrcImage class)
174 * and derivative parameters (DerivativeParams class).
175 */
[12796]176final class DerivativeImage
177{
[25754]178  /** @var SrcImage */
[12796]179  public $src_image;
[25754]180  /** @var array */
[12796]181  private $params;
[25754]182  /** @var string */
183  private $rel_path;
184  /** @var string */
185  private $rel_url;
186  /** @var bool */
187  private $is_cached=true;
[12796]188
[25754]189  /**
190   * @param string|DerivativeParams $type standard derivative param type (e.g. IMG_*)
191   *    or a DerivativeParams object
192   * @param SrcImage $src_image the source image of this derivative
193   */
[19878]194  function __construct($type, SrcImage $src_image)
[12796]195  {
196    $this->src_image = $src_image;
197    if (is_string($type))
198    {
199      $this->params = ImageStdParams::get_by_type($type);
200    }
201    else
202    {
203      $this->params = $type;
204    }
205
[13444]206    self::build($src_image, $this->params, $this->rel_path, $this->rel_url, $this->is_cached);
[12796]207  }
208
[25754]209  /**
210   * Generates the url of a thumbnail.
211   *
212   * @param array|SrcImage $infos array of info from db or SrcImage
213   * @return string
214   */
[12796]215  static function thumb_url($infos)
216  {
[12908]217    return self::url(IMG_THUMB, $infos);
[12796]218  }
219
[20516]220  /**
[25754]221   * Generates the url for a particular photo size.
222   *
223   * @param string|DerivativeParams $type standard derivative param type (e.g. IMG_*)
224   *    or a DerivativeParams object
225   * @param array|SrcImage $infos array of info from db or SrcImage
226   * @return string
227   */
[12796]228  static function url($type, $infos)
229  {
[12908]230    $src_image = is_object($infos) ? $infos : new SrcImage($infos);
[12796]231    $params = is_string($type) ? ImageStdParams::get_by_type($type) : $type;
232    self::build($src_image, $params, $rel_path, $rel_url);
[12954]233    if ($params == null)
234    {
235      return $src_image->get_url();
236    }
237    return embellish_url(
238        trigger_event('get_derivative_url',
239          get_root_url().$rel_url,
240          $params, $src_image, $rel_url
241          ) );
[12796]242  }
243
[19878]244  /**
[25504]245   * Return associative an array of all DerivativeImage for a specific image.
[25754]246   * Disabled derivative types can be still found in the return, mapped to an
[25504]247   * enabled derivative (e.g. the values are not unique in the return array).
248   * This is useful for any plugin/theme to just use $deriv[IMG_XLARGE] even if
249   * the XLARGE is disabled.
250   *
251   * @param array|SrcImage $src_image array of info from db or SrcImage
252   * @return DerivativeImage[]
253   */
[12855]254  static function get_all($src_image)
[12796]255  {
[25504]256    if (!is_object($src_image))
257    {
258      $src_image = new SrcImage($src_image);
259    }
260
[12796]261    $ret = array();
[19878]262    // build enabled types
[12796]263    foreach (ImageStdParams::get_defined_type_map() as $type => $params)
264    {
265      $derivative = new DerivativeImage($params, $src_image);
266      $ret[$type] = $derivative;
267    }
[25504]268    // disabled types, fallback to enabled types
[12796]269    foreach (ImageStdParams::get_undefined_type_map() as $type => $type2)
270    {
271      $ret[$type] = $ret[$type2];
272    }
[12797]273
[12796]274    return $ret;
275  }
276
[25504]277  /**
278   * Returns an instance of DerivativeImage for a specific image and size.
279   * Disabled derivatives fallback to an enabled derivative.
280   *
[25754]281   * @param string $type standard derivative param type (e.g. IMG_*)
[25504]282   * @param array|SrcImage $src_image array of info from db or SrcImage
283   * @return DerivativeImage|null null if $type not found
284   */
285  static function get_one($type, $src_image)
286  {
287    if (!is_object($src_image))
288    {
289      $src_image = new SrcImage($src_image);
290    }
291
292    $defined = ImageStdParams::get_defined_type_map();
293    if (isset($defined[$type]))
294    {
295      return new DerivativeImage($defined[$type], $src_image);
296    }
297
298    $undefined = ImageStdParams::get_undefined_type_map();
299    if (isset($undefined[$type]))
300    {
301      return new DerivativeImage($defined[ $undefined[$type] ], $src_image);
302    }
303
304    return null;
305  }
306
[25754]307  /**
308   * @todo : documentation of DerivativeImage::build
309   */
[13444]310  private static function build($src, &$params, &$rel_path, &$rel_url, &$is_cached=null)
[12796]311  {
312    if ( $src->has_size() && $params->is_identity( $src->get_size() ) )
[19878]313    {// the source image is smaller than what we should do - we do not upsample
[16989]314      if (!$params->will_watermark($src->get_size()) && !$src->rotation)
[19878]315      {// no watermark, no rotation required -> we will use the source image
[14143]316        $params = null;
317        $rel_path = $rel_url = $src->rel_path;
318        return;
319      }
320      $defined_types = array_keys(ImageStdParams::get_defined_type_map());
321      for ($i=0; $i<count($defined_types); $i++)
322      {
323        if ($defined_types[$i] == $params->type)
324        {
325          for ($i--; $i>=0; $i--)
326          {
327            $smaller = ImageStdParams::get_by_type($defined_types[$i]);
328            if ($smaller->sizing->max_crop==$params->sizing->max_crop && $smaller->is_identity( $src->get_size() ))
329            {
330              $params = $smaller;
331              self::build($src, $params, $rel_path, $rel_url, $is_cached);
332              return;
333            }
334          }
335          break;
336        }
337      }
[12796]338    }
339
340    $tokens=array();
341    $tokens[] = substr($params->type,0,2);
342
343    if ($params->type==IMG_CUSTOM)
344    {
345      $params->add_url_tokens($tokens);
346    }
347
348    $loc = $src->rel_path;
349    if (substr_compare($loc, './', 0, 2)==0)
350    {
351      $loc = substr($loc, 2);
352    }
353    elseif (substr_compare($loc, '../', 0, 3)==0)
354    {
355      $loc = substr($loc, 3);
356    }
357    $loc = substr_replace($loc, '-'.implode('_', $tokens), strrpos($loc, '.'), 0 );
358
359    $rel_path = PWG_DERIVATIVE_DIR.$loc;
360
361    global $conf;
362    $url_style=$conf['derivative_url_style'];
363    if (!$url_style)
364    {
365      $mtime = @filemtime(PHPWG_ROOT_PATH.$rel_path);
366      if ($mtime===false or $mtime < $params->last_mod_time)
367      {
[13444]368        $is_cached = false;
[12796]369        $url_style = 2;
370      }
371      else
372      {
373        $url_style = 1;
374      }
375    }
376
377    if ($url_style == 2)
378    {
379      $rel_url = 'i';
380      if ($conf['php_extension_in_urls']) $rel_url .= '.php';
381      if ($conf['question_mark_in_urls']) $rel_url .= '?';
382      $rel_url .= '/'.$loc;
383    }
384    else
385    {
386      $rel_url = $rel_path;
387    }
388  }
389
[25754]390  /**
391   * @return string
392   */
[12865]393  function get_path()
394  {
395    return PHPWG_ROOT_PATH.$this->rel_path;
396  }
397
[25754]398  /**
399   * @return string
400   */
[12796]401  function get_url()
402  {
[12954]403    if ($this->params == null)
404    {
405      return $this->src_image->get_url();
406    }
407    return embellish_url(
408        trigger_event('get_derivative_url',
409          get_root_url().$this->rel_url,
410          $this->params, $this->src_image, $this->rel_url
411          ) );
[12796]412  }
413
[25754]414  /**
415   * @return bool
416   */
[12796]417  function same_as_source()
418  {
[12954]419    return $this->params == null;
[12796]420  }
421
[25754]422  /**
423   * @return string one if IMG_* or 'Original'
424   */
[12797]425  function get_type()
426  {
[12954]427    if ($this->params == null)
[13068]428      return 'Original';
[12797]429    return $this->params->type;
430  }
431
[25754]432  /**
433   * @return int[]
434   */
[12796]435  function get_size()
436  {
[12954]437    if ($this->params == null)
[12796]438    {
439      return $this->src_image->get_size();
440    }
[13038]441    return $this->params->compute_final_size($this->src_image->get_size());
[12796]442  }
443
[25754]444  /**
445   * Returns the size as CSS rule.
446   *
447   * @return string
448   */
[16508]449  function get_size_css()
450  {
451    $size = $this->get_size();
452    if ($size)
453    {
454      return 'width:'.$size[0].'px; height:'.$size[1].'px';
455    }
456  }
457
[25754]458  /**
459   * Returns the size as HTML attributes.
460   *
461   * @return string
462   */
[12796]463  function get_size_htm()
464  {
465    $size = $this->get_size();
466    if ($size)
467    {
[13170]468      return 'width="'.$size[0].'" height="'.$size[1].'"';
[12796]469    }
470  }
471
[25754]472  /**
473   * Returns literal size: $widthx$height.
474   *
475   * @return string
476   */
[12796]477  function get_size_hr()
478  {
479    $size = $this->get_size();
480    if ($size)
481    {
482      return $size[0].' x '.$size[1];
483    }
484  }
485
[25754]486  /**
487   * @param int $maxw
488   * @param int $mawh
489   * @return int[]
490   */
[13252]491  function get_scaled_size($maxw, $maxh)
492  {
493    $size = $this->get_size();
494    if ($size)
495    {
496      $ratio_w = $size[0] / $maxw;
497      $ratio_h = $size[1] / $maxh;
498      if ($ratio_w>1 || $ratio_h>1)
499      {
500        if ($ratio_w > $ratio_h)
501        {
502          $size[0] = $maxw;
503          $size[1] = floor($size[1] / $ratio_w);
504        }
505        else
506        {
507          $size[0] = floor($size[0] / $ratio_h);
508          $size[1] = $maxh;
509        }
510      }
511    }
512    return $size;
513  }
514
[25754]515  /**
516   * Returns the scaled size as HTML attributes.
517   *
518   * @param int $maxw
519   * @param int $mawh
520   * @return string
521   */
[13252]522  function get_scaled_size_htm($maxw=9999, $maxh=9999)
523  {
524    $size = $this->get_scaled_size($maxw, $maxh);
525    if ($size)
526    {
527      return 'width="'.$size[0].'" height="'.$size[1].'"';
528    }
529  }
[13444]530
[25754]531  /**
532   * @return bool
533   */
[13444]534  function is_cached()
535  {
536    return $this->is_cached;
537  }
[12796]538}
539
540?>
Note: See TracBrowser for help on using the repository browser.