Skip to content

Commit

Permalink
Merge pull request #664 from mlocati/circle-rectangle
Browse files Browse the repository at this point in the history
New drawer methods: rectangle and circle
  • Loading branch information
mlocati authored Sep 4, 2018
2 parents 25d3d09 + 836ec2b commit c998405
Show file tree
Hide file tree
Showing 16 changed files with 268 additions and 20 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
* The `paste` method now accepts images not fully included in the destination image (@mlocati)
**BREAKING CHANGE** the paste method doesn't throw an OutOfBoundsException anymore
* Fix handling of PNG compression in Imagick `save` method (@mlocati)
* New drawer methods: `rectangle` and `circle` (@mlocati)
**BREAKING CHANGE** if you have your own implementation of `DrawerTest` you should add these two new methods

### 1.0.0-alpha1 (2018-08-28)
* Imagine is now tested under Windows too (@mlocati)
Expand Down
22 changes: 22 additions & 0 deletions src/Draw/DrawerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,17 @@ public function arc(PointInterface $center, BoxInterface $size, $start, $end, Co
*/
public function chord(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1);

/**
* Draws and circle with center at the given x, y coordinates, and given radius.
*
* @param \Imagine\Image\PointInterface $center
* @param int $radius
* @param \Imagine\Image\Palette\Color\ColorInterface $color
* @param bool $fill
* @param int $thickness
*/
public function circle(PointInterface $center, $radius, ColorInterface $color, $fill = false, $thickness = 1);

/**
* Draws and ellipse with center at the given x, y coordinates, and given width and height.
*
Expand Down Expand Up @@ -112,6 +123,17 @@ public function pieSlice(PointInterface $center, BoxInterface $size, $start, $en
*/
public function dot(PointInterface $position, ColorInterface $color);

/**
* Draws a rectangle from left, top(x, y) to right, bottom(x, y) coordinates.
*
* @param \Imagine\Image\PointInterface $leftTop
* @param \Imagine\Image\PointInterface $rightBottom
* @param \Imagine\Image\Palette\Color\ColorInterface $color
* @param bool $fill
* @param int $thickness
*/
public function rectangle(PointInterface $leftTop, PointInterface $rightBottom, ColorInterface $color, $fill = false, $thickness = 1);

/**
* Draws a polygon using array of x, y coordinates. Must contain at least three coordinates.
*
Expand Down
50 changes: 50 additions & 0 deletions src/Gd/Drawer.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Imagine\Exception\InvalidArgumentException;
use Imagine\Exception\RuntimeException;
use Imagine\Image\AbstractFont;
use Imagine\Image\Box;
use Imagine\Image\BoxInterface;
use Imagine\Image\Palette\Color\ColorInterface;
use Imagine\Image\Palette\Color\RGB as RGBColor;
Expand Down Expand Up @@ -104,13 +105,24 @@ public function chord(PointInterface $center, BoxInterface $size, $start, $end,
return $this;
}

/**
* {@inheritdoc}
*
* @see \Imagine\Draw\DrawerInterface::circle()
*/
public function circle(PointInterface $center, $radius, ColorInterface $color, $fill = false, $thickness = 1)
{
return $this->ellipse($center, new Box($radius, $radius), $color, $fill, $thickness);
}

/**
* {@inheritdoc}
*
* @see \Imagine\Draw\DrawerInterface::ellipse()
*/
public function ellipse(PointInterface $center, BoxInterface $size, ColorInterface $color, $fill = false, $thickness = 1)
{
imageantialias($this->resource, true);
imagesetthickness($this->resource, max(1, (int) $thickness));

if ($fill) {
Expand All @@ -119,10 +131,12 @@ public function ellipse(PointInterface $center, BoxInterface $size, ColorInterfa
$callback = 'imageellipse';
}

imageantialias($this->resource, true);
if (false === imagealphablending($this->resource, true)) {
throw new RuntimeException('Draw ellipse operation failed');
}

imageantialias($this->resource, true);
if (false === $callback($this->resource, $center->getX(), $center->getY(), $size->getWidth(), $size->getHeight(), $this->getColor($color))) {
imagealphablending($this->resource, false);
throw new RuntimeException('Draw ellipse operation failed');
Expand Down Expand Up @@ -214,6 +228,42 @@ public function dot(PointInterface $position, ColorInterface $color)
return $this;
}

/**
* {@inheritdoc}
*
* @see \Imagine\Draw\DrawerInterface::rectangle()
*/
public function rectangle(PointInterface $leftTop, PointInterface $rightBottom, ColorInterface $color, $fill = false, $thickness = 1)
{
imagesetthickness($this->resource, max(1, (int) $thickness));

$minX = min($leftTop->getX(), $rightBottom->getX());
$maxX = max($leftTop->getX(), $rightBottom->getX());
$minY = min($leftTop->getY(), $rightBottom->getY());
$maxY = max($leftTop->getY(), $rightBottom->getY());

if ($fill) {
$callback = 'imagefilledrectangle';
} else {
$callback = 'imagerectangle';
}

if (false === imagealphablending($this->resource, true)) {
throw new RuntimeException('Draw polygon operation failed');
}

if (false === $callback($this->resource, $minX, $minY, $maxX, $maxY, $this->getColor($color))) {
imagealphablending($this->resource, false);
throw new RuntimeException('Draw polygon operation failed');
}

if (false === imagealphablending($this->resource, false)) {
throw new RuntimeException('Draw polygon operation failed');
}

return $this;
}

/**
* {@inheritdoc}
*
Expand Down
44 changes: 44 additions & 0 deletions src/Gmagick/Drawer.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Imagine\Exception\NotSupportedException;
use Imagine\Exception\RuntimeException;
use Imagine\Image\AbstractFont;
use Imagine\Image\Box;
use Imagine\Image\BoxInterface;
use Imagine\Image\Palette\Color\ColorInterface;
use Imagine\Image\Point;
Expand Down Expand Up @@ -125,6 +126,16 @@ public function chord(PointInterface $center, BoxInterface $size, $start, $end,
return $this;
}

/**
* {@inheritdoc}
*
* @see \Imagine\Draw\DrawerInterface::circle()
*/
public function circle(PointInterface $center, $radius, ColorInterface $color, $fill = false, $thickness = 1)
{
return $this->ellipse($center, new Box($radius, $radius), $color, $fill, $thickness);
}

/**
* {@inheritdoc}
*
Expand Down Expand Up @@ -265,6 +276,39 @@ public function dot(PointInterface $position, ColorInterface $color)
return $this;
}

/**
* {@inheritdoc}
*
* @see \Imagine\Draw\DrawerInterface::rectangle()
*/
public function rectangle(PointInterface $leftTop, PointInterface $rightBottom, ColorInterface $color, $fill = false, $thickness = 1)
{
$minX = min($leftTop->getX(), $rightBottom->getX());
$maxX = max($leftTop->getX(), $rightBottom->getX());
$minY = min($leftTop->getY(), $rightBottom->getY());
$maxY = max($leftTop->getY(), $rightBottom->getY());

try {
$pixel = $this->getColor($color);
$rectangle = new \GmagickDraw();

$rectangle->setstrokecolor($pixel);
$rectangle->setstrokewidth(max(1, (int) $thickness));

if ($fill) {
$rectangle->setfillcolor($pixel);
} else {
$rectangle->setfillcolor('transparent');
}
$rectangle->rectangle($minX, $minY, $maxX, $maxY);
$this->gmagick->drawImage($rectangle);
} catch (\GmagickException $e) {
throw new RuntimeException('Draw polygon operation failed', $e->getCode(), $e);
}

return $this;
}

/**
* {@inheritdoc}
*
Expand Down
50 changes: 50 additions & 0 deletions src/Imagick/Drawer.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Imagine\Exception\InvalidArgumentException;
use Imagine\Exception\RuntimeException;
use Imagine\Image\AbstractFont;
use Imagine\Image\Box;
use Imagine\Image\BoxInterface;
use Imagine\Image\Palette\Color\ColorInterface;
use Imagine\Image\Point;
Expand Down Expand Up @@ -127,6 +128,16 @@ public function chord(PointInterface $center, BoxInterface $size, $start, $end,
return $this;
}

/**
* {@inheritdoc}
*
* @see \Imagine\Draw\DrawerInterface::circle()
*/
public function circle(PointInterface $center, $radius, ColorInterface $color, $fill = false, $thickness = 1)
{
return $this->ellipse($center, new Box($radius, $radius), $color, $fill, $thickness);
}

/**
* {@inheritdoc}
*
Expand Down Expand Up @@ -276,6 +287,45 @@ public function dot(PointInterface $position, ColorInterface $color)
return $this;
}

/**
* {@inheritdoc}
*
* @see \Imagine\Draw\DrawerInterface::rectangle()
*/
public function rectangle(PointInterface $leftTop, PointInterface $rightBottom, ColorInterface $color, $fill = false, $thickness = 1)
{
$minX = min($leftTop->getX(), $rightBottom->getX());
$maxX = max($leftTop->getX(), $rightBottom->getX());
$minY = min($leftTop->getY(), $rightBottom->getY());
$maxY = max($leftTop->getY(), $rightBottom->getY());

try {
$pixel = $this->getColor($color);
$rectangle = new \ImagickDraw();
$rectangle->setStrokeColor($pixel);
$rectangle->setStrokeWidth(max(1, (int) $thickness));

if ($fill) {
$rectangle->setFillColor($pixel);
} else {
$rectangle->setFillColor('transparent');
}

$rectangle->rectangle($minX, $minY, $maxX, $maxY);
$this->imagick->drawImage($rectangle);

$pixel->clear();
$pixel->destroy();

$rectangle->clear();
$rectangle->destroy();
} catch (\ImagickException $e) {
throw new RuntimeException('Draw rectangle operation failed', $e->getCode(), $e);
}

return $this;
}

/**
* {@inheritdoc}
*
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
55 changes: 35 additions & 20 deletions tests/Imagine/Test/Constraint/IsImageEqual.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,26 +70,7 @@ protected function matches($other)
throw InvalidArgumentHelper::factory(1, 'Imagine\Image\ImageInterface');
}

list($currentRed, $currentGreen, $currentBlue, $currentAlpha) = $this->normalize($this->value);
list($otherRed, $otherGreen, $otherBlue, $otherAlpha) = $this->normalize($other);

$total = 0;

foreach ($currentRed as $bucket => $count) {
$total += abs($count - $otherRed[$bucket]);
}

foreach ($currentGreen as $bucket => $count) {
$total += abs($count - $otherGreen[$bucket]);
}

foreach ($currentBlue as $bucket => $count) {
$total += abs($count - $otherBlue[$bucket]);
}

foreach ($currentAlpha as $bucket => $count) {
$total += abs($count - $otherAlpha[$bucket]);
}
$total = $this->getDelta($other);

return $total <= $this->delta;
}
Expand All @@ -102,6 +83,14 @@ public function toString()
return sprintf('contains color histogram identical to expected %s', $this->exporter->export($this->value));
}

/**
* {@inheritdoc}
*/
protected function failureDescription($other)
{
return sprintf('contains color histogram identical to the expected one (max delta: %s, actual delta: %s)', $this->delta, $this->getDelta($other));
}

/**
* @param \Imagine\Image\ImageInterface $image
*
Expand Down Expand Up @@ -155,4 +144,30 @@ private function normalize(ImageInterface $image)
array_map($callback, $alpha),
);
}

private function getDelta(ImageInterface $other)
{
list($currentRed, $currentGreen, $currentBlue, $currentAlpha) = $this->normalize($this->value);
list($otherRed, $otherGreen, $otherBlue, $otherAlpha) = $this->normalize($other);

$total = 0;

foreach ($currentRed as $bucket => $count) {
$total += abs($count - $otherRed[$bucket]);
}

foreach ($currentGreen as $bucket => $count) {
$total += abs($count - $otherGreen[$bucket]);
}

foreach ($currentBlue as $bucket => $count) {
$total += abs($count - $otherBlue[$bucket]);
}

foreach ($currentAlpha as $bucket => $count) {
$total += abs($count - $otherAlpha[$bucket]);
}

return $total;
}
}
Loading

0 comments on commit c998405

Please sign in to comment.