Source for file Image.php
Documentation is available at Image.php
6: * @copyright Copyright (c) 2004, 2010 David Grudl
7: * @license http://nettephp.com/license Nette license
8: * @link http://nettephp.com
16: * Basic manipulation with images.
19: * $image = Image::fromFile('nette.jpg');
20: * $image->resize(150, 100);
25: * @copyright Copyright (c) 2004, 2010 David Grudl
28: * @property-read int $width
29: * @property-read int $height
30: * @property-read resource $imageResource
34: /** {@link resize()} allows enlarging image (it only shrinks images by default) */
37: /** {@link resize()} will ignore aspect ratio */
40: /** {@link resize()} fits in given area */
43: /** {@link resize()} fills (and even overflows) given area */
46: /**#@+ @int image types {@link send()} */
48: const PNG =
IMAGETYPE_PNG;
49: const GIF =
IMAGETYPE_GIF;
52: const EMPTY_GIF =
"GIF89a\x01\x00\x01\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00!\xf9\x04\x01\x00\x00\x00\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02D\x01\x00;";
55: public static $useImageMagick =
FALSE;
64: * @param int red 0..255
65: * @param int green 0..255
66: * @param int blue 0..255
67: * @param int transparency 0..127
70: public static function rgb($red, $green, $blue, $transparency =
0)
74: 'green' =>
max(0, min(255, (int)
$green)),
76: 'alpha' =>
max(0, min(127, (int)
$transparency)),
83: * Opens image from file.
85: * @param mixed detected image format
88: public static function fromFile($file, & $format =
NULL)
91: throw new Exception("PHP extension GD is not loaded.");
95: if (self::$useImageMagick &&
(empty($info) ||
$info[0] *
$info[1] >
9e5)) { // cca 1024x768
96: return new ImageMagick($file, $format);
99: switch ($format =
$info[2]) {
110: if (self::$useImageMagick) {
111: return new ImageMagick($file, $format);
113: throw new Exception("Unknown image type or file '$file' not found.");
120: * Create a new image from the image stream in the string.
122: * @param mixed detected image format
128: throw new Exception("PHP extension GD is not loaded.");
132: $format =
self::JPEG;
135: $format =
self::PNG;
138: $format =
self::GIF;
149: * Creates blank image.
155: public static function fromBlank($width, $height, $color =
NULL)
158: throw new Exception("PHP extension GD is not loaded.");
161: $width = (int)
$width;
162: $height = (int)
$height;
163: if ($width <
1 ||
$height <
1) {
164: throw new InvalidArgumentException('Image width and height must be greater than zero.');
169: $color +=
array('alpha' =>
0);
175: return new self($image);
192: * Returns image width.
203: * Returns image height.
214: * Sets image resource.
216: * @return Image provides a fluent interface
221: throw new InvalidArgumentException('Image is not valid.');
223: $this->image =
$image;
230: * Returns image GD resource.
235: return $this->image;
242: * @param mixed width in pixels or percent
243: * @param mixed height in pixels or percent
245: * @return Image provides a fluent interface
247: public function resize($width, $height, $flags =
self::FIT)
249: list($newWidth, $newHeight) =
self::calculateSize($this->getWidth(), $this->getHeight(), $width, $height, $flags);
252: $newImage =
self::fromBlank($newWidth, $newHeight, self::RGB(0, 0, 0, 127))->getImageResource();
258: $this->image =
$newImage;
261: if ($width <
0 ||
$height <
0) { // flip is processed in two steps for better quality
262: $newImage =
self::fromBlank($newWidth, $newHeight, self::RGB(0, 0, 0, 127))->getImageResource();
265: 0, 0, $width <
0 ?
$newWidth -
1 :
0, $height <
0 ?
$newHeight -
1 :
0,
266: $newWidth, $newHeight, $width <
0 ? -
$newWidth :
$newWidth, $height <
0 ? -
$newHeight :
$newHeight
268: $this->image =
$newImage;
276: * Calculates dimensions of resized image.
277: * @param mixed source width
278: * @param mixed source height
279: * @param mixed width in pixels or percent
280: * @param mixed height in pixels or percent
284: public static function calculateSize($srcWidth, $srcHeight, $newWidth, $newHeight, $flags =
self::FIT)
288: $flags |=
self::ENLARGE;
291: $newWidth = (int)
abs($newWidth);
295: $newHeight =
round($srcHeight /
100 *
abs($newHeight));
296: $flags |=
empty($percents) ?
self::ENLARGE :
self::STRETCH;
298: $newHeight = (int)
abs($newHeight);
301: if ($flags & self::STRETCH) { // non-proportional
302: if (empty($newWidth) ||
empty($newHeight)) {
303: throw new InvalidArgumentException('For stretching must be both width and height specified.');
306: if (($flags & self::ENLARGE) ===
0) {
307: $newWidth =
round($srcWidth *
min(1, $newWidth /
$srcWidth));
308: $newHeight =
round($srcHeight *
min(1, $newHeight /
$srcHeight));
311: } else { // proportional
312: if (empty($newWidth) &&
empty($newHeight)) {
313: throw new InvalidArgumentException('At least width or height must be specified.');
317: if ($newWidth >
0) { // fit width
318: $scale[] =
$newWidth /
$srcWidth;
321: if ($newHeight >
0) { // fit height
322: $scale[] =
$newHeight /
$srcHeight;
325: if ($flags & self::FILL) {
329: if (($flags & self::ENLARGE) ===
0) {
335: $newHeight =
round($srcHeight *
$scale);
338: return array((int)
$newWidth, (int)
$newHeight);
345: * @param mixed x-offset in pixels or percent
346: * @param mixed y-offset in pixels or percent
349: * @return Image provides a fluent interface
351: public function crop($left, $top, $width, $height)
366: $newImage =
self::fromBlank($width, $height, self::RGB(0, 0, 0, 127))->getImageResource();
368: $this->image =
$newImage;
376: * @return Image provides a fluent interface
381: array( -
1, -
1, -
1 ),
382: array( -
1, 24, -
1 ),
383: array( -
1, -
1, -
1 ),
391: * Puts another image into this image.
393: * @param mixed x-coordinate in pixels or percent
394: * @param mixed y-coordinate in pixels or percent
395: * @param int opacity 0..100
396: * @return Image provides a fluent interface
398: public function place(Image $image, $left =
0, $top =
0, $opacity =
100)
410: if ($opacity ===
100) {
413: } elseif ($opacity <>
0) {
422: * Saves image to the file.
423: * @param string filename
424: * @param int quality 0..100 (for JPEG and PNG)
425: * @param int optional image type
426: * @return bool TRUE on success or FALSE on failure.
428: public function save($file =
NULL, $quality =
NULL, $type =
NULL)
430: if ($type ===
NULL) {
446: $quality =
$quality ===
NULL ?
85 :
max(0, min(100, (int)
$quality));
450: $quality =
$quality ===
NULL ?
9 :
max(0, min(9, (int)
$quality));
457: throw new Exception("Unsupported image type.");
464: * Outputs image to string.
465: * @param int image type
466: * @param int quality 0..100 (for JPEG and PNG)
469: public function toString($type =
self::JPEG, $quality =
NULL)
472: $this->save(NULL, $quality, $type);
479: * Outputs image to string.
487: } catch (Exception $e) {
495: * Outputs image to browser.
496: * @param int image type
497: * @param int quality 0..100 (for JPEG and PNG)
498: * @return bool TRUE on success or FALSE on failure.
500: public function send($type =
self::JPEG, $quality =
NULL)
502: if ($type !==
self::GIF &&
$type !==
self::PNG &&
$type !==
self::JPEG) {
503: throw new Exception("Unsupported image type.");
506: return $this->save(NULL, $quality, $type);
512: * Call to undefined method.
514: * @param string method name
515: * @param array arguments
517: * @throws MemberAccessException
521: $function =
'image' .
$name;
523: foreach ($args as $key =>
$value) {
524: if ($value instanceof
self) {
525: $args[$key] =
$value->getImageResource();
527: } elseif (is_array($value) &&
isset($value['red'])) { // rgb