source: extensions/derivatives/include/derivative_params.inc.php @ 15907

Last change on this file since 15907 was 12778, checked in by rvelices, 12 years ago

derivatives

  • better status codes + http headers on i.php
  • automatically switch to script mode, regenerate and reload derivatives on demand if their parameters change (without the need to clear the cache)
File size: 8.2 KB
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | Piwigo - a PHP based photo gallery                                    |
4// +-----------------------------------------------------------------------+
5// | Copyright(C) 2008-2012 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
22function size_to_url($s)
23{
24  if ($s[0]==$s[1])
25  {
26    return $s[0];
27  }
28  return $s[0].'x'.$s[1];
29}
30
31function url_to_size($s)
32{
33  $pos = strpos($s, 'x');
34  if ($pos===false)
35  {
36    return array((int)$s, (int)$s);
37  }
38  return array((int)substr($s,0,$pos), (int)substr($s,$pos+1));
39}
40
41function size_equals($s1, $s2)
42{
43  return ($s1[0]==$s2[0] && $s1[1]==$s2[1]);
44}
45
46
47/** small utility to manipulate a 'rectangle'*/
48final class ImageRect
49{
50  public $l,$t,$r,$b;
51
52  function __construct($l)
53  {
54    $this->l = $this->t = 0;
55    $this->r = $l[0];
56    $this->b = $l[1];
57  }
58
59  function width()
60  {
61    return $this->r - $this->l;
62  }
63
64  function height()
65  {
66    return $this->b - $this->t;
67  }
68
69  function crop_h($pixels, $coi, $force)
70  {
71    if ($this->width() <= $pixels)
72      return;
73    $tlcrop = floor($pixels/2);
74
75    if (!empty($coi))
76    {
77      $coil = floor($this->r * (ord($coi[0]) - ord('a'))/25);
78      $coir = ceil($this->r * (ord($coi[2]) - ord('a'))/25);
79      $availableL = $coil > $this->l ? $coil - $this->l : 0;
80      $availableR = $coir < $this->r ? $this->r - $coir : 0;
81      if ($availableL + $availableR <= $pixels)
82      {
83        if (!$force)
84        {
85          $pixels = $availableL + $availableR;
86          $tlcrop = $availableL;
87        }
88      }
89      else
90      {
91        if ($availableL < $tlcrop)
92        {
93          $tlcrop = $availableL;
94        }
95        elseif ($availableR < $tlcrop)
96        {
97          $tlcrop = $pixels - $availableR;
98        }
99      }
100    }
101    $this->l += $tlcrop;
102    $this->r -= $pixels - $tlcrop;
103  }
104
105  function crop_v($pixels, $coi, $force)
106  {
107    if ($this->height() <= $pixels)
108      return;
109    $tlcrop = floor($pixels/2);
110
111    if (!empty($coi))
112    {
113      $coit = floor($this->b * (ord($coi[1]) - ord('a'))/25);
114      $coib = ceil($this->b * (ord($coi[3]) - ord('a'))/25);
115      $availableT = $coit > $this->t ? $coit - $this->t : 0;
116      $availableB = $coib < $this->b ? $this->b - $coib : 0;
117      if ($availableT + $availableB <= $pixels)
118      {
119        if (!$force)
120        {
121          $pixels = $availableT + $availableB;
122          $tlcrop = $availableT;
123        }
124      }
125      else
126      {
127        if ($availableT < $tlcrop)
128        {
129          $tlcrop = $availableT;
130        }
131        elseif ($availableB < $tlcrop)
132        {
133          $tlcrop = $pixels - $availableB;
134        }
135      }
136    }
137    $this->t += $tlcrop;
138    $this->b -= $pixels - $tlcrop;
139  }
140
141}
142
143
144/*how we crop and/or resize an image*/
145final class SizingParams
146{
147  function __construct($ideal_size, $max_crop = 0, $min_size = null)
148  {
149    $this->ideal_size = $ideal_size;
150    $this->max_crop = $max_crop;
151    $this->min_size = $min_size;
152  }
153
154  static function classic($w, $h)
155  {
156    return new SizingParams( array($w,$h) );
157  }
158
159  static function square($w)
160  {
161    return new SizingParams( array($w,$w), 1, array($w,$w) );
162  }
163
164  function add_url_tokens(&$tokens)
165  {
166      if ($this->max_crop == 0)
167      {
168        $tokens[] = 's'.size_to_url($this->ideal_size);
169      }
170      elseif ($this->max_crop == 1 && size_equals($this->ideal_size, $this->min_size) )
171      {
172        $tokens[] = 'e'.size_to_url($this->ideal_size);
173      }
174      else
175      {
176        $tokens[] = size_to_url($this->ideal_size);
177        $tokens[] = sprintf('%02x', round(100*$this->max_crop) );
178        $tokens[] = size_to_url($this->min_size);
179      }
180  }
181
182  static function from_url_tokens($tokens)
183  {
184    if (count($tokens)<1)
185      throw new Exception('Empty array while parsing Sizing');
186    $token = array_shift($tokens);
187    if ($token[0]=='s')
188    {
189      return new SizingParams( url_to_size( substr($token,1) ) );
190    }
191    if ($token[0]=='e')
192    {
193      $s = url_to_size( substr($token,1) );
194      return new SizingParams($s, 1, $s);
195    }
196
197    $ideal_size = url_to_size( $token );
198    if (count($tokens)<2)
199      throw new Exception('Sizing arr');
200
201    $token = array_shift($tokens);
202    $crop = sscanf('%02x' , $token) / 100;
203
204    $token = array_shift($tokens);
205    $min_size = url_to_size( $token );
206    return new SizingParams($ideal_size, $crop, $min_size);
207  }
208
209
210  function compute($in_size, $coi, &$crop_rect, &$scale_size)
211  {
212    $destCrop = new ImageRect($in_size);
213
214    if ($this->max_crop > 0)
215    {
216      $ratio_w = $destCrop->width() / $this->ideal_size[0];
217      $ratio_h = $destCrop->height() / $this->ideal_size[1];
218      if ($ratio_w>1 || $ratio_h>1)
219      {
220        if ($ratio_w > $ratio_h)
221        {
222          $h = $destCrop->height() / $ratio_w;
223          if ($h < $this->min_size[1])
224          {
225            $idealCropPx = $destCrop->width() - round($destCrop->height() * $this->ideal_size[0] / $this->min_size[1], 0);
226            $maxCropPx = round($this->max_crop * $destCrop->width());
227            $destCrop->crop_h( min($idealCropPx, $maxCropPx), $coi, false);
228          }
229        }
230        else
231        {
232          $w = $destCrop->width() / $ratio_h;
233          if ($w < $this->min_size[0])
234          {
235            $idealCropPx = $destCrop->height() - round($destCrop->width() * $this->ideal_size[1] / $this->min_size[0], 0);
236            $maxCropPx = round($this->max_crop * $destCrop->height());
237            $destCrop->crop_v( min($idealCropPx, $maxCropPx), $coi, false);
238          }
239        }
240      }
241    }
242
243    $scale_size = array($destCrop->width(), $destCrop->height());
244
245    $ratio_w = $destCrop->width() / $this->ideal_size[0];
246    $ratio_h = $destCrop->height() / $this->ideal_size[1];
247    if ($ratio_w>1 || $ratio_h>1)
248    {
249      if ($ratio_w > $ratio_h)
250      {
251        $scale_size[0] = $this->ideal_size[0];
252        $scale_size[1] = floor($scale_size[1] / $ratio_w);
253      }
254      else
255      {
256        $scale_size[0] = floor($scale_size[0] / $ratio_h);
257        $scale_size[1] = $this->ideal_size[1];
258      }
259    }
260    else
261    {
262      $scale_size = null;
263    }
264
265    $crop_rect = null;
266    if ($destCrop->width()!=$in_size[0] || $destCrop->height()!=$in_size[1] )
267    {
268      $crop_rect = $destCrop;
269    }
270  }
271
272}
273
274
275/*how we generate a derivative image*/
276final class ImageParams
277{
278  public $type = IMG_CUSTOM;
279  public $last_mod_time = 0; // used for non-custom images to regenerate the cached files
280  public $sizing;
281
282  function __construct($sizing)
283  {
284    $this->sizing = $sizing;
285  }
286
287  function add_url_tokens(&$tokens)
288  {
289    $this->sizing->add_url_tokens($tokens);
290  }
291
292  static function from_url_tokens($tokens)
293  {
294    $sizing = SizingParams::from_url_tokens($tokens);
295    $ret = new ImageParams($sizing);
296    return $ret;
297  }
298
299  function compute_final_size($in_size, $coi)
300  {
301    $this->sizing->compute( $in_size, $coi, $crop_rect, $scale_size );
302    return $scale_size != null ? $scale_size : $in_size;
303  }
304
305  function is_identity($in_size)
306  {
307    if ($in_size[0] > $this->sizing->ideal_size[0] or
308        $in_size[1] > $this->sizing->ideal_size[1] )
309    {
310      return false;
311    }
312    return true;
313  }
314}
315?>
Note: See TracBrowser for help on using the repository browser.