Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a RendererInterface #206

Merged
merged 4 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 22 additions & 13 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Install through [composer](https://getcomposer.org/doc/00-intro.md):
composer require picqer/php-barcode-generator
```

If you want to generate PNG or JPG images, you need the GD library or Imagick installed on your system as well.
If you want to generate PNG or JPG images, you need the GD library or Imagick installed on your system as well. For SVG or HTML renders, there are no dependencies.

## Usage
You want a barcode for a specific "type" (for example Code 128 or UPC) in a specific image format (for example PNG or SVG).
Expand Down Expand Up @@ -54,21 +54,28 @@ $barcode = (new Picqer\Barcode\Types\TypeCode128())->getBarcode('081231723897');
$renderer = new Picqer\Barcode\Renderers\PngRenderer();
$renderer->setForegroundColor($colorRed);

// Save PNG to the filesystem, with widthFactor 3 and height of 50 pixels
file_put_contents('barcode.png', $renderer->render($barcode, 3, 50));
// Save PNG to the filesystem, with widthFactor 3 (width of the barcode x 3) and height of 50 pixels
file_put_contents('barcode.png', $renderer->render($barcode, $barcode->getWidth() * 3, 50));
```

## Image renderers
Available image renderers: SVG, PNG, JPG and HTML.

Each renderer has their own options. Only the barcode is required, the rest is optional. Here are all the options for each renderers:
They all conform to the RendererInterface and have the same `render()` method. Some renderers have extra options as well, via set*() methods.

### Widths
The render() method needs the Barcode object, the width and height. **For JPG/PNG images**, you only get a valid barcode if you give a width that is a factor of the width of the Barcode object. That is why the examples show `$barcode->getWidth() * 2` to make the image 2 times wider in pixels then the width of the barcode data. You *can* give an arbitrary number as width and the image will be scaled as best as possible, but without anti-aliasing, it will not be perfectly valid.

HTML and SVG renderers can handle any width and height, even floats.

Here are all the options for each renderer:

### SVG
A vector based SVG image. Gives the best quality to print.
```php
$renderer = new Picqer\Barcode\Renderers\SvgRenderer();
$renderer->setForegroundColor('red'); // Give a color for the bars, default is black
$renderer->setBackgroundColor('blue'); // Give a color for the background, default is transparent
$renderer->setForegroundColor([255, 0, 0]); // Give a color red for the bars, default is black. Give it as 3 times 0-255 values for red, green and blue.
$renderer->setBackgroundColor([0, 0, 255]); // Give a color blue for the background, default is transparent. Give it as 3 times 0-255 values for red, green and blue.
$renderer->setSvgType($renderer::TYPE_SVG_INLINE); // Changes the output to be used inline inside HTML documents, instead of a standalone SVG image (default)
$renderer->setSvgType($renderer::TYPE_SVG_STANDALONE); // If you want to force the default, create a stand alone SVG image

Expand All @@ -91,8 +98,8 @@ $renderer->render($barcode, 5, 40); // Width factor (how many pixel wide every b
Gives HTML to use inline in a full HTML document.
```php
$renderer = new Picqer\Barcode\Renderers\HtmlRenderer();
$renderer->setForegroundColor('red'); // Give a color for the bars, default is black
$renderer->setBackgroundColor('blue'); // Give a color for the background, default is transparent
$renderer->setForegroundColor([255, 0, 0]); // Give a color red for the bars, default is black. Give it as 3 times 0-255 values for red, green and blue.
$renderer->setBackgroundColor([0, 0, 255]); // Give a color blue for the background, default is transparent. Give it as 3 times 0-255 values for red, green and blue.

$renderer->render($barcode, 450.20, 75); // Width and height support floats
````
Expand All @@ -101,8 +108,8 @@ $renderer->render($barcode, 450.20, 75); // Width and height support floats
Give HTML here the barcode is using the full width and height, to put inside a container/div that has a fixed size.
```php
$renderer = new Picqer\Barcode\Renderers\DynamicHtmlRenderer();
$renderer->setForegroundColor('red'); // Give a color for the bars, default is black
$renderer->setBackgroundColor('blue'); // Give a color for the background, default is transparent
$renderer->setForegroundColor([255, 0, 0]); // Give a color red for the bars, default is black. Give it as 3 times 0-255 values for red, green and blue.
$renderer->setBackgroundColor([0, 0, 255]); // Give a color blue for the background, default is transparent. Give it as 3 times 0-255 values for red, green and blue.

$renderer->render($barcode);
````
Expand Down Expand Up @@ -163,15 +170,15 @@ If you want to use PNG or JPG images, you need to install [Imagick](https://www.
```php
$barcode = (new Picqer\Barcode\Types\TypeCode128())->getBarcode('081231723897');
$renderer = new Picqer\Barcode\Renderers\PngRenderer();
echo '<img src="data:image/png;base64,' . base64_encode($renderer->render($barcode)) . '">';
echo '<img src="data:image/png;base64,' . base64_encode($renderer->render($barcode, $barcode->getWidth() * 2)) . '">';
```

### Save JPG barcode to disk
```php
$barcode = (new Picqer\Barcode\Types\TypeCodabar())->getBarcode('081231723897');
$renderer = new Picqer\Barcode\Renderers\JpgRenderer();

file_put_contents('barcode.jpg', $renderer->render($barcode));
file_put_contents('barcode.jpg', $renderer->render($barcode, $barcode->getWidth() * 2));
```

### Oneliner SVG output to disk
Expand All @@ -182,6 +189,8 @@ file_put_contents('barcode.svg', (new Picqer\Barcode\Renderers\SvgRenderer())->r
## Upgrading to v3
There is no need to change anything when upgrading from v2 to v3. Above you find the new preferred way of using this library since v3. But the old style still works.

To give the renderers the same interface, setting colors is now always with an array of RGB colors. If you use the old BarcodeGenerator* classes and use colors with names ('red') or hex codes (#3399ef), these will be converted using the ColorHelper. All hexcodes are supported, but for names of colors only the basic colors are supported.

If you want to convert to the new style, here is an example:
```php
// Old style
Expand All @@ -194,7 +203,7 @@ $renderer = new Picqer\Barcode\Renderers\SvgRenderer();
echo $renderer->render($barcode);
```

The width in the SVG and HTML renderer is now the width of the end result, instead of the widthFactor. If you want to keep dynamic widths, you can get the width of the encoded Barcode and multiply it by the widthFactor to get the same result as before. See here an example for a widthFactor of 2:
The width in the renderer is now the width of the end result, instead of the widthFactor. If you want to keep dynamic widths, you can get the width of the encoded Barcode and multiply it by the widthFactor to get the same result as before. See here an example for a widthFactor of 2:
```php
// Old style
$generator = new Picqer\Barcode\BarcodeGeneratorSVG();
Expand Down
4 changes: 2 additions & 2 deletions generate-verified-files.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
file_put_contents('tests/verified-files/081231723897-ean13-fractional-width.svg', $svgRenderer->render($barcode, $barcode->getWidth() * 0.25, 25.75));

$svgRendererRed = new Picqer\Barcode\Renderers\SvgRenderer();
$svgRendererRed->setBackgroundColor('red');
$svgRendererRed->setBackgroundColor([255, 0, 0]);
file_put_contents('tests/verified-files/081231723897-ean13-red-background.svg', $svgRendererRed->render($barcode, $barcode->getWidth() * 2));

$barcode = $typeEncoderCode128->getBarcode('081231723897');
file_put_contents('tests/verified-files/081231723897-code128.html', $htmlRenderer->render($barcode, $barcode->getWidth() * 2));
$htmlRendererRed = new Picqer\Barcode\Renderers\HtmlRenderer();
$htmlRendererRed->setBackgroundColor('red');
$htmlRendererRed->setBackgroundColor([255, 0, 0]);
file_put_contents('tests/verified-files/081231723897-code128-red-background.html', $htmlRendererRed->render($barcode, $barcode->getWidth() * 2));

$barcode = $typeEncoderIMB->getBarcode('12345678903');
Expand Down
3 changes: 2 additions & 1 deletion src/BarcodeGeneratorDynamicHTML.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Picqer\Barcode;

use Picqer\Barcode\Exceptions\UnknownTypeException;
use Picqer\Barcode\Helpers\ColorHelper;

class BarcodeGeneratorDynamicHTML extends BarcodeGenerator
{
Expand All @@ -21,7 +22,7 @@ public function getBarcode(string $barcode, $type, string $foregroundColor = 'bl
$barcodeData = $this->getBarcodeData($barcode, $type);

$renderer = new \Picqer\Barcode\Renderers\DynamicHtmlRenderer();
$renderer->setForegroundColor($foregroundColor);
$renderer->setForegroundColor(ColorHelper::getArrayFromColorString($foregroundColor));

return $renderer->render($barcodeData);
}
Expand Down
3 changes: 2 additions & 1 deletion src/BarcodeGeneratorHTML.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Picqer\Barcode;

use Picqer\Barcode\Exceptions\UnknownTypeException;
use Picqer\Barcode\Helpers\ColorHelper;

class BarcodeGeneratorHTML extends BarcodeGenerator
{
Expand All @@ -25,7 +26,7 @@ public function getBarcode(string $barcode, $type, int $widthFactor = 2, int $he
$width = round(($barcodeData->getWidth() * $widthFactor), 3);

$renderer = new \Picqer\Barcode\Renderers\HtmlRenderer();
$renderer->setForegroundColor($foregroundColor);
$renderer->setForegroundColor(ColorHelper::getArrayFromColorString($foregroundColor));

return $renderer->render($barcodeData, $width, $height);
}
Expand Down
2 changes: 1 addition & 1 deletion src/BarcodeGeneratorJPG.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public function getBarcode(string $barcode, $type, int $widthFactor = 2, int $he
}
}

return $renderer->render($barcodeData, $widthFactor, $height);
return $renderer->render($barcodeData, $barcodeData->getWidth() * $widthFactor, $height);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/BarcodeGeneratorPNG.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public function getBarcode(string $barcode, $type, int $widthFactor = 2, int $he
}
}

return $renderer->render($barcodeData, $widthFactor, $height);
return $renderer->render($barcodeData, $barcodeData->getWidth() * $widthFactor, $height);
}

