source: trunk/include/derivative_params.inc.php @ 26920

Last change on this file since 26920 was 26461, checked in by mistic100, 11 years ago

Update headers to 2014. Happy new year!!

File size: 10.6 KB
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | Piwigo - a PHP based photo gallery                                    |
4// +-----------------------------------------------------------------------+
5// | Copyright(C) 2008-2014 Piwigo Team                  http://piwigo.org |
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
22/**
23 * @package Derivatives
24 */
25
26
27/**
28 * Formats a size name into a 2 chars identifier usable in filename.
29 *
30 * @param string $t one of IMG_*
31 * @return string
32 */
33function derivative_to_url($t)
34{
35  return substr($t, 0, 2);
36}
37
38/**
39 * Formats a size array into a identifier usable in filename.
40 *
41 * @param int[] $s
42 * @return string
43 */
44function size_to_url($s)
45{
46  if ($s[0]==$s[1])
47  {
48    return $s[0];
49  }
50  return $s[0].'x'.$s[1];
51}
52
53/**
54 * @param int[] $s1
55 * @param int[] $s2
56 * @return bool
57 */
58function size_equals($s1, $s2)
59{
60  return ($s1[0]==$s2[0] && $s1[1]==$s2[1]);
61}
62
63/**
64 * Converts a char a-z into a float.
65 *
66 * @param string
67 * @return float
68 */
69function char_to_fraction($c)
70{
71        return (ord($c) - ord('a'))/25;
72}
73
74/**
75 * Converts a float into a char a-z.
76 *
77 * @param float
78 * @return string
79 */
80function fraction_to_char($f)
81{
82        return chr(ord('a') + round($f*25));
83}
84
85
86/**
87 * Small utility to manipulate a 'rectangle'.
88 */
89final class ImageRect
90{
91  /**
92   * @var int $l
93   * @var int $t
94   * @var int $r
95   * @var int $b
96   */
97  public $l,$t,$r,$b;
98
99  /**
100   * @param int[] $l width and height
101   */
102  function __construct($l)
103  {
104    $this->l = $this->t = 0;
105    $this->r = $l[0];
106    $this->b = $l[1];
107  }
108
109  /**
110   * @return int
111   */
112  function width()
113  {
114    return $this->r - $this->l;
115  }
116
117  /**
118   * @return int
119   */
120  function height()
121  {
122    return $this->b - $this->t;
123  }
124
125  /**
126   * Crops horizontally this rectangle by increasing left side and/or reducing the right side.
127   *
128   * @param int $pixels - the amount to substract from the width
129   * @param stirng $coi - a 4 character string (or null) containing the center of interest
130   */
131  function crop_h($pixels, $coi)
132  {
133    if ($this->width() <= $pixels)
134      return;
135    $tlcrop = floor($pixels/2);
136
137    if (!empty($coi))
138    {
139      $coil = floor($this->r * char_to_fraction($coi[0]));
140      $coir = ceil($this->r * char_to_fraction($coi[2]));
141      $availableL = $coil > $this->l ? $coil - $this->l : 0;
142      $availableR = $coir < $this->r ? $this->r - $coir : 0;
143      if ($availableL + $availableR >= $pixels)
144      {
145        if ($availableL < $tlcrop)
146        {
147          $tlcrop = $availableL;
148        }
149        elseif ($availableR < $tlcrop)
150        {
151          $tlcrop = $pixels - $availableR;
152        }
153      }
154    }
155    $this->l += $tlcrop;
156    $this->r -= $pixels - $tlcrop;
157  }
158
159  /**
160   * Crops vertically this rectangle by increasing top side and/or reducing the bottom side.
161   *
162   * @param int $pixels - the amount to substract from the height
163   * @param string $coi - a 4 character string (or null) containing the center of interest
164   */
165  function crop_v($pixels, $coi)
166  {
167    if ($this->height() <= $pixels)
168      return;
169    $tlcrop = floor($pixels/2);
170
171    if (!empty($coi))
172    {
173      $coit = floor($this->b * char_to_fraction($coi[1]));
174      $coib = ceil($this->b * char_to_fraction($coi[3]));
175      $availableT = $coit > $this->t ? $coit - $this->t : 0;
176      $availableB = $coib < $this->b ? $this->b - $coib : 0;
177      if ($availableT + $availableB >= $pixels)
178      {
179        if ($availableT < $tlcrop)
180        {
181          $tlcrop = $availableT;
182        }
183        elseif ($availableB < $tlcrop)
184        {
185          $tlcrop = $pixels - $availableB;
186        }
187      }
188    }
189    $this->t += $tlcrop;
190    $this->b -= $pixels - $tlcrop;
191  }
192}
193
194
195/**
196 * Paramaters for derivative scaling and cropping.
197 * Instance of this class contained by DerivativeParams class.
198 */
199final class SizingParams
200{
201  /** @var int[] */
202  var $ideal_size;
203  /** @var float */
204  var $max_crop;
205  /** @var int[] */
206  var $min_size;
207
208  /**
209   * @param int[] $ideal_size - two element array of maximum output dimensions (width, height)
210   * @param float $max_crop - from 0=no cropping to 1= max cropping (100% of width/height);
211   *    expressed as a factor of the input width/height
212   * @param int[] $min_size - (used only if _$max_crop_ !=0) two element array of output dimensions (width, height)
213   */
214  function __construct($ideal_size, $max_crop=0, $min_size=null)
215  {
216    $this->ideal_size = $ideal_size;
217    $this->max_crop = $max_crop;
218    $this->min_size = $min_size;
219  }
220
221  /**
222   * Returns a simple SizingParams object.
223   *
224   * @param int $w
225   * @param int $h
226   * @return SizingParams
227   */
228  static function classic($w, $h)
229  {
230    return new SizingParams( array($w,$h) );
231  }
232
233  /**
234   * Returns a square SizingParams object.
235   *
236   * @param int $x
237   * @return SizingParams
238   */
239  static function square($w)
240  {
241    return new SizingParams( array($w,$w), 1, array($w,$w) );
242  }
243
244  /**
245   * Adds tokens depending on sizing configuration.
246   *
247   * @param array &$tokens
248   */
249  function add_url_tokens(&$tokens)
250  {
251      if ($this->max_crop == 0)
252      {
253        $tokens[] = 's'.size_to_url($this->ideal_size);
254      }
255      elseif ($this->max_crop == 1 && size_equals($this->ideal_size, $this->min_size) )
256      {
257        $tokens[] = 'e'.size_to_url($this->ideal_size);
258      }
259      else
260      {
261        $tokens[] = size_to_url($this->ideal_size);
262        $tokens[] = fraction_to_char($this->max_crop);
263        $tokens[] = size_to_url($this->min_size);
264      }
265  }
266
267  /**
268   * Calculates the cropping rectangle and the scaled size for an input image size.
269   *
270   * @param int[] $in_size - two element array of input dimensions (width, height)
271   * @param string $coi - four character encoded string containing the center of interest (unused if max_crop=0)
272   * @param ImageRect &$crop_rect - ImageRect containing the cropping rectangle or null if cropping is not required
273   * @param int[] &$scale_size - two element array containing width and height of the scaled image
274   */
275  function compute($in_size, $coi, &$crop_rect, &$scale_size)
276  {
277    $destCrop = new ImageRect($in_size);
278
279    if ($this->max_crop > 0)
280    {
281      $ratio_w = $destCrop->width() / $this->ideal_size[0];
282      $ratio_h = $destCrop->height() / $this->ideal_size[1];
283      if ($ratio_w>1 || $ratio_h>1)
284      {
285        if ($ratio_w > $ratio_h)
286        {
287          $h = $destCrop->height() / $ratio_w;
288          if ($h < $this->min_size[1])
289          {
290            $idealCropPx = $destCrop->width() - floor($destCrop->height() * $this->ideal_size[0] / $this->min_size[1]);
291            $maxCropPx = round($this->max_crop * $destCrop->width());
292            $destCrop->crop_h( min($idealCropPx, $maxCropPx), $coi);
293          }
294        }
295        else
296        {
297          $w = $destCrop->width() / $ratio_h;
298          if ($w < $this->min_size[0])
299          {
300            $idealCropPx = $destCrop->height() - floor($destCrop->width() * $this->ideal_size[1] / $this->min_size[0]);
301            $maxCropPx = round($this->max_crop * $destCrop->height());
302            $destCrop->crop_v( min($idealCropPx, $maxCropPx), $coi);
303          }
304        }
305      }
306    }
307
308    $scale_size = array($destCrop->width(), $destCrop->height());
309
310    $ratio_w = $destCrop->width() / $this->ideal_size[0];
311    $ratio_h = $destCrop->height() / $this->ideal_size[1];
312    if ($ratio_w>1 || $ratio_h>1)
313    {
314      if ($ratio_w > $ratio_h)
315      {
316        $scale_size[0] = $this->ideal_size[0];
317        $scale_size[1] = floor(1e-6 + $scale_size[1] / $ratio_w);
318      }
319      else
320      {
321        $scale_size[0] = floor(1e-6 + $scale_size[0] / $ratio_h);
322        $scale_size[1] = $this->ideal_size[1];
323      }
324    }
325    else
326    {
327      $scale_size = null;
328    }
329
330    $crop_rect = null;
331    if ($destCrop->width()!=$in_size[0] || $destCrop->height()!=$in_size[1] )
332    {
333      $crop_rect = $destCrop;
334    }
335  }
336}
337
338
339/**
340 * All needed parameters to generate a derivative image.
341 */
342final class DerivativeParams
343{
344  /** @var SizingParams */
345  public $sizing;
346  /** @var string among IMG_* */
347  public $type = IMG_CUSTOM;
348  /** @var int used for non-custom images to regenerate the cached files */
349  public $last_mod_time = 0;
350  /** @var bool */
351  public $use_watermark = false;
352  /** @var float from 0=no sharpening to 1=max sharpening */
353  public $sharpen = 0;
354
355  /**
356   * @param SizingParams $sizing
357   */
358  function __construct($sizing)
359  {
360    $this->sizing = $sizing;
361  }
362
363  /**
364   * @return array
365   */
366  public function __sleep()
367  {
368    return array('last_mod_time', 'sizing', 'sharpen');
369  }
370
371  /**
372   * Adds tokens depending on sizing configuration.
373   *
374   * @param array &$tokens
375   */
376  function add_url_tokens(&$tokens)
377  {
378    $this->sizing->add_url_tokens($tokens);
379  }
380
381  /**
382   * @return int[]
383   */
384  function compute_final_size($in_size)
385  {
386    $this->sizing->compute( $in_size, null, $crop_rect, $scale_size );
387    return $scale_size != null ? $scale_size : $in_size;
388  }
389
390  /**
391   * @return int
392   */
393  function max_width()
394  {
395    return $this->sizing->ideal_size[0];
396  }
397
398  /**
399   * @return int
400   */
401  function max_height()
402  {
403    return $this->sizing->ideal_size[1];
404  }
405
406  /**
407   * @todo : description of DerivativeParams::is_identity
408   *
409   * @return bool
410   */
411  function is_identity($in_size)
412  {
413    if ($in_size[0] > $this->sizing->ideal_size[0] or
414        $in_size[1] > $this->sizing->ideal_size[1] )
415    {
416      return false;
417    }
418    return true;
419  }
420
421  /**
422   * @return bool
423   */
424  function will_watermark($out_size)
425  {
426    if ($this->use_watermark)
427    {
428      $min_size = ImageStdParams::get_watermark()->min_size;
429      return $min_size[0]<=$out_size[0]
430        || $min_size[1]<=$out_size[1];
431    }
432    return false;
433  }
434}
435
436?>
Note: See TracBrowser for help on using the repository browser.