Namespaces

  • Latte
    • Loaders
    • Macros
    • Runtime
  • Nette
    • Application
      • Responses
      • Routers
      • UI
    • Bridges
      • ApplicationLatte
      • ApplicationTracy
      • CacheLatte
      • DatabaseDI
      • DatabaseTracy
      • DITracy
      • FormsLatte
      • Framework
      • HttpTracy
      • SecurityTracy
    • Caching
      • Storages
    • ComponentModel
    • Database
      • 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

Classes

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

Interfaces

  • IHtmlString

Exceptions

  • AssertionException
  • JsonException
  • RegexpException
  • TokenizerException
  • UnknownImageFileException
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Other releases
  • Nette homepage
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (https://nette.org)
  5:  * Copyright (c) 2004 David Grudl (https://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:         $info = @getimagesize($file); // @ - files smaller than 12 bytes causes read error
151: 
152:         switch ($format = $info[2]) {
153:             case self::JPEG:
154:                 return new static(imagecreatefromjpeg($file));
155: 
156:             case self::PNG:
157:                 return new static(imagecreatefrompng($file));
158: 
159:             case self::GIF:
160:                 return new static(imagecreatefromgif($file));
161: 
162:             default:
163:                 throw new UnknownImageFileException(is_file($file) ? "Unknown type of file '$file'." : "File '$file' not found.");
164:         }
165:     }
166: 
167: 
168:     /**
169:      * Get format from the image stream in the string.
170:      * @param  string
171:      * @return mixed  detected image format
172:      */
173:     public static function getFormatFromString($s)
174:     {
175:         $types = array('image/jpeg' => self::JPEG, 'image/gif' => self::GIF, 'image/png' => self::PNG);
176:         $type = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $s);
177:         return isset($types[$type]) ? $types[$type] : NULL;
178:     }
179: 
180: 
181:     /**
182:      * Create a new image from the image stream in the string.
183:      * @param  string
184:      * @param  mixed  detected image format
185:      * @return Image
186:      * @throws ImageException
187:      */
188:     public static function fromString($s, & $format = NULL)
189:     {
190:         if (!extension_loaded('gd')) {
191:             throw new Nette\NotSupportedException('PHP extension GD is not loaded.');
192:         }
193: 
194:         $format = static::getFormatFromString($s);
195: 
196:         return new static(imagecreatefromstring($s));
197:     }
198: 
199: 
200:     /**
201:      * Creates blank image.
202:      * @param  int
203:      * @param  int
204:      * @param  array
205:      * @return Image
206:      */
207:     public static function fromBlank($width, $height, $color = NULL)
208:     {
209:         if (!extension_loaded('gd')) {
210:             throw new Nette\NotSupportedException('PHP extension GD is not loaded.');
211:         }
212: 
213:         $width = (int) $width;
214:         $height = (int) $height;
215:         if ($width < 1 || $height < 1) {
216:             throw new Nette\InvalidArgumentException('Image width and height must be greater than zero.');
217:         }
218: 
219:         $image = imagecreatetruecolor($width, $height);
220:         if (is_array($color)) {
221:             $color += array('alpha' => 0);
222:             $color = imagecolorresolvealpha($image, $color['red'], $color['green'], $color['blue'], $color['alpha']);
223:             imagealphablending($image, FALSE);
224:             imagefilledrectangle($image, 0, 0, $width - 1, $height - 1, $color);
225:             imagealphablending($image, TRUE);
226:         }
227:         return new static($image);
228:     }
229: 
230: 
231:     /**
232:      * Wraps GD image.
233:      * @param  resource
234:      */
235:     public function __construct($image)
236:     {
237:         $this->setImageResource($image);
238:         imagesavealpha($image, TRUE);
239:     }
240: 
241: 
242:     /**
243:      * Returns image width.
244:      * @return int
245:      */
246:     public function getWidth()
247:     {
248:         return imagesx($this->image);
249:     }
250: 
251: 
252:     /**
253:      * Returns image height.
254:      * @return int
255:      */
256:     public function getHeight()
257:     {
258:         return imagesy($this->image);
259:     }
260: 
261: 
262:     /**
263:      * Sets image resource.
264:      * @param  resource
265:      * @return self
266:      */
267:     protected function setImageResource($image)
268:     {
269:         if (!is_resource($image) || get_resource_type($image) !== 'gd') {
270:             throw new Nette\InvalidArgumentException('Image is not valid.');
271:         }
272:         $this->image = $image;
273:         return $this;
274:     }
275: 
276: 
277:     /**
278:      * Returns image GD resource.
279:      * @return resource
280:      */
281:     public function getImageResource()
282:     {
283:         return $this->image;
284:     }
285: 
286: 
287:     /**
288:      * Resizes image.
289:      * @param  mixed  width in pixels or percent
290:      * @param  mixed  height in pixels or percent
291:      * @param  int    flags
292:      * @return self
293:      */
294:     public function resize($width, $height, $flags = self::FIT)
295:     {
296:         if ($flags & self::EXACT) {
297:             return $this->resize($width, $height, self::FILL)->crop('50%', '50%', $width, $height);
298:         }
299: 
300:         list($newWidth, $newHeight) = static::calculateSize($this->getWidth(), $this->getHeight(), $width, $height, $flags);
301: 
302:         if ($newWidth !== $this->getWidth() || $newHeight !== $this->getHeight()) { // resize
303:             $newImage = static::fromBlank($newWidth, $newHeight, self::RGB(0, 0, 0, 127))->getImageResource();
304:             imagecopyresampled(
305:                 $newImage, $this->image,
306:                 0, 0, 0, 0,
307:                 $newWidth, $newHeight, $this->getWidth(), $this->getHeight()
308:             );
309:             $this->image = $newImage;
310:         }
311: 
312:         if ($width < 0 || $height < 0) { // flip is processed in two steps for better quality
313:             $newImage = static::fromBlank($newWidth, $newHeight, self::RGB(0, 0, 0, 127))->getImageResource();
314:             imagecopyresampled(
315:                 $newImage, $this->image,
316:                 0, 0, $width < 0 ? $newWidth - 1 : 0, $height < 0 ? $newHeight - 1 : 0,
317:                 $newWidth, $newHeight, $width < 0 ? -$newWidth : $newWidth, $height < 0 ? -$newHeight : $newHeight
318:             );
319:             $this->image = $newImage;
320:         }
321:         return $this;
322:     }
323: 
324: 
325:     /**
326:      * Calculates dimensions of resized image.
327:      * @param  mixed  source width
328:      * @param  mixed  source height
329:      * @param  mixed  width in pixels or percent
330:      * @param  mixed  height in pixels or percent
331:      * @param  int    flags
332:      * @return array
333:      */
334:     public static function calculateSize($srcWidth, $srcHeight, $newWidth, $newHeight, $flags = self::FIT)
335:     {
336:         if (substr($newWidth, -1) === '%') {
337:             $newWidth = round($srcWidth / 100 * abs($newWidth));
338:             $percents = TRUE;
339:         } else {
340:             $newWidth = (int) abs($newWidth);
341:         }
342: 
343:         if (substr($newHeight, -1) === '%') {
344:             $newHeight = round($srcHeight / 100 * abs($newHeight));
345:             $flags |= empty($percents) ? 0 : self::STRETCH;
346:         } else {
347:             $newHeight = (int) abs($newHeight);
348:         }
349: 
350:         if ($flags & self::STRETCH) { // non-proportional
351:             if (empty($newWidth) || empty($newHeight)) {
352:                 throw new Nette\InvalidArgumentException('For stretching must be both width and height specified.');
353:             }
354: 
355:             if ($flags & self::SHRINK_ONLY) {
356:                 $newWidth = round($srcWidth * min(1, $newWidth / $srcWidth));
357:                 $newHeight = round($srcHeight * min(1, $newHeight / $srcHeight));
358:             }
359: 
360:         } else {  // proportional
361:             if (empty($newWidth) && empty($newHeight)) {
362:                 throw new Nette\InvalidArgumentException('At least width or height must be specified.');
363:             }
364: 
365:             $scale = array();
366:             if ($newWidth > 0) { // fit width
367:                 $scale[] = $newWidth / $srcWidth;
368:             }
369: 
370:             if ($newHeight > 0) { // fit height
371:                 $scale[] = $newHeight / $srcHeight;
372:             }
373: 
374:             if ($flags & self::FILL) {
375:                 $scale = array(max($scale));
376:             }
377: 
378:             if ($flags & self::SHRINK_ONLY) {
379:                 $scale[] = 1;
380:             }
381: 
382:             $scale = min($scale);
383:             $newWidth = round($srcWidth * $scale);
384:             $newHeight = round($srcHeight * $scale);
385:         }
386: 
387:         return array(max((int) $newWidth, 1), max((int) $newHeight, 1));
388:     }
389: 
390: 
391:     /**
392:      * Crops image.
393:      * @param  mixed  x-offset in pixels or percent
394:      * @param  mixed  y-offset in pixels or percent
395:      * @param  mixed  width in pixels or percent
396:      * @param  mixed  height in pixels or percent
397:      * @return self
398:      */
399:     public function crop($left, $top, $width, $height)
400:     {
401:         list($left, $top, $width, $height) = static::calculateCutout($this->getWidth(), $this->getHeight(), $left, $top, $width, $height);
402:         $newImage = static::fromBlank($width, $height, self::RGB(0, 0, 0, 127))->getImageResource();
403:         imagecopy($newImage, $this->image, 0, 0, $left, $top, $width, $height);
404:         $this->image = $newImage;
405:         return $this;
406:     }
407: 
408: 
409:     /**
410:      * Calculates dimensions of cutout in image.
411:      * @param  mixed  source width
412:      * @param  mixed  source height
413:      * @param  mixed  x-offset in pixels or percent
414:      * @param  mixed  y-offset in pixels or percent
415:      * @param  mixed  width in pixels or percent
416:      * @param  mixed  height in pixels or percent
417:      * @return array
418:      */
419:     public static function calculateCutout($srcWidth, $srcHeight, $left, $top, $newWidth, $newHeight)
420:     {
421:         if (substr($newWidth, -1) === '%') {
422:             $newWidth = round($srcWidth / 100 * $newWidth);
423:         }
424:         if (substr($newHeight, -1) === '%') {
425:             $newHeight = round($srcHeight / 100 * $newHeight);
426:         }
427:         if (substr($left, -1) === '%') {
428:             $left = round(($srcWidth - $newWidth) / 100 * $left);
429:         }
430:         if (substr($top, -1) === '%') {
431:             $top = round(($srcHeight - $newHeight) / 100 * $top);
432:         }
433:         if ($left < 0) {
434:             $newWidth += $left;
435:             $left = 0;
436:         }
437:         if ($top < 0) {
438:             $newHeight += $top;
439:             $top = 0;
440:         }
441:         $newWidth = min((int) $newWidth, $srcWidth - $left);
442:         $newHeight = min((int) $newHeight, $srcHeight - $top);
443:         return array($left, $top, $newWidth, $newHeight);
444:     }
445: 
446: 
447:     /**
448:      * Sharpen image.
449:      * @return self
450:      */
451:     public function sharpen()
452:     {
453:         imageconvolution($this->image, array( // my magic numbers ;)
454:             array(-1, -1, -1),
455:             array(-1, 24, -1),
456:             array(-1, -1, -1),
457:         ), 16, 0);
458:         return $this;
459:     }
460: 
461: 
462:     /**
463:      * Puts another image into this image.
464:      * @param  Image
465:      * @param  mixed  x-coordinate in pixels or percent
466:      * @param  mixed  y-coordinate in pixels or percent
467:      * @param  int  opacity 0..100
468:      * @return self
469:      */
470:     public function place(Image $image, $left = 0, $top = 0, $opacity = 100)
471:     {
472:         $opacity = max(0, min(100, (int) $opacity));
473: 
474:         if (substr($left, -1) === '%') {
475:             $left = round(($this->getWidth() - $image->getWidth()) / 100 * $left);
476:         }
477: 
478:         if (substr($top, -1) === '%') {
479:             $top = round(($this->getHeight() - $image->getHeight()) / 100 * $top);
480:         }
481: 
482:         if ($opacity === 100) {
483:             imagecopy(
484:                 $this->image, $image->getImageResource(),
485:                 $left, $top, 0, 0, $image->getWidth(), $image->getHeight()
486:             );
487: 
488:         } elseif ($opacity != 0) {
489:             $cutting = imagecreatetruecolor($image->getWidth(), $image->getHeight());
490:             imagecopy(
491:                 $cutting, $this->image,
492:                 0, 0, $left, $top, $image->getWidth(), $image->getHeight()
493:             );
494:             imagecopy(
495:                 $cutting, $image->getImageResource(),
496:                 0, 0, 0, 0, $image->getWidth(), $image->getHeight()
497:             );
498: 
499:             imagecopymerge(
500:                 $this->image, $cutting,
501:                 $left, $top, 0, 0, $image->getWidth(), $image->getHeight(),
502:                 $opacity
503:             );
504:         }
505:         return $this;
506:     }
507: 
508: 
509:     /**
510:      * Saves image to the file.
511:      * @param  string  filename
512:      * @param  int  quality 0..100 (for JPEG and PNG)
513:      * @param  int  optional image type
514:      * @return bool TRUE on success or FALSE on failure.
515:      */
516:     public function save($file = NULL, $quality = NULL, $type = NULL)
517:     {
518:         if ($type === NULL) {
519:             switch (strtolower(pathinfo($file, PATHINFO_EXTENSION))) {
520:                 case 'jpg':
521:                 case 'jpeg':
522:                     $type = self::JPEG;
523:                     break;
524:                 case 'png':
525:                     $type = self::PNG;
526:                     break;
527:                 case 'gif':
528:                     $type = self::GIF;
529:             }
530:         }
531: 
532:         switch ($type) {
533:             case self::JPEG:
534:                 $quality = $quality === NULL ? 85 : max(0, min(100, (int) $quality));
535:                 return imagejpeg($this->image, $file, $quality);
536: 
537:             case self::PNG:
538:                 $quality = $quality === NULL ? 9 : max(0, min(9, (int) $quality));
539:                 return imagepng($this->image, $file, $quality);
540: 
541:             case self::GIF:
542:                 return imagegif($this->image, $file);
543: 
544:             default:
545:                 throw new Nette\InvalidArgumentException('Unsupported image type.');
546:         }
547:     }
548: 
549: 
550:     /**
551:      * Outputs image to string.
552:      * @param  int  image type
553:      * @param  int  quality 0..100 (for JPEG and PNG)
554:      * @return string
555:      */
556:     public function toString($type = self::JPEG, $quality = NULL)
557:     {
558:         ob_start();
559:         $this->save(NULL, $quality, $type);
560:         return ob_get_clean();
561:     }
562: 
563: 
564:     /**
565:      * Outputs image to string.
566:      * @return string
567:      */
568:     public function __toString()
569:     {
570:         try {
571:             return $this->toString();
572:         } catch (\Throwable $e) {
573:         } catch (\Exception $e) {
574:         }
575:         if (isset($e)) {
576:             if (func_num_args()) {
577:                 throw $e;
578:             }
579:             trigger_error("Exception in " . __METHOD__ . "(): {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}", E_USER_ERROR);
580:         }
581:     }
582: 
583: 
584:     /**
585:      * Outputs image to browser.
586:      * @param  int  image type
587:      * @param  int  quality 0..100 (for JPEG and PNG)
588:      * @return bool TRUE on success or FALSE on failure.
589:      */
590:     public function send($type = self::JPEG, $quality = NULL)
591:     {
592:         if ($type !== self::GIF && $type !== self::PNG && $type !== self::JPEG) {
593:             throw new Nette\InvalidArgumentException('Unsupported image type.');
594:         }
595:         header('Content-Type: ' . image_type_to_mime_type($type));
596:         return $this->save(NULL, $quality, $type);
597:     }
598: 
599: 
600:     /**
601:      * Call to undefined method.
602:      *
603:      * @param  string  method name
604:      * @param  array   arguments
605:      * @return mixed
606:      * @throws Nette\MemberAccessException
607:      */
608:     public function __call($name, $args)
609:     {
610:         $function = 'image' . $name;
611:         if (!function_exists($function)) {
612:             return parent::__call($name, $args);
613:         }
614: 
615:         foreach ($args as $key => $value) {
616:             if ($value instanceof self) {
617:                 $args[$key] = $value->getImageResource();
618: 
619:             } elseif (is_array($value) && isset($value['red'])) { // rgb
620:                 $args[$key] = imagecolorallocatealpha(
621:                     $this->image,
622:                     $value['red'], $value['green'], $value['blue'], $value['alpha']
623:                 ) ?: imagecolorresolvealpha(
624:                     $this->image,
625:                     $value['red'], $value['green'], $value['blue'], $value['alpha']
626:                 );
627:             }
628:         }
629:         array_unshift($args, $this->image);
630: 
631:         $res = call_user_func_array($function, $args);
632:         return is_resource($res) && get_resource_type($res) === 'gd' ? $this->setImageResource($res) : $res;
633:     }
634: 
635: 
636:     public function __clone()
637:     {
638:         ob_start();
639:         imagegd2($this->image);
640:         $this->setImageResource(imagecreatefromstring(ob_get_clean()));
641:     }
642: 
643: }
644: 
645: 
646: /**
647:  * The exception that indicates invalid image file.
648:  */
649: class UnknownImageFileException extends \Exception
650: {
651: }
652: 
Nette 2.2 API documentation generated by ApiGen 2.8.0