Namespaces

  • Latte
    • Loaders
    • Macros
    • Runtime
  • Nette
    • Application
      • Responses
      • Routers
      • UI
    • Bridges
      • ApplicationDI
      • ApplicationLatte
      • ApplicationTracy
      • CacheDI
      • CacheLatte
      • DatabaseDI
      • DatabaseTracy
      • DITracy
      • FormsDI
      • FormsLatte
      • Framework
      • HttpDI
      • HttpTracy
      • MailDI
      • ReflectionDI
      • SecurityDI
      • SecurityTracy
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Conventions
      • Drivers
      • Reflection
      • Table
    • DI
      • Config
        • Adapters
      • Extensions
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Latte
    • Loaders
    • Localization
    • Mail
    • Neon
    • PhpGenerator
    • Reflection
    • Security
    • Templating
    • Utils
  • NetteModule
  • none
  • Tracy
    • Bridges
      • Nette

Classes

  • ArrayHash
  • ArrayList
  • Arrays
  • Callback
  • DateTime
  • FileSystem
  • Finder
  • Html
  • Image
  • Json
  • LimitedScope
  • MimeTypeDetector
  • ObjectMixin
  • Paginator
  • Random
  • Strings
  • TokenIterator
  • Tokenizer
  • Validators

Interfaces

  • IHtmlString

