1 <?php
2
3 Yii::setPathOfAlias('p3exensions-image-image', dirname(__FILE__));
4 Yii::import('p3exensions-image-image.Image_Driver');
5
6 7 8 9 10 11 12 13 14 15 16
17 class Image {
18
19
20 const NONE = 1;
21 const AUTO = 2;
22 const HEIGHT = 3;
23 const WIDTH = 4;
24
25 const HORIZONTAL = 5;
26 const VERTICAL = 6;
27
28
29 public static $allowed_types = array
30 (
31 IMAGETYPE_GIF => 'gif',
32 IMAGETYPE_JPEG => 'jpg',
33 IMAGETYPE_PNG => 'png',
34 IMAGETYPE_TIFF_II => 'tiff',
35 IMAGETYPE_TIFF_MM => 'tiff',
36 IMAGETYPE_BMP => 'bmp',
37 );
38
39
40 protected $driver;
41
42
43 protected $actions = array();
44
45
46 protected $image = '';
47
48 49 50 51 52 53 54
55 public static function factory($image, $config = NULL)
56 {
57 return new Image($image, $config);
58 }
59
60 61 62 63 64 65 66 67
68 public function __construct($image, $config = NULL)
69 {
70 static $check;
71
72
73 ($check === NULL) and $check = function_exists('getimagesize');
74
75 if ($check === FALSE)
76 throw new CException('image getimagesize missing');
77
78
79 if ( ! is_file($image))
80 throw new CException('image file not found');
81
82
83 $ER = error_reporting(0);
84
85
86 $image_info = getimagesize($image);
87
88
89 error_reporting($ER);
90
91
92 if ( ! is_array($image_info) OR count($image_info) < 3)
93 throw new CException('image file unreadable');
94
95
96 if ( ! isset(Image::$allowed_types[$image_info[2]]))
97 throw new CException('image type '.$image_info[2].' not allowed');
98
99
100 $this->image = array
101 (
102 'file' => str_replace('\\', '/', realpath($image)),
103 'width' => $image_info[0],
104 'height' => $image_info[1],
105 'type' => $image_info[2],
106 'ext' => Image::$allowed_types[$image_info[2]],
107 'mime' => $image_info['mime']
108 );
109
110
111 if ($config === null){
112 $this->config = array(
113 'driver'=>'GD',
114 'params'=>array(),
115 );
116 }
117 else{
118 $this->config = $config;
119 }
120
121
122 $driver = 'Image_'.ucfirst($this->config['driver']).'_Driver';
123
124
125 Yii::import("p3exensions-image-image.drivers.$driver");
126
127
128 $this->driver = new $driver($this->config['params']);
129
130
131 if ( ! ($this->driver instanceof Image_Driver))
132 throw new CException('image driver must be implement Image_Driver class');
133 }
134
135 136 137 138 139 140
141 public function __get($property)
142 {
143 if (isset($this->image[$property]))
144 {
145 return $this->image[$property];
146 }
147 else
148 {
149 throw new CException('invalid property');
150 }
151 }
152
153 154 155 156 157 158 159 160 161 162 163 164
165 public function resize($width, $height, $master = NULL)
166 {
167 if ( ! $this->valid_size('width', $width))
168 throw new CException('image invalid width');
169
170 if ( ! $this->valid_size('height', $height))
171 throw new CException('image invalid height');
172
173 if (empty($width) AND empty($height))
174 throw new CException('image invalid dimensions');
175
176 if ($master === NULL)
177 {
178
179 $master = Image::AUTO;
180 }
181 elseif ( ! $this->valid_size('master', $master))
182 throw new CException('image invalid master');
183
184 $this->actions['resize'] = array
185 (
186 'width' => $width,
187 'height' => $height,
188 'master' => $master,
189 );
190
191 return $this;
192 }
193
194 195 196 197 198 199 200 201 202 203 204 205
206 public function crop($width, $height, $top = 'center', $left = 'center')
207 {
208 if ( ! $this->valid_size('width', $width))
209 throw new CException('image invalid width', $width);
210
211 if ( ! $this->valid_size('height', $height))
212 throw new CException('image invalid height', $height);
213
214 if ( ! $this->valid_size('top', $top))
215 throw new CException('image invalid top', $top);
216
217 if ( ! $this->valid_size('left', $left))
218 throw new CException('image invalid left', $left);
219
220 if (empty($width) AND empty($height))
221 throw new CException('image invalid dimensions');
222
223 $this->actions['crop'] = array
224 (
225 'width' => $width,
226 'height' => $height,
227 'top' => $top,
228 'left' => $left,
229 );
230
231 return $this;
232 }
233
234 235 236 237 238 239
240 public function rotate($degrees)
241 {
242 $degrees = (int) $degrees;
243
244 if ($degrees > 180)
245 {
246 do
247 {
248
249 $degrees -= 360;
250 }
251 while($degrees > 180);
252 }
253
254 if ($degrees < -180)
255 {
256 do
257 {
258
259 $degrees += 360;
260 }
261 while($degrees < -180);
262 }
263
264 $this->actions['rotate'] = $degrees;
265
266 return $this;
267 }
268
269 270 271 272 273 274 275
276 public function flip($direction)
277 {
278 if ($direction !== self::HORIZONTAL AND $direction !== self::VERTICAL)
279 throw new CException('image invalid flip');
280
281 $this->actions['flip'] = $direction;
282
283 return $this;
284 }
285
286 287 288 289 290 291
292 public function quality($amount)
293 {
294 $this->actions['quality'] = max(1, min($amount, 100));
295
296 return $this;
297 }
298
299 300 301 302 303 304
305 public function sharpen($amount)
306 {
307 $this->actions['sharpen'] = max(1, min($amount, 100));
308
309 return $this;
310 }
311
312 313 314 315 316 317 318 319 320
321 public function save($new_image = FALSE, $chmod = 0644, $keep_actions = FALSE)
322 {
323
324 empty($new_image) and $new_image = $this->image['file'];
325
326
327 $dir = pathinfo($new_image, PATHINFO_DIRNAME);
328 $file = pathinfo($new_image, PATHINFO_BASENAME);
329
330
331 $dir = str_replace('\\', '/', realpath($dir)).'/';
332
333 if ( ! is_writable($dir))
334 throw new CException('image directory unwritable');
335
336 if ($status = $this->driver->process($this->image, $this->actions, $dir, $file))
337 {
338 if ($chmod !== FALSE)
339 {
340
341 chmod($new_image, $chmod);
342 }
343 }
344
345
346 if ($keep_actions === FALSE)
347 $this->actions = array();
348
349 return $status;
350 }
351
352 353 354 355 356 357
358 public function render($keep_actions = FALSE)
359 {
360 $new_image = $this->image['file'];
361
362
363 $dir = pathinfo($new_image, PATHINFO_DIRNAME);
364 $file = pathinfo($new_image, PATHINFO_BASENAME);
365
366
367 $dir = str_replace('\\', '/', realpath($dir)).'/';
368
369
370 $status = $this->driver->process($this->image, $this->actions, $dir, $file, $render = TRUE);
371
372
373 if ($keep_actions === FALSE)
374 $this->actions = array();
375
376 return $status;
377 }
378
379 380 381 382 383 384 385
386 protected function valid_size($type, & $value)
387 {
388 if (is_null($value))
389 return TRUE;
390
391 if ( ! is_scalar($value))
392 return FALSE;
393
394 switch ($type)
395 {
396 case 'width':
397 case 'height':
398 if (is_string($value) AND ! ctype_digit($value))
399 {
400
401 if ( ! preg_match('/^[0-9]++%$/D', $value))
402 return FALSE;
403 }
404 else
405 {
406 $value = (int) $value;
407 }
408 break;
409 case 'top':
410 if (is_string($value) AND ! ctype_digit($value))
411 {
412 if ( ! in_array($value, array('top', 'bottom', 'center')))
413 return FALSE;
414 }
415 else
416 {
417 $value = (int) $value;
418 }
419 break;
420 case 'left':
421 if (is_string($value) AND ! ctype_digit($value))
422 {
423 if ( ! in_array($value, array('left', 'right', 'center')))
424 return FALSE;
425 }
426 else
427 {
428 $value = (int) $value;
429 }
430 break;
431 case 'master':
432 if ($value !== Image::NONE AND
433 $value !== Image::AUTO AND
434 $value !== Image::WIDTH AND
435 $value !== Image::HEIGHT)
436 return FALSE;
437 break;
438 }
439
440 return TRUE;
441 }
442
443 }
444