diff --git a/composer.json b/composer.json index 8594a91..073aa31 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ "require": { "php": ">=7.2|^8.0", "ext-gd": "*", - "bacon/bacon-qr-code": "^2.0" + "bacon/bacon-qr-code": "^3.0" }, "require-dev": { "mockery/mockery": "~1", diff --git a/src/CustomEyes/RoundedSquareEye.php b/src/CustomEyes/RoundedSquareEye.php new file mode 100644 index 0000000..363cf4f --- /dev/null +++ b/src/CustomEyes/RoundedSquareEye.php @@ -0,0 +1,87 @@ +move(0, $outerSize) + ->line($outerMidPoint, $outerSize) + ->curve($outerMidPoint, $outerSize, $outerSize, $outerSize, $outerSize, $outerMidPoint) + ->line($outerSize, 0) + ->line($outerSize, -$outerMidPoint) + ->curve($outerSize, -$outerMidPoint, $outerSize, -$outerSize, $outerMidPoint, -$outerSize) + ->line(0, -$outerSize) + ->line(-$outerMidPoint, -$outerSize) + ->curve(-$outerMidPoint, -$outerSize, -$outerSize, -$outerSize, -$outerSize, -$outerMidPoint) + ->line(-$outerSize, 0) + ->line(-$outerSize, $outerMidPoint) + ->curve(-$outerSize, $outerMidPoint, -$outerSize, $outerSize, -$outerMidPoint, $outerSize) + ->line(0, $outerSize) + ->close() + + ->move(0, $innerSize) + ->line($innerMidPoint, $innerSize) + ->curve($innerMidPoint, $innerSize, $innerSize, $innerSize, $innerSize, $innerMidPoint) + ->line($innerSize, 0) + ->line($innerSize, -$innerMidPoint) + ->curve($innerSize, -$innerMidPoint, $innerSize, -$innerSize, $innerMidPoint, -$innerSize) + ->line(0, -$innerSize) + ->line(-$innerMidPoint, -$innerSize) + ->curve(-$innerMidPoint, -$innerSize, -$innerSize, -$innerSize, -$innerSize, -$innerMidPoint) + ->line(-$innerSize, 0) + ->line(-$innerSize, $innerMidPoint) + ->curve(-$innerSize, $innerMidPoint, -$innerSize, $innerSize, -$innerMidPoint, $innerSize) + ->line(0, $innerSize) + ->close(); + } + + + public function getInternalPath(): Path + { + $size = 1.5; + $midPoint = 0.75; + + return (new Path()) + ->move(0, $size) + ->line($midPoint, $size) + ->curve($midPoint, $size, $size, $size, $size, $midPoint) + ->line($size, 0) + ->line($size, -$midPoint) + ->curve($size, -$midPoint, $size, -$size, $midPoint, -$size) + ->line(0, -$size) + ->line(-$midPoint, -$size) + ->curve(-$midPoint, -$size, -$size, -$size, -$size, -$midPoint) + ->line(-$size, 0) + ->line(-$size, $midPoint) + ->curve(-$size, $midPoint, -$size, $size, -$midPoint, $size) + ->line(0, $size) + ->close(); + } +} diff --git a/src/Generator.php b/src/Generator.php index 4ada416..acc51c1 100644 --- a/src/Generator.php +++ b/src/Generator.php @@ -8,8 +8,10 @@ use BaconQrCode\Renderer\Color\Alpha; use BaconQrCode\Renderer\Color\ColorInterface; use BaconQrCode\Renderer\Color\Rgb; +use BaconQrCode\Renderer\Eye\CompositeEye; use BaconQrCode\Renderer\Eye\EyeInterface; use BaconQrCode\Renderer\Eye\ModuleEye; +use BaconQrCode\Renderer\Eye\PointyEye; use BaconQrCode\Renderer\Eye\SimpleCircleEye; use BaconQrCode\Renderer\Eye\SquareEye; use BaconQrCode\Renderer\Image\EpsImageBackEnd; @@ -29,6 +31,7 @@ use BaconQrCode\Writer; use BadMethodCallException; use InvalidArgumentException; +use SimpleSoftwareIO\QrCode\CustomEyes\RoundedSquareEye; use SimpleSoftwareIO\QrCode\DataTypes\DataTypeInterface; class Generator @@ -94,13 +97,21 @@ class Generator protected $styleSize = null; /** - * The style to apply to the eye. - * Possible values are circle and square. + * The style to apply to the internal eye. + * Possible values are circle, square and rounded. * * @var string|null */ protected $eyeStyle = null; + /** + * The style to apply to the external eye. + * Possible values are circle, square, pointy and rounded. + * + * @var string|null + */ + protected $externalEyeStyle = null; + /** * The foreground color of the QrCode. * @@ -334,8 +345,8 @@ public function gradient($startRed, $startGreen, $startBlue, $endRed, $endGreen, */ public function eye(string $style): self { - if (! in_array($style, ['square', 'circle'])) { - throw new InvalidArgumentException("\$style must be square or circle. {$style} is not a valid eye style."); + if (! in_array($style, ['square', 'circle', 'rounded'])) { + throw new InvalidArgumentException("\$style must be square, rounded or circle. {$style} is not a valid eye style."); } $this->eyeStyle = $style; @@ -343,6 +354,24 @@ public function eye(string $style): self return $this; } + /** + * Sets the external eye style. + * + * @param string $style + * @return Generator + * @throws InvalidArgumentException + */ + public function externalEye(string $style): self + { + if (! in_array($style, ['square', 'circle', 'pointy', 'rounded'])) { + throw new InvalidArgumentException("\$style must be square, rounded, pointy or circle. {$style} is not a valid eye style."); + } + + $this->externalEyeStyle = $style; + + return $this; + } + /** * Sets the style of the blocks for the QrCode. * @@ -496,15 +525,41 @@ public function getModule(): ModuleInterface */ public function getEye(): EyeInterface { + // defaults + $internalEye = new ModuleEye($this->getModule()); + $externalEye = new ModuleEye($this->getModule()); + + // external eye + if ($this->externalEyeStyle === 'square') { + $externalEye = SquareEye::instance(); + } + + if ($this->externalEyeStyle === 'circle') { + $externalEye = SimpleCircleEye::instance(); + } + + if ($this->externalEyeStyle === 'pointy') { + $externalEye = PointyEye::instance(); + } + + if ($this->externalEyeStyle === 'rounded') { + $externalEye = RoundedSquareEye::instance(); + } + + // internal eye if ($this->eyeStyle === 'square') { - return SquareEye::instance(); + $internalEye = SquareEye::instance(); } if ($this->eyeStyle === 'circle') { - return SimpleCircleEye::instance(); + $internalEye = SimpleCircleEye::instance(); + } + + if ($this->eyeStyle === 'rounded') { + $internalEye = RoundedSquareEye::instance(); } - return new ModuleEye($this->getModule()); + return new CompositeEye($externalEye, $internalEye); } /** diff --git a/tests/GeneratorTest.php b/tests/GeneratorTest.php index d0d75be..6aa6616 100644 --- a/tests/GeneratorTest.php +++ b/tests/GeneratorTest.php @@ -1,7 +1,5 @@ assertInstanceOf(Gradient::class, $generator->getFill()->getForegroundGradient()); } - public function test_eye_style_is_set() + public function test_invalid_eye_throws_an_exception() { - $generator = (new Generator)->eye('circle'); - $this->assertInstanceOf(SimpleCircleEye::class, $generator->getEye()); - - $generator = (new Generator)->eye('square'); - $this->assertInstanceOf(SquareEye::class, $generator->getEye()); + $this->expectException(InvalidArgumentException::class); + (new Generator)->eye('foo'); } - public function test_invalid_eye_throws_an_exception() + public function test_invalid_external_eye_throws_an_exception() { $this->expectException(InvalidArgumentException::class); - (new Generator)->eye('foo'); + (new Generator)->externalEye('foo'); } public function test_style_is_set()