diff --git a/src/BarcodeGeneratorJPG.php b/src/BarcodeGeneratorJPG.php index 0e33d70..ba89b14 100644 --- a/src/BarcodeGeneratorJPG.php +++ b/src/BarcodeGeneratorJPG.php @@ -2,21 +2,51 @@ namespace Picqer\Barcode; -use Imagick; - -class BarcodeGeneratorJPG extends BarcodeGeneratorPNG +class BarcodeGeneratorJPG extends BarcodeGenerator { - protected function createImagickImageObject(int $width, int $height): Imagick + protected ?bool $useImagick = null; + + /** + * Return a PNG image representation of barcode (requires GD or Imagick library). + * + * @param string $barcode code to print + * @param BarcodeGenerator::TYPE_* $type (string) type of barcode + * @param int $widthFactor Width of a single bar element in pixels. + * @param int $height Height of a single bar element in pixels. + * @param array $foregroundColor RGB (0-255) foreground color for bar elements (background is transparent). + * @return string image data or false in case of error. + */ + public function getBarcode(string $barcode, $type, int $widthFactor = 2, int $height = 30, array $foregroundColor = [0, 0, 0]): string { - $image = new Imagick(); - $image->newImage($width, $height, 'white', 'JPG'); + $barcodeData = $this->getBarcodeData($barcode, $type); + + $renderer = new \Picqer\Barcode\Renderers\JpgRenderer(); + $renderer->setForegroundColor($foregroundColor); + + if (! is_null($this->useImagick)) { + if ($this->useImagick) { + $renderer->useImagick(); + } else { + $renderer->useGd(); + } + } - return $image; + return $renderer->render($barcodeData, $widthFactor, $height); + } + + /** + * Force the use of Imagick image extension + */ + public function useImagick() + { + $this->useImagick = true; } - protected function generateGdImage($image) + /** + * Force the use of the GD image library + */ + public function useGd() { - imagejpeg($image); - imagedestroy($image); + $this->useImagick = false; } } diff --git a/src/BarcodeGeneratorPNG.php b/src/BarcodeGeneratorPNG.php index 150e1e4..f2c0b39 100644 --- a/src/BarcodeGeneratorPNG.php +++ b/src/BarcodeGeneratorPNG.php @@ -2,45 +2,9 @@ namespace Picqer\Barcode; -use Imagick; -use imagickdraw; -use imagickpixel; -use Picqer\Barcode\Exceptions\BarcodeException; - class BarcodeGeneratorPNG extends BarcodeGenerator { - protected $useImagick = true; - - /** - * @throws BarcodeException - */ - public function __construct() - { - // Auto switch between GD and Imagick based on what is installed - if (extension_loaded('imagick')) { - $this->useImagick = true; - } elseif (function_exists('imagecreate')) { - $this->useImagick = false; - } else { - throw new BarcodeException('Neither gd-lib or imagick are installed!'); - } - } - - /** - * Force the use of Imagick image extension - */ - public function useImagick() - { - $this->useImagick = true; - } - - /** - * Force the use of the GD image library - */ - public function useGd() - { - $this->useImagick = false; - } + protected ?bool $useImagick = null; /** * Return a PNG image representation of barcode (requires GD or Imagick library). @@ -55,67 +19,34 @@ public function useGd() public function getBarcode(string $barcode, $type, int $widthFactor = 2, int $height = 30, array $foregroundColor = [0, 0, 0]): string { $barcodeData = $this->getBarcodeData($barcode, $type); - $width = round($barcodeData->getWidth() * $widthFactor); - - if ($this->useImagick) { - $imagickBarsShape = new imagickdraw(); - $imagickBarsShape->setFillColor(new imagickpixel('rgb(' . implode(',', $foregroundColor) .')')); - } else { - $image = $this->createGdImageObject($width, $height); - $gdForegroundColor = imagecolorallocate($image, $foregroundColor[0], $foregroundColor[1], $foregroundColor[2]); - } - // print bars - $positionHorizontal = 0; - /** @var BarcodeBar $bar */ - foreach ($barcodeData->getBars() as $bar) { - $barWidth = round(($bar->getWidth() * $widthFactor), 3); + $renderer = new \Picqer\Barcode\Renderers\PngRenderer(); + $renderer->setForegroundColor($foregroundColor); - if ($bar->isBar() && $barWidth > 0) { - $y = round(($bar->getPositionVertical() * $height / $barcodeData->getHeight()), 3); - $barHeight = round(($bar->getHeight() * $height / $barcodeData->getHeight()), 3); - - // draw a vertical bar - if ($this->useImagick) { - $imagickBarsShape->rectangle($positionHorizontal, $y, ($positionHorizontal + $barWidth - 1), ($y + $barHeight)); - } else { - imagefilledrectangle($image, $positionHorizontal, $y, ($positionHorizontal + $barWidth - 1), ($y + $barHeight), $gdForegroundColor); - } + if (! is_null($this->useImagick)) { + if ($this->useImagick) { + $renderer->useImagick(); + } else { + $renderer->useGd(); } - $positionHorizontal += $barWidth; - } - - if ($this->useImagick) { - $image = $this->createImagickImageObject($width, $height); - $image->drawImage($imagickBarsShape); - return $image->getImageBlob(); } - ob_start(); - $this->generateGdImage($image); - return ob_get_clean(); + return $renderer->render($barcodeData, $widthFactor, $height); } - protected function createGdImageObject(int $width, int $height) - { - $image = imagecreate($width, $height); - $colorBackground = imagecolorallocate($image, 255, 255, 255); - imagecolortransparent($image, $colorBackground); - - return $image; - } - - protected function createImagickImageObject(int $width, int $height): Imagick + /** + * Force the use of Imagick image extension + */ + public function useImagick() { - $image = new Imagick(); - $image->newImage($width, $height, 'none', 'PNG'); - - return $image; + $this->useImagick = true; } - protected function generateGdImage($image) + /** + * Force the use of the GD image library + */ + public function useGd() { - imagepng($image); - imagedestroy($image); + $this->useImagick = false; } } diff --git a/src/Exceptions/InvalidOptionException.php b/src/Exceptions/InvalidOptionException.php new file mode 100644 index 0000000..6a9b5ad --- /dev/null +++ b/src/Exceptions/InvalidOptionException.php @@ -0,0 +1,5 @@ +newImage($width, $height, 'none', 'JPG'); + + return $image; + } + + protected function generateGdImage($image) + { + \imagejpeg($image); + \imagedestroy($image); + } +} diff --git a/src/Renderers/PngRenderer.php b/src/Renderers/PngRenderer.php new file mode 100644 index 0000000..2009635 --- /dev/null +++ b/src/Renderers/PngRenderer.php @@ -0,0 +1,118 @@ +useImagick = true; + } elseif (function_exists('imagecreate')) { + $this->useImagick = false; + } else { + throw new BarcodeException('Neither gd-lib or imagick are installed!'); + } + } + + /** + * Force the use of Imagick image extension + */ + public function useImagick() + { + $this->useImagick = true; + } + + /** + * Force the use of the GD image library + */ + public function useGd() + { + $this->useImagick = false; + } + + public function render(Barcode $barcode, int $widthFactor = 2, int $height = 30): string + { + $width = round($barcode->getWidth() * $widthFactor); + + if ($this->useImagick) { + $imagickBarsShape = new ImagickDraw(); + $imagickBarsShape->setFillColor(new ImagickPixel('rgb(' . implode(',', $this->foregroundColor) .')')); + } else { + $image = $this->createGdImageObject($width, $height); + $gdForegroundColor = \imagecolorallocate($image, $this->foregroundColor[0], $this->foregroundColor[1], $this->foregroundColor[2]); + } + + // print bars + $positionHorizontal = 0; + /** @var BarcodeBar $bar */ + foreach ($barcode->getBars() as $bar) { + $barWidth = round(($bar->getWidth() * $widthFactor), 3); + + if ($bar->isBar() && $barWidth > 0) { + $y = round(($bar->getPositionVertical() * $height / $barcode->getHeight()), 3); + $barHeight = round(($bar->getHeight() * $height / $barcode->getHeight()), 3); + + // draw a vertical bar + if ($this->useImagick) { + $imagickBarsShape->rectangle($positionHorizontal, $y, ($positionHorizontal + $barWidth - 1), ($y + $barHeight)); + } else { + \imagefilledrectangle($image, $positionHorizontal, $y, ($positionHorizontal + $barWidth - 1), ($y + $barHeight), $gdForegroundColor); + } + } + $positionHorizontal += $barWidth; + } + + if ($this->useImagick) { + $image = $this->createImagickImageObject($width, $height); + $image->drawImage($imagickBarsShape); + return $image->getImageBlob(); + } + + ob_start(); + $this->generateGdImage($image); + return ob_get_clean(); + } + + public function setForegroundColor(array $color) + { + $this->foregroundColor = $color; + } + + protected function createGdImageObject(int $width, int $height) + { + $image = \imagecreate($width, $height); + $colorBackground = \imagecolorallocate($image, 255, 255, 255); + \imagecolortransparent($image, $colorBackground); + + return $image; + } + + protected function createImagickImageObject(int $width, int $height): Imagick + { + $image = new Imagick(); + $image->newImage($width, $height, 'none', 'PNG'); + + return $image; + } + + protected function generateGdImage($image) + { + \imagepng($image); + \imagedestroy($image); + } +} diff --git a/src/Renderers/SvgRenderer.php b/src/Renderers/SvgRenderer.php index 72dd993..6587d99 100644 --- a/src/Renderers/SvgRenderer.php +++ b/src/Renderers/SvgRenderer.php @@ -4,28 +4,27 @@ use Picqer\Barcode\Barcode; use Picqer\Barcode\BarcodeBar; +use Picqer\Barcode\Exceptions\InvalidOptionException; class SvgRenderer { protected string $foregroundColor = 'black'; + protected string $svgType = self::TYPE_SVG_STANDALONE; + + public const TYPE_SVG_STANDALONE = 'standalone'; + public const TYPE_SVG_INLINE = 'inline'; public function render(Barcode $barcode, float $width = 200, float $height = 30): string { - // replace table for special characters - $repstr = [ - "\0" => '', - '&' => '&', - '<' => '<', - '>' => '>', - ]; - -// $width = round(($barcode->getWidth() * $widthFactor), 3); $widthFactor = $width / $barcode->getWidth(); - $svg = '' . PHP_EOL; - $svg .= '' . PHP_EOL; + $svg = ''; + if ($this->svgType === self::TYPE_SVG_STANDALONE) { + $svg .= '' . PHP_EOL; + $svg .= '' . PHP_EOL; + } $svg .= '' . PHP_EOL; - $svg .= "\t" . '' . strtr($barcode->getBarcode(), $repstr) . '' . PHP_EOL; + $svg .= "\t" . '' . htmlspecialchars($barcode->getBarcode()) . '' . PHP_EOL; $svg .= "\t" . '' . PHP_EOL; // print bars @@ -50,8 +49,17 @@ public function render(Barcode $barcode, float $width = 200, float $height = 30) return $svg; } - public function setForegroundColor(string $color) + public function setForegroundColor(string $color): void { $this->foregroundColor = $color; } + + public function setSvgType(string $svgType): void + { + if (! in_array($svgType, [self::TYPE_SVG_INLINE, self::TYPE_SVG_STANDALONE])) { + throw new InvalidOptionException(); + } + + $this->svgType = $svgType; + } } diff --git a/tests/BarcodeSvgv3Test.php b/tests/BarcodeSvgv3Test.php deleted file mode 100644 index 5af16b7..0000000 --- a/tests/BarcodeSvgv3Test.php +++ /dev/null @@ -1,26 +0,0 @@ -getBarcode('081231723897'); - - $renderer = new Picqer\Barcode\Renderers\SvgRenderer(); - $generated = $renderer->render($barcode, 190); - - $this->assertStringEqualsFile('tests/verified-files/081231723897-ean13.svg', $generated); - } - - public function test_svg_barcode_generator_can_generate_ean_13_barcode_with_fractional_width() - { - $barcode = (new Picqer\Barcode\Types\TypeEan13())->getBarcode('081231723897'); - - $renderer = new Picqer\Barcode\Renderers\SvgRenderer(); - $generated = $renderer->render($barcode, 23.75, 25.75); - - $this->assertStringEqualsFile('tests/verified-files/081231723897-ean13-fractional-width.svg', $generated); - } -} diff --git a/tests/SvgRendererTest.php b/tests/SvgRendererTest.php new file mode 100644 index 0000000..aa1e97f --- /dev/null +++ b/tests/SvgRendererTest.php @@ -0,0 +1,59 @@ +getBarcode('081231723897'); + + $renderer = new Picqer\Barcode\Renderers\SvgRenderer(); + $generated = $renderer->render($barcode, 190); + + $this->assertStringEqualsFile('tests/verified-files/081231723897-ean13.svg', $generated); + } + + public function test_svg_barcode_generator_can_generate_ean_13_barcode_with_fractional_width() + { + $barcode = (new Picqer\Barcode\Types\TypeEan13())->getBarcode('081231723897'); + + $renderer = new Picqer\Barcode\Renderers\SvgRenderer(); + $generated = $renderer->render($barcode, 23.75, 25.75); + + $this->assertStringEqualsFile('tests/verified-files/081231723897-ean13-fractional-width.svg', $generated); + } + + public function test_svg_barcode_generator_as_standalone() + { + $barcode = (new Picqer\Barcode\Types\TypeEan13())->getBarcode('081231723897'); + + $renderer = new Picqer\Barcode\Renderers\SvgRenderer(); + $renderer->setSvgType(\Picqer\Barcode\Renderers\SvgRenderer::TYPE_SVG_STANDALONE); + $generated = $renderer->render($barcode); + + $this->assertStringStartsWith('assertStringContainsString('getBarcode('081231723897'); + + $renderer = new Picqer\Barcode\Renderers\SvgRenderer(); + $renderer->setSvgType(\Picqer\Barcode\Renderers\SvgRenderer::TYPE_SVG_INLINE); + $generated = $renderer->render($barcode); + + $this->assertStringStartsWith('assertStringNotContainsString('expectException(\Picqer\Barcode\Exceptions\InvalidOptionException::class); + + $renderer = new Picqer\Barcode\Renderers\SvgRenderer(); + $renderer->setSvgType('other'); + } +}