Exceptions

  • AssertionException
  • ImageException
  • JsonException
  • RegexpException
  • TokenizerException
  • UnknownImageFileException
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (http://nette.org)
  5:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  6:  */
  7: 
  8: namespace Nette\Utils;
  9: 
 10: use Nette;
 11: 
 12: 
 13: /**
 14:  * Basic manipulation with images.
 15:  *
 16:  * <code>
 17:  * $image = Image::fromFile('nette.jpg');
 18:  * $image->resize(150, 100);
 19:  * $image->sharpen();
 20:  * $image->send();
 21:  * </code>
 22:  *
 23:  * @author     David Grudl
 24:  *
 25:  * @method void alphaBlending(bool $on)
 26:  * @method void antialias(bool $on)
 27:  * @method void arc($x, $y, $w, $h, $start, $end, $color)
 28:  * @method void char(int $font, $x, $y, string $char, $color)
 29:  * @method void charUp(int $font, $x, $y, string $char, $color)
 30:  * @method int colorAllocate($red, $green, $blue)
 31:  * @method int colorAllocateAlpha($red, $green, $blue, $alpha)
 32:  * @method int colorAt($x, $y)
 33:  * @method int colorClosest($red, $green, $blue)
 34:  * @method int colorClosestAlpha($red, $green, $blue, $alpha)
 35:  * @method int colorClosestHWB($red, $green, $blue)
 36:  * @method void colorDeallocate($color)
 37:  * @method int colorExact($red, $green, $blue)
 38:  * @method int colorExactAlpha($red, $green, $blue, $alpha)
 39:  * @method void colorMatch(Image $image2)
 40:  * @method int colorResolve($red, $green, $blue)
 41:  * @method int colorResolveAlpha($red, $green, $blue, $alpha)
 42:  * @method void colorSet($index, $red, $green, $blue)
 43:  * @method array colorsForIndex($index)
 44:  * @method int colorsTotal()
 45:  * @method int colorTransparent($color = NULL)
 46:  * @method void convolution(array $matrix, float $div, float $offset)
 47:  * @method void copy(Image $src, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH)
 48:  * @method void copyMerge(Image $src, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH, $opacity)
 49:  * @method void copyMergeGray(Image $src, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH, $opacity)
 50:  * @method void copyResampled(Image $src, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH)
 51:  * @method void copyResized(Image $src, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH)
 52:  * @method void dashedLine($x1, $y1, $x2, $y2, $color)
 53:  * @method void ellipse($cx, $cy, $w, $h, $color)
 54:  * @method void fill($x, $y, $color)
 55:  * @method void filledArc($cx, $cy, $w, $h, $s, $e, $color, $style)
 56:  * @method void filledEllipse($cx, $cy, $w, $h, $color)
 57:  * @method void filledPolygon(array $points, $numPoints, $color)
 58:  * @method void filledRectangle($x1, $y1, $x2, $y2, $color)
 59:  * @method void fillToBorder($x, $y, $border, $color)
 60:  * @method void filter($filtertype)
 61:  * @method array ftText($size, $angle, $x, $y, $col, string $fontFile, string $text, array $extrainfo = NULL)
 62:  * @method void gammaCorrect(float $inputgamma, float $outputgamma)
 63:  * @method int interlace($interlace = NULL)
 64:  * @method bool isTrueColor()
 65:  * @method void layerEffect($effect)
 66:  * @method void line($x1, $y1, $x2, $y2, $color)
 67:  * @method void paletteCopy(Image $source)
 68:  * @method void polygon(array $points, $numPoints, $color)
 69:  * @method array psText(string $text, $font, $size, $color, $backgroundColor, $x, $y, $space = NULL, $tightness = NULL, float $angle = NULL, $antialiasSteps = NULL)
 70:  * @method void rectangle($x1, $y1, $x2, $y2, $col)
 71:  * @method Image rotate(float $angle, $backgroundColor)
 72:  * @method void saveAlpha(bool $saveflag)
 73:  * @method void setBrush(Image $brush)
 74:  * @method void setPixel($x, $y, $color)
 75:  * @method void setStyle(array $style)
 76:  * @method void setThickness($thickness)
 77:  * @method void setTile(Image $tile)
 78:  * @method void string($font, $x, $y, string $s, $col)
 79:  * @method void stringUp($font, $x, $y, string $s, $col)
 80:  * @method void trueColorToPalette(bool $dither, $ncolors)
 81:  * @method array ttfText($size, $angle, $x, $y, $color, string $fontfile, string $text)
 82:  * @property-read int $width
 83:  * @property-read int $height
 84:  * @property-read resource $imageResource
 85:  */
 86: class Image extends Nette\Object
 87: {
 88:     /** {@link resize()} only shrinks images */
 89:     const SHRINK_ONLY = 1;
 90: 
 91:     /** {@link resize()} will ignore aspect ratio */
 92:     const STRETCH = 2;
 93: 
 94:     /** {@link resize()} fits in given area so its dimensions are less than or equal to the required dimensions */
 95:     const FIT = 0;
 96: 
 97:     /** {@link resize()} fills given area so its dimensions are greater than or equal to the required dimensions */
 98:     const FILL = 4;
 99: 
100:     /** {@link resize()} fills given area exactly */
101:     const EXACT = 8;
102: 
103:     /** @int image types {@link send()} */
104:     const JPEG = IMAGETYPE_JPEG,
105:         PNG = IMAGETYPE_PNG,
106:         GIF = IMAGETYPE_GIF;
107: 
108:     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;";
109: 
110:     /** @deprecated */
111:     const ENLARGE = 0;
112: 
113:     /** @var resource */
114:     private $image;
115: 
116: 
117:     /**
118:      * Returns RGB color.
119:      * @param  int  red 0..255
120:      * @param  int  green 0..255
121:      * @param  int  blue 0..255
122:      * @param  int  transparency 0..127
123:      * @return array
124:      */
125:     public static function rgb($red, $green, $blue, $transparency = 0)
126:     {
127:         return array(
128:             'red' => max(0, min(255, (int) $red)),
129:             'green' => max(0, min(255, (int) $green)),
130:             'blue' => max(0, min(255, (int) $blue)),
131:             'alpha' => max(0, min(127, (int) $transparency)),
132:         );
133:     }
134: 
135: 
136:     /**
137:      * Opens image from file.
138:      * @param  string
139:      * @param  mixed  detected image format
140:      * @throws Nette\NotSupportedException if gd extension is not loaded
141:      * @throws UnknownImageFileException if file not found or file type is not known
142:      * @return Image
143:      */
144:     public static function fromFile($file, & $format = NULL)
145:     {
146:         if (!extension_loaded('gd')) {
147:             throw new Nette\NotSupportedException('PHP extension GD is not loaded.');
148:         }
149: 
150:         static $funcs = array(
151:             self::JPEG => 'imagecreatefromjpeg',
152:             self::PNG => 'imagecreatefrompng',
153:             self::GIF => 'imagecreatefromgif',
154:         );
155:         $info = @getimagesize($file); // @ - files smaller than 12 bytes causes read error
156:         $format = $info[2];
157: 
158:         if (!isset($funcs[$format])) {
159:             throw new UnknownImageFileException(is_file($file) ? "Unknown type of file '$file'." : "File '$file' not found.");
160:         }
161:         return new static(Callback::invokeSafe($funcs[$format], array($file), function($message) {
162:             throw new ImageException($message);
163:         }));
164:     }
165: 
166: 
167:     /**
168:      * @deprecated
169:      */
170:     public static function getFormatFromString($s)
171:     {
172:         trigger_error(__METHOD__ . '() is deprecated; use finfo_buffer() instead.', E_USER_DEPRECATED);
173:         $types = array('image/jpeg' => self::JPEG, 'image/gif' => self::GIF, 'image/png' => self::PNG);
174:         $type = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $s);
175:         return isset($types[$type]) ? $types[$type] : NULL;
176:     }
177: 
178: 
179:     /**
180:      * Create a new image from the image stream in the string.
181:      * @param  string
182:      * @param  mixed  detected image format
183:      * @return Image
184:      * @throws ImageException
185:      */
186:     public static function fromString($s, & $format = NULL)
187:     {
188:         if (!extension_loaded('gd')) {
189:             throw new Nette\NotSupportedException('PHP extension GD is not loaded.');
190:         }
191: 
192:         if (func_num_args() > 1) {
193:             trigger_error(__METHOD__ . '() second argument $format is deprecated; use finfo_buffer() instead.', E_USER_DEPRECATED);
194:             $format = @static::getFormatFromString($s);
195:         }
196: 
197:         return new static(Callback::invokeSafe('imagecreatefromstring', array($s), function($message) {
198:             throw new ImageException($message);
199:         }));
200:     }
201: 
202: 
203:     /**
204:      * Creates blank image.
205:      * @param  int
206:      * @param  int
207:      * @param  array
208:      * @return Image
209:      */
210:     public static function fromBlank($width, $height, $color = NULL)
211:     {
212:         if (!extension_loaded('gd')) {
213:             throw new Nette\NotSupportedException('PHP extension GD is not loaded.');
214:         }
215: 
216:         $width = (int) $width;
217:         $height = (int) $height;
218:         if ($width < 1 || $height < 1) {
219:             throw new Nette\InvalidArgumentException('Image width and height must be greater than zero.');
220:         }
221: 
222:         $image = imagecreatetruecolor($width, $height);
223:         if (is_array($color)) {
224:             $color += array('alpha' => 0);
225:             $color = imagecolorallocatealpha($image, $color['red'], $color['green'], $color['blue'], $color['alpha']);
226:             imagealphablending($image, FALSE);
227:             imagefilledrectangle($image, 0, 0, $width - 1, $height - 1, $color);
228:             imagealphablending($image, TRUE);
229:         }
230:         return new static($image);
231:     }
232: 
233: 
234:     /**
235:      * Wraps GD image.
236:      * @param  resource
237:      */
238:     public function __construct($image)
239:     {
240:         $this->setImageResource($image);
241:         imagesavealpha($image, TRUE);
242:     }
243: 
244: 
245:     /**
246:      * Returns image width.
247:      * @return int
248:      */
249:     public function getWidth()
250:     {
251:         return imagesx($this->image);
252:     }
253: 
254: 
255:     /**
256:      * Returns image height.
257:      * @return int
258:      */
259:     public function getHeight()
260:     {
261:         return imagesy($this->image);
262:     }
263: 
264: 
265:     /**
266:      * Sets image resource.
267:      * @param  resource
268:      * @return self
269:      */
270:     protected function setImageResource($image)
271:     {
272:         if (!is_resource($image) || get_resource_type($image) !== 'gd') {
273:             throw new Nette\InvalidArgumentException('Image is not valid.');
274:         }
275:         $this->image = $image;
276:         return $this;
277:     }
278: 
279: 
280:     /**
281:      * Returns image GD resource.
282:      * @return resource
283:      */
284:     public function getImageResource()
285:     {
286:         return $this->image;
287:     }
288: 
289: 
290:     /**
291:      * Resizes image.
292:      * @param  mixed  width in pixels or percent
293:      * @param  mixed  height in pixels or percent
294:      * @param  int    flags
295:      * @return self
296:      */
297:     public function resize($width, $height, $flags = self::FIT)
298:     {
299:         if ($flags & self::EXACT) {
300:             return $this->resize($width, $height, self::FILL)->crop('50%', '50%', $width, $height);
301:         }
302: 
303:         list($newWidth, $newHeight) = static::calculateSize($this->getWidth(), $this->getHeight(), $width, $height, $flags);
304: 
305:         if ($newWidth !== $this->getWidth() || $newHeight !== $this->getHeight()) { // resize
306:             $newImage = static::fromBlank($newWidth, $newHeight, self::RGB(0, 0, 0, 127))->getImageResource();
307:             imagecopyresampled(
308:                 $newImage, $this->image,
309:                 0, 0, 0, 0,
310:                 $newWidth, $newHeight, $this->getWidth(), $this->getHeight()
311:             );
312:             $this->image = $newImage;
313:         }
314: 
315:         if ($width < 0 || $height < 0) { // flip is processed in two steps for better quality
316:             $newImage = static::fromBlank($newWidth, $newHeight, self::RGB(0, 0, 0, 127))->getImageResource();
317:             imagecopyresampled(
318:                 $newImage, $this->image,
319:                 0, 0, $width < 0 ? $newWidth - 1 : 0, $height < 0 ? $newHeight - 1 : 0,
320:                 $newWidth, $newHeight, $width < 0 ? -$newWidth : $newWidth, $height < 0 ? -$newHeight : $newHeight
321:             );
322:             $this->image = $newImage;
323:         }
324:         return $this;
325:     }
326: 
327: 
328:     /**
329:      * Calculates dimensions of resized image.
330:      * @param  mixed  source width
331:      * @param  mixed  source height
332:      * @param  mixed  width in pixels or percent
333:      * @param  mixed  height in pixels or percent
334:      * @param  int    flags
335:      * @return array
336:      */
337:     public static function calculateSize($srcWidth, $srcHeight, $newWidth, $newHeight, $flags = self::FIT)
338:     {
339:         if (substr($newWidth, -1) === '%') {
340:             $newWidth = round($srcWidth / 100 * abs($newWidth));
341:             $percents = TRUE;
342:         } else {
343:             $newWidth = (int) abs($newWidth);
344:         }
345: 
346:         if (substr($newHeight, -1) === '%') {
347:             $newHeight = round($srcHeight / 100 * abs($newHeight));
348:             $flags |= empty($percents) ? 0 : self::STRETCH;
349:         } else {
350:             $newHeight = (int) abs($newHeight);
351:         }
352: 
353:         if ($flags & self::STRETCH) { // non-proportional
354:             if (empty($newWidth) || empty($newHeight)) {
355:                 throw new Nette\InvalidArgumentException('For stretching must be both width and height specified.');
356:             }
357: 
358:             if ($flags & self::SHRINK_ONLY) {
359:                 $newWidth = round($srcWidth * min(1, $newWidth / $srcWidth));
360:                 $newHeight = round($srcHeight * min(1, $newHeight / $srcHeight));
361:             }
362: 
363:         } else {  // proportional
364:             if (empty($newWidth) && empty($newHeight)) {
365:                 throw new Nette\InvalidArgumentException('At least width or height must be specified.');
366:             }
367: 
368:             $scale = array();
369:             if ($newWidth > 0) { // fit width
370:                 $scale[] = $newWidth / $srcWidth;
371:             }
372: 
373:             if ($newHeight > 0) { // fit height
374:                 $scale[] = $newHeight / $srcHeight;
375:             }
376: 
377:             if ($flags & self::FILL) {
378:                 $scale = array(max($scale));
379:             }
380: 
381:             if ($flags & self::SHRINK_ONLY) {
382:                 $scale[] = 1;
383:             }
384: 
385:             $scale = min($scale);
386:             $newWidth = round($srcWidth * $scale);
387:             $newHeight = round($srcHeight * $scale);
388:         }
389: 
390:         return array(max((int) $newWidth, 1), max((int) $newHeight, 1));
391:     }
392: 
393: 
394:     /**
395:      * Crops image.
396:      * @param  mixed  x-offset in pixels or percent
397:      * @param  mixed  y-offset in pixels or percent
398:      * @param  mixed  width in pixels or percent
399:      * @param  mixed  height in pixels or percent
400:      * @return self
401:      */
402:     public function crop($left, $top, $width, $height)
403:     {
404:         list($left, $top, $width, $height) = static::calculateCutout($this->getWidth(), $this->getHeight(), $left, $top, $width, $height);
405:         $newImage = static::fromBlank($width, $height, self::RGB(0, 0, 0, 127))->getImageResource();
406:         imagecopy($newImage, $this->image, 0, 0, $left, $top, $width, $height);
407:         $this->image = $newImage;
408:         return $this;
409:     }
410: 
411: 
412:     /**
413:      * Calculates dimensions of cutout in image.
414:      * @param  mixed  source width
415:      * @param  mixed  source height
416:      * @param  mixed  x-offset in pixels or percent
417:      * @param  mixed  y-offset in pixels or percent
418:      * @param  mixed  width in pixels or percent
419:      * @param  mixed  height in pixels or percent
420:      * @return array
421:      */
422:     public static function calculateCutout($srcWidth, $srcHeight, $left, $top, $newWidth, $newHeight)
423:     {
424:         if (substr($newWidth, -1) === '%') {
425:             $newWidth = round($srcWidth / 100 * $newWidth);
426:         }
427:         if (substr($newHeight, -1) === '%') {
428:             $newHeight = round($srcHeight / 100 * $newHeight);
429:         }
430:         if (substr($left, -1) === '%') {
431:             $left = round(($srcWidth - $newWidth) / 100 * $left);
432:         }
433:         if (substr($top, -1) === '%') {
434:             $top = round(($srcHeight - $newHeight) / 100 * $top);
435:         }
436:         if ($left < 0) {
437:             $newWidth += $left; $left = 0;
438:         }
439:         if ($top < 0) {
440:             $newHeight += $top; $top = 0;
441:         }
442:         $newWidth = min((int) $newWidth, $srcWidth - $left);
443:         $newHeight = min((int) $newHeight, $srcHeight - $top);
444:         return array($left, $top, $newWidth, $newHeight);
445:     }
446: 
447: 
448:     /**
449:      * Sharpen image.
450:      * @return self
451:      */
452:     public function sharpen()
453:     {
454:         imageconvolution($this->image, array( // my magic numbers ;)
455:             array( -1, -1, -1 ),
456:             array( -1, 24, -1 ),
457:             array( -1, -1, -1 ),
458:         ), 16, 0);
459:         return $this;
460:     }
461: 
462: 
463:     /**
464:      * Puts another image into this image.
465:      * @param  Image
466:      * @param  mixed  x-coordinate in pixels or percent
467:      * @param  mixed  y-coordinate in pixels or percent
468:      * @param  int  opacity 0..100
469:      * @return self
470:      */
471:     public function place(Image $image, $left = 0, $top = 0, $opacity = 100)
472:     {
473:         $opacity = max(0, min(100, (int) $opacity));
474: 
475:         if (substr($left, -1) === '%') {
476:             $left = round(($this->getWidth() - $image->getWidth()) / 100 * $left);
477:         }
478: 
479:         if (substr($top, -1) === '%') {
480:             $top = round(($this->getHeight() - $image->getHeight()) / 100 * $top);
481:         }
482: 
483:         if ($opacity === 100) {
484:             imagecopy(
485:                 $this->image, $image->getImageResource(),
486:                 $left, $top, 0, 0, $image->getWidth(), $image->getHeight()
487:             );
488: 
489:         } elseif ($opacity <> 0) {
490:             $cutting = imagecreatetruecolor($image->getWidth(), $image->getHeight());
491:             imagecopy(
492:                 $cutting, $this->image,
493:                 0, 0, $left, $top, $image->getWidth(), $image->getHeight()
494:             );
495:             imagecopy(
496:                 $cutting, $image->getImageResource(),
497:                 0, 0, 0, 0, $image->getWidth(), $image->getHeight()
498:             );
499: 
500:             imagecopymerge(
501:                 $this->image, $cutting,
502:                 $left, $top, 0, 0, $image->getWidth(), $image->getHeight(),
503:                 $opacity
504:             );
505:         }
506:         return $this;
507:     }
508: 
509: 
510:     /**
511:      * Saves image to the file.
512:      * @param  string  filename
513:      * @param  int  quality 0..100 (for JPEG and PNG)
514:      * @param  int  optional image type
515:      * @return bool TRUE on success or FALSE on failure.
516:      */
517:     public function save($file = NULL, $quality = NULL, $type = NULL)
518:     {
519:         if ($type === NULL) {
520:             switch (strtolower(pathinfo($file, PATHINFO_EXTENSION))) {
521:                 case 'jpg':
522:                 case 'jpeg':
523:                     $type = self::JPEG;
524:                     break;
525:                 case 'png':
526:                     $type = self::PNG;
527:                     break;
528:                 case 'gif':
529:                     $type = self::GIF;
530:             }
531:         }
532: 
533:         switch ($type) {
534:             case self::JPEG:
535:                 $quality = $quality === NULL ? 85 : max(0, min(100, (int) $quality));
536:                 return imagejpeg($this->image, $file, $quality);
537: 
538:             case self::PNG:
539:                 $quality = $quality === NULL ? 9 : max(0, min(9, (int) $quality));
540:                 return imagepng($this->image, $file, $quality);
541: 
542:             case self::GIF:
543:                 return imagegif($this->image, $file);
544: 
545:             default:
546:                 throw new Nette\InvalidArgumentException('Unsupported image type \'$type\'.');
547:         }
548:     }
549: 
550: 
551:     /**
552:      * Outputs image to string.
553:      * @param  int  image type
554:      * @param  int  quality 0..100 (for JPEG and PNG)
555:      * @return string
556:      */
557:     public function toString($type = self::JPEG, $quality = NULL)
558:     {
559:         ob_start();
560:         $this->save(NULL, $quality, $type);
561:         return ob_get_clean();
562:     }
563: 
564: 
565:     /**
566:      * Outputs image to string.
567:      * @return string
568:      */
569:     public function __toString()
570:     {
571:         try {
572:             return $this->toString();
573:         } catch (\Exception $e) {
574:             if (func_num_args()) {
575:                 throw $e;
576:             }
577:             trigger_error("Exception in " . __METHOD__ . "(): {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}", E_USER_ERROR);
578:         }
579:     }
580: 
581: 
582:     /**
583:      * Outputs image to browser.
584:      * @param  int  image type
585:      * @param  int  quality 0..100 (for JPEG and PNG)
586:      * @return bool TRUE on success or FALSE on failure.
587:      */
588:     public function send($type = self::JPEG, $quality = NULL)
589:     {
590:         if ($type !== self::GIF && $type !== self::PNG && $type !== self::JPEG) {
591:             throw new Nette\InvalidArgumentException('Unsupported image type \'$type\'.');
592:         }
593:         header('Content-Type: ' . image_type_to_mime_type($type));
594:         return $this->save(NULL, $quality, $type);
595:     }
596: 
597: 
598:     /**
599:      * Call to undefined method.
600:      *
601:      * @param  string  method name
602:      * @param  array   arguments
603:      * @return mixed
604:      * @throws Nette\MemberAccessException
605:      */
606:     public function __call($name, $args)
607:     {
608:         $function = 'image' . $name;
609:         if (function_exists($function)) {
610:             foreach ($args as $key => $value) {
611:                 if ($value instanceof self) {
612:                     $args[$key] = $value->getImageResource();
613: 
614:                 } elseif (is_array($value) && isset($value['red'])) { // rgb
615:                     $args[$key] = imagecolorallocatealpha(
616:                         $this->image,
617:                         $value['red'], $value['green'], $value['blue'], $value['alpha']
618:                     );
619:                 }
620:             }
621:             array_unshift($args, $this->image);
622: 
623:             $res = call_user_func_array($function, $args);
624:             return is_resource($res) && get_resource_type($res) === 'gd' ? $this->setImageResource($res) : $res;
625:         }
626: 
627:         return parent::__call($name, $args);
628:     }
629: 
630: 
631:     public function __clone()
632:     {
633:         ob_start();
634:         imagegd2($this->image);
635:         $this->setImageResource(imagecreatefromstring(ob_get_clean()));
636:     }
637: 
638: }
639: 
640: 
641: /**
642:  * The exception that is thrown when an image error occurs.
643:  */
644: class ImageException extends \Exception
645: {
646: }
647: 
648: 
649: /**
650:  * The exception that indicates invalid image file.
651:  */
652: class UnknownImageFileException extends ImageException
653: {
654: }
655: 
Nette 2.3.1 API API documentation generated by ApiGen 2.8.0