1 | <?php |
---|
2 | /*********************************************************************** |
---|
3 | ** Title.........: Image Transformation Interface |
---|
4 | ** Version.......: 1.0 |
---|
5 | ** Author........: Xiang Wei ZHUO <wei@zhuo.org> |
---|
6 | ** Filename......: Transform.php |
---|
7 | ** Last changed..: 30 Aug 2003 |
---|
8 | ** Notes.........: Orginal is from PEAR |
---|
9 | |
---|
10 | Added a few extra, |
---|
11 | - create unique filename in a particular directory, |
---|
12 | used for temp image files. |
---|
13 | - added cropping to GD, NetPBM, ImageMagick |
---|
14 | **/ |
---|
15 | |
---|
16 | // +----------------------------------------------------------------------+ |
---|
17 | // | PHP Version 4 | |
---|
18 | // +----------------------------------------------------------------------+ |
---|
19 | // | Copyright (c) 1997-2002 The PHP Group | |
---|
20 | // +----------------------------------------------------------------------+ |
---|
21 | // | This source file is subject to version 2.02 of the PHP license, | |
---|
22 | // | that is bundled with this package in the file LICENSE, and is | |
---|
23 | // | available at through the world-wide-web at | |
---|
24 | // | http://www.php.net/license/2_02.txt. | |
---|
25 | // | If you did not receive a copy of the PHP license and are unable to | |
---|
26 | // | obtain it through the world-wide-web, please send a note to | |
---|
27 | // | license@php.net so we can mail you a copy immediately. | |
---|
28 | // +----------------------------------------------------------------------+ |
---|
29 | // | Authors: Peter Bowyer <peter@mapledesign.co.uk> | |
---|
30 | // | Alan Knowles <alan@akbkhome.com> | |
---|
31 | // | Vincent Oostindie <vincent@sunlight.tmfweb.nl> | |
---|
32 | // +----------------------------------------------------------------------+ |
---|
33 | // |
---|
34 | // |
---|
35 | // Image Transformation interface |
---|
36 | // |
---|
37 | |
---|
38 | |
---|
39 | /** |
---|
40 | * The main "Image_Resize" class is a container and base class which |
---|
41 | * provides the static methods for creating Image objects as well as |
---|
42 | * some utility functions (maths) common to all parts of Image Resize. |
---|
43 | * |
---|
44 | * The object model of DB is as follows (indentation means inheritance): |
---|
45 | * |
---|
46 | * Image_Resize The base for each Image implementation. Provides default |
---|
47 | * | implementations (in OO lingo virtual methods) for |
---|
48 | * | the actual Image implementations as well as a bunch of |
---|
49 | * | maths methods. |
---|
50 | * | |
---|
51 | * +-Image_GD The Image implementation for the PHP GD extension . Inherits |
---|
52 | * Image_Resize |
---|
53 | * When calling DB::setup for GD images the object returned is an |
---|
54 | * instance of this class. |
---|
55 | * |
---|
56 | * @package Image Resize |
---|
57 | * @version 1.00 |
---|
58 | * @author Peter Bowyer <peter@mapledesign.co.uk> |
---|
59 | * @since PHP 4.0 |
---|
60 | */ |
---|
61 | Class Image_Transform |
---|
62 | { |
---|
63 | /** |
---|
64 | * Name of the image file |
---|
65 | * @var string |
---|
66 | */ |
---|
67 | var $image = ''; |
---|
68 | /** |
---|
69 | * Type of the image file (eg. jpg, gif png ...) |
---|
70 | * @var string |
---|
71 | */ |
---|
72 | var $type = ''; |
---|
73 | /** |
---|
74 | * Original image width in x direction |
---|
75 | * @var int |
---|
76 | */ |
---|
77 | var $img_x = ''; |
---|
78 | /** |
---|
79 | * Original image width in y direction |
---|
80 | * @var int |
---|
81 | */ |
---|
82 | var $img_y = ''; |
---|
83 | /** |
---|
84 | * New image width in x direction |
---|
85 | * @var int |
---|
86 | */ |
---|
87 | var $new_x = ''; |
---|
88 | /** |
---|
89 | * New image width in y direction |
---|
90 | * @var int |
---|
91 | */ |
---|
92 | var $new_y = ''; |
---|
93 | /** |
---|
94 | * Path the the library used |
---|
95 | * e.g. /usr/local/ImageMagick/bin/ or |
---|
96 | * /usr/local/netpbm/ |
---|
97 | */ |
---|
98 | var $lib_path = ''; |
---|
99 | /** |
---|
100 | * Flag to warn if image has been resized more than once before displaying |
---|
101 | * or saving. |
---|
102 | */ |
---|
103 | var $resized = false; |
---|
104 | |
---|
105 | |
---|
106 | var $uid = ''; |
---|
107 | |
---|
108 | var $lapse_time =900; //15 mins |
---|
109 | |
---|
110 | /** |
---|
111 | * Create a new Image_resize object |
---|
112 | * |
---|
113 | * @param string $driver name of driver class to initialize |
---|
114 | * |
---|
115 | * @return mixed a newly created Image_Transform object, or a PEAR |
---|
116 | * error object on error |
---|
117 | * |
---|
118 | * @see PEAR::isError() |
---|
119 | * @see Image_Transform::setOption() |
---|
120 | */ |
---|
121 | function &factory($driver) |
---|
122 | { |
---|
123 | if ('' == $driver) { |
---|
124 | die("No image library specified... aborting. You must call ::factory() with one parameter, the library to load."); |
---|
125 | |
---|
126 | } |
---|
127 | $this->uid = md5($_SERVER['REMOTE_ADDR']); |
---|
128 | |
---|
129 | include_once "$driver.php"; |
---|
130 | |
---|
131 | $classname = "Image_Transform_Driver_{$driver}"; |
---|
132 | $obj =& new $classname; |
---|
133 | return $obj; |
---|
134 | } |
---|
135 | |
---|
136 | |
---|
137 | /** |
---|
138 | * Resize the Image in the X and/or Y direction |
---|
139 | * If either is 0 it will be scaled proportionally |
---|
140 | * |
---|
141 | * @access public |
---|
142 | * |
---|
143 | * @param mixed $new_x (0, number, percentage 10% or 0.1) |
---|
144 | * @param mixed $new_y (0, number, percentage 10% or 0.1) |
---|
145 | * |
---|
146 | * @return mixed none or PEAR_error |
---|
147 | */ |
---|
148 | function resize($new_x = 0, $new_y = 0) |
---|
149 | { |
---|
150 | // 0 means keep original size |
---|
151 | $new_x = (0 == $new_x) ? $this->img_x : $this->_parse_size($new_x, $this->img_x); |
---|
152 | $new_y = (0 == $new_y) ? $this->img_y : $this->_parse_size($new_y, $this->img_y); |
---|
153 | // Now do the library specific resizing. |
---|
154 | return $this->_resize($new_x, $new_y); |
---|
155 | } // End resize |
---|
156 | |
---|
157 | |
---|
158 | /** |
---|
159 | * Scale the image to have the max x dimension specified. |
---|
160 | * |
---|
161 | * @param int $new_x Size to scale X-dimension to |
---|
162 | * @return none |
---|
163 | */ |
---|
164 | function scaleMaxX($new_x) |
---|
165 | { |
---|
166 | $new_y = round(($new_x / $this->img_x) * $this->img_y, 0); |
---|
167 | return $this->_resize($new_x, $new_y); |
---|
168 | } // End resizeX |
---|
169 | |
---|
170 | /** |
---|
171 | * Scale the image to have the max y dimension specified. |
---|
172 | * |
---|
173 | * @access public |
---|
174 | * @param int $new_y Size to scale Y-dimension to |
---|
175 | * @return none |
---|
176 | */ |
---|
177 | function scaleMaxY($new_y) |
---|
178 | { |
---|
179 | $new_x = round(($new_y / $this->img_y) * $this->img_x, 0); |
---|
180 | return $this->_resize($new_x, $new_y); |
---|
181 | } // End resizeY |
---|
182 | |
---|
183 | /** |
---|
184 | * Scale Image to a maximum or percentage |
---|
185 | * |
---|
186 | * @access public |
---|
187 | * @param mixed (number, percentage 10% or 0.1) |
---|
188 | * @return mixed none or PEAR_error |
---|
189 | */ |
---|
190 | function scale($size) |
---|
191 | { |
---|
192 | if ((strlen($size) > 1) && (substr($size,-1) == '%')) { |
---|
193 | return $this->scaleByPercentage(substr($size, 0, -1)); |
---|
194 | } elseif ($size < 1) { |
---|
195 | return $this->scaleByFactor($size); |
---|
196 | } else { |
---|
197 | return $this->scaleByLength($size); |
---|
198 | } |
---|
199 | } // End scale |
---|
200 | |
---|
201 | /** |
---|
202 | * Scales an image to a percentage of its original size. For example, if |
---|
203 | * my image was 640x480 and I called scaleByPercentage(10) then the image |
---|
204 | * would be resized to 64x48 |
---|
205 | * |
---|
206 | * @access public |
---|
207 | * @param int $size Percentage of original size to scale to |
---|
208 | * @return none |
---|
209 | */ |
---|
210 | function scaleByPercentage($size) |
---|
211 | { |
---|
212 | return $this->scaleByFactor($size / 100); |
---|
213 | } // End scaleByPercentage |
---|
214 | |
---|
215 | /** |
---|
216 | * Scales an image to a factor of its original size. For example, if |
---|
217 | * my image was 640x480 and I called scaleByFactor(0.5) then the image |
---|
218 | * would be resized to 320x240. |
---|
219 | * |
---|
220 | * @access public |
---|
221 | * @param float $size Factor of original size to scale to |
---|
222 | * @return none |
---|
223 | */ |
---|
224 | function scaleByFactor($size) |
---|
225 | { |
---|
226 | $new_x = round($size * $this->img_x, 0); |
---|
227 | $new_y = round($size * $this->img_y, 0); |
---|
228 | return $this->_resize($new_x, $new_y); |
---|
229 | } // End scaleByFactor |
---|
230 | |
---|
231 | /** |
---|
232 | * Scales an image so that the longest side has this dimension. |
---|
233 | * |
---|
234 | * @access public |
---|
235 | * @param int $size Max dimension in pixels |
---|
236 | * @return none |
---|
237 | */ |
---|
238 | function scaleByLength($size) |
---|
239 | { |
---|
240 | if ($this->img_x >= $this->img_y) { |
---|
241 | $new_x = $size; |
---|
242 | $new_y = round(($new_x / $this->img_x) * $this->img_y, 0); |
---|
243 | } else { |
---|
244 | $new_y = $size; |
---|
245 | $new_x = round(($new_y / $this->img_y) * $this->img_x, 0); |
---|
246 | } |
---|
247 | return $this->_resize($new_x, $new_y); |
---|
248 | } // End scaleByLength |
---|
249 | |
---|
250 | |
---|
251 | /** |
---|
252 | * |
---|
253 | * @access public |
---|
254 | * @return void |
---|
255 | */ |
---|
256 | function _get_image_details($image) |
---|
257 | { |
---|
258 | //echo $image; |
---|
259 | $data = @GetImageSize($image); |
---|
260 | #1 = GIF, 2 = JPG, 3 = PNG, 4 = SWF, 5 = PSD, 6 = BMP, 7 = TIFF(intel byte order), 8 = TIFF(motorola byte order, |
---|
261 | # 9 = JPC, 10 = JP2, 11 = JPX, 12 = JB2, 13 = SWC |
---|
262 | if (is_array($data)){ |
---|
263 | switch($data[2]){ |
---|
264 | case 1: |
---|
265 | $type = 'gif'; |
---|
266 | break; |
---|
267 | case 2: |
---|
268 | $type = 'jpeg'; |
---|
269 | break; |
---|
270 | case 3: |
---|
271 | $type = 'png'; |
---|
272 | break; |
---|
273 | case 4: |
---|
274 | $type = 'swf'; |
---|
275 | break; |
---|
276 | case 5: |
---|
277 | $type = 'psd'; |
---|
278 | case 6: |
---|
279 | $type = 'bmp'; |
---|
280 | case 7: |
---|
281 | case 8: |
---|
282 | $type = 'tiff'; |
---|
283 | default: |
---|
284 | echo("We do not recognize this image format"); |
---|
285 | } |
---|
286 | $this->img_x = $data[0]; |
---|
287 | $this->img_y = $data[1]; |
---|
288 | $this->type = $type; |
---|
289 | |
---|
290 | return true; |
---|
291 | } else { |
---|
292 | echo("Cannot fetch image or images details."); |
---|
293 | return null; |
---|
294 | } |
---|
295 | /* |
---|
296 | $output = array( |
---|
297 | 'width' => $data[0], |
---|
298 | 'height' => $data[1], |
---|
299 | 'type' => $type |
---|
300 | ); |
---|
301 | return $output; |
---|
302 | */ |
---|
303 | } |
---|
304 | |
---|
305 | |
---|
306 | /** |
---|
307 | * Parse input and convert |
---|
308 | * If either is 0 it will be scaled proportionally |
---|
309 | * |
---|
310 | * @access private |
---|
311 | * |
---|
312 | * @param mixed $new_size (0, number, percentage 10% or 0.1) |
---|
313 | * @param int $old_size |
---|
314 | * |
---|
315 | * @return mixed none or PEAR_error |
---|
316 | */ |
---|
317 | function _parse_size($new_size, $old_size) |
---|
318 | { |
---|
319 | if ('%' == $new_size) { |
---|
320 | $new_size = str_replace('%','',$new_size); |
---|
321 | $new_size = $new_size / 100; |
---|
322 | } |
---|
323 | if ($new_size > 1) { |
---|
324 | return (int) $new_size; |
---|
325 | } elseif ($new_size == 0) { |
---|
326 | return (int) $old_size; |
---|
327 | } else { |
---|
328 | return (int) round($new_size * $old_size, 0); |
---|
329 | } |
---|
330 | } |
---|
331 | |
---|
332 | |
---|
333 | function uniqueStr() |
---|
334 | { |
---|
335 | return substr(md5(microtime()),0,6); |
---|
336 | } |
---|
337 | |
---|
338 | //delete old tmp files, and allow only 1 file per remote host. |
---|
339 | function cleanUp($id, $dir) |
---|
340 | { |
---|
341 | $d = dir($dir); |
---|
342 | $id_length = strlen($id); |
---|
343 | |
---|
344 | while (false !== ($entry = $d->read())) { |
---|
345 | if (is_file($dir.'/'.$entry) && substr($entry,0,1) == '.' && !ereg($entry, $this->image)) |
---|
346 | { |
---|
347 | //echo filemtime($this->directory.'/'.$entry)."<br>"; |
---|
348 | //echo time(); |
---|
349 | |
---|
350 | if (filemtime($dir.'/'.$entry) + $this->lapse_time < time()) |
---|
351 | unlink($dir.'/'.$entry); |
---|
352 | |
---|
353 | if (substr($entry, 1, $id_length) == $id) |
---|
354 | { |
---|
355 | if (is_file($dir.'/'.$entry)) |
---|
356 | unlink($dir.'/'.$entry); |
---|
357 | } |
---|
358 | } |
---|
359 | } |
---|
360 | $d->close(); |
---|
361 | } |
---|
362 | |
---|
363 | |
---|
364 | function createUnique($dir) |
---|
365 | { |
---|
366 | $unique_str = '.'.$this->uid.'_'.$this->uniqueStr().".".$this->type; |
---|
367 | |
---|
368 | //make sure the the unique temp file does not exists |
---|
369 | while (file_exists($dir.$unique_str)) |
---|
370 | { |
---|
371 | $unique_str = '.'.$this->uid.'_'.$this->uniqueStr().".".$this->type; |
---|
372 | } |
---|
373 | |
---|
374 | $this->cleanUp($this->uid, $dir); |
---|
375 | |
---|
376 | return $unique_str; |
---|
377 | } |
---|
378 | |
---|
379 | |
---|
380 | /** |
---|
381 | * Set the image width |
---|
382 | * @param int $size dimension to set |
---|
383 | * @since 29/05/02 13:36:31 |
---|
384 | * @return |
---|
385 | */ |
---|
386 | function _set_img_x($size) |
---|
387 | { |
---|
388 | $this->img_x = $size; |
---|
389 | } |
---|
390 | |
---|
391 | /** |
---|
392 | * Set the image height |
---|
393 | * @param int $size dimension to set |
---|
394 | * @since 29/05/02 13:36:31 |
---|
395 | * @return |
---|
396 | */ |
---|
397 | function _set_img_y($size) |
---|
398 | { |
---|
399 | $this->img_y = $size; |
---|
400 | } |
---|
401 | |
---|
402 | /** |
---|
403 | * Set the image width |
---|
404 | * @param int $size dimension to set |
---|
405 | * @since 29/05/02 13:36:31 |
---|
406 | * @return |
---|
407 | */ |
---|
408 | function _set_new_x($size) |
---|
409 | { |
---|
410 | $this->new_x = $size; |
---|
411 | } |
---|
412 | |
---|
413 | /** |
---|
414 | * Set the image height |
---|
415 | * @param int $size dimension to set |
---|
416 | * @since 29/05/02 13:36:31 |
---|
417 | * @return |
---|
418 | */ |
---|
419 | function _set_new_y($size) |
---|
420 | { |
---|
421 | $this->new_y = $size; |
---|
422 | } |
---|
423 | |
---|
424 | /** |
---|
425 | * Get the type of the image being manipulated |
---|
426 | * |
---|
427 | * @return string $this->type the image type |
---|
428 | */ |
---|
429 | function getImageType() |
---|
430 | { |
---|
431 | return $this->type; |
---|
432 | } |
---|
433 | |
---|
434 | /** |
---|
435 | * |
---|
436 | * @access public |
---|
437 | * @return string web-safe image type |
---|
438 | */ |
---|
439 | function getWebSafeFormat() |
---|
440 | { |
---|
441 | switch($this->type){ |
---|
442 | case 'gif': |
---|
443 | case 'png': |
---|
444 | return 'png'; |
---|
445 | break; |
---|
446 | default: |
---|
447 | return 'jpeg'; |
---|
448 | } // switch |
---|
449 | } |
---|
450 | |
---|
451 | /** |
---|
452 | * Place holder for the real resize method |
---|
453 | * used by extended methods to do the resizing |
---|
454 | * |
---|
455 | * @access private |
---|
456 | * @return PEAR_error |
---|
457 | */ |
---|
458 | function _resize() { |
---|
459 | return null; //PEAR::raiseError("No Resize method exists", true); |
---|
460 | } |
---|
461 | |
---|
462 | /** |
---|
463 | * Place holder for the real load method |
---|
464 | * used by extended methods to do the resizing |
---|
465 | * |
---|
466 | * @access public |
---|
467 | * @return PEAR_error |
---|
468 | */ |
---|
469 | function load($filename) { |
---|
470 | return null; //PEAR::raiseError("No Load method exists", true); |
---|
471 | } |
---|
472 | |
---|
473 | /** |
---|
474 | * Place holder for the real display method |
---|
475 | * used by extended methods to do the resizing |
---|
476 | * |
---|
477 | * @access public |
---|
478 | * @param string filename |
---|
479 | * @return PEAR_error |
---|
480 | */ |
---|
481 | function display($type, $quality) { |
---|
482 | return null; //PEAR::raiseError("No Display method exists", true); |
---|
483 | } |
---|
484 | |
---|
485 | /** |
---|
486 | * Place holder for the real save method |
---|
487 | * used by extended methods to do the resizing |
---|
488 | * |
---|
489 | * @access public |
---|
490 | * @param string filename |
---|
491 | * @return PEAR_error |
---|
492 | */ |
---|
493 | function save($filename, $type, $quality) { |
---|
494 | return null; //PEAR::raiseError("No Save method exists", true); |
---|
495 | } |
---|
496 | |
---|
497 | /** |
---|
498 | * Place holder for the real free method |
---|
499 | * used by extended methods to do the resizing |
---|
500 | * |
---|
501 | * @access public |
---|
502 | * @return PEAR_error |
---|
503 | */ |
---|
504 | function free() { |
---|
505 | return null; //PEAR::raiseError("No Free method exists", true); |
---|
506 | } |
---|
507 | |
---|
508 | /** |
---|
509 | * Reverse of rgb2colorname. |
---|
510 | * |
---|
511 | * @access public |
---|
512 | * @return PEAR_error |
---|
513 | * |
---|
514 | * @see rgb2colorname |
---|
515 | */ |
---|
516 | function colorhex2colorarray($colorhex) { |
---|
517 | $r = hexdec(substr($colorhex, 1, 2)); |
---|
518 | $g = hexdec(substr($colorhex, 3, 2)); |
---|
519 | $b = hexdec(substr($colorhex, 4, 2)); |
---|
520 | return array($r,$g,$b); |
---|
521 | } |
---|
522 | |
---|
523 | /** |
---|
524 | * Reverse of rgb2colorname. |
---|
525 | * |
---|
526 | * @access public |
---|
527 | * @return PEAR_error |
---|
528 | * |
---|
529 | * @see rgb2colorname |
---|
530 | */ |
---|
531 | function colorarray2colorhex($color) { |
---|
532 | $color = '#'.dechex($color[0]).dechex($color[1]).dechex($color[2]); |
---|
533 | return strlen($color)>6?false:$color; |
---|
534 | } |
---|
535 | |
---|
536 | |
---|
537 | /* Methods to add to the driver classes in the future */ |
---|
538 | function addText() |
---|
539 | { |
---|
540 | return null; //PEAR::raiseError("No addText method exists", true); |
---|
541 | } |
---|
542 | |
---|
543 | function addDropShadow() |
---|
544 | { |
---|
545 | return null; //PEAR::raiseError("No AddDropShadow method exists", true); |
---|
546 | } |
---|
547 | |
---|
548 | function addBorder() |
---|
549 | { |
---|
550 | return null; //PEAR::raiseError("No addBorder method exists", true); |
---|
551 | } |
---|
552 | |
---|
553 | function crop() |
---|
554 | { |
---|
555 | return null; //PEAR::raiseError("No crop method exists", true); |
---|
556 | } |
---|
557 | |
---|
558 | function flip() |
---|
559 | { |
---|
560 | return null; |
---|
561 | } |
---|
562 | |
---|
563 | function gamma() |
---|
564 | { |
---|
565 | return null; //PEAR::raiseError("No gamma method exists", true); |
---|
566 | } |
---|
567 | } |
---|
568 | ?> |
---|