diff --git a/composer.json b/composer.json index 3817a4b52..61e250535 100644 --- a/composer.json +++ b/composer.json @@ -1,23 +1,23 @@ { "name": "intervention/image", - "description": "Image handling and manipulation library with support for Laravel integration", + "description": "PHP Image Manipulation", "homepage": "http://image.intervention.io/", - "keywords": ["image", "gd", "imagick", "laravel", "watermark", "thumbnail"], + "keywords": ["image", "gd", "imagick", "laravel", "watermark", "thumbnail", "animation", "resize"], "license": "MIT", "authors": [ { "name": "Oliver Vogel", - "email": "oliver@olivervogel.net", - "homepage": "http://olivervogel.net/" + "email": "oliver@olivervogel.com", + "homepage": "http://olivervogel.com/" } ], "require": { "php": ">=5.4.0", - "ext-fileinfo": "*", - "guzzlehttp/psr7": "~1.1" + "intervention/gif": "dev-master", + "ext-fileinfo": "*" }, "require-dev": { - "phpunit/phpunit": "3.*", + "phpunit/phpunit": "~4.0", "mockery/mockery": "~0.9.2" }, "suggest": { @@ -30,6 +30,9 @@ "Intervention\\Image\\": "src/Intervention/Image" } }, + "autoload-dev": { + "classmap": ["tests"] + }, "extra": { "branch-alias": { "dev-master": "2.3-dev" diff --git a/src/Intervention/Image/AbstractDriver.php b/src/Intervention/Image/AbstractDriver.php index dfa1649b8..67e45d3f2 100644 --- a/src/Intervention/Image/AbstractDriver.php +++ b/src/Intervention/Image/AbstractDriver.php @@ -37,20 +37,20 @@ abstract public function newImage($width, $height, $background); abstract public function parseColor($value); /** - * Checks if core module installation is available + * Checks if image module installation is available * * @return boolean */ - abstract protected function coreAvailable(); + abstract protected function moduleAvailable(); /** - * Returns clone of given core + * Returns clone of given container * * @return mixed */ - public function cloneCore($core) + public function cloneContainer(ContainerInterface $container) { - return clone $core; + return clone $container; } /** diff --git a/src/Intervention/Image/AbstractFont.php b/src/Intervention/Image/AbstractFont.php index 9e3cca92c..f89a98de2 100644 --- a/src/Intervention/Image/AbstractFont.php +++ b/src/Intervention/Image/AbstractFont.php @@ -4,6 +4,11 @@ abstract class AbstractFont { + /** + * Security padding to prevent text being cut off + */ + const PADDING = 10; + /** * Text to be written * @@ -53,6 +58,20 @@ abstract class AbstractFont */ public $file; + /** + * Line height of the text + * + * @var float + */ + public $lineHeight = 1; + + /** + * Textbox + * + * @var Size + */ + public $box; + /** * Draws font to given image on given position * @@ -63,6 +82,22 @@ abstract class AbstractFont */ abstract public function applyToImage(Image $image, $posx = 0, $posy = 0); + /** + * Calculate boxsize including own features + * + * @param string $text + * @return \Intervention\Image\Size + */ + abstract public function getBoxSize($text = null); + + /** + * Get raw boxsize without any non-core features + * + * @param string $text + * @return \Intervention\Image\Size + */ + abstract protected function getCoreBoxSize($text = null); + /** * Create a new instance of Font * @@ -220,6 +255,49 @@ public function getFile() return $this->file; } + /** + * Set line-height + * + * @param float $height + * @return void + */ + public function lineHeight($lineHeight) + { + $this->lineHeight = $lineHeight; + } + + /** + * Get line-height of instance + * + * @return float + */ + public function getLineHeight() + { + return $this->lineHeight; + } + + /** + * Set size of boxed text + * + * @param integer $width + * @param integer $height + * @return void + */ + public function box($width, $height) + { + $this->box = new Size($width, $height); + } + + /** + * Get width of textbox + * + * @return integer + */ + public function getBox() + { + return $this->box; + } + /** * Checks if current font has access to an applicable font file * @@ -241,6 +319,70 @@ protected function hasApplicableFontFile() */ public function countLines() { - return count(explode(PHP_EOL, $this->text)); + return count($this->getLines()); + } + + /** + * Get array of lines to be written + * + * @return array + */ + public function getLines($text = null) + { + $text = is_null($text) ? $this->text : $text; + + return explode(PHP_EOL, $text); + } + + /** + * Get array of words to be written + * + * @return array + */ + public function getWords() + { + return explode(' ', $this->text); + } + + /** + * Determines if text has defined box size + * + * @return boolean + */ + protected function isBoxed() + { + return is_a($this->box, 'Intervention\Image\Size'); + } + + /** + * Returns formated text according to box settings + * + * @return string + */ + protected function format() + { + if ($this->isBoxed()) { + + $line = array(); + $lines = array(); + + foreach ($this->getWords() as $word) { + + $linesize = $this->getCoreBoxSize( + implode(' ', array_merge($line, array(trim($word)))) + ); + + if ($linesize->getWidth() <= $this->box->getWidth()) { + $line[] = trim($word); + } else { + $lines[] = implode(' ', $line); + $line = array(trim($word)); + } + } + + $lines[] = trim(implode(' ', $line)); + + return implode(PHP_EOL, $lines); + } } } diff --git a/src/Intervention/Image/Animation.php b/src/Intervention/Image/Animation.php new file mode 100644 index 000000000..53bcd1c05 --- /dev/null +++ b/src/Intervention/Image/Animation.php @@ -0,0 +1,106 @@ +loops = $loops; + } + + /** + * Returns Iterator + * + * @return ArrayIterator + */ + public function getIterator() + { + return new ArrayIterator($this->frames); + } + + /** + * Set the number of loops + * + * @param integer $value + */ + public function setLoops($value) + { + $this->loops = $value; + } + + /** + * Return number of loops + * + * @return integer + */ + public function getLoops() + { + return $this->loops; + } + + /** + * Add one frame to the Animation + * + * @param Frame $frame + */ + public function addFrame(Frame $frame) + { + $this->frames[] = $frame; + } + + /** + * Append an array of frames to the Animation + * + * @param Array $frames + */ + public function addFrames(Array $frames) + { + $this->frames = array_merge($this->frames, $frames); + } + + /** + * Overwrite the current frames with array of frames + * + * @param Array $frames + */ + public function setFrames(Array $frames) + { + $this->frames = $frames; + + return $this; + } + + /** + * Get the current set of frames + * + * @return Array + */ + public function getFrames() + { + return $this->frames; + } +} diff --git a/src/Intervention/Image/Commands/ChecksumCommand.php b/src/Intervention/Image/Commands/ChecksumCommand.php index f8944bf18..8350388ef 100644 --- a/src/Intervention/Image/Commands/ChecksumCommand.php +++ b/src/Intervention/Image/Commands/ChecksumCommand.php @@ -12,17 +12,7 @@ class ChecksumCommand extends AbstractCommand */ public function execute($image) { - $colors = array(); - - $size = $image->getSize(); - - for ($x=0; $x <= ($size->width-1); $x++) { - for ($y=0; $y <= ($size->height-1); $y++) { - $colors[] = $image->pickColor($x, $y, 'array'); - } - } - - $this->setOutput(md5(serialize($colors))); + $this->setOutput(md5($image->encode('png'))); return true; } diff --git a/src/Intervention/Image/Commands/CircleCommand.php b/src/Intervention/Image/Commands/CircleCommand.php index 993b56731..91f3db326 100644 --- a/src/Intervention/Image/Commands/CircleCommand.php +++ b/src/Intervention/Image/Commands/CircleCommand.php @@ -20,7 +20,8 @@ public function execute($image) $callback = $this->argument(3)->type('closure')->value(); $circle_classname = sprintf('\Intervention\Image\%s\Shapes\CircleShape', - $image->getDriver()->getDriverName()); + $image->getDriver()->getDriverName() + ); $circle = new $circle_classname($diameter); diff --git a/src/Intervention/Image/Commands/PsrResponseCommand.php b/src/Intervention/Image/Commands/PsrResponseCommand.php deleted file mode 100644 index ab47be10c..000000000 --- a/src/Intervention/Image/Commands/PsrResponseCommand.php +++ /dev/null @@ -1,45 +0,0 @@ -argument(0)->value(); - $quality = $this->argument(1)->between(0, 100)->value(); - - //Encoded property will be populated at this moment - $stream = $image->stream($format, $quality); - - $mimetype = finfo_buffer( - finfo_open(FILEINFO_MIME_TYPE), - $image->getEncoded() - ); - - $this->setOutput(new Response( - 200, - array( - 'Content-Type' => $mimetype, - 'Content-Length' => strlen($image->getEncoded()) - ), - $stream - )); - - return true; - } -} \ No newline at end of file diff --git a/src/Intervention/Image/Commands/StreamCommand.php b/src/Intervention/Image/Commands/StreamCommand.php deleted file mode 100644 index 111c47569..000000000 --- a/src/Intervention/Image/Commands/StreamCommand.php +++ /dev/null @@ -1,25 +0,0 @@ -argument(0)->value(); - $quality = $this->argument(1)->between(0, 100)->value(); - - $this->setOutput(\GuzzleHttp\Psr7\stream_for( - $image->encode($format, $quality)->getEncoded() - )); - - return true; - } -} \ No newline at end of file diff --git a/src/Intervention/Image/ContainerInterface.php b/src/Intervention/Image/ContainerInterface.php new file mode 100644 index 000000000..39593eb30 --- /dev/null +++ b/src/Intervention/Image/ContainerInterface.php @@ -0,0 +1,10 @@ +core = $core; + $this->delay = $delay; + $this->disposal = is_null($disposal) ? self::DISPOSAL_METHOD_LEAVE : $disposal; + } + + /** + * Gets core of current frame + * + * @return mixed + */ + public function getCore() + { + return $this->core; + } + + /** + * Set core of current frame + * + * @param mixed $core + * @return Intervention\Image\Frame + */ + public function setCore($core) + { + $this->core = $core; + + return $this; + } +} diff --git a/src/Intervention/Image/Gd/Commands/BlurCommand.php b/src/Intervention/Image/Gd/Commands/BlurCommand.php index d53f59d7c..6ec4a9935 100644 --- a/src/Intervention/Image/Gd/Commands/BlurCommand.php +++ b/src/Intervention/Image/Gd/Commands/BlurCommand.php @@ -5,7 +5,7 @@ class BlurCommand extends \Intervention\Image\Commands\AbstractCommand { /** - * Applies blur effect on image + * Apply blur effect on image frames * * @param \Intervention\Image\Image $image * @return boolean @@ -14,10 +14,24 @@ public function execute($image) { $amount = $this->argument(0)->between(0, 100)->value(1); - for ($i=0; $i < intval($amount); $i++) { - imagefilter($image->getCore(), IMG_FILTER_GAUSSIAN_BLUR); + foreach ($image as $frame) { + $this->applyBlur($frame->getCore(), $amount); } return true; } + + /** + * Apply blur effect on GD resource + * + * @param resource $resource + * @param integer $amount + * @return void + */ + private function applyBlur($resource, $amount) + { + for ($i=0; $i < intval($amount); $i++) { + imagefilter($resource, IMG_FILTER_GAUSSIAN_BLUR); + } + } } diff --git a/src/Intervention/Image/Gd/Commands/ColorizeCommand.php b/src/Intervention/Image/Gd/Commands/ColorizeCommand.php index 8f539638b..30f89b14a 100644 --- a/src/Intervention/Image/Gd/Commands/ColorizeCommand.php +++ b/src/Intervention/Image/Gd/Commands/ColorizeCommand.php @@ -22,6 +22,10 @@ public function execute($image) $blue = round($blue * 2.55); // apply filter - return imagefilter($image->getCore(), IMG_FILTER_COLORIZE, $red, $green, $blue); + foreach ($image as $frame) { + imagefilter($frame->getCore(), IMG_FILTER_COLORIZE, $red, $green, $blue); + } + + return true; } } diff --git a/src/Intervention/Image/Gd/Commands/ContrastCommand.php b/src/Intervention/Image/Gd/Commands/ContrastCommand.php index e43b761af..ebe3b69e5 100644 --- a/src/Intervention/Image/Gd/Commands/ContrastCommand.php +++ b/src/Intervention/Image/Gd/Commands/ContrastCommand.php @@ -14,6 +14,10 @@ public function execute($image) { $level = $this->argument(0)->between(-100, 100)->required()->value(); - return imagefilter($image->getCore(), IMG_FILTER_CONTRAST, ($level * -1)); + foreach ($image as $frame) { + imagefilter($frame->getCore(), IMG_FILTER_CONTRAST, ($level * -1)); + } + + return true; } } diff --git a/src/Intervention/Image/Gd/Commands/DestroyCommand.php b/src/Intervention/Image/Gd/Commands/DestroyCommand.php index 403e8b801..c7a975ea3 100644 --- a/src/Intervention/Image/Gd/Commands/DestroyCommand.php +++ b/src/Intervention/Image/Gd/Commands/DestroyCommand.php @@ -12,8 +12,10 @@ class DestroyCommand extends \Intervention\Image\Commands\AbstractCommand */ public function execute($image) { - // destroy image core - imagedestroy($image->getCore()); + // destroy image cores + foreach ($image as $frame) { + imagedestroy($frame->getCore()); + } // destroy backups foreach ($image->getBackups() as $backup) { diff --git a/src/Intervention/Image/Gd/Commands/FillCommand.php b/src/Intervention/Image/Gd/Commands/FillCommand.php index aaecb7fb9..e42f579e4 100644 --- a/src/Intervention/Image/Gd/Commands/FillCommand.php +++ b/src/Intervention/Image/Gd/Commands/FillCommand.php @@ -19,17 +19,13 @@ public function execute($image) $x = $this->argument(1)->type('digit')->value(); $y = $this->argument(2)->type('digit')->value(); - $width = $image->getWidth(); - $height = $image->getHeight(); - $resource = $image->getCore(); + $width = imagesx($image->getCore()); + $height = imagesy($image->getCore()); try { // set image tile filling - $source = new Decoder; - $tile = $source->init($filling); - imagesettile($image->getCore(), $tile->getCore()); - $filling = IMG_COLOR_TILED; + $tile = $image->getDriver()->init($filling); } catch (\Intervention\Image\Exception\NotReadableException $e) { @@ -38,27 +34,45 @@ public function execute($image) $filling = $color->getInt(); } - imagealphablending($resource, true); - if (is_int($x) && is_int($y)) { + foreach ($image as $frame) { - // resource should be visible through transparency - $base = $image->getDriver()->newImage($width, $height)->getCore(); - imagecopy($base, $resource, 0, 0, 0, 0, $width, $height); + if (isset($tile)) { + imagesettile($frame->getCore(), $tile->getCore()); + $filling = IMG_COLOR_TILED; + } - // floodfill if exact position is defined - imagefill($resource, $x, $y, $filling); + imagealphablending($frame->getCore(), true); - // copy filled original over base - imagecopy($base, $resource, 0, 0, 0, 0, $width, $height); + if (is_int($x) && is_int($y)) { - // set base as new resource-core - $image->setCore($base); - imagedestroy($resource); + // resource should be visible through transparency + $base = $image->getDriver()->newImage($width, $height)->getCore(); + imagecopy($base, $frame->getCore(), 0, 0, 0, 0, $width, $height); - } else { - // fill whole image otherwise - imagefilledrectangle($resource, 0, 0, $width - 1, $height - 1, $filling); + // floodfill if exact position is defined + imagefill($frame->getCore(), $x, $y, $filling); + + // copy filled original over base + imagecopy($base, $frame->getCore(), 0, 0, 0, 0, $width, $height); + + // set base as new resource-core + imagedestroy($frame->getCore()); + $frame->setCore($base); + + } else { + + // fill whole image otherwise + imagefilledrectangle( + $frame->getCore(), + 0, + 0, + ($width - 1), + ($height - 1), + $filling + ); + + } } isset($tile) ? imagedestroy($tile->getCore()) : null; diff --git a/src/Intervention/Image/Gd/Commands/FitCommand.php b/src/Intervention/Image/Gd/Commands/FitCommand.php index 492b72186..c659ff1d2 100644 --- a/src/Intervention/Image/Gd/Commands/FitCommand.php +++ b/src/Intervention/Image/Gd/Commands/FitCommand.php @@ -26,7 +26,16 @@ public function execute($image) $resized = $resized->resize($width, $height, $constraints); // modify image - $this->modify($image, 0, 0, $cropped->pivot->x, $cropped->pivot->y, $resized->getWidth(), $resized->getHeight(), $cropped->getWidth(), $cropped->getHeight()); + $this->modify($image, + 0, + 0, + $cropped->pivot->x, + $cropped->pivot->y, + $resized->getWidth(), + $resized->getHeight(), + $cropped->getWidth(), + $cropped->getHeight() + ); return true; } diff --git a/src/Intervention/Image/Gd/Commands/FlipCommand.php b/src/Intervention/Image/Gd/Commands/FlipCommand.php index aa8f230e8..0248f6e95 100644 --- a/src/Intervention/Image/Gd/Commands/FlipCommand.php +++ b/src/Intervention/Image/Gd/Commands/FlipCommand.php @@ -32,6 +32,16 @@ public function execute($image) break; } - return $this->modify($image, 0, 0, $size->pivot->x, $size->pivot->y, $dst->width, $dst->height, $size->width, $size->height); + return $this->modify( + $image, + 0, + 0, + $size->pivot->x, + $size->pivot->y, + $dst->width, + $dst->height, + $size->width, + $size->height + ); } } diff --git a/src/Intervention/Image/Gd/Commands/GammaCommand.php b/src/Intervention/Image/Gd/Commands/GammaCommand.php index 366f11808..f1c82f65e 100644 --- a/src/Intervention/Image/Gd/Commands/GammaCommand.php +++ b/src/Intervention/Image/Gd/Commands/GammaCommand.php @@ -14,6 +14,10 @@ public function execute($image) { $gamma = $this->argument(0)->type('numeric')->required()->value(); - return imagegammacorrect($image->getCore(), 1, $gamma); + foreach ($image as $frame) { + imagegammacorrect($frame->getCore(), 1, $gamma); + } + + return true; } } diff --git a/src/Intervention/Image/Gd/Commands/GreyscaleCommand.php b/src/Intervention/Image/Gd/Commands/GreyscaleCommand.php index ded8e0d8f..7e7af7cb5 100644 --- a/src/Intervention/Image/Gd/Commands/GreyscaleCommand.php +++ b/src/Intervention/Image/Gd/Commands/GreyscaleCommand.php @@ -12,6 +12,10 @@ class GreyscaleCommand extends \Intervention\Image\Commands\AbstractCommand */ public function execute($image) { - return imagefilter($image->getCore(), IMG_FILTER_GRAYSCALE); + foreach ($image as $frame) { + imagefilter($frame->getCore(), IMG_FILTER_GRAYSCALE); + } + + return true; } } diff --git a/src/Intervention/Image/Gd/Commands/HeightenCommand.php b/src/Intervention/Image/Gd/Commands/HeightenCommand.php index 51e0abdf5..7a7d5f8bb 100644 --- a/src/Intervention/Image/Gd/Commands/HeightenCommand.php +++ b/src/Intervention/Image/Gd/Commands/HeightenCommand.php @@ -19,8 +19,9 @@ public function execute($image) $this->arguments[1] = $height; $this->arguments[2] = function ($constraint) use ($additionalConstraints) { $constraint->aspectRatio(); - if(is_callable($additionalConstraints)) + if(is_callable($additionalConstraints)) { $additionalConstraints($constraint); + } }; return parent::execute($image); diff --git a/src/Intervention/Image/Gd/Commands/InsertCommand.php b/src/Intervention/Image/Gd/Commands/InsertCommand.php index eba75f012..6bcfe258b 100644 --- a/src/Intervention/Image/Gd/Commands/InsertCommand.php +++ b/src/Intervention/Image/Gd/Commands/InsertCommand.php @@ -26,7 +26,22 @@ public function execute($image) $target = $image_size->relativePosition($watermark_size); // insert image at position - imagealphablending($image->getCore(), true); - return imagecopy($image->getCore(), $watermark->getCore(), $target->x, $target->y, 0, 0, $watermark_size->width, $watermark_size->height); + foreach ($image as $frame) { + + imagealphablending($frame->getCore(), true); + + imagecopy( + $frame->getCore(), + $watermark->getCore(), + $target->x, + $target->y, + 0, + 0, + $watermark_size->width, + $watermark_size->height + ); + } + + return true; } } diff --git a/src/Intervention/Image/Gd/Commands/InvertCommand.php b/src/Intervention/Image/Gd/Commands/InvertCommand.php index f72e7e305..7601306ee 100644 --- a/src/Intervention/Image/Gd/Commands/InvertCommand.php +++ b/src/Intervention/Image/Gd/Commands/InvertCommand.php @@ -12,6 +12,10 @@ class InvertCommand extends \Intervention\Image\Commands\AbstractCommand */ public function execute($image) { - return imagefilter($image->getCore(), IMG_FILTER_NEGATE); + foreach ($image as $frame) { + imagefilter($frame->getCore(), IMG_FILTER_NEGATE); + } + + return true; } } diff --git a/src/Intervention/Image/Gd/Commands/PixelCommand.php b/src/Intervention/Image/Gd/Commands/PixelCommand.php index a9ac3ec99..dc255f1f5 100644 --- a/src/Intervention/Image/Gd/Commands/PixelCommand.php +++ b/src/Intervention/Image/Gd/Commands/PixelCommand.php @@ -19,6 +19,10 @@ public function execute($image) $x = $this->argument(1)->type('digit')->required()->value(); $y = $this->argument(2)->type('digit')->required()->value(); - return imagesetpixel($image->getCore(), $x, $y, $color->getInt()); + foreach ($image as $frame) { + imagesetpixel($frame->getCore(), $x, $y, $color->getInt()); + } + + return true; } } diff --git a/src/Intervention/Image/Gd/Commands/PixelateCommand.php b/src/Intervention/Image/Gd/Commands/PixelateCommand.php index 2e2093d7d..b1c8c2165 100644 --- a/src/Intervention/Image/Gd/Commands/PixelateCommand.php +++ b/src/Intervention/Image/Gd/Commands/PixelateCommand.php @@ -14,6 +14,10 @@ public function execute($image) { $size = $this->argument(0)->type('digit')->value(10); - return imagefilter($image->getCore(), IMG_FILTER_PIXELATE, $size, true); + foreach ($image as $frame) { + imagefilter($frame->getCore(), IMG_FILTER_PIXELATE, $size, true); + } + + return true; } } diff --git a/src/Intervention/Image/Gd/Commands/ResizeCommand.php b/src/Intervention/Image/Gd/Commands/ResizeCommand.php index 2b5700f1b..97aeacb8d 100644 --- a/src/Intervention/Image/Gd/Commands/ResizeCommand.php +++ b/src/Intervention/Image/Gd/Commands/ResizeCommand.php @@ -41,42 +41,49 @@ public function execute($image) */ protected function modify($image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) { - // create new image - $modified = imagecreatetruecolor($dst_w, $dst_h); + foreach ($image as $frame) { - // get current image - $resource = $image->getCore(); + // create new image + $modified = imagecreatetruecolor($dst_w, $dst_h); - // preserve transparency - $transIndex = imagecolortransparent($resource); + // get current image + $resource = $frame->getCore(); - if ($transIndex != -1) { - $rgba = imagecolorsforindex($modified, $transIndex); - $transColor = imagecolorallocatealpha($modified, $rgba['red'], $rgba['green'], $rgba['blue'], 127); - imagefill($modified, 0, 0, $transColor); - imagecolortransparent($modified, $transColor); - } else { - imagealphablending($modified, false); - imagesavealpha($modified, true); - } + // preserve transparency + $transIndex = imagecolortransparent($resource); + + if ($transIndex != -1) { + $rgba = imagecolorsforindex($modified, $transIndex); + $transColor = imagecolorallocatealpha($modified, $rgba['red'], $rgba['green'], $rgba['blue'], 127); + imagefill($modified, 0, 0, $transColor); + imagecolortransparent($modified, $transColor); + } else { + imagealphablending($modified, false); + imagesavealpha($modified, true); + } - // copy content from resource - $result = imagecopyresampled( - $modified, - $resource, - $dst_x, - $dst_y, - $src_x, - $src_y, - $dst_w, - $dst_h, - $src_w, - $src_h - ); + // copy content from resource + imagecopyresampled( + $modified, + $resource, + $dst_x, + $dst_y, + $src_x, + $src_y, + $dst_w, + $dst_h, + $src_w, + $src_h + ); - // set new content as recource - $image->setCore($modified); + // free memory of old core + imagedestroy($resource); - return $result; + // set new content as recource + $frame->setCore($modified); + + } + + return true; } } diff --git a/src/Intervention/Image/Gd/Commands/RotateCommand.php b/src/Intervention/Image/Gd/Commands/RotateCommand.php index 306fef1b5..f1fee9460 100644 --- a/src/Intervention/Image/Gd/Commands/RotateCommand.php +++ b/src/Intervention/Image/Gd/Commands/RotateCommand.php @@ -19,7 +19,9 @@ public function execute($image) $color = new Color($color); // rotate image - $image->setCore(imagerotate($image->getCore(), $angle, $color->getInt())); + foreach ($image as $frame) { + $frame->setCore(imagerotate($frame->getCore(), $angle, $color->getInt())); + } return true; } diff --git a/src/Intervention/Image/Gd/Commands/SharpenCommand.php b/src/Intervention/Image/Gd/Commands/SharpenCommand.php index 9c1ca2063..5c4ec11a5 100644 --- a/src/Intervention/Image/Gd/Commands/SharpenCommand.php +++ b/src/Intervention/Image/Gd/Commands/SharpenCommand.php @@ -27,6 +27,10 @@ public function execute($image) ); // apply the matrix - return imageconvolution($image->getCore(), $matrix, $div, 0); + foreach ($image as $frame) { + imageconvolution($frame->getCore(), $matrix, $div, 0); + } + + return true; } } diff --git a/src/Intervention/Image/Gd/Commands/StopAnimationCommand.php b/src/Intervention/Image/Gd/Commands/StopAnimationCommand.php new file mode 100644 index 000000000..bf488af02 --- /dev/null +++ b/src/Intervention/Image/Gd/Commands/StopAnimationCommand.php @@ -0,0 +1,25 @@ +argument(0)->type('int')->value(0); + + $container = new Container; + $container->add($image->getCore($keepIndex)); + $image->setContainer($container); + + return true; + } +} diff --git a/src/Intervention/Image/Gd/Commands/WidenCommand.php b/src/Intervention/Image/Gd/Commands/WidenCommand.php index c7d396f1b..940c8e49c 100644 --- a/src/Intervention/Image/Gd/Commands/WidenCommand.php +++ b/src/Intervention/Image/Gd/Commands/WidenCommand.php @@ -19,8 +19,9 @@ public function execute($image) $this->arguments[1] = null; $this->arguments[2] = function ($constraint) use ($additionalConstraints) { $constraint->aspectRatio(); - if(is_callable($additionalConstraints)) + if(is_callable($additionalConstraints)) { $additionalConstraints($constraint); + } }; return parent::execute($image); diff --git a/src/Intervention/Image/Gd/Container.php b/src/Intervention/Image/Gd/Container.php new file mode 100644 index 000000000..ad7594133 --- /dev/null +++ b/src/Intervention/Image/Gd/Container.php @@ -0,0 +1,121 @@ +getFrames(); + + if (array_key_exists($index, $frames)) { + return $frames[$index]->getCore(); + } + + throw new \Intervention\Image\Exception\NotFoundException( + "Animation has no index with number {$index}." + ); + } + + /** + * Setup image stack with new resource + * + * @param resource $core + * @return \Intervention\Image\Gd\Container + */ + public function setCore($core) + { + $this->setFrames(array( + new Frame($core) + )); + + return $this; + } + + /** + * Return number of frames in container + * + * @return int + */ + public function countFrames() + { + return count($this->getFrames()); + } + + /** + * Add image source to Container + * + * @param mixed $source + * @param integer $delay + * @return \Intervention\Image\Gd\Container + */ + public function add($source, $delay = 0) + { + $driver = new Driver; + + $this->addFrame(new Frame( + $driver->init($source)->getCore(), + $delay + )); + + return $this; + } + + public static function initFromDecoded(Decoded $decoded) + { + $container = new self; + $container->setLoops($decoded->getLoops()); + + // create empty canvas + $driver = new Driver; + $canvas = $driver->newImage($decoded->getCanvasWidth(), $decoded->getCanvasHeight())->getCore(); + + foreach ($decoded->getFrames() as $key => $frame) { + + // create resource from frame + $encoder = new GifEncoder; + $encoder->setFromDecoded($decoded, $key); + $frame_resource = imagecreatefromstring($encoder->encode()); + + // insert frame image data into canvas + imagecopy( + $canvas, + $frame_resource, + $frame->getOffset()->left, + $frame->getOffset()->top, + 0, + 0, + $frame->getSize()->width, + $frame->getSize()->height + ); + + // destory frame resource + imagedestroy($frame_resource); + + // add frame to container + $container->addFrame(new \Intervention\Image\Frame( + $canvas, + $frame->getDelay() + )); + + // prepare next canvas + $canvas = Helper::cloneResource($canvas); + } + + return $container; + + } +} diff --git a/src/Intervention/Image/Gd/Decoder.php b/src/Intervention/Image/Gd/Decoder.php index fe10ebff4..94ca62a44 100644 --- a/src/Intervention/Image/Gd/Decoder.php +++ b/src/Intervention/Image/Gd/Decoder.php @@ -2,8 +2,10 @@ namespace Intervention\Image\Gd; +use \Intervention\Gif\Decoder as GifDecoder; use \Intervention\Image\Image; use \Intervention\Image\Size; +use \Intervention\Image\ContainerInterface; class Decoder extends \Intervention\Image\AbstractDecoder { @@ -23,31 +25,40 @@ public function initFromPath($path) ); } - // define core - switch ($info[2]) { - case IMAGETYPE_PNG: + // try to decode animated gif + if ($info['mime'] == 'image/gif') { + + return $this->initFromBinary(file_get_contents($path)); + + } else { + + // define core + switch ($info[2]) { + case IMAGETYPE_PNG: $core = imagecreatefrompng($path); - $this->gdResourceToTruecolor($core); + Helper::gdResourceToTruecolor($core); break; - case IMAGETYPE_JPEG: + case IMAGETYPE_JPEG: $core = imagecreatefromjpeg($path); - $this->gdResourceToTruecolor($core); + Helper::gdResourceToTruecolor($core); break; - case IMAGETYPE_GIF: + case IMAGETYPE_GIF: $core = imagecreatefromgif($path); - $this->gdResourceToTruecolor($core); + Helper::gdResourceToTruecolor($core); break; - default: + default: throw new \Intervention\Image\Exception\NotReadableException( "Unable to read image type. GD driver is only able to decode JPG, PNG or GIF files." - ); + ); + } + + // build image + $image = $this->initFromGdResource($core); } - // build image - $image = $this->initFromGdResource($core); $image->mime = $info['mime']; $image->setFileInfoFromPath($path); @@ -62,7 +73,17 @@ public function initFromPath($path) */ public function initFromGdResource($resource) { - return new Image(new Driver, $resource); + $driver = new Driver; + + return new Image($driver, $driver->newContainer($resource)); + } + + + public function initFromContainer(Container $container) + { + $driver = new Driver; + + return new Image($driver, $container); } /** @@ -86,47 +107,43 @@ public function initFromImagick(\Imagick $object) */ public function initFromBinary($binary) { - $resource = @imagecreatefromstring($binary); + try { + // try to custom decode gif + $gifDecoder = new GifDecoder; + $decoded = $gifDecoder->initFromData($binary)->decode(); - if ($resource === false) { - throw new \Intervention\Image\Exception\NotReadableException( - "Unable to init from given binary data." - ); - } + // create image + $container = Container::initFromDecoded($decoded); + $image = $this->initFromContainer($container); + $image->mime = 'image/gif'; - $image = $this->initFromGdResource($resource); - $image->mime = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $binary); + } catch (\Exception $e) { + + $resource = @imagecreatefromstring($binary); + + if ($resource === false) { + throw new \Intervention\Image\Exception\NotReadableException( + "Unable to init from given binary data." + ); + } + + // create image + $image = $this->initFromGdResource($resource); + $image->mime = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $binary); + + } return $image; } /** - * Transform GD resource into Truecolor version + * Initiates new image from container object * - * @param resource $resource - * @return bool + * @param ContainerInterface $container + * @return \Intervention\Image\Image */ - public function gdResourceToTruecolor(&$resource) + public function initFromInterventionContainer(ContainerInterface $container) { - $width = imagesx($resource); - $height = imagesy($resource); - - // new canvas - $canvas = imagecreatetruecolor($width, $height); - - // fill with transparent color - imagealphablending($canvas, false); - $transparent = imagecolorallocatealpha($canvas, 255, 255, 255, 127); - imagefilledrectangle($canvas, 0, 0, $width, $height, $transparent); - imagecolortransparent($canvas, $transparent); - imagealphablending($canvas, true); - - // copy original - imagecopy($canvas, $resource, 0, 0, 0, 0, $width, $height); - imagedestroy($resource); - - $resource = $canvas; - - return true; + return new Image(new Driver, $container); } } diff --git a/src/Intervention/Image/Gd/Driver.php b/src/Intervention/Image/Gd/Driver.php index aaf01170e..e482cd387 100644 --- a/src/Intervention/Image/Gd/Driver.php +++ b/src/Intervention/Image/Gd/Driver.php @@ -2,7 +2,9 @@ namespace Intervention\Image\Gd; +use \Intervention\Image\ContainerInterface; use \Intervention\Image\Size; +use \Intervention\Image\Frame; class Driver extends \Intervention\Image\AbstractDriver { @@ -14,7 +16,7 @@ class Driver extends \Intervention\Image\AbstractDriver */ public function __construct(Decoder $decoder = null, Encoder $encoder = null) { - if ( ! $this->coreAvailable()) { + if ( ! $this->moduleAvailable()) { throw new \Intervention\Image\Exception\NotSupportedException( "GD Library extension not available with this PHP installation." ); @@ -36,7 +38,7 @@ public function newImage($width, $height, $background = null) { // create empty resource $core = imagecreatetruecolor($width, $height); - $image = new \Intervention\Image\Image(new self, $core); + $image = new \Intervention\Image\Image(new self, $this->newContainer($core)); // set background color $background = new Color($background); @@ -45,6 +47,40 @@ public function newImage($width, $height, $background = null) return $image; } + /** + * Creates a new animation image instance + * + * @param integer $width + * @param integer $height + * @param \Closure $callback + * @param integer $loops + * + * @return \Intervention\Image\Image + */ + public function newAnimation($width, $height, $callback = null, $loops = null) + { + // create container + $container = new Container; + $container->setLoops($loops); + + // create empty canvas + $canvas = $this->newImage($width, $height)->getCore(); + + // build frames from callback + if (is_callable($callback)) { + + $callback($container); + + } else { + $container->setCore($canvas); + } + + // setup image instance + $image = new \Intervention\Image\Image(new self, $container); + + return $image; + } + /** * Reads given string into color object * @@ -57,11 +93,11 @@ public function parseColor($value) } /** - * Checks if core module installation is available + * Checks if image module installation is available * * @return boolean */ - protected function coreAvailable() + protected function moduleAvailable() { return (extension_loaded('gd') && function_exists('gd_info')); } @@ -83,4 +119,40 @@ public function cloneCore($core) return $clone; } + + /** + * Returns clone of current container + * + * @param ContainerInterface $container + * @return \Intervention\Image\Gd\Container + */ + public function cloneContainer(ContainerInterface $container) + { + $cloneContainer = clone $container; + $cloneFrames = array(); + + // clone each resource of container + foreach ($container as $frame) { + $cloneFrames[] = new Frame($this->cloneCore($frame->getCore())); + } + + $cloneContainer->setFrames($cloneFrames); + + return $cloneContainer; + } + + /** + * Builds new container from GD resource + * + * @param resource $resource + * @return \Intervention\Image\Gd\Container + */ + public function newContainer($resource) + { + $container = new Container; + + $container->setFrames(array(new Frame($resource))); + + return $container; + } } diff --git a/src/Intervention/Image/Gd/Encoder.php b/src/Intervention/Image/Gd/Encoder.php index 97a2c271e..4fbdda360 100644 --- a/src/Intervention/Image/Gd/Encoder.php +++ b/src/Intervention/Image/Gd/Encoder.php @@ -2,6 +2,9 @@ namespace Intervention\Image\Gd; +use Intervention\Gif\Encoder as GifEncoder; +use Intervention\Gif\Decoder as GifDecoder; + class Encoder extends \Intervention\Image\AbstractEncoder { /** @@ -46,13 +49,35 @@ protected function processPng() */ protected function processGif() { - ob_start(); - imagegif($this->image->getCore()); - $this->image->mime = image_type_to_mime_type(IMAGETYPE_GIF); - $buffer = ob_get_contents(); - ob_end_clean(); + $image = $this->image; - return $buffer; + $encoder = new GifEncoder; + $encoder->setCanvas($image->getWidth(), $image->getHeight()); + $encoder->setLoops($image->getContainer()->getLoops()); + + // set frames + foreach ($image as $frame) { + + // extract each frame + ob_start(); + imagegif($frame->getCore()); + $frame_data = ob_get_contents(); + ob_end_clean(); + + // decode frame + $decoder = new GifDecoder; + $decoder->initFromData($frame_data); + $decoded = $decoder->decode(); + + // add each frame + $encoder->addFrame( + $decoded->getFrame() + ->setLocalColorTable($decoded->getGlobalColorTable()) + ->setDelay($frame->delay) + ); + } + + return $encoder->encode(); } /** diff --git a/src/Intervention/Image/Gd/Font.php b/src/Intervention/Image/Gd/Font.php index a01552498..3a2dede38 100644 --- a/src/Intervention/Image/Gd/Font.php +++ b/src/Intervention/Image/Gd/Font.php @@ -3,6 +3,7 @@ namespace Intervention\Image\Gd; use \Intervention\Image\Image; +use \Intervention\Image\Size; class Font extends \Intervention\Image\AbstractFont { @@ -70,186 +71,224 @@ private function getInternalFontHeight() } } - /** - * Calculates bounding box of current font setting - * - * @return Array - */ - public function getBoxSize() + private function getInternalFontBaseline() { - $box = array(); + switch ($this->getInternalFont()) { + case 1: + return 6; - if ($this->hasApplicableFontFile()) { + case 2: + return 10; + + case 3: + return 10; + + case 4: + return 12; + + case 5: + return 12; + } + } + + public function applyToImage(Image $image, $posx = 0, $posy = 0) + { + // format text + $text = $this->format(); + + // box size + $box = $this->isBoxed() ? $this->box : $this->getBoxSize($text); + + // create empty resource + $canvas = imagecreatetruecolor( + $box->getWidth() + self::PADDING * 2, + $box->getHeight() + self::PADDING * 2 + ); + + imagealphablending($canvas, true); - // get bounding box with angle 0 - $box = imagettfbbox($this->getPointSize(), 0, $this->file, $this->text); + // set background color transparent (2147483647 (1291845632)) + imagefill($canvas, 0, 0, 2147483647); - // rotate points manually - if ($this->angle != 0) { + // parse text color + $color = new Color($this->color); + + $lines = $this->getLines($text); - $angle = pi() * 2 - $this->angle * pi() * 2 / 360; + $baseline = $this->getCoreBoxSize($lines[0]); - for ($i=0; $i<4; $i++) { - $x = $box[$i * 2]; - $y = $box[$i * 2 + 1]; - $box[$i * 2] = cos($angle) * $x - sin($angle) * $y; - $box[$i * 2 + 1] = sin($angle) * $x + cos($angle) * $y; - } + $box->align(sprintf('%s-%s', $this->align, 'top')); + + $ystart = 0; + + if ($this->isBoxed()) { + switch (strtolower($this->valign)) { + case 'bottom': + $ystart = $box->getHeight() - $this->getBoxSize($text)->getHeight(); + break; + + case 'center': + case 'middle': + $ystart = ($box->getHeight() - $this->getBoxSize($text)->getHeight()) / 2; + break; } + } - $box['width'] = intval(abs($box[4] - $box[0])); - $box['height'] = intval(abs($box[5] - $box[1])); + // write line by line + foreach ($lines as $count => $line) { - } else { + $linesize = $this->getCoreBoxSize(trim($line)); + $relative = $box->relativePosition($linesize->align($this->align)); - // get current internal font size - $width = $this->getInternalFontWidth(); - $height = $this->getInternalFontHeight(); + if ($this->hasApplicableFontFile()) { + + // draw ttf text + imagettftext( + $canvas, + $this->getPointSize(), // size + 0, // angle + self::PADDING + $relative->x, // x + self::PADDING + $ystart + $baseline->getHeight() + $count * $this->lineHeight * $this->size * 1.5, // y + $color->getInt(), + $this->file, + $line + ); - if (strlen($this->text) == 0) { - // no text -> no boxsize - $box['width'] = 0; - $box['height'] = 0; } else { - // calculate boxsize - $box['width'] = strlen($this->text) * $width; - $box['height'] = $height; + + // draw text + imagestring( + $canvas, + $this->getInternalFont(), + self::PADDING + $relative->x, // x + self::PADDING + $ystart + $count * $this->lineHeight * $baseline->getHeight(), // y + trim($line), + $color->getInt() + ); + } + + } + + // valign + switch (strtolower($this->valign)) { + case 'top': + # nothing to do... + break; + + case 'center': + case 'middle': + $box->pivot->moveY($box->getHeight() / 2); + break; + + case 'bottom': + $box->pivot->moveY($box->getHeight()); + break; + + default: + case 'baseline': + $baseline = $this->hasApplicableFontFile() ? $baseline->getHeight() : $this->getInternalFontBaseline(); + $box->pivot->moveY($baseline); + break; } - return $box; + if ($this->isBoxed()) { + $box->align('top-left'); + } + + // rotate canvas + if ($this->angle != 0) { + $canvas = imagerotate($canvas, $this->angle, 2147483647); + $box->rotate($this->angle); + } + + // enable alphablending for imagecopy + imagealphablending($image->getCore(), true); + + foreach ($image as $frame) { + // insert canvas + imagecopy( + $frame->getCore(), + $canvas, + $posx - $box->pivot->x - self::PADDING, + $posy - $box->pivot->y - self::PADDING, + 0, + 0, + imagesx($canvas), + imagesy($canvas) + ); + } } /** - * Draws font to given image at given position + * Calculate boxsize including own features * - * @param Image $image - * @param integer $posx - * @param integer $posy - * @return void + * @param string $text + * @return \Intervention\Image\Size */ - public function applyToImage(Image $image, $posx = 0, $posy = 0) + public function getBoxSize($text = null) { - // parse text color - $color = new Color($this->color); + $text = is_null($text) ? $this->text : $text; - if ($this->hasApplicableFontFile()) { + $lines = $this->getLines($text); + $baseline = $this->getCoreBoxSize($lines[0]); - if ($this->angle != 0 || is_string($this->align) || is_string($this->valign)) { - - $box = $this->getBoxSize(); - - $align = is_null($this->align) ? 'left' : strtolower($this->align); - $valign = is_null($this->valign) ? 'bottom' : strtolower($this->valign); - - // correction on position depending on v/h alignment - switch ($align.'-'.$valign) { - - case 'center-top': - $posx = $posx - round(($box[6]+$box[4])/2); - $posy = $posy - round(($box[7]+$box[5])/2); - break; - - case 'right-top': - $posx = $posx - $box[4]; - $posy = $posy - $box[5]; - break; - - case 'left-top': - $posx = $posx - $box[6]; - $posy = $posy - $box[7]; - break; - - case 'center-center': - case 'center-middle': - $posx = $posx - round(($box[0]+$box[4])/2); - $posy = $posy - round(($box[1]+$box[5])/2); - break; - - case 'right-center': - case 'right-middle': - $posx = $posx - round(($box[2]+$box[4])/2); - $posy = $posy - round(($box[3]+$box[5])/2); - break; - - case 'left-center': - case 'left-middle': - $posx = $posx - round(($box[0]+$box[6])/2); - $posy = $posy - round(($box[1]+$box[7])/2); - break; - - case 'center-bottom': - $posx = $posx - round(($box[0]+$box[2])/2); - $posy = $posy - round(($box[1]+$box[3])/2); - break; - - case 'right-bottom': - $posx = $posx - $box[2]; - $posy = $posy - $box[3]; - break; - - case 'left-bottom': - $posx = $posx - $box[0]; - $posy = $posy - $box[1]; - break; - } - } + $width_values = array(); - // enable alphablending for imagettftext - imagealphablending($image->getCore(), true); + // cycle through each line + foreach ($lines as $line) { + $width_values[] = $this->getCoreBoxSize($line)->getWidth(); + } + + // maximal line width is box width + $width = max($width_values); - // draw ttf text - imagettftext($image->getCore(), $this->getPointSize(), $this->angle, $posx, $posy, $color->getInt(), $this->file, $this->text); + if ($this->hasApplicableFontFile()) { + + $height = $baseline->getHeight() + (count($lines) - 1) * $this->lineHeight * $this->size * 1.5; + $height = $height + $baseline->getHeight() / 3; } else { + + $height = $baseline->getHeight() + (count($lines) - 1) * $this->lineHeight * $this->getInternalFontHeight(); - // get box size - $box = $this->getBoxSize(); - $width = $box['width']; - $height = $box['height']; - - // internal font specific position corrections - if ($this->getInternalFont() == 1) { - $top_correction = 1; - $bottom_correction = 2; - } elseif ($this->getInternalFont() == 3) { - $top_correction = 2; - $bottom_correction = 4; - } else { - $top_correction = 3; - $bottom_correction = 4; - } + } - // x-position corrections for horizontal alignment - switch (strtolower($this->align)) { - case 'center': - $posx = ceil($posx - ($width / 2)); - break; + return new Size($width, $height); + } - case 'right': - $posx = ceil($posx - $width) + 1; - break; - } + /** + * Get raw boxsize without any non-core features + * + * @param string $text + * @return \Intervention\Image\Size + */ + protected function getCoreBoxSize($text = null) + { + $text = is_null($text) ? $this->text : $text; - // y-position corrections for vertical alignment - switch (strtolower($this->valign)) { - case 'center': - case 'middle': - $posy = ceil($posy - ($height / 2)); - break; + if ($this->hasApplicableFontFile()) { + + // get boxsize + $box = imagettfbbox($this->getPointSize(), 0, $this->file, $text); + + // calculate width/height + $width = intval(abs($box[4] - $box[0])); + $height = intval(abs($box[5] - $box[1])); - case 'top': - $posy = ceil($posy - $top_correction); - break; + } else { - default: - case 'bottom': - $posy = round($posy - $height + $bottom_correction); - break; + if (strlen($text) == 0) { + // no text -> no boxsize + $width = 0; + $height = 0; + } else { + // calculate boxsize + $width = strlen($text) * $this->getInternalFontWidth(); + $height = $this->getInternalFontHeight(); } - - // draw text - imagestring($image->getCore(), $this->getInternalFont(), $posx, $posy, $this->text, $color->getInt()); } + + return new Size($width, $height); } } diff --git a/src/Intervention/Image/Gd/Helper.php b/src/Intervention/Image/Gd/Helper.php new file mode 100644 index 000000000..a92c574f3 --- /dev/null +++ b/src/Intervention/Image/Gd/Helper.php @@ -0,0 +1,55 @@ +applyToResource($frame->getCore(), $x, $y); + } + + return true; + } + + /** + * Draw ellipse on given gd resource + * + * @param resource $resource + * @return boolean + */ + private function applyToResource($resource, $x, $y) { // parse background color $background = new Color($this->background); if ($this->hasBorder()) { // slightly smaller ellipse to keep 1px bordered edges clean - imagefilledellipse($image->getCore(), $x, $y, $this->width-1, $this->height-1, $background->getInt()); + imagefilledellipse($resource, $x, $y, $this->width-1, $this->height-1, $background->getInt()); $border_color = new Color($this->border_color); - imagesetthickness($image->getCore(), $this->border_width); + imagesetthickness($resource, $this->border_width); // gd's imageellipse doesn't respect imagesetthickness so i use imagearc with 359.9 degrees here - imagearc($image->getCore(), $x, $y, $this->width, $this->height, 0, 359.99, $border_color->getInt()); + imagearc($resource, $x, $y, $this->width, $this->height, 0, 359.99, $border_color->getInt()); } else { - imagefilledellipse($image->getCore(), $x, $y, $this->width, $this->height, $background->getInt()); + imagefilledellipse($resource, $x, $y, $this->width, $this->height, $background->getInt()); } - - return true; } } diff --git a/src/Intervention/Image/Gd/Shapes/LineShape.php b/src/Intervention/Image/Gd/Shapes/LineShape.php index c3c1ea36d..5e2c8aacd 100644 --- a/src/Intervention/Image/Gd/Shapes/LineShape.php +++ b/src/Intervention/Image/Gd/Shapes/LineShape.php @@ -82,7 +82,10 @@ public function width($width) public function applyToImage(Image $image, $x = 0, $y = 0) { $color = new Color($this->color); - imageline($image->getCore(), $x, $y, $this->x, $this->y, $color->getInt()); + + foreach ($image as $frame) { + imageline($frame->getCore(), $x, $y, $this->x, $this->y, $color->getInt()); + } return true; } diff --git a/src/Intervention/Image/Gd/Shapes/PolygonShape.php b/src/Intervention/Image/Gd/Shapes/PolygonShape.php index b64fb5d4c..14129b3a2 100644 --- a/src/Intervention/Image/Gd/Shapes/PolygonShape.php +++ b/src/Intervention/Image/Gd/Shapes/PolygonShape.php @@ -33,16 +33,33 @@ public function __construct($points) * @return boolean */ public function applyToImage(Image $image, $x = 0, $y = 0) + { + foreach ($image as $frame) { + $this->applyToResource($frame->getCore(), $x, $y); + } + + return true; + } + + /** + * Draw polygon on given GD resource + * + * @param resource $resource + * @param integer $x + * @param interger $y + * @return boolean + */ + private function applyToResource($resource, $x, $y) { $background = new Color($this->background); - imagefilledpolygon($image->getCore(), $this->points, intval(count($this->points) / 2), $background->getInt()); + imagefilledpolygon($resource, $this->points, intval(count($this->points) / 2), $background->getInt()); if ($this->hasBorder()) { $border_color = new Color($this->border_color); - imagesetthickness($image->getCore(), $this->border_width); - imagepolygon($image->getCore(), $this->points, intval(count($this->points) / 2), $border_color->getInt()); + imagesetthickness($resource, $this->border_width); + imagepolygon($resource, $this->points, intval(count($this->points) / 2), $border_color->getInt()); } - + return true; } } diff --git a/src/Intervention/Image/Gd/Shapes/RectangleShape.php b/src/Intervention/Image/Gd/Shapes/RectangleShape.php index c25ebe5eb..111da144a 100644 --- a/src/Intervention/Image/Gd/Shapes/RectangleShape.php +++ b/src/Intervention/Image/Gd/Shapes/RectangleShape.php @@ -60,14 +60,47 @@ public function __construct($x1 = null, $y1 = null, $x2 = null, $y2 = null) * @return boolean */ public function applyToImage(Image $image, $x = 0, $y = 0) + { + foreach ($image as $frame) { + $this->applyToResource($frame->getCore(), $x, $y); + } + + return true; + } + + /** + * Draw rectangle to given GD resource + * + * @param resource $resource + * @param integer $x + * @param integer $y + * @return boolean + */ + private function applyToResource($resource, $x, $y) { $background = new Color($this->background); - imagefilledrectangle($image->getCore(), $this->x1, $this->y1, $this->x2, $this->y2, $background->getInt()); + + imagefilledrectangle( + $resource, + $this->x1, + $this->y1, + $this->x2, + $this->y2, + $background->getInt() + ); if ($this->hasBorder()) { + $border_color = new Color($this->border_color); - imagesetthickness($image->getCore(), $this->border_width); - imagerectangle($image->getCore(), $this->x1, $this->y1, $this->x2, $this->y2, $border_color->getInt()); + imagesetthickness($resource, $this->border_width); + imagerectangle( + $resource, + $this->x1, + $this->y1, + $this->x2, + $this->y2, + $border_color->getInt() + ); } return true; diff --git a/src/Intervention/Image/Image.php b/src/Intervention/Image/Image.php index 4c8e690e0..e06349fd5 100644 --- a/src/Intervention/Image/Image.php +++ b/src/Intervention/Image/Image.php @@ -2,9 +2,6 @@ namespace Intervention\Image; -use Psr\Http\Message\ResponseInterface; -use Psr\Http\Message\StreamInterface; - /** * @method \Intervention\Image\Image backup(string $name = 'default') Backups current image state as fallback for reset method under an optional name. Overwrites older state on every call, unless a different name is passed. * @method \Intervention\Image\Image blur(integer $amount = 1) Apply a gaussian blur filter with a optional amount on the current image. Use values between 0 and 100. @@ -48,10 +45,9 @@ * @method \Intervention\Image\Image text(string $text, integer $x = 0, integer $y = 0, \Closure $callback = null) Write a text string to the current image at an optional x,y basepoint position. You can define more details like font-size, font-file and alignment via a callback as the fourth parameter. * @method \Intervention\Image\Image trim(string $base = 'top-left', array $away = array('top', 'bottom', 'left', 'right'), integer $tolerance = 0, integer $feather = 0) Trim away image space in given color. Define an optional base to pick a color at a certain position and borders that should be trimmed away. You can also set an optional tolerance level, to trim similar colors and add a feathering border around the trimed image. * @method \Intervention\Image\Image widen(integer $width, \Closure $callback = null) Resizes the current image to new width, constraining aspect ratio. Pass an optional Closure callback as third parameter, to apply additional constraints like preventing possible upsizing. - * @method StreamInterface stream(string $format = null, integer $quality = 90) Build PSR-7 compatible StreamInterface with current image in given format and quality. - * @method ResponseInterface psrResponse(string $format = null, integer $quality = 90) Build PSR-7 compatible ResponseInterface with current image in given format and quality. */ -class Image extends File + +class Image extends File implements \IteratorAggregate { /** * Instance of current image driver @@ -61,11 +57,11 @@ class Image extends File protected $driver; /** - * Image resource/object of current image processor + * Container object of resources/objects of current image processor * * @var mixed */ - protected $core; + protected $container; /** * Array of Image resource backups of current image processor @@ -84,13 +80,13 @@ class Image extends File /** * Creates a new Image instance * - * @param AbstractDriver $driver - * @param mixed $core + * @param AbstractDriver $driver + * @param ContainerInterface $container */ - public function __construct(AbstractDriver $driver = null, $core = null) + public function __construct(AbstractDriver $driver = null, ContainerInterface $container = null) { $this->driver = $driver; - $this->core = $core; + $this->container = $container; } /** @@ -107,6 +103,16 @@ public function __call($name, $arguments) return $command->hasOutput() ? $command->getOutput() : $this; } + /** + * Returns Iterator + * + * @return \Intervention\Image\ContainerInterface + */ + public function getIterator() + { + return $this->getContainer(); + } + /** * Starts encoding of current image * @@ -186,11 +192,12 @@ public function setDriver(AbstractDriver $driver) /** * Returns current image resource/obj * + * @param integer $index * @return mixed */ - public function getCore() + public function getCore($index = null) { - return $this->core; + return $this->container->getCore($index); } /** @@ -200,7 +207,29 @@ public function getCore() */ public function setCore($core) { - $this->core = $core; + $this->container->setCore($core); + + return $this; + } + + /** + * Returns current image container + * + * @return \Intervention\Image\ContainerInterface + */ + public function getContainer() + { + return $this->container; + } + + /** + * Set current image container + * + * @param mixed $core + */ + public function setContainer(ContainerInterface $container) + { + $this->container = $container; return $this; } @@ -261,6 +290,16 @@ private function backupExists($name) return array_key_exists($name, $this->backups); } + /** + * Determines if current image has multiple animation frames + * + * @return boolean + */ + public function isAnimated() + { + return ($this->container->countFrames() > 1); + } + /** * Checks if current image is already encoded * @@ -358,6 +397,6 @@ public function __toString() */ public function __clone() { - $this->core = $this->driver->cloneCore($this->core); + $this->container = $this->driver->cloneContainer($this->container); } } diff --git a/src/Intervention/Image/ImageManager.php b/src/Intervention/Image/ImageManager.php index a5df0540b..8fb7443d2 100644 --- a/src/Intervention/Image/ImageManager.php +++ b/src/Intervention/Image/ImageManager.php @@ -64,6 +64,21 @@ public function canvas($width, $height, $background = null) return $this->createDriver()->newImage($width, $height, $background); } + /** + * Creates a new animation + * + * @param integer $width + * @param integer $height + * @param \Closure $callback + * @param integer $loops + * + * @return \Intervention\Image\Image + */ + public function animate($width, $height, $callback = null, $loops = null) + { + return $this->createDriver()->newAnimation($width, $height, $callback, $loops); + } + /** * Create new cached image and run callback * (requires additional package intervention/imagecache) diff --git a/src/Intervention/Image/ImageManagerStatic.php b/src/Intervention/Image/ImageManagerStatic.php index 3088bf55b..94a67138b 100644 --- a/src/Intervention/Image/ImageManagerStatic.php +++ b/src/Intervention/Image/ImageManagerStatic.php @@ -71,6 +71,21 @@ public static function canvas($width, $height, $background = null) return self::getManager()->canvas($width, $height, $background); } + /** + * Creates a new animation + * + * @param integer $width + * @param integer $height + * @param \Closure $callback + * @param integer $loops + * + * @return \Intervention\Image\Image + */ + public static function animate($width, $height, $callback = null, $loops = null) + { + return self::getManager()->animate($width, $height, $callback, $loops); + } + /** * Create new cached image and run callback statically * diff --git a/src/Intervention/Image/Imagick/Commands/BlurCommand.php b/src/Intervention/Image/Imagick/Commands/BlurCommand.php index b037c1516..2859c2a3d 100644 --- a/src/Intervention/Image/Imagick/Commands/BlurCommand.php +++ b/src/Intervention/Image/Imagick/Commands/BlurCommand.php @@ -14,6 +14,10 @@ public function execute($image) { $amount = $this->argument(0)->between(0, 100)->value(1); - return $image->getCore()->blurImage(1 * $amount, 0.5 * $amount); + foreach ($image as $frame) { + $frame->getCore()->blurImage(1 * $amount, 0.5 * $amount); + } + + return true; } } diff --git a/src/Intervention/Image/Imagick/Commands/ColorizeCommand.php b/src/Intervention/Image/Imagick/Commands/ColorizeCommand.php index 51142be27..3299f375e 100644 --- a/src/Intervention/Image/Imagick/Commands/ColorizeCommand.php +++ b/src/Intervention/Image/Imagick/Commands/ColorizeCommand.php @@ -21,16 +21,23 @@ public function execute($image) $green = $this->normalizeLevel($green); $blue = $this->normalizeLevel($blue); - $qrange = $image->getCore()->getQuantumRange(); - - // apply - $image->getCore()->levelImage(0, $red, $qrange['quantumRangeLong'], \Imagick::CHANNEL_RED); - $image->getCore()->levelImage(0, $green, $qrange['quantumRangeLong'], \Imagick::CHANNEL_GREEN); - $image->getCore()->levelImage(0, $blue, $qrange['quantumRangeLong'], \Imagick::CHANNEL_BLUE); + // apply on each frame + foreach ($image as $frame) { + $qrange = $frame->getCore()->getQuantumRange(); + $frame->getCore()->levelImage(0, $red, $qrange['quantumRangeLong'], \Imagick::CHANNEL_RED); + $frame->getCore()->levelImage(0, $green, $qrange['quantumRangeLong'], \Imagick::CHANNEL_GREEN); + $frame->getCore()->levelImage(0, $blue, $qrange['quantumRangeLong'], \Imagick::CHANNEL_BLUE); + } return true; } + /** + * Return normalized level value + * + * @param numeric $level + * @return numeric + */ private function normalizeLevel($level) { if ($level > 0) { diff --git a/src/Intervention/Image/Imagick/Commands/ContrastCommand.php b/src/Intervention/Image/Imagick/Commands/ContrastCommand.php index 113a2186c..bda3f350e 100644 --- a/src/Intervention/Image/Imagick/Commands/ContrastCommand.php +++ b/src/Intervention/Image/Imagick/Commands/ContrastCommand.php @@ -14,6 +14,10 @@ public function execute($image) { $level = $this->argument(0)->between(-100, 100)->required()->value(); - return $image->getCore()->sigmoidalContrastImage($level > 0, $level / 4, 0); + foreach ($image as $frame) { + $frame->getCore()->sigmoidalContrastImage($level > 0, $level / 4, 0); + } + + return true; } } diff --git a/src/Intervention/Image/Imagick/Commands/CropCommand.php b/src/Intervention/Image/Imagick/Commands/CropCommand.php index 498064ef7..22388511d 100644 --- a/src/Intervention/Image/Imagick/Commands/CropCommand.php +++ b/src/Intervention/Image/Imagick/Commands/CropCommand.php @@ -34,9 +34,11 @@ public function execute($image) $position = $image->getSize()->align('center')->relativePosition($cropped->align('center')); } - // crop image core - $image->getCore()->cropImage($cropped->width, $cropped->height, $position->x, $position->y); - $image->getCore()->setImagePage(0,0,0,0); + // crop image cores + foreach ($image as $frame) { + $frame->getCore()->cropImage($cropped->width, $cropped->height, $position->x, $position->y); + $frame->getCore()->setImagePage(0,0,0,0); + } return true; } diff --git a/src/Intervention/Image/Imagick/Commands/FillCommand.php b/src/Intervention/Image/Imagick/Commands/FillCommand.php index 15a2adaf5..3b022e98e 100644 --- a/src/Intervention/Image/Imagick/Commands/FillCommand.php +++ b/src/Intervention/Image/Imagick/Commands/FillCommand.php @@ -20,18 +20,10 @@ public function execute($image) $x = $this->argument(1)->type('digit')->value(); $y = $this->argument(2)->type('digit')->value(); - $imagick = $image->getCore(); + $width = $image->width(); + $height = $image->height(); - try { - // set image filling - $source = new Decoder; - $filling = $source->init($filling); - - } catch (\Intervention\Image\Exception\NotReadableException $e) { - - // set solid color filling - $filling = new Color($filling); - } + $filling = $this->decodeFilling($filling); // flood fill if coordinates are set if (is_int($x) && is_int($y)) { @@ -39,65 +31,130 @@ public function execute($image) // flood fill with texture if ($filling instanceof Image) { - // create tile - $tile = clone $image->getCore(); + foreach ($image as $frame) { + // create tile + $tile = clone $frame->getCore()->getImage(); + + $alpha = false; - // mask away color at position - $tile->transparentPaintImage($tile->getImagePixelColor($x, $y), 0, 0, false); + if ($tile->getImageAlphaChannel() !== \Imagick::ALPHACHANNEL_UNDEFINED) { + // clone alpha channel + $alpha = clone $frame->getCore()->getImage(); + } - // create canvas - $canvas = clone $image->getCore(); + // mask away color at position + $tile->transparentPaintImage($tile->getImagePixelColor($x, $y), 0, 0, false); - // fill canvas with texture - $canvas = $canvas->textureImage($filling->getCore()); + // fill canvas with texture + $canvas = $frame->getCore()->textureImage($filling->getCore()); - // merge canvas and tile - $canvas->compositeImage($tile, \Imagick::COMPOSITE_DEFAULT, 0, 0); + // merge canvas and tile + $canvas->compositeImage($tile, \Imagick::COMPOSITE_DEFAULT, 0, 0); - // replace image core - $image->setCore($canvas); + if ($alpha) { + // restore alpha channel of original image + $canvas->compositeImage($alpha, \Imagick::COMPOSITE_COPYOPACITY, 0, 0); + } + + // replace image core + $frame->getCore()->setImage($canvas); + + $tile->clear(); + $canvas->clear(); + } // flood fill with color } elseif ($filling instanceof Color) { - // create canvas with filling - $canvas = new \Imagick; - $canvas->newImage($image->getWidth(), $image->getHeight(), $filling->getPixel(), 'png'); + // create filling + $fill = new \Imagick; + $fill->newImage($width, $height, 'none', 'png'); + $draw = new \ImagickDraw; + $draw->setFillColor($filling->getPixel()); + $draw->rectangle(0, 0, $width, $height); + $fill->drawImage($draw); + + foreach ($image as $frame) { + + // create tile + $tile = clone $frame->getCore()->getImage(); + + $alpha = false; + + if ($tile->getImageAlphaChannel() !== \Imagick::ALPHACHANNEL_UNDEFINED) { + // clone alpha channel + $alpha = clone $frame->getCore()->getImage(); + } + + // mask away color at position + $tile->transparentPaintImage($tile->getImagePixelColor($x, $y), 0, 0, false); - // create tile to put on top - $tile = clone $image->getCore(); + // fill canvas with texture + $canvas = $frame->getCore()->textureImage($fill); - // mask away color at pos. - $tile->transparentPaintImage($tile->getImagePixelColor($x, $y), 0, 0, false); + // merge canvas and tile + $canvas->compositeImage($tile, \Imagick::COMPOSITE_DEFAULT, 0, 0); - // save alpha channel of original image - $alpha = clone $image->getCore(); + if ($alpha) { + // restore alpha channel of original image + $canvas->compositeImage($alpha, \Imagick::COMPOSITE_COPYOPACITY, 0, 0); + } - // merge original with canvas and tile - $image->getCore()->compositeImage($canvas, \Imagick::COMPOSITE_DEFAULT, 0, 0); - $image->getCore()->compositeImage($tile, \Imagick::COMPOSITE_DEFAULT, 0, 0); + // replace image core + $frame->getCore()->setImage($canvas); - // restore alpha channel of original image - $image->getCore()->compositeImage($alpha, \Imagick::COMPOSITE_COPYOPACITY, 0, 0); + $tile->clear(); + $canvas->clear(); + + } } } else { if ($filling instanceof Image) { - // fill whole image with texture - $image->setCore($image->getCore()->textureImage($filling->getCore())); + // fill each frame with texture + foreach ($image as $frame) { + $filled = $frame->getCore()->textureImage($filling->getCore()); + $frame->getCore()->setImage($filled); + } } elseif ($filling instanceof Color) { - // fill whole image with color + // setup draw object $draw = new \ImagickDraw(); $draw->setFillColor($filling->getPixel()); - $draw->rectangle(0, 0, $image->getWidth(), $image->getHeight()); - $image->getCore()->drawImage($draw); + $draw->rectangle(0, 0, $width, $height); + + // fill each frame with color + foreach ($image as $frame) { + $frame->getCore()->drawImage($draw); + } } } return true; } + + /** + * Decodes given filling value into Image or Color object + * + * @param mixed $value + * @return Decoder|Color + */ + private function decodeFilling($value) + { + try { + // set image filling + $source = new Decoder; + $filling = $source->init($value); + + } catch (\Intervention\Image\Exception\NotReadableException $e) { + + // set solid color filling + $filling = new Color($value); + } + + return $filling; + } } diff --git a/src/Intervention/Image/Imagick/Commands/FitCommand.php b/src/Intervention/Image/Imagick/Commands/FitCommand.php index 2a0f1817a..1c8dd01f6 100644 --- a/src/Intervention/Image/Imagick/Commands/FitCommand.php +++ b/src/Intervention/Image/Imagick/Commands/FitCommand.php @@ -24,17 +24,20 @@ public function execute($image) $resized = clone $cropped; $resized = $resized->resize($width, $height, $constraints); - // crop image - $image->getCore()->cropImage( - $cropped->width, - $cropped->height, - $cropped->pivot->x, - $cropped->pivot->y - ); - - // resize image - $image->getCore()->scaleImage($resized->getWidth(), $resized->getHeight()); - $image->getCore()->setImagePage(0,0,0,0); + foreach ($image as $frame) { + + // crop image + $frame->getCore()->cropImage( + $cropped->width, + $cropped->height, + $cropped->pivot->x, + $cropped->pivot->y + ); + + // resize image + $frame->getCore()->scaleImage($resized->getWidth(), $resized->getHeight()); + $frame->getCore()->setImagePage(0,0,0,0); + } return true; } diff --git a/src/Intervention/Image/Imagick/Commands/FlipCommand.php b/src/Intervention/Image/Imagick/Commands/FlipCommand.php index 746650c1c..85afde963 100644 --- a/src/Intervention/Image/Imagick/Commands/FlipCommand.php +++ b/src/Intervention/Image/Imagick/Commands/FlipCommand.php @@ -14,12 +14,23 @@ public function execute($image) { $mode = $this->argument(0)->value('h'); - if (in_array(strtolower($mode), array(2, 'v', 'vert', 'vertical'))) { - // flip vertical - return $image->getCore()->flipImage(); - } else { - // flip horizontal - return $image->getCore()->flopImage(); + $methodName = $this->modeIsVertical($mode) ? 'flipImage' : 'flopImage'; + + foreach ($image as $frame) { + call_user_func(array($frame->getCore(), $methodName)); } + + return true; + } + + /** + * Check if mode is vertical + * + * @param mixed $mode + * @return bool + */ + private function modeIsVertical($mode) + { + return in_array(strtolower($mode), array(2, 'v', 'vert', 'vertical')); } } diff --git a/src/Intervention/Image/Imagick/Commands/GammaCommand.php b/src/Intervention/Image/Imagick/Commands/GammaCommand.php index e70cbdd36..a213d00db 100644 --- a/src/Intervention/Image/Imagick/Commands/GammaCommand.php +++ b/src/Intervention/Image/Imagick/Commands/GammaCommand.php @@ -14,6 +14,10 @@ public function execute($image) { $gamma = $this->argument(0)->type('numeric')->required()->value(); - return $image->getCore()->gammaImage($gamma); + foreach ($image as $frame) { + $frame->getCore()->gammaImage($gamma); + } + + return true; } } diff --git a/src/Intervention/Image/Imagick/Commands/GreyscaleCommand.php b/src/Intervention/Image/Imagick/Commands/GreyscaleCommand.php index bb3f47260..d916a2b7a 100644 --- a/src/Intervention/Image/Imagick/Commands/GreyscaleCommand.php +++ b/src/Intervention/Image/Imagick/Commands/GreyscaleCommand.php @@ -12,6 +12,10 @@ class GreyscaleCommand extends \Intervention\Image\Commands\AbstractCommand */ public function execute($image) { - return $image->getCore()->modulateImage(100, 0, 100); + foreach ($image as $frame) { + $frame->getCore()->modulateImage(100, 0, 100); + } + + return true; } } diff --git a/src/Intervention/Image/Imagick/Commands/HeightenCommand.php b/src/Intervention/Image/Imagick/Commands/HeightenCommand.php index 9d10973f2..d19e1d053 100644 --- a/src/Intervention/Image/Imagick/Commands/HeightenCommand.php +++ b/src/Intervention/Image/Imagick/Commands/HeightenCommand.php @@ -19,8 +19,9 @@ public function execute($image) $this->arguments[1] = $height; $this->arguments[2] = function ($constraint) use ($additionalConstraints) { $constraint->aspectRatio(); - if(is_callable($additionalConstraints)) + if(is_callable($additionalConstraints)) { $additionalConstraints($constraint); + } }; return parent::execute($image); diff --git a/src/Intervention/Image/Imagick/Commands/InsertCommand.php b/src/Intervention/Image/Imagick/Commands/InsertCommand.php index 542feb2ae..4e0a55ae6 100644 --- a/src/Intervention/Image/Imagick/Commands/InsertCommand.php +++ b/src/Intervention/Image/Imagick/Commands/InsertCommand.php @@ -26,6 +26,15 @@ public function execute($image) $target = $image_size->relativePosition($watermark_size); // insert image at position - return $image->getCore()->compositeImage($watermark->getCore(), \Imagick::COMPOSITE_DEFAULT, $target->x, $target->y); + foreach ($image as $frame) { + $frame->getCore()->compositeImage( + $watermark->getCore(), + \Imagick::COMPOSITE_DEFAULT, + $target->x, + $target->y + ); + } + + return true; } } diff --git a/src/Intervention/Image/Imagick/Commands/InvertCommand.php b/src/Intervention/Image/Imagick/Commands/InvertCommand.php index 125fbddee..06867ad8d 100644 --- a/src/Intervention/Image/Imagick/Commands/InvertCommand.php +++ b/src/Intervention/Image/Imagick/Commands/InvertCommand.php @@ -12,6 +12,10 @@ class InvertCommand extends \Intervention\Image\Commands\AbstractCommand */ public function execute($image) { - return $image->getCore()->negateImage(false); + foreach ($image as $frame) { + $frame->getCore()->negateImage(false); + } + + return true; } } diff --git a/src/Intervention/Image/Imagick/Commands/PixelCommand.php b/src/Intervention/Image/Imagick/Commands/PixelCommand.php index 8a467f798..ca7a8d46b 100644 --- a/src/Intervention/Image/Imagick/Commands/PixelCommand.php +++ b/src/Intervention/Image/Imagick/Commands/PixelCommand.php @@ -25,6 +25,10 @@ public function execute($image) $draw->point($x, $y); // apply pixel - return $image->getCore()->drawImage($draw); + foreach ($image as $frame) { + $frame->getCore()->drawImage($draw); + } + + return true; } } diff --git a/src/Intervention/Image/Imagick/Commands/PixelateCommand.php b/src/Intervention/Image/Imagick/Commands/PixelateCommand.php index 75f2218f5..cee95de97 100644 --- a/src/Intervention/Image/Imagick/Commands/PixelateCommand.php +++ b/src/Intervention/Image/Imagick/Commands/PixelateCommand.php @@ -17,8 +17,10 @@ public function execute($image) $width = $image->getWidth(); $height = $image->getHeight(); - $image->getCore()->scaleImage(max(1, ($width / $size)), max(1, ($height / $size))); - $image->getCore()->scaleImage($width, $height); + foreach ($image as $frame) { + $frame->getCore()->scaleImage(max(1, ($width / $size)), max(1, ($height / $size))); + $frame->getCore()->scaleImage($width, $height); + } return true; } diff --git a/src/Intervention/Image/Imagick/Commands/ResizeCanvasCommand.php b/src/Intervention/Image/Imagick/Commands/ResizeCanvasCommand.php index 8884230eb..fba61d61b 100644 --- a/src/Intervention/Image/Imagick/Commands/ResizeCanvasCommand.php +++ b/src/Intervention/Image/Imagick/Commands/ResizeCanvasCommand.php @@ -76,13 +76,17 @@ public function execute($image) $canvas->getCore()->setImageColorspace($image->getCore()->getImageColorspace()); - // copy image into new canvas - $image->getCore()->cropImage($src_w, $src_h, $src_x, $src_y); - $canvas->getCore()->compositeImage($image->getCore(), \Imagick::COMPOSITE_DEFAULT, $dst_x, $dst_y); - $canvas->getCore()->setImagePage(0,0,0,0); + foreach ($image as $frame) { + // copy image into new canvas + $frame->getCore()->cropImage($src_w, $src_h, $src_x, $src_y); + $canvas->getCore()->compositeImage($frame->getCore(), \Imagick::COMPOSITE_DEFAULT, $dst_x, $dst_y); + $canvas->getCore()->setImagePage(0,0,0,0); + $canvas->getCore()->setImageDelay($frame->getCore()->getImageDelay()); + $canvas->getCore()->setImageIterations($frame->getCore()->getImageIterations()); - // set new core to canvas - $image->setCore($canvas->getCore()); + // set new canvas as core + $frame->getCore()->setImage($canvas->getCore()); + } return true; } diff --git a/src/Intervention/Image/Imagick/Commands/ResizeCommand.php b/src/Intervention/Image/Imagick/Commands/ResizeCommand.php index 9ccc202c2..451b7d13c 100644 --- a/src/Intervention/Image/Imagick/Commands/ResizeCommand.php +++ b/src/Intervention/Image/Imagick/Commands/ResizeCommand.php @@ -20,7 +20,9 @@ public function execute($image) $resized = $image->getSize()->resize($width, $height, $constraints); // modify image - $image->getCore()->scaleImage($resized->getWidth(), $resized->getHeight()); + foreach ($image as $frame) { + $frame->getCore()->scaleImage($resized->getWidth(), $resized->getHeight()); + } return true; } diff --git a/src/Intervention/Image/Imagick/Commands/RotateCommand.php b/src/Intervention/Image/Imagick/Commands/RotateCommand.php index 7d2a81de1..68af569e3 100644 --- a/src/Intervention/Image/Imagick/Commands/RotateCommand.php +++ b/src/Intervention/Image/Imagick/Commands/RotateCommand.php @@ -19,7 +19,9 @@ public function execute($image) $color = new Color($color); // rotate image - $image->getCore()->rotateImage($color->getPixel(), ($angle * -1)); + foreach ($image as $frame) { + $frame->getCore()->rotateImage($color->getPixel(), ($angle * -1)); + } return true; } diff --git a/src/Intervention/Image/Imagick/Commands/SharpenCommand.php b/src/Intervention/Image/Imagick/Commands/SharpenCommand.php index 4f2fc8c29..95a0cd0ae 100644 --- a/src/Intervention/Image/Imagick/Commands/SharpenCommand.php +++ b/src/Intervention/Image/Imagick/Commands/SharpenCommand.php @@ -14,6 +14,10 @@ public function execute($image) { $amount = $this->argument(0)->between(0, 100)->value(10); - return $image->getCore()->unsharpMaskImage(1, 1, $amount / 6.25, 0); + foreach ($image as $frame) { + $frame->getCore()->unsharpMaskImage(1, 1, $amount / 6.25, 0); + } + + return true; } } diff --git a/src/Intervention/Image/Imagick/Commands/StopAnimationCommand.php b/src/Intervention/Image/Imagick/Commands/StopAnimationCommand.php new file mode 100644 index 000000000..29b51b236 --- /dev/null +++ b/src/Intervention/Image/Imagick/Commands/StopAnimationCommand.php @@ -0,0 +1,37 @@ +argument(0)->type('int')->value(0); + + foreach ($image as $key => $frame) { + if ($keepIndex == $key) { + break; + } + } + + $frame = $image->getDriver()->init( + $image->getCore()->getImageBlob() + ); + + // remove old core + $image->getCore()->clear(); + + // set new core + $image->setContainer($frame->getContainer()); + + return true; + } +} diff --git a/src/Intervention/Image/Imagick/Commands/WidenCommand.php b/src/Intervention/Image/Imagick/Commands/WidenCommand.php index 467fe800a..0651b9317 100644 --- a/src/Intervention/Image/Imagick/Commands/WidenCommand.php +++ b/src/Intervention/Image/Imagick/Commands/WidenCommand.php @@ -19,8 +19,9 @@ public function execute($image) $this->arguments[1] = null; $this->arguments[2] = function ($constraint) use ($additionalConstraints) { $constraint->aspectRatio(); - if(is_callable($additionalConstraints)) + if(is_callable($additionalConstraints)) { $additionalConstraints($constraint); + } }; return parent::execute($image); diff --git a/src/Intervention/Image/Imagick/Container.php b/src/Intervention/Image/Imagick/Container.php new file mode 100644 index 000000000..780e1b4ac --- /dev/null +++ b/src/Intervention/Image/Imagick/Container.php @@ -0,0 +1,79 @@ +imagick = $imagick; + } + + public function getCore($index = null) + { + if (is_numeric($index)) { + return $this->getImagickAtPosition($index); + } + + return $this->imagick; + } + + public function setCore($core) + { + $this->imagick = $core; + } + + public function countFrames() + { + return $this->imagick->getNumberImages(); + } + + public function rewind() + { + $this->position = 0; + } + + public function current() + { + $imagick = $this->getImagickAtPosition(); + + return new Frame( + $imagick, + $imagick->getImageDelay(), + $imagick->getImageDispose() + ); + } + + public function key() + { + return $this->position; + } + + public function next() + { + ++$this->position; + } + + public function valid() + { + return is_a($this->getImagickAtPosition(), 'Imagick'); + } + + private function getImagickAtPosition($position = null) + { + $position = is_numeric($position) ? $position : $this->position; + + foreach ($this->imagick as $key => $imagick) { + if ($key == $position) { + return $imagick; + } + } + } +} diff --git a/src/Intervention/Image/Imagick/Decoder.php b/src/Intervention/Image/Imagick/Decoder.php index 3f11dd4b9..63e93dcb5 100644 --- a/src/Intervention/Image/Imagick/Decoder.php +++ b/src/Intervention/Image/Imagick/Decoder.php @@ -15,12 +15,12 @@ class Decoder extends \Intervention\Image\AbstractDecoder */ public function initFromPath($path) { - $core = new \Imagick; + $imagick = new \Imagick; try { - $core->readImage($path); - $core->setImageType(\Imagick::IMGTYPE_TRUECOLORMATTE); + $imagick->readImage($path); + $imagick->setImageType(\Imagick::IMGTYPE_TRUECOLORMATTE); } catch (\ImagickException $e) { throw new \Intervention\Image\Exception\NotReadableException( @@ -29,7 +29,7 @@ public function initFromPath($path) } // build image - $image = $this->initFromImagick($core); + $image = $this->initFromImagick($imagick); $image->setFileInfoFromPath($path); return $image; @@ -51,19 +51,18 @@ public function initFromGdResource($resource) /** * Initiates new image from Imagick object * - * @param Imagick $object + * @param Imagick $imagick * @return \Intervention\Image\Image */ - public function initFromImagick(\Imagick $object) + public function initFromImagick(\Imagick $imagick) { - // currently animations are not supported - // so all images are turned into static - $object = $this->removeAnimation($object); - // reset image orientation - $object->setImageOrientation(\Imagick::ORIENTATION_UNDEFINED); + $imagick->setImageOrientation(\Imagick::ORIENTATION_UNDEFINED); - return new Image(new Driver, $object); + // coalesce possible animation + $imagick = $imagick->coalesceImages(); + + return new Image(new Driver, new Container($imagick)); } /** @@ -74,11 +73,11 @@ public function initFromImagick(\Imagick $object) */ public function initFromBinary($binary) { - $core = new \Imagick; + $imagick = new \Imagick; try { - $core->readImageBlob($binary); + $imagick->readImageBlob($binary); } catch (\ImagickException $e) { throw new \Intervention\Image\Exception\NotReadableException( @@ -87,7 +86,7 @@ public function initFromBinary($binary) } // build image - $image = $this->initFromImagick($core); + $image = $this->initFromImagick($imagick); $image->mime = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $binary); return $image; diff --git a/src/Intervention/Image/Imagick/Driver.php b/src/Intervention/Image/Imagick/Driver.php index b8bfef482..55e005425 100644 --- a/src/Intervention/Image/Imagick/Driver.php +++ b/src/Intervention/Image/Imagick/Driver.php @@ -14,7 +14,7 @@ class Driver extends \Intervention\Image\AbstractDriver */ public function __construct(Decoder $decoder = null, Encoder $encoder = null) { - if ( ! $this->coreAvailable()) { + if ( ! $this->moduleAvailable()) { throw new \Intervention\Image\Exception\NotSupportedException( "ImageMagick module not available with this PHP installation." ); @@ -44,7 +44,7 @@ public function newImage($width, $height, $background = null) $core->setColorspace(\Imagick::COLORSPACE_UNDEFINED); // build image - $image = new \Intervention\Image\Image(new self, $core); + $image = new \Intervention\Image\Image(new self, new Container($core)); return $image; } @@ -61,11 +61,11 @@ public function parseColor($value) } /** - * Checks if core module installation is available + * Checks if image module installation is available * * @return boolean */ - protected function coreAvailable() + protected function moduleAvailable() { return (extension_loaded('imagick') && class_exists('Imagick')); } diff --git a/src/Intervention/Image/Imagick/Font.php b/src/Intervention/Image/Imagick/Font.php index 1a91066c1..91c015b75 100644 --- a/src/Intervention/Image/Imagick/Font.php +++ b/src/Intervention/Image/Imagick/Font.php @@ -3,6 +3,7 @@ namespace Intervention\Image\Imagick; use \Intervention\Image\Image; +use \Intervention\Image\Size; class Font extends \Intervention\Image\AbstractFont { @@ -16,63 +17,172 @@ class Font extends \Intervention\Image\AbstractFont */ public function applyToImage(Image $image, $posx = 0, $posy = 0) { - // build draw object $draw = new \ImagickDraw(); - $draw->setStrokeAntialias(true); - $draw->setTextAntialias(true); - // set font file if ($this->hasApplicableFontFile()) { + $draw->setStrokeAntialias(true); + $draw->setTextAntialias(true); + + // font file $draw->setFont($this->file); + + // font size + $draw->setFontSize($this->size); + + // parse text color + $color = new Color($this->color); + $draw->setFillColor($color->getPixel()); + } else { throw new \Intervention\Image\Exception\RuntimeException( "Font file must be provided to apply text to image." ); } - // parse text color - $color = new Color($this->color); + // format text + $text = $this->format(); - $draw->setFontSize($this->size); - $draw->setFillColor($color->getPixel()); + // box size + $box = $this->isBoxed() ? $this->box : $this->getBoxSize($text); + + // create empty canvas + $canvas = $image->getDriver()->newImage( + $box->getWidth() + self::PADDING * 2, + $box->getHeight() + self::PADDING * 2 + )->getCore(); + + $lines = $this->getLines($text); + + $baseline = $this->getCoreBoxSize($lines[0]); + + $box->align(sprintf('%s-%s', $this->align, 'top')); + + $ystart = 0; + + if ($this->isBoxed()) { + switch (strtolower($this->valign)) { + case 'bottom': + $ystart = $box->getHeight() - $this->getBoxSize($text)->getHeight(); + break; + + case 'center': + case 'middle': + $ystart = ($box->getHeight() - $this->getBoxSize($text)->getHeight()) / 2; + break; + } + } + + // write line by line + foreach ($lines as $count => $line) { + + $linesize = $this->getCoreBoxSize(trim($line)); + $relative = $box->relativePosition($linesize->align($this->align)); + + // write line of text + $canvas->annotateImage( + $draw, + self::PADDING + $relative->x, // x + self::PADDING + $ystart + $baseline->getHeight() + $count * $this->lineHeight * $this->size * 1.5, // y + 0, // angle + trim($line) + ); + } + + // valign + switch (strtolower($this->valign)) { + case 'top': + # nothing to do... + break; - // align horizontal - switch (strtolower($this->align)) { case 'center': - $align = \Imagick::ALIGN_CENTER; - break; + case 'middle': + $box->pivot->moveY($box->getHeight() / 2); + break; - case 'right': - $align = \Imagick::ALIGN_RIGHT; - break; + case 'bottom': + $box->pivot->moveY($box->getHeight()); + break; default: - $align = \Imagick::ALIGN_LEFT; - break; + case 'baseline': + $box->pivot->moveY($baseline->getHeight()); + break; } - $draw->setTextAlignment($align); + if ($this->isBoxed()) { + $box->align('top-left'); + } - // align vertical - if (strtolower($this->valign) != 'bottom') { + // rotate canvas + if ($this->angle != 0) { + $canvas->rotateImage(new \ImagickPixel('none'), ($this->angle * -1)); + $box->rotate($this->angle); + } - // calculate box size - $dimensions = $image->getCore()->queryFontMetrics($draw, $this->text); + // insert canvas + foreach ($image as $frame) { + $frame->getCore()->compositeImage( + $canvas, + \Imagick::COMPOSITE_DEFAULT, + $posx - $box->pivot->x - self::PADDING, + $posy - $box->pivot->y - self::PADDING + ); + } - // corrections on y-position - switch (strtolower($this->valign)) { - case 'center': - case 'middle': - $posy = $posy + $dimensions['textHeight'] * 0.65 / 2; - break; + + } - case 'top': - $posy = $posy + $dimensions['textHeight'] * 0.65; - break; - } + /** + * Calculate boxsize including own features + * + * @param string $text + * @return \Intervention\Image\Size + */ + public function getBoxSize($text = null) + { + $text = is_null($text) ? $this->text : $text; + + $lines = $this->getLines($text); + $baseline = $this->getCoreBoxSize($lines[0]); + + $width_values = array(); + + // cycle through each line + foreach ($lines as $line) { + $width_values[] = $this->getCoreBoxSize($line)->getWidth(); } - // apply to image - $image->getCore()->annotateImage($draw, $posx, $posy, $this->angle * (-1), $this->text); + // maximal line width is box width + $width = max($width_values); + + // calculate height + $height = $baseline->getHeight() + (count($lines) - 1) * $this->lineHeight * $this->size * 1.5; + $height = $height + $baseline->getHeight() / 3; + + return new Size($width, $height); + } + + /** + * Get raw boxsize without any non-core features + * + * @param string $text + * @return \Intervention\Image\Size + */ + protected function getCoreBoxSize($text = null) + { + $text = is_null($text) ? $this->text : $text; + + $imagick = new \Imagick(); + $draw = new \ImagickDraw(); + + $draw->setStrokeAntialias(true); + $draw->setTextAntialias(true); + $draw->setFontSize($this->size); + $draw->setFont($this->file); + + // get boxsize + $size = $imagick->queryFontMetrics($draw, $text); + + return new Size($size['textWidth'], $size['textHeight']); } } diff --git a/src/Intervention/Image/Imagick/Shapes/EllipseShape.php b/src/Intervention/Image/Imagick/Shapes/EllipseShape.php index c6ca147a5..039d94d38 100644 --- a/src/Intervention/Image/Imagick/Shapes/EllipseShape.php +++ b/src/Intervention/Image/Imagick/Shapes/EllipseShape.php @@ -58,7 +58,9 @@ public function applyToImage(Image $image, $x = 0, $y = 0) $circle->ellipse($x, $y, $this->width / 2, $this->height / 2, 0, 360); - $image->getCore()->drawImage($circle); + foreach ($image as $frame) { + $frame->getCore()->drawImage($circle); + } return true; } diff --git a/src/Intervention/Image/Imagick/Shapes/LineShape.php b/src/Intervention/Image/Imagick/Shapes/LineShape.php index 6e22f93a3..aa028137e 100644 --- a/src/Intervention/Image/Imagick/Shapes/LineShape.php +++ b/src/Intervention/Image/Imagick/Shapes/LineShape.php @@ -86,7 +86,10 @@ public function applyToImage(Image $image, $x = 0, $y = 0) $line->setStrokeWidth($this->width); $line->line($this->x, $this->y, $x, $y); - $image->getCore()->drawImage($line); + + foreach ($image as $frame) { + $frame->getCore()->drawImage($line); + } return true; } diff --git a/src/Intervention/Image/Imagick/Shapes/PolygonShape.php b/src/Intervention/Image/Imagick/Shapes/PolygonShape.php index dec4a3396..b5d1e20ad 100644 --- a/src/Intervention/Image/Imagick/Shapes/PolygonShape.php +++ b/src/Intervention/Image/Imagick/Shapes/PolygonShape.php @@ -49,7 +49,9 @@ public function applyToImage(Image $image, $x = 0, $y = 0) $polygon->polygon($this->points); - $image->getCore()->drawImage($polygon); + foreach ($image as $frame) { + $frame->getCore()->drawImage($polygon); + } return true; } diff --git a/src/Intervention/Image/Imagick/Shapes/RectangleShape.php b/src/Intervention/Image/Imagick/Shapes/RectangleShape.php index ad65ddf07..c12c990be 100644 --- a/src/Intervention/Image/Imagick/Shapes/RectangleShape.php +++ b/src/Intervention/Image/Imagick/Shapes/RectangleShape.php @@ -76,7 +76,9 @@ public function applyToImage(Image $image, $x = 0, $y = 0) $rectangle->rectangle($this->x1, $this->y1, $this->x2, $this->y2); - $image->getCore()->drawImage($rectangle); + foreach ($image as $frame) { + $frame->getCore()->drawImage($rectangle); + } return true; } diff --git a/src/Intervention/Image/MimeDetector.php b/src/Intervention/Image/MimeDetector.php new file mode 100644 index 000000000..f230a4dd0 --- /dev/null +++ b/src/Intervention/Image/MimeDetector.php @@ -0,0 +1,177 @@ +data = $data; + } + + /** + * Set data to be detected + * + * @param string $value + */ + public function setData($value) + { + $this->data = $value; + + return $this; + } + + /** + * Return MIME type of current data + * + * @return string + */ + public function getMimeType() + { + switch (true) { + + case $this->isJpeg(): + return 'image/jpeg'; + + case $this->isPng(): + return 'image/png'; + + case $this->isGif(): + return 'image/gif'; + + case $this->isBitmap(): + return 'image/bmp'; + + case $this->isTiff(): + return 'image/tif'; + + case $this->isWebp(): + return 'image/webp'; + + case $this->isPsd(): + return 'image/vnd.adobe.photoshop'; + + case $this->isIco(): + return 'image/x-icon'; + } + + throw new Exception\NotSupportedException( + "MIME type could not be identified." + ); + } + + /** + * Determine if current data is PNG + * + * @return boolean + */ + private function isPng() + { + return ($this->getHexBytes(0, 8) == '89504e470d0a1a0a'); + } + + /** + * Determine if current data is JPG + * + * @return boolean + */ + private function isJpeg() + { + $bytes1 = $this->getHexBytes(0, 4); + $bytes2 = $this->getHexBytes(6, 5); + + return ($bytes1 == 'ffd8ffe0') && ($bytes2 == '4a46494600'); + } + + /** + * Determine if current data is GIF + * + * @return boolean + */ + private function isGif() + { + $bytes = $this->getHexBytes(0, 6); + + return ($bytes == '474946383761') || ($bytes == '474946383961'); + } + + /** + * Determine if current data is Bitmap + * + * @return boolean + */ + private function isBitmap() + { + return ($this->getHexBytes(0, 2) == '424d'); + } + + /** + * Determine if current data is TIF + * + * @return boolean + */ + private function isTiff() + { + $bytes1 = $this->getHexBytes(0, 3); + $bytes2 = $this->getHexBytes(0, 4); + + return ($bytes1 == '492049') || ($bytes2 == '49492a00'); + } + + /** + * Determine if current data is ICO + * + * @return boolean + */ + private function isIco() + { + return ($this->getHexBytes(0, 4) == '00000100'); + } + + /** + * Determine if current data is Photoshop + * + * @return boolean + */ + private function isPsd() + { + return ($this->getHexBytes(0, 4) == '38425053'); + } + + /** + * Determine if current data is WEBP + * + * @return boolean + */ + private function isWebp() + { + $bytes1 = $this->getHexBytes(0, 4); + $bytes2 = $this->getHexBytes(8, 4); + + return ($bytes1 == '52494646') && ($bytes2 == '57454250'); + } + + /** + * Return hexadecimal formated bytes from current data + * + * @param int $start + * @param int $length + * @return string + */ + private function getHexBytes($start, $length) + { + return bin2hex(substr($this->data, $start, $length)); + } +} diff --git a/src/Intervention/Image/Point.php b/src/Intervention/Image/Point.php index bb17fb7c1..02d786618 100644 --- a/src/Intervention/Image/Point.php +++ b/src/Intervention/Image/Point.php @@ -51,14 +51,55 @@ public function setY($y) } /** - * Sets both X and Y coordinate + * Move X coordinate * * @param integer $x + */ + public function moveX($x) + { + $this->x = $this->x + intval($x); + } + + /** + * Move Y coordinate + * * @param integer $y */ + public function moveY($y) + { + $this->y = $this->y + intval($y); + } + + /** + * Sets both X and Y coordinate + * + * @param integer $x + * @param integer $y + * @return Point + */ public function setPosition($x, $y) { $this->setX($x); $this->setY($y); + + return $this; + } + + /** + * Rotate point ccw around pivot + * + * @param float $angle + * @param Point $pivot + * @return Point + */ + public function rotate($angle, Point $pivot) + { + $sin = round(sin(deg2rad($angle)), 6); + $cos = round(cos(deg2rad($angle)), 6); + + $x = $cos * ($this->x - $pivot->x) - $sin * ($this->y - $pivot->y) + $pivot->x; + $y = $sin * ($this->x - $pivot->x) + $cos * ($this->y - $pivot->y) + $pivot->y; + + return $this->setPosition($x, $y); } } diff --git a/src/Intervention/Image/Size.php b/src/Intervention/Image/Size.php index bfea4d41e..03638a295 100644 --- a/src/Intervention/Image/Size.php +++ b/src/Intervention/Image/Size.php @@ -354,6 +354,82 @@ public function align($position, $offset_x = 0, $offset_y = 0) return $this; } + /** + * Rotate rectangular size and return bounding rectangle + * + * @param float $angle + * @return \Intervention\Image\Size + */ + public function rotate($angle) + { + if ($angle != 0) { + + // recreate rectangle with 4 points + $points = array( + new Point(0, 0), + new Point($this->width, 0), + new Point($this->width, $this->height * (-1)), + new Point(0, $this->height * (-1)) + ); + + $x_values = array(); + $y_values = array(); + + $pivot = clone $this->pivot; + $pivot->y = $pivot->y * (-1); + + // rotate 4 points + foreach ($points as $point) { + $point->rotate($angle, $pivot); + $x_values[] = $point->x; + $y_values[] = $point->y; + } + + // find max/min x/y values + $max_x_value = max($x_values); + $max_y_value = max($y_values); + $min_x_value = min($x_values); + $min_y_value = min($y_values); + + // set new bounding box + $this->set( + abs($min_x_value - $max_x_value), + abs($min_y_value - $max_y_value) + ); + + // set new pivot + $this->setPivot($pivot->setPosition( + abs($pivot->x + $min_x_value * (-1)), + abs($pivot->y + $max_y_value * (-1)) + )); + } + + return $this; + } + + /** + * Resize rectangular and keeps pivot point relative + * + * @param integer $width + * @param integer $height + * @param boolean $relative + * @return \Intervention\Image\Size + */ + public function resizeCanvas($width, $height, $relative = false) + { + $width = $relative ? $this->width + $width * 2 : $width; + $height = $relative ? $this->height + $height * 2 : $height; + + $px = $this->pivot->x == 0 ? 0 : $width / ($this->width / $this->pivot->x); + $py = $this->pivot->y == 0 ? 0 : $height / ($this->height / $this->pivot->y); + + $this->width = $width; + $this->height = $height; + $this->setPivot(new Point($px, $py)); + + return $this; + } + /** * Runs constraints on current size * diff --git a/tests/AbstractFontTest.php b/tests/AbstractFontTest.php index cf1d03b5a..9058ffb1b 100644 --- a/tests/AbstractFontTest.php +++ b/tests/AbstractFontTest.php @@ -62,6 +62,23 @@ public function testFile() $this->assertEquals('test.ttf', $font->file); } + public function testLineHeight() + { + $font = $this->getMockForAbstractClass('\Intervention\Image\AbstractFont'); + $font->lineHeight(1.5); + $this->assertEquals(1.5, $font->lineHeight); + } + + public function testBox() + { + $font = $this->getMockForAbstractClass('\Intervention\Image\AbstractFont'); + $this->assertEquals(null, $font->box); + $font->box(300, 200); + $this->assertInstanceOf('Intervention\Image\Size', $font->box); + $this->assertEquals(300, $font->box->width); + $this->assertEquals(200, $font->box->height); + } + public function testCountLines() { $font = $this->getMockForAbstractClass('\Intervention\Image\AbstractFont'); @@ -74,4 +91,25 @@ public function testCountLines() baz'); $this->assertEquals(3, $font->countLines()); } + + public function testGetLines() + { + $font = $this->getMockForAbstractClass('\Intervention\Image\AbstractFont'); + $font->text('foo'.PHP_EOL.'bar'.PHP_EOL.'baz'); + $this->assertEquals(array('foo', 'bar', 'baz'), $font->getLines()); + } + + public function testGetWord() + { + $font = $this->getMockForAbstractClass('\Intervention\Image\AbstractFont'); + + $font->text('foo bar baz'); + $this->assertEquals(array('foo', 'bar', 'baz'), $font->getWords()); + + $font->text('foo bar'); + $this->assertEquals(array('foo', 'bar'), $font->getWords()); + + $font->text('foo'); + $this->assertEquals(array('foo'), $font->getWords()); + } } diff --git a/tests/AnimationTest.php b/tests/AnimationTest.php new file mode 100644 index 000000000..62186affb --- /dev/null +++ b/tests/AnimationTest.php @@ -0,0 +1,88 @@ +assertInstanceOf('Intervention\Image\Animation', $animation); + $this->assertNull($animation->loops); + } + + public function testConstructorWithParameters() + { + $animation = new Animation(12); + $this->assertInstanceOf('Intervention\Image\Animation', $animation); + $this->assertEquals(12, $animation->loops); + } + + public function testIterate() + { + $frame = Mockery::mock('Intervention\Image\Frame'); + $animation = new Animation; + $animation->addFrame($frame); + $animation->addFrame($frame); + $animation->addFrame($frame); + $counter = 0; + foreach ($animation as $frame) { + $counter++; + } + $this->assertEquals(3, $counter); + } + + public function testSetLoops() + { + $animation = new Animation(12); + $animation->setLoops(13); + $this->assertEquals(13, $animation->loops); + } + + public function testAddFrame() + { + $frame = Mockery::mock('Intervention\Image\Frame'); + $animation = new Animation; + $animation->addFrame($frame); + $this->assertHasFrames(1, $animation); + $animation->addFrame($frame); + $this->assertHasFrames(2, $animation); + } + + public function testAddFrames() + { + $frame = Mockery::mock('Intervention\Image\Frame'); + $animation = new Animation; + $animation->addFrames(array($frame, $frame)); + $this->assertHasFrames(2, $animation); + $animation->addFrames(array($frame, $frame, $frame)); + $this->assertHasFrames(5, $animation); + $animation->addFrames(array($frame, $frame)); + $this->assertHasFrames(7, $animation); + } + + public function testSetFrames() + { + $frame = Mockery::mock('Intervention\Image\Frame'); + $animation = new Animation; + $animation->setFrames(array($frame, $frame, $frame)); + $this->assertHasFrames(3, $animation); + } + + public function testGetFrames() + { + $animation = new Animation; + $this->assertEquals(array(), $animation->getFrames()); + } + + private function assertHasFrames($number, $animation) + { + $this->assertEquals($number, count($animation->getFrames())); + } + +} \ No newline at end of file diff --git a/tests/BackupCommandTest.php b/tests/BackupCommandTest.php deleted file mode 100644 index 3f7967dda..000000000 --- a/tests/BackupCommandTest.php +++ /dev/null @@ -1,60 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('getSize')->once()->andReturn($size); - $image->shouldReceive('setBackup')->once(); - $command = new BackupGd(array()); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testGdWithName() - { - $size = Mockery::mock('Intervention\Image\Size', array(800, 600)); - $resource = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('getSize')->once()->andReturn($size); - $image->shouldReceive('setBackup')->once(); - $command = new BackupGd(array('name' => 'fooBackup')); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagickWithoutName() - { - $imagick = Mockery::mock('Imagick'); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $image->shouldReceive('setBackup')->once(); - $command = new BackupImagick(array()); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagickWithName() - { - $imagick = Mockery::mock('Imagick'); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $image->shouldReceive('setBackup')->once(); - $command = new BackupImagick(array('name' => 'fooBackup')); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/BlurCommandTest.php b/tests/BlurCommandTest.php deleted file mode 100644 index 2380c3fce..000000000 --- a/tests/BlurCommandTest.php +++ /dev/null @@ -1,33 +0,0 @@ -shouldReceive('getCore')->times(2)->andReturn($resource); - $command = new BlurGd(array(2)); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('blurimage')->with(2, 1)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new BlurImagick(array(2)); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/BrightnessCommandTest.php b/tests/BrightnessCommandTest.php deleted file mode 100644 index 999a966c8..000000000 --- a/tests/BrightnessCommandTest.php +++ /dev/null @@ -1,33 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $command = new BrightnessGd(array(12)); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('modulateimage')->with(112, 100, 100)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new BrightnessImagick(array(12)); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/ChecksumCommandTest.php b/tests/ChecksumCommandTest.php index cf42f7ddf..5435e6efd 100644 --- a/tests/ChecksumCommandTest.php +++ b/tests/ChecksumCommandTest.php @@ -11,16 +11,13 @@ public function tearDown() public function testExecute() { - $size = Mockery::mock('Intervention\Image\Size', array(3, 3)); - $color = array(0,0,0,1); - $resource = imagecreatefrompng(__DIR__.'/images/tile.png'); $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getSize')->once()->andReturn($size); - $image->shouldReceive('pickColor')->times(9)->andReturn($color); + $image->shouldReceive('encode')->once()->andReturn('encoded_image_data'); + $command = new ChecksumCommand(array()); $result = $command->execute($image); $this->assertTrue($result); $this->assertTrue($command->hasOutput()); - $this->assertEquals('ec9cbdb71be04e26b4a89333f20c273b', $command->getOutput()); + $this->assertEquals(md5('encoded_image_data'), $command->getOutput()); } } diff --git a/tests/CircleCommandTest.php b/tests/CircleCommandTest.php deleted file mode 100644 index 241440ec4..000000000 --- a/tests/CircleCommandTest.php +++ /dev/null @@ -1,42 +0,0 @@ -shouldReceive('getDriverName')->once()->andReturn('Gd'); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $command = new CircleCommand(array(250, 10, 20)); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertFalse($command->hasOutput()); - } - - public function testImagick() - { - $imagick = Mockery::mock('\Imagick'); - $imagick->shouldReceive('drawimage'); - $driver = Mockery::mock('\Intervention\Image\Imagick\Driver'); - $driver->shouldReceive('getDriverName')->once()->andReturn('Imagick'); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - - $command = new CircleCommand(array(25, 10, 20)); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertFalse($command->hasOutput()); - } - -} diff --git a/tests/CircleShapeTest.php b/tests/CircleShapeTest.php index 71b40d23a..44c404eaa 100644 --- a/tests/CircleShapeTest.php +++ b/tests/CircleShapeTest.php @@ -18,34 +18,10 @@ public function testGdConstructor() } - public function testGdApplyToImage() - { - $core = imagecreatetruecolor(300, 200); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $circle = new CircleGd(250); - $result = $circle->applyToImage($image, 10, 20); - $this->assertInstanceOf('Intervention\Image\Gd\Shapes\CircleShape', $circle); - $this->assertTrue($result); - } - public function testImagickConstructor() { $circle = new CircleImagick(250); $this->assertInstanceOf('Intervention\Image\Imagick\Shapes\CircleShape', $circle); $this->assertEquals(250, $circle->width); } - - public function testImagickApplyToImage() - { - $core = Mockery::mock('\Imagick'); - $core->shouldReceive('drawimage')->once(); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $circle = new CircleImagick(250); - $result = $circle->applyToImage($image, 10, 20); - $this->assertInstanceOf('Intervention\Image\Imagick\Shapes\CircleShape', $circle); - $this->assertTrue($result); - } - } diff --git a/tests/ColorizeCommandTest.php b/tests/ColorizeCommandTest.php deleted file mode 100644 index c89d0d4a9..000000000 --- a/tests/ColorizeCommandTest.php +++ /dev/null @@ -1,36 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $command = new ColorizeGd(array(20, 0, -40)); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('getquantumrange')->with()->once()->andReturn(array('quantumRangeLong' => 42)); - $imagick->shouldReceive('levelimage')->with(0, 4, 42, \Imagick::CHANNEL_RED)->once()->andReturn(true); - $imagick->shouldReceive('levelimage')->with(0, 1, 42, \Imagick::CHANNEL_GREEN)->once()->andReturn(true); - $imagick->shouldReceive('levelimage')->with(0, 0.6, 42, \Imagick::CHANNEL_BLUE)->once()->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->times(4)->andReturn($imagick); - $command = new ColorizeImagick(array(20, 0, -40)); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/ContrastCommandTest.php b/tests/ContrastCommandTest.php deleted file mode 100644 index 2c18f0866..000000000 --- a/tests/ContrastCommandTest.php +++ /dev/null @@ -1,33 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $command = new ContrastGd(array(20)); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('sigmoidalcontrastimage')->with(true, 5, 0)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new ContrastImagick(array(20)); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/CropCommandTest.php b/tests/CropCommandTest.php deleted file mode 100644 index 94cc5c04f..000000000 --- a/tests/CropCommandTest.php +++ /dev/null @@ -1,35 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('setCore')->once(); - $command = new CropGd(array(100, 150, 10, 20)); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('cropimage')->with(100, 150, 10, 20)->andReturn(true); - $imagick->shouldReceive('setimagepage')->with(0, 0, 0, 0)->once(); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->times(2)->andReturn($imagick); - $command = new CropImagick(array(100, 150, 10, 20)); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/DestroyCommandTest.php b/tests/DestroyCommandTest.php deleted file mode 100644 index f25719644..000000000 --- a/tests/DestroyCommandTest.php +++ /dev/null @@ -1,45 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('getBackups')->once()->andReturn($backups); - $command = new DestroyGd(array()); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('clear')->with()->andReturn(true); - - $backup = Mockery::mock('Imagick'); - $backup->shouldReceive('clear')->with()->andReturn(true); - $backups = array($backup); - - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $image->shouldReceive('getBackups')->once()->andReturn($backups); - $command = new DestroyImagick(array()); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/EllipseCommandTest.php b/tests/EllipseCommandTest.php deleted file mode 100644 index 8ac42e007..000000000 --- a/tests/EllipseCommandTest.php +++ /dev/null @@ -1,42 +0,0 @@ -shouldReceive('getDriverName')->once()->andReturn('Gd'); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $command = new EllipseCommand(array(250, 150, 10, 20)); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertFalse($command->hasOutput()); - } - - public function testImagick() - { - $imagick = Mockery::mock('\Imagick'); - $imagick->shouldReceive('drawimage'); - $driver = Mockery::mock('\Intervention\Image\Imagick\Driver'); - $driver->shouldReceive('getDriverName')->once()->andReturn('Imagick'); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - - $command = new EllipseCommand(array(250, 150, 10, 20)); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertFalse($command->hasOutput()); - } - -} diff --git a/tests/EllipseShapeTest.php b/tests/EllipseShapeTest.php index 773373f69..d505afbdb 100644 --- a/tests/EllipseShapeTest.php +++ b/tests/EllipseShapeTest.php @@ -19,17 +19,6 @@ public function testGdConstructor() } - public function testGdApplyToImage() - { - $core = imagecreatetruecolor(300, 200); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $ellipse = new EllipseGd(250, 150); - $result = $ellipse->applyToImage($image, 10, 20); - $this->assertInstanceOf('Intervention\Image\Gd\Shapes\EllipseShape', $ellipse); - $this->assertTrue($result); - } - public function testImagickConstructor() { $ellipse = new EllipseImagick(250, 150); @@ -38,17 +27,4 @@ public function testImagickConstructor() $this->assertEquals(150, $ellipse->height); } - - public function testImagickApplyToImage() - { - $core = Mockery::mock('\Imagick'); - $core->shouldReceive('drawimage')->once(); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $ellipse = new EllipseImagick(250, 150); - $result = $ellipse->applyToImage($image, 10, 20); - $this->assertInstanceOf('Intervention\Image\Imagick\Shapes\EllipseShape', $ellipse); - $this->assertTrue($result); - } - } diff --git a/tests/EncoderTest.php b/tests/EncoderTest.php index 0b7eba8b3..34ea46aa8 100644 --- a/tests/EncoderTest.php +++ b/tests/EncoderTest.php @@ -38,9 +38,17 @@ public function testProcessGifGd() { $core = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); $encoder = new GdEncoder; + $frame = Mockery::mock('\Intervention\Image\Frame'); + $frame->shouldReceive('getCore')->andReturn($core); + $container = Mockery::mock('\Intervention\Image\Gd\Container'); + $container->shouldReceive('getLoops')->once()->andReturn(1); + $container->shouldReceive('getIterator')->andReturn(new ArrayIterator(array($frame))); $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); + $image->shouldReceive('getWidth')->once()->andReturn(800); + $image->shouldReceive('getHeight')->once()->andReturn(600); + $image->shouldReceive('getContainer')->once()->andReturn($container); $image->shouldReceive('setEncoded')->once()->andReturn($image); + $image->shouldReceive('getIterator')->andReturn($container); $img = $encoder->process($image, 'gif', 90); $this->assertInstanceOf('Intervention\Image\Image', $img); $this->assertEquals('image/gif; charset=binary', $this->getMime($encoder->result)); @@ -239,6 +247,7 @@ public function getImagickMock($type) $imagick->shouldReceive('setimagecompressionquality'); $imagick->shouldReceive('setimagebackgroundcolor'); $imagick->shouldReceive('setbackgroundcolor'); + $imagick->shouldReceive('optimizeimagelayers')->andReturn($imagick); $imagick->shouldReceive('mergeimagelayers')->andReturn($imagick); $imagick->shouldReceive('getimagesblob')->once()->andReturn(sprintf('mock-%s', $type)); return $imagick; diff --git a/tests/ExifCommandTest.php b/tests/ExifCommandTest.php deleted file mode 100644 index dac43fa97..000000000 --- a/tests/ExifCommandTest.php +++ /dev/null @@ -1,60 +0,0 @@ -dirname = __DIR__.'/images'; - $image->basename = 'exif.jpg'; - $command = new ExifCommand(array()); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertInternalType('array', $command->getOutput()); - } - - public function testFetchDefined() - { - $image = new Image; - $image->dirname = __DIR__.'/images'; - $image->basename = 'exif.jpg'; - $command = new ExifCommand(array('Artist')); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertEquals('Oliver Vogel', $command->getOutput()); - } - - public function testFetchNonExisting() - { - $image = new Image; - $image->dirname = __DIR__.'/images'; - $image->basename = 'exif.jpg'; - $command = new ExifCommand(array('xxx')); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertEquals(null, $command->getOutput()); - } - - public function testFetchFromPng() - { - $image = new Image; - $image->dirname = __DIR__.'/images'; - $image->basename = 'star.png'; - $command = new ExifCommand(array('Orientation')); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertEquals(null, $command->getOutput()); - } -} diff --git a/tests/FillCommandTest.php b/tests/FillCommandTest.php deleted file mode 100644 index b4d92c9fa..000000000 --- a/tests/FillCommandTest.php +++ /dev/null @@ -1,92 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $command = new FillGd(array('666666')); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testGdFillArray() - { - $resource = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $command = new FillGd(array(array(50, 50, 50))); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testGdFillArrayWithAlpha() - { - $resource = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $command = new FillGd(array(array(50, 50, 50, .50))); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testGdFillWithCoordinates() - { - $driver = Mockery::mock('\Intervention\Image\Gd\Driver'); - $resource = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->times(2)->andReturn($resource); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $image->shouldReceive('setCore')->once(); - $driver->shouldReceive('newImage')->with(800, 600)->once()->andReturn($image); - $command = new FillGd(array('#666666', 0, 0)); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagickFill() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('drawimage')->once()->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $image->shouldReceive('getCore')->andReturn($imagick); - $command = new FillImagick(array('666666')); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagickFillWithCoordinates() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('getimagepixelcolor')->once()->andReturn('#000000'); - $imagick->shouldReceive('transparentpaintimage')->once()->andReturn(true); - $imagick->shouldReceive('compositeimage')->times(3)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->andReturn($imagick); - $image->shouldReceive('getWidth')->andReturn(800); - $image->shouldReceive('getHeight')->andReturn(600); - $command = new FillImagick(array('666666', 0, 0)); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/FitCommandTest.php b/tests/FitCommandTest.php deleted file mode 100644 index bdc4c8081..000000000 --- a/tests/FitCommandTest.php +++ /dev/null @@ -1,92 +0,0 @@ -shouldReceive('getWidth')->times(2)->andReturn(800); - $cropped_size->shouldReceive('getHeight')->times(2)->andReturn(400); - $cropped_size->shouldReceive('resize')->with(200, 100, null)->once()->andReturn($cropped_size); - $cropped_size->pivot = Mockery::mock('\Intervention\Image\Point', array(0, 100)); - $original_size = Mockery::mock('\Intervention\Image\Size', array(800, 600)); - $original_size->shouldReceive('fit')->with(Mockery::any(), 'center')->once()->andReturn($cropped_size); - $resource = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getSize')->once()->andReturn($original_size); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('setCore')->once(); - $command = new FitGd(array(200, 100)); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testGdFitWithPosition() - { - $cropped_size = Mockery::mock('\Intervention\Image\Size', array(800, 400)); - $cropped_size->shouldReceive('getWidth')->times(2)->andReturn(800); - $cropped_size->shouldReceive('getHeight')->times(2)->andReturn(400); - $cropped_size->shouldReceive('resize')->with(200, 100, null)->once()->andReturn($cropped_size); - $cropped_size->pivot = Mockery::mock('\Intervention\Image\Point', array(0, 100)); - $original_size = Mockery::mock('\Intervention\Image\Size', array(800, 600)); - $original_size->shouldReceive('fit')->with(Mockery::any(), 'top-left')->once()->andReturn($cropped_size); - $resource = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getSize')->once()->andReturn($original_size); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('setCore')->once(); - $command = new FitGd(array(200, 100, null, 'top-left')); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagickFit() - { - $cropped_size = Mockery::mock('\Intervention\Image\Size', array(800, 400)); - $cropped_size->shouldReceive('getWidth')->once()->andReturn(200); - $cropped_size->shouldReceive('getHeight')->once()->andReturn(100); - $cropped_size->shouldReceive('resize')->with(200, 100, null)->once()->andReturn($cropped_size); - $cropped_size->pivot = Mockery::mock('\Intervention\Image\Point', array(0, 100)); - $original_size = Mockery::mock('\Intervention\Image\Size', array(800, 600)); - $original_size->shouldReceive('fit')->with(Mockery::any(), 'center')->once()->andReturn($cropped_size); - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('cropimage')->with(800, 400, 0, 100)->andReturn(true); - $imagick->shouldReceive('scaleimage')->with(200, 100)->once()->andReturn(true); - $imagick->shouldReceive('setimagepage')->with(0, 0, 0, 0)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getSize')->once()->andReturn($original_size); - $image->shouldReceive('getCore')->times(3)->andReturn($imagick); - $command = new FitImagick(array(200, 100)); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagickFitWithPosition() - { - $cropped_size = Mockery::mock('\Intervention\Image\Size', array(800, 400)); - $cropped_size->shouldReceive('getWidth')->once()->andReturn(200); - $cropped_size->shouldReceive('getHeight')->once()->andReturn(100); - $cropped_size->shouldReceive('resize')->with(200, 100, null)->once()->andReturn($cropped_size); - $cropped_size->pivot = Mockery::mock('\Intervention\Image\Point', array(0, 100)); - $original_size = Mockery::mock('\Intervention\Image\Size', array(800, 600)); - $original_size->shouldReceive('fit')->with(Mockery::any(), 'top-left')->once()->andReturn($cropped_size); - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('cropimage')->with(800, 400, 0, 100)->andReturn(true); - $imagick->shouldReceive('scaleimage')->with(200, 100)->once()->andReturn(true); - $imagick->shouldReceive('setimagepage')->with(0, 0, 0, 0)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getSize')->once()->andReturn($original_size); - $image->shouldReceive('getCore')->times(3)->andReturn($imagick); - $command = new FitImagick(array(200, 100, null, 'top-left')); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/FlipCommandTest.php b/tests/FlipCommandTest.php deleted file mode 100644 index a38070da5..000000000 --- a/tests/FlipCommandTest.php +++ /dev/null @@ -1,44 +0,0 @@ -shouldReceive('getSize')->once()->andReturn($size); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('setCore')->once(); - $command = new FlipGd(array('h')); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('flopimage')->with()->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new FlipImagick(array('h')); - $result = $command->execute($image); - $this->assertTrue($result); - - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('flipimage')->with()->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new FlipImagick(array('v')); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/FrameTest.php b/tests/FrameTest.php new file mode 100644 index 000000000..4d14ff87d --- /dev/null +++ b/tests/FrameTest.php @@ -0,0 +1,22 @@ +assertInstanceOf('Intervention\Image\Frame', $frame); + $this->assertEquals('foo', $frame->core); + $this->assertEquals(0, $frame->delay); + + $frame = new Frame('foo', 250); + $this->assertEquals(250, $frame->delay); + } +} diff --git a/tests/GammaCommandTest.php b/tests/GammaCommandTest.php deleted file mode 100644 index 48d6bb9f6..000000000 --- a/tests/GammaCommandTest.php +++ /dev/null @@ -1,33 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $command = new GammaGd(array(1.4)); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('gammaimage')->with(1.4)->once()->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new GammaImagick(array(1.4)); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/GdContainerTest.php b/tests/GdContainerTest.php new file mode 100644 index 000000000..dc6a5c79b --- /dev/null +++ b/tests/GdContainerTest.php @@ -0,0 +1,36 @@ +setCore('foo'); + $this->assertEquals('foo', $container->getCore()); + } + + public function testCountFrames() + { + $container = new Container; + $container->addFrames(array('foo', 'bar', 'baz')); + $this->assertEquals(3, $container->countFrames()); + } + + public function testIterateToFrames() + { + $frame = Mockery::mock('Intervention\Image\Frame'); + $container = new Container; + $container->addFrame($frame); + $container->addFrame($frame); + foreach ($container as $key => $value) { + $this->assertInstanceOf('Intervention\Image\Frame', $value); + } + } +} diff --git a/tests/GdHelperTest.php b/tests/GdHelperTest.php new file mode 100644 index 000000000..c14f7bcd1 --- /dev/null +++ b/tests/GdHelperTest.php @@ -0,0 +1,26 @@ +assertFalse(imageistruecolor($resource)); + Helper::gdResourceToTruecolor($resource); + $this->assertTrue(imageistruecolor($resource)); + } + + public function testCloneResource() + { + $resource = imagecreate(10, 10); + $clone = Helper::cloneResource($resource); + $this->assertNotEquals($resource, $clone); + } +} diff --git a/tests/GetsizeCommandTest.php b/tests/GetsizeCommandTest.php deleted file mode 100644 index 76072b487..000000000 --- a/tests/GetsizeCommandTest.php +++ /dev/null @@ -1,38 +0,0 @@ -shouldReceive('getCore')->times(2)->andReturn($resource); - $command = new GetSizeGd(array()); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertInstanceOf('Intervention\Image\Size', $command->getOutput()); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('getimagewidth')->with(); - $imagick->shouldReceive('getimageheight')->with(); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new GetSizeImagick(array()); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertInstanceOf('Intervention\Image\Size', $command->getOutput()); - } -} diff --git a/tests/GreyscaleCommandTest.php b/tests/GreyscaleCommandTest.php deleted file mode 100644 index 1fa8d3a10..000000000 --- a/tests/GreyscaleCommandTest.php +++ /dev/null @@ -1,33 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $command = new GreyscaleGd(array()); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('modulateimage')->with(100, 0, 100)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new GreyscaleImagick(array()); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/HeightenCommandTest.php b/tests/HeightenCommandTest.php deleted file mode 100644 index 7290f4274..000000000 --- a/tests/HeightenCommandTest.php +++ /dev/null @@ -1,48 +0,0 @@ -aspectRatio(); }; - $resource = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $image = Mockery::mock('Intervention\Image\Image'); - $size = Mockery::mock('Intervention\Image\Size', array(800, 600)); - $size->shouldReceive('resize')->once()->andReturn($size); - $size->shouldReceive('getWidth')->once()->andReturn(800); - $size->shouldReceive('getHeight')->once()->andReturn(600); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $image->shouldReceive('getSize')->once()->andReturn($size); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('setCore')->once(); - $command = new HeightenGd(array(200)); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $callback = function ($constraint) { $constraint->upsize(); }; - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('scaleimage')->with(300, 200)->once()->andReturn(true); - $size = Mockery::mock('Intervention\Image\Size', array(800, 600)); - $size->shouldReceive('resize')->once()->andReturn($size); - $size->shouldReceive('getWidth')->once()->andReturn(300); - $size->shouldReceive('getHeight')->once()->andReturn(200); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $image->shouldReceive('getSize')->once()->andReturn($size); - $command = new HeightenImagick(array(200)); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/ImageTest.php b/tests/ImageTest.php index 245d4df9a..f38b26f16 100644 --- a/tests/ImageTest.php +++ b/tests/ImageTest.php @@ -12,14 +12,29 @@ public function tearDown() public function testGetCore() { $image = $this->getTestImage(); - $this->assertEquals('mock', $image->getCore()); + $this->assertEquals('core', $image->getCore()); + } + + public function testGetContainer() + { + $image = $this->getTestImage(); + $this->assertInstanceOf('\Intervention\Image\ContainerInterface', $image->getContainer()); + } + + public function testSetContainer() + { + $image = $this->getTestImage(); + $container = Mockery::mock('\Intervention\Image\ContainerInterface'); + $container->shouldReceive('isReplaced')->andReturn(true); + $image->setContainer($container); + $this->assertTrue($image->getContainer()->isReplaced()); } public function testCommandCall() { $image = $this->getTestImage(); $result = $image->test(1, 2, 3); - $this->assertEquals('mock', $result); + $this->assertEquals('result', $result); } public function testEncode() @@ -108,11 +123,14 @@ private function getTestImage() { $size = Mockery::mock('\Intervention\Image\Size', array(800, 600)); $driver = Mockery::mock('\Intervention\Image\AbstractDriver'); + $container = Mockery::mock('\Intervention\Image\ContainerInterface'); + $container->shouldReceive('setCore'); + $container->shouldReceive('getCore')->andReturn('core'); $command = Mockery::mock('\Intervention\Image\Commands\AbstractCommand'); $command->shouldReceive('hasOutput')->andReturn(true); - $command->shouldReceive('getOutput')->andReturn('mock'); + $command->shouldReceive('getOutput')->andReturn('result'); $driver->shouldReceive('executeCommand')->andReturn($command); - $image = new Image($driver, 'mock'); + $image = new Image($driver, $container); $image->mime = 'image/png'; $image->dirname = './tmp'; $image->basename = 'foo.png'; diff --git a/tests/ImagickContainerTest.php b/tests/ImagickContainerTest.php new file mode 100644 index 000000000..5cf68ff50 --- /dev/null +++ b/tests/ImagickContainerTest.php @@ -0,0 +1,27 @@ +setCore('foo'); + $this->assertEquals('foo', $container->getCore()); + } + + public function testCountFrames() + { + $imagick = Mockery::mock('Imagick'); + $imagick->shouldReceive('getnumberimages')->once()->andReturn(3); + $container = new Container($imagick); + $this->assertEquals(3, $container->countFrames()); + } +} diff --git a/tests/InsertCommandTest.php b/tests/InsertCommandTest.php deleted file mode 100644 index f2fa9001e..000000000 --- a/tests/InsertCommandTest.php +++ /dev/null @@ -1,66 +0,0 @@ -shouldReceive('align')->with('center', 10, 20)->once()->andReturn($image_size); - $watermark_size = Mockery::mock('\Intervention\Image\Size', array(800, 600)); - $watermark_size->shouldReceive('align')->with('center')->once()->andReturn($watermark_size); - $image_size->shouldReceive('relativePosition')->with($watermark_size)->once()->andReturn($position); - - $path = __DIR__.'/images/test.jpg'; - $resource = imagecreatefromjpeg($path); - $watermark = Mockery::mock('Intervention\Image\Image'); - $driver = Mockery::mock('Intervention\Image\Gd\Driver'); - $driver->shouldReceive('init')->with($path)->once()->andReturn($watermark); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->times(2)->andReturn($resource); - $image->shouldReceive('getSize')->once()->andReturn($image_size); - $watermark->shouldReceive('getSize')->once()->andReturn($watermark_size); - $watermark->shouldReceive('getCore')->once()->andReturn($resource); - - $command = new InsertGd(array($path, 'center', 10, 20)); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $position = Mockery::mock('\Intervention\Image\Point', array(10, 20)); - - $image_size = Mockery::mock('\Intervention\Image\Size', array(800, 600)); - $image_size->shouldReceive('align')->with('center', 10, 20)->once()->andReturn($image_size); - $watermark_size = Mockery::mock('\Intervention\Image\Size', array(800, 600)); - $watermark_size->shouldReceive('align')->with('center')->once()->andReturn($watermark_size); - $image_size->shouldReceive('relativePosition')->with($watermark_size)->once()->andReturn($position); - - $path = __DIR__.'/images/test.jpg'; - $watermark = Mockery::mock('Intervention\Image\Image'); - $driver = Mockery::mock('Intervention\Image\Imagick\Driver'); - $driver->shouldReceive('init')->with($path)->once()->andReturn($watermark); - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('compositeimage')->with($imagick, \Imagick::COMPOSITE_DEFAULT, 10, 20)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getSize')->once()->andReturn($image_size); - $watermark->shouldReceive('getSize')->once()->andReturn($watermark_size); - $watermark->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new InsertImagick(array($path, 'center', 10, 20)); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/GdSystemTest.php b/tests/IntegrationTestGd.php similarity index 98% rename from tests/GdSystemTest.php rename to tests/IntegrationTestGd.php index 5fdcd3397..4b21c9b86 100644 --- a/tests/GdSystemTest.php +++ b/tests/IntegrationTestGd.php @@ -1,6 +1,6 @@ manager()->canvas(16, 16, 'ffffff'); $img = $img->text('0', 3, 11); $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertEquals('a9e2b15452b2a4637b65625188d206f6', $img->checksum()); + $this->assertEquals('aebd2eea279b29f8d5264b9a53c1846e', $img->checksum()); - $img = $this->manager()->canvas(16, 16, 'ffffff'); - $img = $img->text('0', 8, 2, function($font) { + $img = $img->text('0', 8, 8, function($font) { + $font->file(3); $font->align('center'); - $font->valign('top'); + $font->valign('center'); $font->color('000000'); }); $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertEquals('649f3f529d3931c56601155fd2680959', $img->checksum()); + $this->assertEquals('9a11953d892c1e53659b9e3441ab3783', $img->checksum()); $img = $this->manager()->canvas(16, 16, 'ffffff'); $img = $img->text('0', 8, 8, function($font) { @@ -1044,35 +1044,48 @@ public function testTextImage() $font->color('000000'); }); $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertEquals('c0dda67589c46a90d78a97b891a811ee', $img->checksum()); + $this->assertEquals('6058fcde6d9273e02b94c38235aa7e28', $img->checksum()); + + $img = $this->manager()->canvas(100, 100, 'ffffff'); + $txt = 'The quick brown fox jumps over the lazy dog'; + $img = $img->text($txt, 10, 10, function($font) { + $font->align('center'); + $font->valign('top'); + $font->file(2); + $font->color('000000'); + $font->lineHeight(1.4); + $font->box(80, 80); + }); + $this->assertInstanceOf('Intervention\Image\Image', $img); + $this->assertEquals('36ab16d344a603cb87bac981a486f964', $img->checksum()); } public function testRectangleImage() { $img = $this->manager()->canvas(16, 16, 'ffffff'); $img->rectangle(5, 5, 11, 11, function ($draw) { $draw->background('#ff0000'); $draw->border(1, '#0000ff'); }); - $this->assertEquals('e95487dcc29daf371a0e9190bff8dbfe', $img->checksum()); + $this->assertEquals('e8c79ad201c20d54eedafde5c4d165f0', $img->checksum()); } public function testLineImage() { $img = $this->manager()->canvas(16, 16, 'ffffff'); $img->line(0, 0, 15, 15, function ($draw) { $draw->color('#ff0000'); }); - $this->assertEquals('a6237d34f6e95f30d2fc91a46bd058e6', $img->checksum()); + $this->assertEquals('92f5891680b215f699e4efd52aa4bfac', $img->checksum()); } public function testEllipseImage() { $img = $this->manager()->canvas(16, 16, 'ffffff'); $img->ellipse(12, 8, 8, 8, function ($draw) { $draw->background('#ff0000'); $draw->border(1, '#0000ff'); }); - $this->assertEquals('080d9dd92ebe22f976c3c703cba33510', $img->checksum()); + $this->assertEquals('e3231057c907a6f1457370e1f4f9d712', $img->checksum()); } public function testCircleImage() { $img = $this->manager()->canvas(16, 16, 'ffffff'); $img->circle(12, 8, 8, function ($draw) { $draw->background('#ff0000'); $draw->border(1, '#0000ff'); }); - $this->assertEquals('c3bff06c20244ba14e898e39ea0efd76', $img->checksum()); + $this->assertEquals('a109b98254329484489548b618d8cb92', $img->checksum()); } public function testPolygonImage() @@ -1080,7 +1093,7 @@ public function testPolygonImage() $img = $this->manager()->canvas(16, 16, 'ffffff'); $points = array(3, 3, 11, 11, 7, 13); $img->polygon($points, function ($draw) { $draw->background('#ff0000'); $draw->border(1, '#0000ff'); }); - $this->assertEquals('e534ff90c8026f9317b99071fda01ed4', $img->checksum()); + $this->assertEquals('37298b58a42eb1c664d52e10496a56cf', $img->checksum()); } public function testResetImage() diff --git a/tests/ImagickSystemTest.php b/tests/IntegrationTestImagick.php similarity index 99% rename from tests/ImagickSystemTest.php rename to tests/IntegrationTestImagick.php index 89b8f8ee6..0ea7192a8 100644 --- a/tests/ImagickSystemTest.php +++ b/tests/IntegrationTestImagick.php @@ -1,6 +1,6 @@ manager()->canvas(16, 16, 'ffffff'); $img->rectangle(5, 5, 11, 11, function ($draw) { $draw->background('#ff0000'); $draw->border(1, '#0000ff'); }); - $this->assertEquals('32ceca9759d1973dd461b39664df604d', $img->checksum()); + $this->assertEquals('d4a3924299387f5eb6f42c74626c9446', $img->checksum()); } public function testLineImage() { $img = $this->manager()->canvas(16, 16, 'ffffff'); $img->line(0, 0, 15, 15, function ($draw) { $draw->color('#ff0000'); }); - $this->assertEquals('f5c585019bff361d91e2928b2ac2286b', $img->checksum()); + $this->assertEquals('859b0c6cbd21cabd9e525efb5023ad27', $img->checksum()); } public function testEllipseImage() { $img = $this->manager()->canvas(16, 16, 'ffffff'); $img->ellipse(12, 8, 8, 8, function ($draw) { $draw->background('#ff0000'); $draw->border(1, '#0000ff'); }); - $this->assertEquals('9dc5bbec6d45868610c082a1d67640b5', $img->checksum()); + $this->assertEquals('74bcee1addf3309a8bd9f27171bf37f4', $img->checksum()); } public function testCircleImage() { $img = $this->manager()->canvas(16, 16, 'ffffff'); $img->circle(12, 8, 8, function ($draw) { $draw->background('#ff0000'); $draw->border(1, '#0000ff'); }); - $this->assertEquals('a433c7c1a842ef83e1cb45875371358c', $img->checksum()); + $this->assertEquals('bf6293c79bb50997bbb659e07bccfe37', $img->checksum()); } public function testPolygonImage() @@ -1057,7 +1057,7 @@ public function testPolygonImage() $img = $this->manager()->canvas(16, 16, 'ffffff'); $points = array(3, 3, 11, 11, 7, 13); $img->polygon($points, function ($draw) { $draw->background('#ff0000'); $draw->border(1, '#0000ff'); }); - $this->assertEquals('e301afe179da858d441ad8fc0eb5490a', $img->checksum()); + $this->assertEquals('0f77f38b9c500536fec937348d9abe88', $img->checksum()); } public function testResetImage() diff --git a/tests/InterlaceCommandTest.php b/tests/InterlaceCommandTest.php deleted file mode 100644 index 102f1faad..000000000 --- a/tests/InterlaceCommandTest.php +++ /dev/null @@ -1,33 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $command = new InterlaceGd(array(true)); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('setinterlacescheme')->with(\Imagick::INTERLACE_LINE)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new InterlaceImagick(array(true)); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/InvertCommandTest.php b/tests/InvertCommandTest.php deleted file mode 100644 index e7cabba25..000000000 --- a/tests/InvertCommandTest.php +++ /dev/null @@ -1,33 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $command = new InvertGd(array()); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('negateimage')->with(false)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new InvertImagick(array()); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/IptcCommandTest.php b/tests/IptcCommandTest.php deleted file mode 100644 index d1ca865ff..000000000 --- a/tests/IptcCommandTest.php +++ /dev/null @@ -1,71 +0,0 @@ -dirname = __DIR__.'/images'; - $image->basename = 'iptc.jpg'; - $command = new IptcCommand(array()); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertInternalType('array', $command->getOutput()); - } - - public function testFetchDefined() - { - $image = Mockery::mock('Intervention\Image\Image'); - $image->dirname = __DIR__.'/images'; - $image->basename = 'exif.jpg'; - $command = new IptcCommand(array('AuthorByline')); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertEquals('Oliver Vogel', $command->getOutput()); - } - - - public function testFetchNonExisting() - { - $image = Mockery::mock('Intervention\Image\Image'); - $image->dirname = __DIR__.'/images'; - $image->basename = 'exif.jpg'; - $command = new IptcCommand(array('xxx')); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertEquals(null, $command->getOutput()); - } - - - public function testFetchFromPng() - { - $image = Mockery::mock('Intervention\Image\Image'); - $image->dirname = __DIR__.'/images'; - $image->basename = 'star.png'; - $command = new IptcCommand(array('Orientation')); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertEquals(null, $command->getOutput()); - } - - public function testReturnNullOnIptcReadFail() - { - $image = Mockery::mock('Intervention\Image\Image'); - $command = new IptcCommand(array('Orientation')); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertEquals(null, $command->getOutput()); - } -} diff --git a/tests/LimitColorsCommandTest.php b/tests/LimitColorsCommandTest.php deleted file mode 100644 index 181343083..000000000 --- a/tests/LimitColorsCommandTest.php +++ /dev/null @@ -1,42 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('setCore')->once(); - $image->shouldReceive('getSize')->once()->andReturn($size); - $command = new LimitColorsGd(array(16)); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $size = Mockery::mock('\Intervention\Image\Size', array(32, 32)); - $imagick = Mockery::mock('\Imagick'); - $imagick->shouldReceive('separateimagechannel')->with(\Imagick::CHANNEL_ALPHA)->times(2); - $imagick->shouldReceive('transparentpaintimage')->with('#ffffff', 0, 0, false)->once(); - $imagick->shouldReceive('negateimage')->with(false)->once(); - $imagick->shouldReceive('quantizeimage')->with(16, \Imagick::COLORSPACE_RGB, 0, false, false)->once(); - $imagick->shouldReceive('compositeimage')->once(); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getSize')->once()->andReturn($size); - $image->shouldReceive('getCore')->times(3)->andReturn($imagick); - $command = new LimitColorsImagick(array(16)); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/LineCommandTest.php b/tests/LineCommandTest.php deleted file mode 100644 index 16495fd11..000000000 --- a/tests/LineCommandTest.php +++ /dev/null @@ -1,42 +0,0 @@ -shouldReceive('getDriverName')->once()->andReturn('Gd'); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $command = new LineCommand(array(10, 15, 100, 150)); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertFalse($command->hasOutput()); - } - - public function testImagick() - { - $imagick = Mockery::mock('\Imagick'); - $imagick->shouldReceive('drawimage'); - $driver = Mockery::mock('\Intervention\Image\Imagick\Driver'); - $driver->shouldReceive('getDriverName')->once()->andReturn('Imagick'); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - - $command = new LineCommand(array(10, 15, 100, 150)); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertFalse($command->hasOutput()); - } - -} diff --git a/tests/LineShapeTest.php b/tests/LineShapeTest.php index 506fd4ed0..0fc8253e4 100644 --- a/tests/LineShapeTest.php +++ b/tests/LineShapeTest.php @@ -24,26 +24,4 @@ public function testConstructor() $this->assertEquals(10, $line->x); $this->assertEquals(15, $line->y); } - - public function testApplyToImage() - { - // gd - $core = imagecreatetruecolor(300, 200); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $line = new LineGd(10, 15); - $result = $line->applyToImage($image, 100, 200); - $this->assertInstanceOf('Intervention\Image\Gd\Shapes\LineShape', $line); - $this->assertTrue($result); - - // imagick - $core = Mockery::mock('\Imagick'); - $core->shouldReceive('drawimage')->once(); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $line = new LineImagick(10, 15); - $result = $line->applyToImage($image, 100, 200); - $this->assertInstanceOf('Intervention\Image\Imagick\Shapes\LineShape', $line); - $this->assertTrue($result); - } } diff --git a/tests/MaskCommandTest.php b/tests/MaskCommandTest.php deleted file mode 100644 index fd9a734dc..000000000 --- a/tests/MaskCommandTest.php +++ /dev/null @@ -1,67 +0,0 @@ -shouldReceive('getSize')->once()->andReturn($mask_size); - $mask_image->shouldReceive('pickColor')->andReturn(array(0,0,0,0)); - - $canvas_image = Mockery::mock('Intervention\Image\Image'); - $canvas_core = imagecreatetruecolor(32, 32); - $canvas_image->shouldReceive('getCore')->times(2)->andReturn($canvas_core); - $canvas_image->shouldReceive('pixel'); - - $driver = Mockery::mock('Intervention\Image\Gd\Driver'); - $driver->shouldReceive('newImage')->with(32, 32, array(0,0,0,0))->once()->andReturn($canvas_image); - $driver->shouldReceive('init')->with($mask_path)->once()->andReturn($mask_image); - - $image_size = Mockery::mock('Intervention\Image\Size', array(32, 32)); - $image_core = imagecreatefrompng(__DIR__.'/images/trim.png'); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getSize')->once()->andReturn($image_size); - $image->shouldReceive('getDriver')->times(2)->andReturn($driver); - $image->shouldReceive('pickColor')->andReturn(array(0,0,0,0)); - $image->shouldReceive('setCore')->with($canvas_core)->once(); - - $command = new MaskGd(array($mask_path, true)); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $mask_core = Mockery::mock('Imagick'); - $mask_path = __DIR__.'images/star.png'; - $mask_image = Mockery::mock('Intervention\Image\Image'); - $mask_image->shouldReceive('getCore')->once()->andReturn($mask_core); - $mask_size = Mockery::mock('Intervention\Image\Size', array(32, 32)); - $mask_image->shouldReceive('getSize')->once()->andReturn($mask_size); - - $driver = Mockery::mock('Intervention\Image\Imagick\Driver'); - $driver->shouldReceive('init')->with($mask_path)->once()->andReturn($mask_image); - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('setimagematte')->with(true)->once(); - $imagick->shouldReceive('compositeimage')->with($mask_core, \Imagick::COMPOSITE_DSTIN, 0, 0)->once(); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $image_size = Mockery::mock('Intervention\Image\Size', array(32, 32)); - $image->shouldReceive('getSize')->once()->andReturn($image_size); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - - $command = new MaskImagick(array($mask_path, true)); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/MimeDetectorTest.php b/tests/MimeDetectorTest.php new file mode 100644 index 000000000..fa8016c9d --- /dev/null +++ b/tests/MimeDetectorTest.php @@ -0,0 +1,51 @@ +getMimeType(); + } + + public function testDetectJpeg() + { + $detector = new Detector(file_get_contents('tests/images/test.jpg')); + $this->assertEquals('image/jpeg', $detector->getMimeType()); + } + + public function testDetectPng() + { + $detector = new Detector(file_get_contents('tests/images/tile.png')); + $this->assertEquals('image/png', $detector->getMimeType()); + } + + public function testDetectGif() + { + $detector = new Detector(file_get_contents('tests/images/animation.gif')); + $this->assertEquals('image/gif', $detector->getMimeType()); + } + + public function testDetectBitmap() + { + $detector = new Detector(file_get_contents('tests/images/test.bmp')); + $this->assertEquals('image/bmp', $detector->getMimeType()); + } + + public function testDetectIco() + { + $detector = new Detector(file_get_contents('tests/images/test.ico')); + $this->assertEquals('image/x-icon', $detector->getMimeType()); + } + + public function testDetectWebp() + { + $detector = new Detector(file_get_contents('tests/images/test.webp')); + $this->assertEquals('image/webp', $detector->getMimeType()); + } +} diff --git a/tests/OpacityCommandTest.php b/tests/OpacityCommandTest.php deleted file mode 100644 index 9fdf7a98d..000000000 --- a/tests/OpacityCommandTest.php +++ /dev/null @@ -1,43 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($mask_core); - - $resource = imagecreatefrompng(__DIR__.'/images/trim.png'); - $driver = Mockery::mock('\Intervention\Image\Gd\Driver'); - $driver->shouldReceive('newImage')->with(32, 32, 'rgba(0, 0, 0, 0.5)')->andReturn($mask); - - $size = Mockery::mock('\Intervention\Image\Size', array(32, 32)); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getSize')->once()->andReturn($size); - $image->shouldReceive('mask')->with($mask_core, true)->once(); - $command = new OpacityGd(array(50)); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('evaluateimage')->with(\Imagick::EVALUATE_DIVIDE, 2, \Imagick::CHANNEL_ALPHA)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new OpacityImagick(array(50)); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/OrientateCommandTest.php b/tests/OrientateCommandTest.php deleted file mode 100644 index 6b86c23f3..000000000 --- a/tests/OrientateCommandTest.php +++ /dev/null @@ -1,93 +0,0 @@ -shouldReceive('exif')->with('Orientation')->once()->andReturn(2); - $image->shouldReceive('flip')->once(); - $command = new OrientateCommand(array()); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testExecuteOrientationThree() - { - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('exif')->with('Orientation')->once()->andReturn(3); - $image->shouldReceive('rotate')->with(180)->once(); - $command = new OrientateCommand(array()); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testExecuteOrientationFour() - { - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('exif')->with('Orientation')->once()->andReturn(4); - $image->shouldReceive('rotate')->with(180)->once()->andReturn($image); - $image->shouldReceive('flip')->once(); - $command = new OrientateCommand(array()); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testExecuteOrientationFive() - { - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('exif')->with('Orientation')->once()->andReturn(5); - $image->shouldReceive('rotate')->with(270)->once()->andReturn($image); - $image->shouldReceive('flip')->once(); - $command = new OrientateCommand(array()); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testExecuteOrientationSix() - { - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('exif')->with('Orientation')->once()->andReturn(6); - $image->shouldReceive('rotate')->with(270)->once(); - $command = new OrientateCommand(array()); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testExecuteOrientationSeven() - { - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('exif')->with('Orientation')->once()->andReturn(7); - $image->shouldReceive('rotate')->with(90)->once()->andReturn($image); - $image->shouldReceive('flip')->once(); - $command = new OrientateCommand(array()); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testExecuteOrientationEight() - { - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('exif')->with('Orientation')->once()->andReturn(8); - $image->shouldReceive('rotate')->with(90)->once(); - $command = new OrientateCommand(array()); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testExecuteOrientationNoExifData() - { - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('exif')->with('Orientation')->once()->andReturn(null); - $command = new OrientateCommand(array()); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/PickColorCommandTest.php b/tests/PickColorCommandTest.php deleted file mode 100644 index 731de04e5..000000000 --- a/tests/PickColorCommandTest.php +++ /dev/null @@ -1,66 +0,0 @@ -shouldReceive('getCore')->times(2)->andReturn($resource); - $command = new PickColorGd(array(1, 2)); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertInternalType('array', $command->getOutput()); - $this->assertEquals(4, count($command->getOutput())); - } - - public function testGdWithFormat() - { - $resource = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->times(2)->andReturn($resource); - $command = new PickColorGd(array(1, 2, 'hex')); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertInternalType('string', $command->getOutput()); - $this->assertEquals('#ffffff', $command->getOutput()); - } - - public function testImagickWithCoordinates() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('getimagepixelcolor')->with(1, 2)->andReturn(new ImagickPixel); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new PickColorImagick(array(1, 2)); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertInternalType('array', $command->getOutput()); - $this->assertEquals(4, count($command->getOutput())); - } - - public function testImagickWithFormat() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('getimagepixelcolor')->with(1, 2)->andReturn(new ImagickPixel('#ff0000')); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new PickColorImagick(array(1, 2, 'hex')); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertInternalType('string', $command->getOutput()); - $this->assertEquals('#ff0000', $command->getOutput()); - } -} diff --git a/tests/PixelCommandTest.php b/tests/PixelCommandTest.php deleted file mode 100644 index e1e2dcfb6..000000000 --- a/tests/PixelCommandTest.php +++ /dev/null @@ -1,33 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $command = new PixelGd(array('#b53717', 10, 20)); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('drawimage')->once()->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new PixelImagick(array('#b53717', 10, 20)); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/PixelateCommandTest.php b/tests/PixelateCommandTest.php deleted file mode 100644 index 76314ba4f..000000000 --- a/tests/PixelateCommandTest.php +++ /dev/null @@ -1,36 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $command = new PixelateGd(array(10)); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('scaleimage')->with(80, 60)->once()->andReturn(true); - $imagick->shouldReceive('scaleimage')->with(800, 600)->once()->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->times(2)->andReturn($imagick); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $command = new PixelateImagick(array(10)); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/PointTest.php b/tests/PointTest.php index aaac80d8b..e463bf245 100644 --- a/tests/PointTest.php +++ b/tests/PointTest.php @@ -36,6 +36,22 @@ public function testSetY() $this->assertEquals(100, $point->y); } + public function testmoveX() + { + $point = new Point(50, 50); + $point->moveX(100); + $this->assertEquals(150, $point->x); + $this->assertEquals(50, $point->y); + } + + public function testmoveY() + { + $point = new Point(50, 50); + $point->moveY(100); + $this->assertEquals(50, $point->x); + $this->assertEquals(150, $point->y); + } + public function testSetPosition() { $point = new Point(0, 0); @@ -43,4 +59,21 @@ public function testSetPosition() $this->assertEquals(100, $point->x); $this->assertEquals(200, $point->y); } + + public function testRotate() + { + $point = new Point(30, 0); + $point->rotate(90, new Point(0, 0)); + $this->assertEquals(0, $point->x); + $this->assertEquals(30, $point->y); + + $point->rotate(90, new Point(0, 0)); + $this->assertEquals(-30, $point->x); + $this->assertEquals(0, $point->y); + + $point = new Point(300, 200); + $point->rotate(90, new Point(0, 0)); + $this->assertEquals(-200, $point->x); + $this->assertEquals(300, $point->y); + } } diff --git a/tests/PolygonCommandTest.php b/tests/PolygonCommandTest.php deleted file mode 100644 index c3eaf7165..000000000 --- a/tests/PolygonCommandTest.php +++ /dev/null @@ -1,44 +0,0 @@ -shouldReceive('getDriverName')->once()->andReturn('Gd'); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $command = new PolygonCommand(array($points)); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertFalse($command->hasOutput()); - } - - public function testImagick() - { - $points = array(1, 2, 3, 4, 5, 6); - $imagick = Mockery::mock('\Imagick'); - $imagick->shouldReceive('drawimage'); - $driver = Mockery::mock('\Intervention\Image\Imagick\Driver'); - $driver->shouldReceive('getDriverName')->once()->andReturn('Imagick'); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - - $command = new PolygonCommand(array($points)); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertFalse($command->hasOutput()); - } - -} diff --git a/tests/PolygonShapeTest.php b/tests/PolygonShapeTest.php index 4f87b2b30..d28de3368 100644 --- a/tests/PolygonShapeTest.php +++ b/tests/PolygonShapeTest.php @@ -18,17 +18,6 @@ public function testGdConstructor() } - public function testGdApplyToImage() - { - $core = imagecreatetruecolor(300, 200); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $polygon = new PolygonGd(array(1, 2, 3, 4, 5, 6)); - $result = $polygon->applyToImage($image); - $this->assertInstanceOf('Intervention\Image\Gd\Shapes\PolygonShape', $polygon); - $this->assertTrue($result); - } - public function testImagickConstructor() { $polygon = new PolygonImagick(array(1, 2, 3, 4, 5, 6)); @@ -40,17 +29,4 @@ public function testImagickConstructor() $polygon->points); } - - public function testImagickApplyToImage() - { - $core = Mockery::mock('\Imagick'); - $core->shouldReceive('drawimage')->once(); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $polygon = new PolygonImagick(array(1, 2, 3, 4, 5, 6)); - $result = $polygon->applyToImage($image); - $this->assertInstanceOf('Intervention\Image\Imagick\Shapes\PolygonShape', $polygon); - $this->assertTrue($result); - } - } diff --git a/tests/PsrResponseCommandTest.php b/tests/PsrResponseCommandTest.php deleted file mode 100644 index b28a45f99..000000000 --- a/tests/PsrResponseCommandTest.php +++ /dev/null @@ -1,57 +0,0 @@ -'; - - $image = Mockery::mock('Intervention\Image\Image'); - $stream = \GuzzleHttp\Psr7\stream_for($encodedContent); - - $image->shouldReceive('stream') - ->with('jpg', 87) - ->once() - ->andReturn($stream); - - $image->shouldReceive('getEncoded') - ->twice() - ->andReturn($encodedContent); - - $command = new PsrResponseCommand(array('jpg', 87)); - $result = $command->execute($image); - - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - - $output = $command->getOutput(); - - $this->assertInstanceOf('Psr\Http\Message\ResponseInterface', $output); - - /** - * @var \Psr\Http\Message\ResponseInterface $output - */ - $this->assertEquals($stream, $output->getBody()); - $this->assertEquals($encodedContent, (string)$output->getBody()); - - $this->assertTrue($output->hasHeader('Content-Type')); - $this->assertTrue($output->hasHeader('Content-Length')); - - $this->assertEquals( - "application/xml", - $output->getHeaderLine('Content-Type') - ); - - $this->assertEquals( - strlen($encodedContent), - $output->getHeaderLine('Content-Length') - ); - } -} \ No newline at end of file diff --git a/tests/RectangleCommandTest.php b/tests/RectangleCommandTest.php deleted file mode 100644 index d3742f132..000000000 --- a/tests/RectangleCommandTest.php +++ /dev/null @@ -1,42 +0,0 @@ -shouldReceive('getDriverName')->once()->andReturn('Gd'); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $command = new RectangleCommand(array(10, 15, 100, 150)); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertFalse($command->hasOutput()); - } - - public function testImagick() - { - $imagick = Mockery::mock('\Imagick'); - $imagick->shouldReceive('drawimage'); - $driver = Mockery::mock('\Intervention\Image\Imagick\Driver'); - $driver->shouldReceive('getDriverName')->once()->andReturn('Imagick'); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - - $command = new RectangleCommand(array(10, 15, 100, 150)); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertFalse($command->hasOutput()); - } - -} diff --git a/tests/RectangleShapeTest.php b/tests/RectangleShapeTest.php index 1f652ab0d..67f03440c 100644 --- a/tests/RectangleShapeTest.php +++ b/tests/RectangleShapeTest.php @@ -28,26 +28,4 @@ public function testConstructor() $this->assertEquals(100, $rectangle->x2); $this->assertEquals(150, $rectangle->y2); } - - public function testApplyToImage() - { - // gd - $core = imagecreatetruecolor(300, 200); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $rectangle = new RectangleGd(10, 15, 100, 150); - $result = $rectangle->applyToImage($image, 10, 20); - $this->assertInstanceOf('Intervention\Image\Gd\Shapes\RectangleShape', $rectangle); - $this->assertTrue($result); - - // imagick - $core = Mockery::mock('\Imagick'); - $core->shouldReceive('drawimage')->once(); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $rectangle = new RectangleImagick(10, 15, 100, 150); - $result = $rectangle->applyToImage($image, 10, 20); - $this->assertInstanceOf('Intervention\Image\Imagick\Shapes\RectangleShape', $rectangle); - $this->assertTrue($result); - } } diff --git a/tests/ResetCommandTest.php b/tests/ResetCommandTest.php deleted file mode 100644 index 18d823dda..000000000 --- a/tests/ResetCommandTest.php +++ /dev/null @@ -1,70 +0,0 @@ -shouldReceive('cloneCore')->with($resource)->once()->andReturn($resource); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('setCore')->once(); - $image->shouldReceive('getBackup')->once()->andReturn($resource); - $command = new ResetGd(array()); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testGdWithName() - { - $size = Mockery::mock('Intervention\Image\Size', array(800, 600)); - $resource = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $image = Mockery::mock('Intervention\Image\Image'); - $driver = Mockery::mock('Intervention\Image\Gd\Driver'); - $driver->shouldReceive('cloneCore')->with($resource)->once()->andReturn($resource); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('setCore')->once(); - $image->shouldReceive('getBackup')->once()->withArgs(array('fooBackup'))->andReturn($resource); - $command = new ResetGd(array('fooBackup')); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagickWithoutName() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('clear')->once(); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $image->shouldReceive('setCore')->once(); - $image->shouldReceive('getBackup')->once()->andReturn($imagick); - $command = new ResetImagick(array()); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagickWithName() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('clear')->once(); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $image->shouldReceive('setCore')->once(); - $image->shouldReceive('getBackup')->once()->withArgs(array('fooBackup'))->andReturn($imagick); - $command = new ResetImagick(array('fooBackup')); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/ResizeCanvasCommandTest.php b/tests/ResizeCanvasCommandTest.php deleted file mode 100644 index c183ff1bf..000000000 --- a/tests/ResizeCanvasCommandTest.php +++ /dev/null @@ -1,79 +0,0 @@ -shouldReceive('align')->with('center')->andReturn($canvas_size); - $canvas_size->shouldReceive('relativePosition')->andReturn($canvas_pos); - $image_pos = Mockery::mock('\Intervention\Image\Point', array(0, 0)); - $image_size = Mockery::mock('\Intervention\Image\Size', array(800, 600)); - $image_size->shouldReceive('align')->with('center')->andReturn($image_size); - $image_size->shouldReceive('relativePosition')->andReturn($image_pos); - $canvas = Mockery::mock('\Intervention\Image\Image'); - $canvas->shouldReceive('getCore')->times(5)->andReturn($resource); - $canvas->shouldReceive('getSize')->andReturn($canvas_size); - $driver = Mockery::mock('\Intervention\Image\Gd\Driver'); - $driver->shouldReceive('newImage')->with(820, 640, '#b53717')->once()->andReturn($canvas); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getSize')->once()->andReturn($image_size); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('setCore')->once(); - $command = new ResizeCanvasGd(array(20, 40, 'center', true, '#b53717')); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $canvas_pos = Mockery::mock('\Intervention\Image\Point', array(0, 0)); - $canvas_size = Mockery::mock('\Intervention\Image\Size', array(820, 640)); - $canvas_size->shouldReceive('align')->with('center')->andReturn($canvas_size); - $canvas_size->shouldReceive('relativePosition')->andReturn($canvas_pos); - $image_pos = Mockery::mock('\Intervention\Image\Point', array(0, 0)); - $image_size = Mockery::mock('\Intervention\Image\Size', array(800, 600)); - $image_size->shouldReceive('align')->with('center')->andReturn($image_size); - $image_size->shouldReceive('relativePosition')->andReturn($image_pos); - $canvas = Mockery::mock('\Intervention\Image\Image'); - - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('cropimage')->with(800, 600, 0, 0)->once(); - $imagick->shouldReceive('compositeimage')->with($imagick, 40, 0, 0)->once(); - $imagick->shouldReceive('setimagepage')->with(0, 0, 0, 0)->once(); - $imagick->shouldReceive('drawimage')->once(); - $imagick->shouldReceive('transparentpaintimage')->once(); - $imagick->shouldReceive('getimagecolorspace')->once(); - $imagick->shouldReceive('setimagecolorspace')->once(); - - $canvas->shouldReceive('getCore')->times(6)->andReturn($imagick); - $canvas->shouldReceive('getSize')->andReturn($canvas_size); - $canvas->shouldReceive('pickColor')->with(0, 0, 'hex')->once()->andReturn('#000000'); - $driver = Mockery::mock('\Intervention\Image\Gd\Driver'); - $driver->shouldReceive('newImage')->with(820, 640, '#b53717')->once()->andReturn($canvas); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getSize')->once()->andReturn($image_size); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $image->shouldReceive('getCore')->times(3)->andReturn($imagick); - $image->shouldReceive('setCore')->once(); - $command = new ResizeCanvasImagick(array(20, 40, 'center', true, '#b53717')); - $result = $command->execute($image); - $this->assertTrue($result); - } - -} diff --git a/tests/ResizeCommandTest.php b/tests/ResizeCommandTest.php deleted file mode 100644 index e9af7669b..000000000 --- a/tests/ResizeCommandTest.php +++ /dev/null @@ -1,48 +0,0 @@ -upsize(); }; - $resource = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $image = Mockery::mock('Intervention\Image\Image'); - $size = Mockery::mock('Intervention\Image\Size', array(800, 600)); - $size->shouldReceive('resize')->with(300, 200, $callback)->once()->andReturn($size); - $size->shouldReceive('getWidth')->once()->andReturn(800); - $size->shouldReceive('getHeight')->once()->andReturn(600); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $image->shouldReceive('getSize')->once()->andReturn($size); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('setCore')->once(); - $command = new ResizeCommandGd(array(300, 200, $callback)); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $callback = function ($constraint) { $constraint->upsize(); }; - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('scaleimage')->with(300, 200)->once()->andReturn(true); - $size = Mockery::mock('Intervention\Image\Size', array(800, 600)); - $size->shouldReceive('resize')->with(300, 200, $callback)->once()->andReturn($size); - $size->shouldReceive('getWidth')->once()->andReturn(300); - $size->shouldReceive('getHeight')->once()->andReturn(200); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $image->shouldReceive('getSize')->once()->andReturn($size); - $command = new ResizeCommandImagick(array(300, 200, $callback)); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/RotateCommandTest.php b/tests/RotateCommandTest.php deleted file mode 100644 index dedf8a0fc..000000000 --- a/tests/RotateCommandTest.php +++ /dev/null @@ -1,35 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('setCore')->once()->andReturn($resource); - $command = new RotateGd(array(45, '#b53717')); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $pixel = Mockery::mock('ImagickPixel', array('#b53717')); - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('rotateimage')->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new RotateImagick(array(45, '#b53717')); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/SharpenCommandTest.php b/tests/SharpenCommandTest.php deleted file mode 100644 index b88869468..000000000 --- a/tests/SharpenCommandTest.php +++ /dev/null @@ -1,33 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $command = new SharpenGd(array(50)); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('unsharpmaskimage')->with(1, 1, 8, 0)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new SharpenImagick(array(50)); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/SizeTest.php b/tests/SizeTest.php index 4be87ee09..79c84cb32 100644 --- a/tests/SizeTest.php +++ b/tests/SizeTest.php @@ -424,6 +424,125 @@ public function testFitsInto() $this->assertFalse($fits); } + public function testRotate() + { + $box = new Size(300, 200); + $box = $box->rotate(90); + $this->assertEquals(200, $box->width); + $this->assertEquals(300, $box->height); + $this->assertEquals(0, $box->pivot->x); + $this->assertEquals(300, $box->pivot->y); + + $box = new Size(300, 200); + $box = $box->rotate(180); + $this->assertEquals(300, $box->width); + $this->assertEquals(200, $box->height); + $this->assertEquals(300, $box->pivot->x); + $this->assertEquals(200, $box->pivot->y); + + $box = new Size(300, 200); + $box = $box->rotate(270); + $this->assertEquals(200, $box->width); + $this->assertEquals(300, $box->height); + $this->assertEquals(200, $box->pivot->x); + $this->assertEquals(0, $box->pivot->y); + + $box = new Size(300, 200); + $box = $box->rotate(360); + $this->assertEquals(300, $box->width); + $this->assertEquals(200, $box->height); + $this->assertEquals(0, $box->pivot->x); + $this->assertEquals(0, $box->pivot->y); + + $box = new Size(200, 200); + $box = $box->rotate(45); + $this->assertEquals(282, $box->width); + $this->assertEquals(282, $box->height); + $this->assertEquals(0, $box->pivot->x); + $this->assertEquals(141, $box->pivot->y); + + $box = new Size(300, 200); + $box = $box->rotate(45); + $this->assertEquals(353, $box->width); + $this->assertEquals(353, $box->height); + $this->assertEquals(0, $box->pivot->x); + $this->assertEquals(212, $box->pivot->y); + + $box = new Size(300, 200); + $box->align('bottom-right'); + $box = $box->rotate(45); + $this->assertEquals(353, $box->width); + $this->assertEquals(354, $box->height); + $this->assertEquals(353, $box->pivot->x); + $this->assertEquals(142, $box->pivot->y); + + $box = new Size(300, 200); + $box->align('center'); + $box = $box->rotate(100); + $this->assertEquals(249, $box->width); + $this->assertEquals(330, $box->height); + $this->assertEquals(125, $box->pivot->x); + $this->assertEquals(165, $box->pivot->y); + + $box = new Size(300, 200); + $box->align('left-bottom'); + $box = $box->rotate(90); + $this->assertEquals(200, $box->width); + $this->assertEquals(300, $box->height); + $this->assertEquals(200, $box->pivot->x); + $this->assertEquals(300, $box->pivot->y); + } + + public function testResizeCanvas() + { + $box = new Size(300, 200); + $box->resizeCanvas(400, 500); + $this->assertEquals(400, $box->width); + $this->assertEquals(500, $box->height); + $this->assertEquals(0, $box->pivot->x); + $this->assertEquals(0, $box->pivot->y); + + $box = new Size(300, 200); + $box->align('top'); + $box->resizeCanvas(50, 100, true); + $this->assertEquals(400, $box->width); + $this->assertEquals(400, $box->height); + $this->assertEquals(200, $box->pivot->x); + $this->assertEquals(0, $box->pivot->y); + + $box = new Size(300, 200); + $box->align('center'); + $box->resizeCanvas(150, 120, true); + $this->assertEquals(600, $box->width); + $this->assertEquals(440, $box->height); + $this->assertEquals(300, $box->pivot->x); + $this->assertEquals(220, $box->pivot->y); + + $box = new Size(300, 200); + $box->align('right'); + $box->resizeCanvas(300, 1000); + $this->assertEquals(300, $box->width); + $this->assertEquals(1000, $box->height); + $this->assertEquals(300, $box->pivot->x); + $this->assertEquals(500, $box->pivot->y); + + $box = new Size(300, 200); + $box->align('right-bottom'); + $box->resizeCanvas(50, 100); + $this->assertEquals(50, $box->width); + $this->assertEquals(100, $box->height); + $this->assertEquals(50, $box->pivot->x); + $this->assertEquals(100, $box->pivot->y); + + $box = new Size(300, 200); + $box->align('bottom'); + $box->resizeCanvas(50, 100); + $this->assertEquals(50, $box->width); + $this->assertEquals(100, $box->height); + $this->assertEquals(25, $box->pivot->x); + $this->assertEquals(100, $box->pivot->y); + } + /** * @expectedException \Intervention\Image\Exception\InvalidArgumentException */ diff --git a/tests/StreamCommandTest.php b/tests/StreamCommandTest.php deleted file mode 100644 index 79d1048f1..000000000 --- a/tests/StreamCommandTest.php +++ /dev/null @@ -1,35 +0,0 @@ -shouldReceive('encode') - ->with('jpg', 87) - ->once() - ->andReturnSelf(); - - $image->shouldReceive('getEncoded') - ->once() - ->andReturn($encodedContent); - - $command = new StreamCommand(array('jpg', 87)); - $result = $command->execute($image); - - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - - $output = $command->getOutput(); - $this->assertInstanceOf('Psr\Http\Message\StreamInterface', $output); - $this->assertEquals($encodedContent, (string)$output); - } -} \ No newline at end of file diff --git a/tests/TextCommandTest.php b/tests/TextCommandTest.php deleted file mode 100644 index 53df1650d..000000000 --- a/tests/TextCommandTest.php +++ /dev/null @@ -1,31 +0,0 @@ -shouldReceive('getDriverName')->once()->andReturn('Gd'); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $command = new TextCommand(array('test', 10, 20)); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertFalse($command->hasOutput()); - } - - public function testImagick() - { - # code... - } - -} diff --git a/tests/TrimCommandTest.php b/tests/TrimCommandTest.php deleted file mode 100644 index de6d65ee1..000000000 --- a/tests/TrimCommandTest.php +++ /dev/null @@ -1,53 +0,0 @@ -shouldReceive('differs')->with($baseColor, 45)->andReturn(true); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $image->shouldReceive('pickColor')->with(0, 0, 'object')->times(2)->andReturn($baseColor); - $image->shouldReceive('pickColor')->with(799, 0, 'object')->once()->andReturn($baseColor); - $image->shouldReceive('setCore')->once(); - $command = new TrimGd(array('top-left', array('left', 'right'), 45, 2)); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $baseColorPixel = new \ImagickPixel; - $baseColor = Mockery::mock('Intervention\Image\Gd\Color'); - $baseColor->shouldReceive('getPixel')->once()->andReturn($baseColorPixel); - $imagick = Mockery::mock('Imagick'); - $imagick->width = 100; - $imagick->height = 100; - $imagick->shouldReceive('borderimage')->with($baseColorPixel, 1, 1)->once()->andReturn(true); - $imagick->shouldReceive('trimimage')->with(29632.5)->once()->andReturn(true); - $imagick->shouldReceive('getimagepage')->once()->andReturn(array('x' => 50, 'y' => 50)); - $imagick->shouldReceive('cropimage')->with(104, 202, 47, 0)->once()->andReturn(true); - $imagick->shouldReceive('setimagepage')->with(0, 0, 0, 0)->once()->andReturn(true); - $imagick->shouldReceive('destroy')->with()->once()->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $image->shouldReceive('pickColor')->with(0, 0, 'object')->once()->andReturn($baseColor); - $image->shouldReceive('getCore')->times(3)->andReturn($imagick); - $command = new TrimImagick(array('top-left', array('left', 'right'), 45, 2)); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/WidenCommandTest.php b/tests/WidenCommandTest.php deleted file mode 100644 index a5444dfb3..000000000 --- a/tests/WidenCommandTest.php +++ /dev/null @@ -1,48 +0,0 @@ -aspectRatio(); }; - $resource = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $image = Mockery::mock('Intervention\Image\Image'); - $size = Mockery::mock('Intervention\Image\Size', array(800, 600)); - $size->shouldReceive('resize')->once()->andReturn($size); - $size->shouldReceive('getWidth')->once()->andReturn(800); - $size->shouldReceive('getHeight')->once()->andReturn(600); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $image->shouldReceive('getSize')->once()->andReturn($size); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('setCore')->once(); - $command = new WidenGd(array(200)); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $callback = function ($constraint) { $constraint->upsize(); }; - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('scaleimage')->with(300, 200)->once()->andReturn(true); - $size = Mockery::mock('Intervention\Image\Size', array(800, 600)); - $size->shouldReceive('resize')->once()->andReturn($size); - $size->shouldReceive('getWidth')->once()->andReturn(300); - $size->shouldReceive('getHeight')->once()->andReturn(200); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $image->shouldReceive('getSize')->once()->andReturn($size); - $command = new WidenImagick(array(200)); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/images/animation.gif b/tests/images/animation.gif new file mode 100644 index 000000000..c45bb7771 Binary files /dev/null and b/tests/images/animation.gif differ diff --git a/tests/images/frame1.png b/tests/images/frame1.png new file mode 100644 index 000000000..ed59bbe4f Binary files /dev/null and b/tests/images/frame1.png differ diff --git a/tests/images/frame2.png b/tests/images/frame2.png new file mode 100644 index 000000000..f126811de Binary files /dev/null and b/tests/images/frame2.png differ diff --git a/tests/images/frame3.png b/tests/images/frame3.png new file mode 100644 index 000000000..3875688ce Binary files /dev/null and b/tests/images/frame3.png differ diff --git a/tests/images/test.bmp b/tests/images/test.bmp new file mode 100644 index 000000000..61bbc71b4 Binary files /dev/null and b/tests/images/test.bmp differ diff --git a/tests/images/test.ico b/tests/images/test.ico new file mode 100644 index 000000000..a6e497f09 Binary files /dev/null and b/tests/images/test.ico differ diff --git a/tests/images/test.webp b/tests/images/test.webp new file mode 100644 index 000000000..8fa3cad0c Binary files /dev/null and b/tests/images/test.webp differ