mirror of
https://github.com/Intervention/image.git
synced 2025-08-28 16:19:50 +02:00
Modifier & tests
This commit is contained in:
@@ -36,6 +36,11 @@ abstract class AbstractImage
|
||||
return $this->frames;
|
||||
}
|
||||
|
||||
public function getFrame(int $key = 0): ?FrameInterface
|
||||
{
|
||||
return $this->frames->get($key);
|
||||
}
|
||||
|
||||
public function addFrame(FrameInterface $frame): ImageInterface
|
||||
{
|
||||
$this->frames->push($frame);
|
||||
@@ -115,6 +120,16 @@ abstract class AbstractImage
|
||||
);
|
||||
}
|
||||
|
||||
public function pickColors(int $x, int $y): Collection
|
||||
{
|
||||
$colors = new Collection();
|
||||
foreach ($this->getFrames() as $key => $frame) {
|
||||
$colors->push($this->pickColor($x, $y, $key));
|
||||
}
|
||||
|
||||
return $colors;
|
||||
}
|
||||
|
||||
public function resize(...$arguments): ImageInterface
|
||||
{
|
||||
$size = $this->getResizer()->setTargetSizeByArray($arguments)->resize();
|
||||
@@ -150,4 +165,17 @@ abstract class AbstractImage
|
||||
$this->resolveDriverClass('Modifiers\ResizeModifier', $size)
|
||||
);
|
||||
}
|
||||
|
||||
public function place($element, string $position = 'top-left', int $offset_x = 0, int $offset_y = 0): ImageInterface
|
||||
{
|
||||
return $this->modify(
|
||||
$this->resolveDriverClass(
|
||||
'Modifiers\PlaceModifier',
|
||||
$element,
|
||||
$position,
|
||||
$offset_x,
|
||||
$offset_y
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Intervention\Image\Drivers\Gd\Decoders;
|
||||
|
||||
use GdImage;
|
||||
use Intervention\Image\Collection;
|
||||
use Intervention\Image\Drivers\Abstract\Decoders\AbstractDecoder;
|
||||
use Intervention\Image\Drivers\Gd\Frame;
|
||||
@@ -26,13 +27,15 @@ class BinaryImageDecoder extends AbstractDecoder implements DecoderInterface
|
||||
return $this->decodeGif($input); // decode (animated) gif
|
||||
}
|
||||
|
||||
$resource = @imagecreatefromstring($input);
|
||||
$gd = @imagecreatefromstring($input);
|
||||
|
||||
if ($resource === false) {
|
||||
if ($gd === false) {
|
||||
$this->fail();
|
||||
}
|
||||
|
||||
return new Image(new Collection([new Frame($resource)]));
|
||||
$gd = $this->gdImageToTruecolor($gd);
|
||||
|
||||
return new Image(new Collection([new Frame($gd)]));
|
||||
}
|
||||
|
||||
protected function decodeGif($input): ImageInterface
|
||||
@@ -55,4 +58,32 @@ class BinaryImageDecoder extends AbstractDecoder implements DecoderInterface
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform GD image into truecolor version
|
||||
*
|
||||
* @param GdImage $gd
|
||||
* @return bool
|
||||
*/
|
||||
public function gdImageToTruecolor(GdImage $gd): GdImage
|
||||
{
|
||||
$width = imagesx($gd);
|
||||
$height = imagesy($gd);
|
||||
|
||||
// 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, $gd, 0, 0, 0, 0, $width, $height);
|
||||
imagedestroy($gd);
|
||||
|
||||
return $canvas;
|
||||
}
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@ use Intervention\Image\Drivers\Abstract\AbstractImage;
|
||||
use Intervention\Image\Drivers\Gd\Frame;
|
||||
use Intervention\Image\Geometry\Resizer;
|
||||
use Intervention\Image\Geometry\Size;
|
||||
use Intervention\Image\Interfaces\ColorInterface;
|
||||
use Intervention\Image\Interfaces\EncoderInterface;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
use Intervention\Image\Interfaces\SizeInterface;
|
||||
@@ -17,11 +18,20 @@ class Image extends AbstractImage implements ImageInterface, IteratorAggregate
|
||||
{
|
||||
public function width(): int
|
||||
{
|
||||
return imagesx($this->frames->first()->getCore());
|
||||
return imagesx($this->getFrame()->getCore());
|
||||
}
|
||||
|
||||
public function height(): int
|
||||
{
|
||||
return imagesy($this->frames->first()->getCore());
|
||||
return imagesy($this->getFrame()->getCore());
|
||||
}
|
||||
|
||||
public function pickColor(int $x, int $y, int $frame_key = 0): ?ColorInterface
|
||||
{
|
||||
if ($frame = $this->getFrame($frame_key)) {
|
||||
return new Color(imagecolorat($frame->getCore(), $x, $y));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ use Intervention\Image\Collection;
|
||||
use Intervention\Image\Drivers\Abstract\AbstractImage;
|
||||
use Intervention\Image\Drivers\Imagick\Frame;
|
||||
use Intervention\Image\Geometry\Size;
|
||||
use Intervention\Image\Interfaces\ColorInterface;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
use Intervention\Image\Interfaces\SizeInterface;
|
||||
use IteratorAggregate;
|
||||
@@ -22,4 +23,13 @@ class Image extends AbstractImage implements ImageInterface, IteratorAggregate
|
||||
{
|
||||
return $this->frames->first()->getCore()->getImageHeight();
|
||||
}
|
||||
|
||||
public function pickColor(int $x, int $y, int $frame_key = 0): ?ColorInterface
|
||||
{
|
||||
if ($frame = $this->getFrame($frame_key)) {
|
||||
return new Color($frame->getCore()->getImagePixelColor($x, $y));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Intervention\Image\Interfaces;
|
||||
|
||||
use Intervention\Image\Collection;
|
||||
use Intervention\Image\EncodedImage;
|
||||
|
||||
interface ImageInterface
|
||||
@@ -14,4 +15,6 @@ interface ImageInterface
|
||||
public function encode(EncoderInterface $encoder): EncodedImage;
|
||||
public function setLoops(int $count): ImageInterface;
|
||||
public function loops(): int;
|
||||
public function pickColor(int $x, int $y, int $frame_key = 0): ?ColorInterface;
|
||||
public function pickColors(int $x, int $y): Collection;
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@
|
||||
namespace Intervention\Image\Tests\Drivers\Gd;
|
||||
|
||||
use Intervention\Image\Collection;
|
||||
use Intervention\Image\Drivers\Gd\Color;
|
||||
use Intervention\Image\Drivers\Gd\Frame;
|
||||
use Intervention\Image\Drivers\Gd\Image;
|
||||
use Intervention\Image\Geometry\Size;
|
||||
@@ -14,7 +15,17 @@ class ImageTest extends TestCase
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->image = new Image(new Collection([new Frame(imagecreatetruecolor(3, 2))]));
|
||||
$gd1 = imagecreatetruecolor(3, 2);
|
||||
imagefill($gd1, 0, 0, imagecolorallocate($gd1, 255, 0, 0));
|
||||
$gd2 = imagecreatetruecolor(3, 2);
|
||||
imagefill($gd2, 0, 0, imagecolorallocate($gd1, 0, 255, 0));
|
||||
$gd3 = imagecreatetruecolor(3, 2);
|
||||
imagefill($gd3, 0, 0, imagecolorallocate($gd1, 0, 0, 255));
|
||||
$this->image = new Image(new Collection([
|
||||
new Frame($gd1),
|
||||
new Frame($gd2),
|
||||
new Frame($gd3),
|
||||
]));
|
||||
}
|
||||
|
||||
public function testConstructor(): void
|
||||
@@ -43,4 +54,47 @@ class ImageTest extends TestCase
|
||||
{
|
||||
$this->assertInstanceOf(Size::class, $this->image->getSize());
|
||||
}
|
||||
|
||||
public function testPickColor(): void
|
||||
{
|
||||
$color = $this->image->pickColor(0, 0);
|
||||
$this->assertInstanceOf(Color::class, $color);
|
||||
$this->assertEquals(255, $color->red());
|
||||
$this->assertEquals(0, $color->green());
|
||||
$this->assertEquals(0, $color->blue());
|
||||
|
||||
$color = $this->image->pickColor(0, 0, 1);
|
||||
$this->assertInstanceOf(Color::class, $color);
|
||||
$this->assertEquals(0, $color->red());
|
||||
$this->assertEquals(255, $color->green());
|
||||
$this->assertEquals(0, $color->blue());
|
||||
|
||||
$color = $this->image->pickColor(0, 0, 2);
|
||||
$this->assertInstanceOf(Color::class, $color);
|
||||
$this->assertEquals(0, $color->red());
|
||||
$this->assertEquals(0, $color->green());
|
||||
$this->assertEquals(255, $color->blue());
|
||||
|
||||
$color = $this->image->pickColor(0, 0, 3);
|
||||
$this->assertNull($color);
|
||||
}
|
||||
|
||||
public function testPickColors(): void
|
||||
{
|
||||
$colors = $this->image->pickColors(0, 0);
|
||||
$this->assertInstanceOf(Collection::class, $colors);
|
||||
$this->assertCount(3, $colors);
|
||||
|
||||
$this->assertEquals(255, $colors->get(0)->red());
|
||||
$this->assertEquals(0, $colors->get(0)->green());
|
||||
$this->assertEquals(0, $colors->get(0)->blue());
|
||||
|
||||
$this->assertEquals(0, $colors->get(1)->red());
|
||||
$this->assertEquals(255, $colors->get(1)->green());
|
||||
$this->assertEquals(0, $colors->get(1)->blue());
|
||||
|
||||
$this->assertEquals(0, $colors->get(2)->red());
|
||||
$this->assertEquals(0, $colors->get(2)->green());
|
||||
$this->assertEquals(255, $colors->get(2)->blue());
|
||||
}
|
||||
}
|
||||
|
21
tests/Drivers/Gd/Modifiers/BlurModifierTest.php
Normal file
21
tests/Drivers/Gd/Modifiers/BlurModifierTest.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Tests\Drivers\Gd\Modifiers;
|
||||
|
||||
use Intervention\Image\Drivers\Gd\Image;
|
||||
use Intervention\Image\Drivers\Gd\Modifiers\BlurModifier;
|
||||
use Intervention\Image\Tests\TestCase;
|
||||
use Intervention\Image\Tests\Traits\CanCreateGdTestImage;
|
||||
|
||||
class BlurModifierTest extends TestCase
|
||||
{
|
||||
use CanCreateGdTestImage;
|
||||
|
||||
public function testColorChange(): void
|
||||
{
|
||||
$image = $this->createTestImage('trim.png');
|
||||
$this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());
|
||||
$image->modify(new BlurModifier(30));
|
||||
$this->assertEquals('4fa68d', $image->pickColor(14, 14)->toHex());
|
||||
}
|
||||
}
|
21
tests/Drivers/Imagick/Modifiers/BlurModifierTest.php
Normal file
21
tests/Drivers/Imagick/Modifiers/BlurModifierTest.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Tests\Drivers\Imagick\Modifiers;
|
||||
|
||||
use Intervention\Image\Tests\TestCase;
|
||||
use Intervention\Image\Drivers\Imagick\Image;
|
||||
use Intervention\Image\Drivers\Imagick\Modifiers\BlurModifier;
|
||||
use Intervention\Image\Tests\Traits\CanCreateImagickTestImage;
|
||||
|
||||
class BlurModifierTest extends TestCase
|
||||
{
|
||||
use CanCreateImagickTestImage;
|
||||
|
||||
public function testColorChange(): void
|
||||
{
|
||||
$image = $this->createTestImage('trim.png');
|
||||
$this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());
|
||||
$image->modify(new BlurModifier(30));
|
||||
$this->assertEquals('42acb2', $image->pickColor(14, 14)->toHex());
|
||||
}
|
||||
}
|
38
tests/Traits/CanCreateGdTestImage.php
Normal file
38
tests/Traits/CanCreateGdTestImage.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Tests\Traits;
|
||||
|
||||
use Intervention\Image\Collection;
|
||||
use Intervention\Image\Drivers\Gd\Decoders\FilePathImageDecoder;
|
||||
use Intervention\Image\Drivers\Gd\Frame;
|
||||
use Intervention\Image\Drivers\Gd\Image;
|
||||
|
||||
trait CanCreateGdTestImage
|
||||
{
|
||||
public function createTestImage($filename = 'test.jpg'): Image
|
||||
{
|
||||
return $this->testImageDecoder()->handle(
|
||||
sprintf('%s/../images/%s', __DIR__, $filename)
|
||||
);
|
||||
}
|
||||
|
||||
public function createTestAnimation(): Image
|
||||
{
|
||||
$gd1 = imagecreatetruecolor(3, 2);
|
||||
imagefill($gd1, 0, 0, imagecolorallocate($gd1, 255, 0, 0));
|
||||
$gd2 = imagecreatetruecolor(3, 2);
|
||||
imagefill($gd2, 0, 0, imagecolorallocate($gd1, 0, 255, 0));
|
||||
$gd3 = imagecreatetruecolor(3, 2);
|
||||
imagefill($gd3, 0, 0, imagecolorallocate($gd1, 0, 0, 255));
|
||||
return new Image(new Collection([
|
||||
new Frame($gd1),
|
||||
new Frame($gd2),
|
||||
new Frame($gd3),
|
||||
]));
|
||||
}
|
||||
|
||||
protected function testImageDecoder(): FilePathImageDecoder
|
||||
{
|
||||
return new FilePathImageDecoder();
|
||||
}
|
||||
}
|
23
tests/Traits/CanCreateImagickTestImage.php
Normal file
23
tests/Traits/CanCreateImagickTestImage.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Tests\Traits;
|
||||
|
||||
use Intervention\Image\Collection;
|
||||
use Intervention\Image\Drivers\Imagick\Decoders\FilePathImageDecoder;
|
||||
use Intervention\Image\Drivers\Imagick\Frame;
|
||||
use Intervention\Image\Drivers\Imagick\Image;
|
||||
|
||||
trait CanCreateImagickTestImage
|
||||
{
|
||||
public function createTestImage($filename = 'test.jpg'): Image
|
||||
{
|
||||
return $this->testImageDecoder()->handle(
|
||||
sprintf('%s/../images/%s', __DIR__, $filename)
|
||||
);
|
||||
}
|
||||
|
||||
protected function testImageDecoder(): FilePathImageDecoder
|
||||
{
|
||||
return new FilePathImageDecoder();
|
||||
}
|
||||
}
|
BIN
tests/images/circle.png
Normal file
BIN
tests/images/circle.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 383 B |
BIN
tests/images/test.jpg
Normal file
BIN
tests/images/test.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
tests/images/trim.png
Normal file
BIN
tests/images/trim.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 258 B |
Reference in New Issue
Block a user