/**
Expand Down
3 changes: 2 additions & 1 deletion src/BarcodeGeneratorSVG.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Picqer\Barcode;

use Picqer\Barcode\Exceptions\UnknownTypeException;
use Picqer\Barcode\Helpers\ColorHelper;

class BarcodeGeneratorSVG extends BarcodeGenerator
{
Expand All @@ -25,7 +26,7 @@ public function getBarcode(string $barcode, $type, float $widthFactor = 2, float
$width = round(($barcodeData->getWidth() * $widthFactor), 3);

$renderer = new \Picqer\Barcode\Renderers\SvgRenderer();
$renderer->setForegroundColor($foregroundColor);
$renderer->setForegroundColor(ColorHelper::getArrayFromColorString($foregroundColor));

return $renderer->render($barcodeData, $width, $height);
}
Expand Down
5 changes: 5 additions & 0 deletions src/Exceptions/UnknownColorException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

namespace Picqer\Barcode\Exceptions;

class UnknownColorException extends BarcodeException {}
46 changes: 46 additions & 0 deletions src/Helpers/ColorHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

namespace Picqer\Barcode\Helpers;

use Picqer\Barcode\Exceptions\UnknownColorException;

class ColorHelper
{
// Convert textual color values, to array of 3 colors 0-255
// Can be "red", "#333" or "#009945" styles
public static function getArrayFromColorString(string $color): array {
if ($color == 'black') {
return [0, 0, 0];
} elseif ($color == 'white') {
return [255, 255, 255];
} elseif ($color == 'red') {
return [255, 0, 0];
} elseif ($color == 'green') {
return [0, 255, 0];
} elseif ($color == 'blue') {
return [0, 0, 255];
} elseif ($color == 'yellow') {
return [255, 255, 0];
}

// #333 style
if (str_starts_with($color, '#') && strlen($color) === 4) {
return [
hexdec(substr($color, 1, 1) . substr($color, 1, 1)),
hexdec(substr($color, 2, 1) . substr($color, 2, 1)),
hexdec(substr($color, 3, 1) . substr($color, 3, 1)),
];
}

// #009933 style
if (str_starts_with($color, '#') && strlen($color) === 7) {
return [
hexdec(substr($color, 1, 2)),
hexdec(substr($color, 2, 2)),
hexdec(substr($color, 3, 2)),
];
}

throw new UnknownColorException('Only basic string-based colors are supported in v3.');
}
}
19 changes: 9 additions & 10 deletions src/Renderers/DynamicHtmlRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@
use Picqer\Barcode\Barcode;
use Picqer\Barcode\BarcodeBar;

class DynamicHtmlRenderer
class DynamicHtmlRenderer implements RendererInterface
{
protected const WIDTH_PRECISION = 6;

protected string $foregroundColor = 'black';
protected ?string $backgroundColor = null;
protected array $foregroundColor = [0, 0, 0];
protected ?array $backgroundColor = null;

public function render(Barcode $barcode): string
// Width and height are ignored in this renderer
public function render(Barcode $barcode, float $width = 200, float $height = 30): string
{
$html = '<div style="font-size:0;position:relative;width:100%;height:100%' . ($this->backgroundColor ? ';background-color:' . $this->backgroundColor : '') . '">' . PHP_EOL;
$html = '<div style="font-size:0;position:relative;width:100%;height:100%' . ($this->backgroundColor ? ';background-color:rgb(' . implode(',', $this->backgroundColor) . ')' : '') . '">' . PHP_EOL;

$positionHorizontal = 0;
/** @var BarcodeBar $bar */
Expand All @@ -26,7 +27,7 @@ public function render(Barcode $barcode): string
$positionVertical = round(($bar->getPositionVertical() / $barcode->getHeight() * 100), 3);

// draw a vertical bar
$html .= '<div style="background-color:' . $this->foregroundColor . ';width:' . round($barWidth, self::WIDTH_PRECISION) . '%;height:' . $barHeight . '%;position:absolute;left:' . round($positionHorizontal, self::WIDTH_PRECISION) . '%;top:' . $positionVertical . (($positionVertical > 0) ? '%' : '') . '">&nbsp;</div>' . PHP_EOL;
$html .= '<div style="background-color:rgb(' . implode(',', $this->foregroundColor) . ');width:' . round($barWidth, self::WIDTH_PRECISION) . '%;height:' . $barHeight . '%;position:absolute;left:' . round($positionHorizontal, self::WIDTH_PRECISION) . '%;top:' . $positionVertical . (($positionVertical > 0) ? '%' : '') . '">&nbsp;</div>' . PHP_EOL;
}

$positionHorizontal += $barWidth;
Expand All @@ -37,15 +38,13 @@ public function render(Barcode $barcode): string
return $html;
}

// Use HTML color definitions, like 'red' or '#ff0000'
public function setForegroundColor(string $color): self
public function setForegroundColor(array $color): self
{
$this->foregroundColor = $color;
return $this;
}

// Use HTML color definitions, like 'red' or '#ff0000'
public function setBackgroundColor(?string $color): self
public function setBackgroundColor(?array $color): self
{
$this->backgroundColor = $color;
return $this;
Expand Down
16 changes: 7 additions & 9 deletions src/Renderers/HtmlRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@
use Picqer\Barcode\Barcode;
use Picqer\Barcode\BarcodeBar;

class HtmlRenderer
class HtmlRenderer implements RendererInterface
{
protected string $foregroundColor = 'black';
protected ?string $backgroundColor = null;
protected array $foregroundColor = [0, 0, 0];
protected ?array $backgroundColor = null;

public function render(Barcode $barcode, float $width = 200, float $height = 30): string
{
$widthFactor = $width / $barcode->getWidth();

$html = '<div style="font-size:0;position:relative;width:' . $width . 'px;height:' . ($height) . 'px;' . ($this->backgroundColor ? 'background-color:' . $this->backgroundColor . ';' : '') . '">' . PHP_EOL;
$html = '<div style="font-size:0;position:relative;width:' . $width . 'px;height:' . ($height) . 'px;' . ($this->backgroundColor ? 'background-color:rgb(' . implode(',', $this->backgroundColor) . ');' : '') . '">' . PHP_EOL;

$positionHorizontal = 0;
/** @var BarcodeBar $bar */
Expand All @@ -26,7 +26,7 @@ public function render(Barcode $barcode, float $width = 200, float $height = 30)
$positionVertical = round(($bar->getPositionVertical() * $height / $barcode->getHeight()), 3);

// draw a vertical bar
$html .= '<div style="background-color:' . $this->foregroundColor . ';width:' . $barWidth . 'px;height:' . $barHeight . 'px;position:absolute;left:' . $positionHorizontal . 'px;top:' . $positionVertical . (($positionVertical > 0) ? 'px' : '') . '">&nbsp;</div>' . PHP_EOL;
$html .= '<div style="background-color:rgb(' . implode(',', $this->foregroundColor) . ');width:' . $barWidth . 'px;height:' . $barHeight . 'px;position:absolute;left:' . $positionHorizontal . 'px;top:' . $positionVertical . (($positionVertical > 0) ? 'px' : '') . '">&nbsp;</div>' . PHP_EOL;
}

$positionHorizontal += $barWidth;
Expand All @@ -37,15 +37,13 @@ public function render(Barcode $barcode, float $width = 200, float $height = 30)
return $html;
}

// Use HTML color definitions, like 'red' or '#ff0000'
public function setForegroundColor(string $color): self
public function setForegroundColor(array $color): self
{
$this->foregroundColor = $color;
return $this;
}

// Use HTML color definitions, like 'red' or '#ff0000'
public function setBackgroundColor(?string $color): self
public function setBackgroundColor(?array $color): self
{
$this->backgroundColor = $color;
return $this;
Expand Down
18 changes: 12 additions & 6 deletions src/Renderers/PngRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
use Picqer\Barcode\BarcodeBar;
use Picqer\Barcode\Exceptions\BarcodeException;

class PngRenderer
class PngRenderer implements RendererInterface
{
protected array $foregroundColor = [0, 0, 0];
protected ?array $backgroundColor = null;
Expand Down Expand Up @@ -49,9 +49,15 @@ public function useGd(): self
return $this;
}

public function render(Barcode $barcode, int $widthFactor = 2, int $height = 30): string
// Floats in width and height will be rounded to integers
// For best (and valid) result, use a width as a factor of the width of the Barcode object
// Example: $width = $barcode->getWidth() * 3
public function render(Barcode $barcode, float $width = 200, float $height = 30): string
{
$width = (int)round($barcode->getWidth() * $widthFactor);
$width = (int)round($width);
$height = (int)round($height);

$widthFactor = $width / $barcode->getWidth();

if ($this->useImagick) {
$image = $this->createImagickImageObject($width, $height);
Expand All @@ -66,17 +72,17 @@ public function render(Barcode $barcode, int $widthFactor = 2, int $height = 30)
$positionHorizontal = 0;
/** @var BarcodeBar $bar */
foreach ($barcode->getBars() as $bar) {
$barWidth = (int)round(($bar->getWidth() * $widthFactor));
$barWidth = $bar->getWidth() * $widthFactor;

if ($bar->isBar() && $barWidth > 0) {
$y = (int)round(($bar->getPositionVertical() * $height / $barcode->getHeight()));
$barHeight = (int)round(($bar->getHeight() * $height / $barcode->getHeight()));

// draw a vertical bar
if ($this->useImagick) {
$imagickBarsShape->rectangle($positionHorizontal, $y, ($positionHorizontal + $barWidth - 1), ($y + $barHeight));
$imagickBarsShape->rectangle((int)round($positionHorizontal), $y, (int)round($positionHorizontal + $barWidth - 1), ($y + $barHeight));
} else {
\imagefilledrectangle($image, $positionHorizontal, $y, ($positionHorizontal + $barWidth - 1), ($y + $barHeight), $gdForegroundColor);
\imagefilledrectangle($image, (int)round($positionHorizontal), $y, (int)round($positionHorizontal + $barWidth - 1), ($y + $barHeight), $gdForegroundColor);
}
}
$positionHorizontal += $barWidth;
Expand Down
14 changes: 14 additions & 0 deletions src/Renderers/RendererInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace Picqer\Barcode\Renderers;

use Picqer\Barcode\Barcode;

interface RendererInterface
{
public function render(Barcode $barcode, float $width = 200, float $height = 30): string;

public function setForegroundColor(array $color): self;

public function setBackgroundColor(?array $color): self;
}
Loading