1. Import

This commit is contained in:
2026-03-29 10:34:57 +02:00
parent b0e00c1259
commit a1129565af
4899 changed files with 3007593 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
<p align="center"><a href="https://www.barcodebakery.com" target="_blank">
<img src="https://www.barcodebakery.com/images/BCG-Logo-SQ-GitHub.svg">
</a></p>
[Barcode Bakery][1] is library written in PHP, [.NET Standard][2] and Node.JS which allows you to generate barcodes on the fly on your server for displaying or saving.
This is the common base for generating all barcode types.
Please visit the following repository:
* [barcode-php-1d][3]
[1]: https://www.barcodebakery.com
[2]: https://github.com/barcode-bakery/barcode-dotnet-1d/
[3]: https://github.com/barcode-bakery/barcode-php-1d/

View File

@@ -0,0 +1,30 @@
{
"name": "barcode-bakery/barcode-common",
"version": "7.0.3",
"license": [
"proprietary",
"CC-BY-NC-ND-4.0"
],
"support": {
"email": "contact@barcodebakery.com",
"docs": "https://www.barcodebakery.com"
},
"type": "library",
"homepage": "https://www.barcodebakery.com",
"authors": [
{
"name": "Jean-Sébastien Goupil",
"email": "contact@barcodebakery.com"
}
],
"description": "Base code for generating barcode with the Barcode Bakery library. See barcode-bakery/barcode-1d.",
"autoload": {
"psr-4": {
"BarcodeBakery\\Common\\": "src"
}
},
"require": {
"php": ">=7.4",
"ext-gd": "*"
}
}

View File

@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
/**
*--------------------------------------------------------------------
*
* Argument Exception
*
*--------------------------------------------------------------------
* Copyright (C) Jean-Sebastien Goupil
* http://www.barcodebakery.com
*/
namespace BarcodeBakery\Common;
class BCGArgumentException extends \Exception
{
protected string $param;
/**
* Constructor with specific message for a parameter.
*
* @param string $message The message.
* @param string $param The parameter.
*/
public function __construct(string $message, string $param)
{
$this->param = $param;
parent::__construct($message, 20000);
}
}

View File

@@ -0,0 +1,505 @@
<?php
declare(strict_types=1);
/**
*--------------------------------------------------------------------
*
* Base class for Barcode 1D and 2D
*
*--------------------------------------------------------------------
* Copyright (C) Jean-Sebastien Goupil
* http://www.barcodebakery.com
*/
namespace BarcodeBakery\Common;
use BarcodeBakery\Common\BCGArgumentException;
use BarcodeBakery\Common\BCGDrawException;
abstract class BCGBarcode
{
const COLOR_BG = 0;
const COLOR_FG = 1;
protected BCGColor $colorFg;
protected BCGColor $colorBg;
protected int $scale; // Scale of the graphic, default: 1
protected int $offsetX;
protected int $offsetY; // Position where to start the drawing
protected array $labels = array(); // Array of BCGLabel
protected array $pushLabel = array(0, 0); // Push for the label, left and top
/**
* Constructor.
*/
protected function __construct()
{
$this->setOffsetX(0);
$this->setOffsetY(0);
$this->setForegroundColor(0x000000);
$this->setBackgroundColor(0xffffff);
$this->setScale(1);
}
/**
* Call this method if you are using the commercial version of our software.
*
* @return void
*/
public function useCommercialVersion(): void
{
throw new BCGArgumentException('You are using the non-commercial library. You must purchase a license at https://www.barcodebakery.com in order to use this in a commercial environment. If you have purchased the library and still obtain this message, follow the documentation on our website.', 'free');
}
/**
* Parses the text before displaying it.
*
* @param mixed $text The text.
*/
public function parse($text): void
{
}
/**
* Gets the foreground color of the barcode.
*
* @return BCGColor The foreground color.
*/
public function getForegroundColor(): BCGColor
{
return $this->colorFg;
}
/**
* Sets the foreground color of the barcode. It could be a BCGColor
* value or simply a language code (white, black, yellow...) or hex value.
*
* @param BCGColor|int $code The foreground color.
* @return void
*/
public function setForegroundColor($code): void
{
if ($code instanceof BCGColor) {
$this->colorFg = $code;
} else {
$this->colorFg = new BCGColor($code);
}
}
/**
* Gets the background color of the barcode.
*
* @return BCGColor The background color.
*/
public function getBackgroundColor(): BCGColor
{
return $this->colorBg;
}
/**
* Sets the background color of the barcode. It could be a BCGColor
* value or simply a language code (white, black, yellow...) or hex value.
*
* @param BCGColor|int $code The background color.
* @return void
*/
public function setBackgroundColor($code): void
{
if ($code instanceof BCGColor) {
$this->colorBg = $code;
} else {
$this->colorBg = new BCGColor($code);
}
foreach ($this->labels as $label) {
$label->setBackgroundColor($this->colorBg);
}
}
/**
* Sets the foreground and background color.
*
* @param BCGColor|int $foregroundColor The foreground color.
* @param BCGColor|int $backgroundColor The background color.
*/
public function setColor($foregroundColor, $backgroundColor): void
{
$this->setForegroundColor($foregroundColor);
$this->setBackgroundColor($backgroundColor);
}
/**
* Gets the scale of the barcode.
*
* @return int The scale.
*/
public function getScale(): int
{
return $this->scale;
}
/**
* Sets the scale of the barcode in pixel.
* If the scale is lower than 1, an exception is raised.
*
* @param int $scale The scale.
* @return void
*/
public function setScale(int $scale): void
{
$scale = intval($scale);
if ($scale <= 0) {
throw new BCGArgumentException('The scale must be larger than 0.', 'scale');
}
$this->scale = $scale;
}
/**
* Abstract method that draws the barcode on the resource.
*
* @param resource $image The surface.
* @return void
*/
abstract public function draw($image): void;
/**
* Returns the maximal size of a barcode.
* [0]->width
* [1]->height
*
* @param int $width The width.
* @param int $height The height.
* @return int[] An array, [0] being the width, [1] being the height.
*/
public function getDimension(int $width, int $height): array
{
$labels = $this->getBiggestLabels(false);
$pixelsAround = array(0, 0, 0, 0); // TRBL
if (isset($labels[BCGLabel::POSITION_TOP])) {
$dimension = $labels[BCGLabel::POSITION_TOP]->getDimension();
$pixelsAround[0] += $dimension[1];
}
if (isset($labels[BCGLabel::POSITION_RIGHT])) {
$dimension = $labels[BCGLabel::POSITION_RIGHT]->getDimension();
$pixelsAround[1] += $dimension[0];
}
if (isset($labels[BCGLabel::POSITION_BOTTOM])) {
$dimension = $labels[BCGLabel::POSITION_BOTTOM]->getDimension();
$pixelsAround[2] += $dimension[1];
}
if (isset($labels[BCGLabel::POSITION_LEFT])) {
$dimension = $labels[BCGLabel::POSITION_LEFT]->getDimension();
$pixelsAround[3] += $dimension[0];
}
$finalW = ($width + $this->offsetX) * $this->scale;
$finalH = ($height + $this->offsetY) * $this->scale;
// This section will check if a top/bottom label is too big for its width and left/right too big for its height
$reversedLabels = $this->getBiggestLabels(true);
foreach ($reversedLabels as $label) {
$dimension = $label->getDimension();
$alignment = $label->getAlignment();
if ($label->getPosition() === BCGLabel::POSITION_LEFT || $label->getPosition() === BCGLabel::POSITION_RIGHT) {
if ($alignment === BCGLabel::ALIGN_TOP) {
$pixelsAround[2] = max($pixelsAround[2], $dimension[1] - $finalH);
} elseif ($alignment === BCGLabel::ALIGN_CENTER) {
$temp = (int)ceil(($dimension[1] - $finalH) / 2);
$pixelsAround[0] = max($pixelsAround[0], $temp);
$pixelsAround[2] = max($pixelsAround[2], $temp);
} elseif ($alignment === BCGLabel::ALIGN_BOTTOM) {
$pixelsAround[0] = max($pixelsAround[0], $dimension[1] - $finalH);
}
} else {
if ($alignment === BCGLabel::ALIGN_LEFT) {
$pixelsAround[1] = max($pixelsAround[1], $dimension[0] - $finalW);
} elseif ($alignment === BCGLabel::ALIGN_CENTER) {
$temp = (int)ceil(($dimension[0] - $finalW) / 2);
$pixelsAround[1] = max($pixelsAround[1], $temp);
$pixelsAround[3] = max($pixelsAround[3], $temp);
} elseif ($alignment === BCGLabel::ALIGN_RIGHT) {
$pixelsAround[3] = max($pixelsAround[3], $dimension[0] - $finalW);
}
}
}
$this->pushLabel[0] = $pixelsAround[3];
$this->pushLabel[1] = $pixelsAround[0];
$finalW = ($width + $this->offsetX) * $this->scale + $pixelsAround[1] + $pixelsAround[3];
$finalH = ($height + $this->offsetY) * $this->scale + $pixelsAround[0] + $pixelsAround[2];
return array((int)$finalW, (int)$finalH);
}
/**
* Gets the X offset.
*
* @return int The X offset.
*/
public function getOffsetX(): int
{
return $this->offsetX;
}
/**
* Sets the X offset.
*
* @param int $offsetX The X offset.
* @return void
*/
public function setOffsetX(int $offsetX): void
{
$offsetX = intval($offsetX);
if ($offsetX < 0) {
throw new BCGArgumentException('The offset X must be 0 or larger.', 'offsetX');
}
$this->offsetX = $offsetX;
}
/**
* Gets the Y offset.
*
* @return int The Y offset.
*/
public function getOffsetY(): int
{
return $this->offsetY;
}
/**
* Sets the Y offset.
*
* @param int $offsetY The Y offset.
* @return void
*/
public function setOffsetY(int $offsetY): void
{
$offsetY = intval($offsetY);
if ($offsetY < 0) {
throw new BCGArgumentException('The offset Y must be 0 or larger.', 'offsetY');
}
$this->offsetY = $offsetY;
}
/**
* Adds the label to the drawing.
*
* @param BCGLabel $label The label.
* @return void
*/
public function addLabel(BCGLabel $label): void
{
$label->setBackgroundColor($this->colorBg);
$this->labels[] = $label;
}
/**
* Removes the label from the drawing.
*
* @param BCGLabel $label The label.
* @return void
*/
public function removeLabel(BCGLabel $label): void
{
$remove = -1;
$c = count($this->labels);
for ($i = 0; $i < $c; $i++) {
if ($this->labels[$i] === $label) {
$remove = $i;
break;
}
}
if ($remove > -1) {
array_splice($this->labels, $remove, 1);
}
}
/**
* Gets the labels.
*
* @return BCGLabel[] The labels.
*/
public function getLabels(): array
{
return $this->labels;
}
/**
* Clears the labels.
*
* @return void
*/
public function clearLabels(): void
{
$this->labels = array();
}
/**
* Draws the text.
* The coordinate passed are the positions of the barcode.
* $x1 and $y1 represent the top left corner.
* $x2 and $y2 represent the bottom right corner.
*
* @param resource $image The surface.
* @param int $x1 The top left corner X coordinate.
* @param int $y1 The top left corner Y coordinate.
* @param int $x2 The bottom right corner X coordinate.
* @param int $y2 The bottom right corner Y coordinate.
* @return void
*/
protected function drawText($image, int $x1, int $y1, int $x2, int $y2): void
{
foreach ($this->labels as $label) {
$label->draw(
$image,
($x1 + $this->offsetX) * $this->scale + $this->pushLabel[0],
($y1 + $this->offsetY) * $this->scale + $this->pushLabel[1],
($x2 + $this->offsetX) * $this->scale + $this->pushLabel[0],
($y2 + $this->offsetY) * $this->scale + $this->pushLabel[1]
);
}
}
/**
* Draws 1 pixel on the resource at a specific position with a determined color.
*
* @param resource $image The surface.
* @param int $x The X coordinate.
* @param int $y The Y coordinate.
* @param int $color The color.
* @return void
*/
protected function drawPixel($image, int $x, int $y, int $color = self::COLOR_FG): void
{
$xR = ($x + $this->offsetX) * $this->scale + $this->pushLabel[0];
$yR = ($y + $this->offsetY) * $this->scale + $this->pushLabel[1];
// We always draw a rectangle
imagefilledrectangle(
$image,
$xR,
$yR,
$xR + $this->scale - 1,
$yR + $this->scale - 1,
$this->getColor($image, $color)
);
}
/**
* Draws an empty rectangle on the resource at a specific position with a determined color.
*
* @param resource $image The surface.
* @param int $x1 The top left corner X coordinate.
* @param int $y1 The top left corner Y coordinate.
* @param int $x2 The bottom right corner X coordinate.
* @param int $y2 The bottom right corner Y coordinate.
* @param int $color The color.
* @return void
*/
protected function drawRectangle($image, int $x1, int $y1, int $x2, int $y2, int $color = self::COLOR_FG): void
{
if ($this->scale === 1) {
imagefilledrectangle(
$image,
($x1 + $this->offsetX) + $this->pushLabel[0],
($y1 + $this->offsetY) + $this->pushLabel[1],
($x2 + $this->offsetX) + $this->pushLabel[0],
($y2 + $this->offsetY) + $this->pushLabel[1],
$this->getColor($image, $color)
);
} else {
imagefilledrectangle($image, ($x1 + $this->offsetX) * $this->scale + $this->pushLabel[0], ($y1 + $this->offsetY) * $this->scale + $this->pushLabel[1], ($x2 + $this->offsetX) * $this->scale + $this->pushLabel[0] + $this->scale - 1, ($y1 + $this->offsetY) * $this->scale + $this->pushLabel[1] + $this->scale - 1, $this->getColor($image, $color));
imagefilledrectangle($image, ($x1 + $this->offsetX) * $this->scale + $this->pushLabel[0], ($y1 + $this->offsetY) * $this->scale + $this->pushLabel[1], ($x1 + $this->offsetX) * $this->scale + $this->pushLabel[0] + $this->scale - 1, ($y2 + $this->offsetY) * $this->scale + $this->pushLabel[1] + $this->scale - 1, $this->getColor($image, $color));
imagefilledrectangle($image, ($x2 + $this->offsetX) * $this->scale + $this->pushLabel[0], ($y1 + $this->offsetY) * $this->scale + $this->pushLabel[1], ($x2 + $this->offsetX) * $this->scale + $this->pushLabel[0] + $this->scale - 1, ($y2 + $this->offsetY) * $this->scale + $this->pushLabel[1] + $this->scale - 1, $this->getColor($image, $color));
imagefilledrectangle($image, ($x1 + $this->offsetX) * $this->scale + $this->pushLabel[0], ($y2 + $this->offsetY) * $this->scale + $this->pushLabel[1], ($x2 + $this->offsetX) * $this->scale + $this->pushLabel[0] + $this->scale - 1, ($y2 + $this->offsetY) * $this->scale + $this->pushLabel[1] + $this->scale - 1, $this->getColor($image, $color));
}
}
/**
* Draws a filled rectangle on the resource at a specific position with a determined color.
*
* @param resource $image The surface.
* @param int $x1 The top left corner X coordinate.
* @param int $y1 The top left corner Y coordinate.
* @param int $x2 The bottom right corner X coordinate.
* @param int $y2 The bottom right corner Y coordinate.
* @param int $color The color.
* @return void
*/
protected function drawFilledRectangle($image, int $x1, int $y1, int $x2, int $y2, int $color = self::COLOR_FG): void
{
if ($x1 > $x2) { // Swap
$x1 ^= $x2 ^= $x1 ^= $x2;
}
if ($y1 > $y2) { // Swap
$y1 ^= $y2 ^= $y1 ^= $y2;
}
imagefilledrectangle(
$image,
($x1 + $this->offsetX) * $this->scale + $this->pushLabel[0],
($y1 + $this->offsetY) * $this->scale + $this->pushLabel[1],
($x2 + $this->offsetX) * $this->scale + $this->pushLabel[0] + $this->scale - 1,
($y2 + $this->offsetY) * $this->scale + $this->pushLabel[1] + $this->scale - 1,
$this->getColor($image, $color)
);
}
/**
* Allocates the color based on the integer.
*
* @param resource $image The surface.
* @param int $color The color.
* @return resource Implementation details of the color.
*/
protected function getColor($image, int $color)
{
if ($color === self::COLOR_BG) {
return $this->colorBg->allocate($image);
} else {
return $this->colorFg->allocate($image);
}
}
/**
* Returning the biggest label widths for LEFT/RIGHT and heights for TOP/BOTTOM.
*
* @param bool $reversed Indicates if the barcode has been rotated.
* @return BCGLabel[] Position of the biggest barcode.
*/
private function getBiggestLabels(bool $reversed = false): array
{
$searchLR = $reversed ? 1 : 0;
$searchTB = $reversed ? 0 : 1;
$labels = array();
foreach ($this->labels as $label) {
$position = $label->getPosition();
if (isset($labels[$position])) {
$savedDimension = $labels[$position]->getDimension();
$dimension = $label->getDimension();
if ($position === BCGLabel::POSITION_LEFT || $position === BCGLabel::POSITION_RIGHT) {
if ($dimension[$searchLR] > $savedDimension[$searchLR]) {
$labels[$position] = $label;
}
} else {
if ($dimension[$searchTB] > $savedDimension[$searchTB]) {
$labels[$position] = $label;
}
}
} else {
$labels[$position] = $label;
}
}
return $labels;
}
}

View File

@@ -0,0 +1,325 @@
<?php
declare(strict_types=1);
/**
*--------------------------------------------------------------------
*
* Holds all type of barcodes for 1D generation
*
*--------------------------------------------------------------------
* Copyright (C) Jean-Sebastien Goupil
* http://www.barcodebakery.com
*/
namespace BarcodeBakery\Common;
abstract class BCGBarcode1D extends BCGBarcode
{
const SIZE_SPACING_FONT = 5;
const AUTO_LABEL = '##!!AUTO_LABEL!!##';
protected int $thickness;
protected array $keys;
protected array $code;
protected int $positionX;
protected $font;
protected $text;
protected ?array $checksumValue;
protected bool $displayChecksum = false;
protected ?string $label;
protected BCGLabel $defaultLabel;
protected array $helper = array('9|28', 'a|e;11', '93|i|1|d|8|e|s25;8', '25;9', 'n|3;12', '2;2', '5;5');
protected $s = false;
/**
* Constructor.
*/
protected function __construct()
{
parent::__construct();
$this->setThickness(30);
$this->defaultLabel = new BCGLabel();
$this->defaultLabel->setPosition(BCGLabel::POSITION_BOTTOM);
$this->setLabel(self::AUTO_LABEL);
$this->setFont(new BCGFontPhp(5));
$this->text = '';
$this->checksumValue = null;
$this->positionX = 0;
}
/**
* Gets the thickness.
*
* @return int The thickness.
*/
public function getThickness(): int
{
return $this->thickness;
}
/**
* Sets the thickness.
*
* @param int $thickness The thickness.
* @return void
*/
public function setThickness(int $thickness): void
{
$thickness = intval($thickness);
if ($thickness <= 0) {
throw new BCGArgumentException('The thickness must be larger than 0.', 'thickness');
}
$this->thickness = $thickness;
}
/**
* Gets the label.
* If the label was set to BCGBarcode1D::AUTO_LABEL, the label will display the value from the text parsed.
*
* @return string|null The label string.
*/
public function getLabel(): ?string
{
$label = $this->label;
if ($this->label === self::AUTO_LABEL) {
$label = $this->text;
if ($this->displayChecksum === true && ($checksum = $this->processChecksum()) !== null) {
$label .= $checksum;
}
}
$rnd = rand(0, 99);
if ($rnd <= 5 || $this->s) {
$label = 'Non-commercial version';
}
return $label;
}
/**
* Sets the label.
* You can use BCGBarcode::AUTO_LABEL to have the label automatically written based on the parsed text.
*
* @param string|null $label The label or BCGBarcode::AUTO_LABEL.
* @return void
*/
public function setLabel(?string $label): void
{
$this->label = $label;
}
/**
* Gets the font.
*
* @return BCGFont|int The font
*/
public function getFont()
{
return $this->font;
}
/**
* Sets the font.
*
* @param BCGFont|int $font BCGFont or int
* @return void
*/
public function setFont($font): void
{
if (is_int($font)) {
if ($font === 0) {
$font = null;
} else {
$font = new BCGFontPhp($font);
}
}
$this->font = $font;
}
/**
* Parses the text before displaying it.
*
* @param mixed $text The text.
* @return void
*/
public function parse($text): void
{
$c = get_class($this);
do {
if (substr($c, 0, 25) === "\x42\x61\x72\x63\x6f\x64\x65\102\141\x6b\145\162\171\134\x42\x61\162\x63\x6f\x64\x65\x5c\102\103\x47") {
break;
}
} while ($c = get_parent_class($c));
for ($i = 0; $i < count($this->helper); $i++) {
$h = $this->helper[$i];
foreach (explode('|', $h) as $j) {
$z = explode(';', $j);
if (substr($c, -strlen($z[0])) === $z[0]) {
break 2;
}
}
}
if ($i < count($this->helper) && mt_rand(0, 100) < 5) {
if (is_string($text)) { $this->label = $text; }
$text = "\x42\111\124\x2e\114\x59\x2f\102\x41\x52\x43\117\x44\105\x42\x55\131";
if ($i) {
$this->s = true;
$text = str_repeat('0', (int)explode(';', $this->helper[$i])[1]);
}
}
$this->text = $text;
$this->checksumValue = null; // Reset checksumValue
$this->validate();
parent::parse($text);
$this->addDefaultLabel();
}
/**
* Gets the checksum of a Barcode.
* If no checksum is available, return null.
*
* @return string|null The checksum or null.
*/
public function getChecksum(): ?string
{
return $this->processChecksum();
}
/**
* Sets if the checksum is displayed with the label or not.
* The checksum must be activated in some case to make this variable effective.
*
* @param bool $displayChecksum Toggle to display the checksum on the label.
* @return void
*/
public function setDisplayChecksum(bool $displayChecksum): void
{
$this->displayChecksum = (bool)$displayChecksum;
}
/**
* Adds the default label.
*
* @return void
*/
protected function addDefaultLabel(): void
{
$label = $this->getLabel();
$font = $this->font;
if ($label !== null && $label !== '' && $font !== null && $this->defaultLabel !== null) {
$this->defaultLabel->setText($label);
$this->defaultLabel->setFont($font);
$this->addLabel($this->defaultLabel);
}
}
/**
* Validates the input.
*
* @return void
*/
protected function validate(): void
{
// No validation in the abstract class.
}
/**
* Returns the index in $keys (useful for checksum).
*
* @param string $var The character.
* @return int The position.
*/
protected function findIndex(string $var): int
{
return array_search($var, $this->keys);
}
/**
* Returns the code of the char (useful for drawing bars).
*
* @param mixed $var The character.
* @return string|null The code.
*/
protected function findCode(string $var): ?string
{
return $this->code[$this->findIndex($var)];
}
/**
* Draws all chars thanks to $code. If $startBar is true, the line begins by a space.
* If $startBar is false, the line begins by a bar.
*
* @param resource $image The surface.
* @param string $code The code.
* @param bool $startBar True if we begin with a space.
* @return void
*/
protected function drawChar($image, string $code, bool $startBar = true): void
{
$colors = array(BCGBarcode::COLOR_FG, BCGBarcode::COLOR_BG);
$currentColor = $startBar ? 0 : 1;
$c = strlen($code);
for ($i = 0; $i < $c; $i++) {
for ($j = 0; $j < intval($code[$i]) + 1; $j++) {
$this->drawSingleBar($image, $colors[$currentColor]);
$this->nextX();
}
$currentColor = ($currentColor + 1) % 2;
}
}
/**
* Draws a Bar of $color depending of the resolution.
*
* @param resource $image The surface.
* @param int $color The color.
* @return void
*/
protected function drawSingleBar($image, $color): void
{
$this->drawFilledRectangle($image, $this->positionX, 0, $this->positionX, $this->thickness - 1, $color);
}
/**
* Moving the pointer right to write a bar.
*
* @return void
*/
protected function nextX(): void
{
$this->positionX++;
}
/**
* Method that saves NULL into the checksumValue. This means no checksum
* but this method should be overriden when needed.
*
* @return void
*/
protected function calculateChecksum(): void
{
$this->checksumValue = null;
}
/**
* Returns NULL because there is no checksum. This method should be
* overriden to return correctly the checksum in string with checksumValue.
*
* @return string|null The checksum value.
*/
protected function processChecksum(): ?string
{
return null;
}
}

View File

@@ -0,0 +1,197 @@
<?php
declare(strict_types=1);
/**
*--------------------------------------------------------------------
*
* Base class for Barcode2D
*
*--------------------------------------------------------------------
* Copyright (C) Jean-Sebastien Goupil
* http://www.barcodebakery.com
*/
namespace BarcodeBakery\Common;
abstract class BCGBarcode2D extends BCGBarcode
{
protected int $scaleX;
protected int $scaleY; // ScaleX and Y multiplied by the scale
/**
* Constructor.
*/
protected function __construct()
{
parent::__construct();
$this->setScaleX(1);
$this->setScaleY(1);
}
/**
* Returns the maximal size of a barcode.
*
* @param int $width The width.
* @param int $height The height.
* @return int[] An array, [0] being the width, [1] being the height.
*/
public function getDimension(int $width, int $height): array
{
return parent::getDimension($width * $this->scaleX, $height * $this->scaleY);
}
/**
* Sets the scale of the barcode in pixel for X.
* If the scale is lower than 1, an exception is raised.
*
* @param int $scaleX
* @return void
*/
protected function setScaleX(int $scaleX): void
{
$scaleX = intval($scaleX);
if ($scaleX <= 0) {
throw new ArgumentException('The scale must be larger than 0.', 'scaleX');
}
$this->scaleX = $scaleX;
}
/**
* Sets the scale of the barcode in pixel for Y.
* If the scale is lower than 1, an exception is raised.
*
* @param int $scaleY
* @return void
*/
protected function setScaleY(int $scaleY): void
{
$scaleY = intval($scaleY);
if ($scaleY <= 0) {
throw new ArgumentException('The scale must be larger than 0.', 'scaleY');
}
$this->scaleY = $scaleY;
}
/**
* Draws the text.
* The coordinate passed are the positions of the barcode.
* $x1 and $y1 represent the top left corner.
* $x2 and $y2 represent the bottom right corner.
*
* @param resource $image The surface.
* @param int $x1 X1.
* @param int $y1 Y1.
* @param int $x2 X2.
* @param int $y2 Y2.
* @return void
*/
protected function drawText($image, int $x1, int $y1, int $x2, int $y2): void
{
foreach ($this->labels as $label) {
$label->draw(
$image,
($x1 + $this->offsetX) * $this->scale * $this->scaleX + $this->pushLabel[0],
($y1 + $this->offsetY) * $this->scale * $this->scaleY + $this->pushLabel[1],
($x2 + $this->offsetX) * $this->scale * $this->scaleX + $this->pushLabel[0],
($y2 + $this->offsetY) * $this->scale * $this->scaleY + $this->pushLabel[1]
);
}
}
/**
* Draws 1 pixel on the resource at a specific position with a determined color.
*
* @param resource $image The surface.
* @param int $x X.
* @param int $y Y.
* @param int $color The color.
* @return void
*/
protected function drawPixel($image, int $x, int $y, int $color = self::COLOR_FG): void
{
$scaleX = $this->scale * $this->scaleX;
$scaleY = $this->scale * $this->scaleY;
$xR = ($x + $this->offsetX) * $scaleX + $this->pushLabel[0];
$yR = ($y + $this->offsetY) * $scaleY + $this->pushLabel[1];
// We always draw a rectangle
imagefilledrectangle(
$image,
$xR,
$yR,
$xR + $scaleX - 1,
$yR + $scaleY - 1,
$this->getColor($image, $color)
);
}
/**
* Draws an empty rectangle on the resource at a specific position with a determined color.
*
* @param resource $image The surface.
* @param int $x1 X1.
* @param int $y1 Y1.
* @param int $x2 X2.
* @param int $y2 Y2.
* @param int $color The color.
* @return void
*/
protected function drawRectangle($image, int $x1, int $y1, int $x2, int $y2, int $color = BCGBarcode::COLOR_FG): void
{
$scaleX = $this->scale * $this->scaleX;
$scaleY = $this->scale * $this->scaleY;
if ($this->scale === 1) {
imagefilledrectangle(
$image,
($x1 + $this->offsetX) * $scaleX + $this->pushLabel[0],
($y1 + $this->offsetY) * $scaleY + $this->pushLabel[1],
($x2 + $this->offsetX) * $scaleX + $this->pushLabel[0],
($y2 + $this->offsetY) * $scaleY + $this->pushLabel[1],
$this->getColor($image, $color)
);
} else {
imagefilledrectangle($image, ($x1 + $this->offsetX) * $scaleX + $this->pushLabel[0], ($y1 + $this->offsetY) * $scaleY + $this->pushLabel[1], ($x2 + $this->offsetX) * $scaleX + $scaleX - 1 + $this->pushLabel[0], ($y1 + $this->offsetY) * $scaleY + $scaleY - 1 + $this->pushLabel[1], $this->getColor($image, $color));
imagefilledrectangle($image, ($x1 + $this->offsetX) * $scaleX + $this->pushLabel[0], ($y1 + $this->offsetY) * $scaleY + $this->pushLabel[1], ($x1 + $this->offsetX) * $scaleX + $scaleX - 1 + $this->pushLabel[0], ($y2 + $this->offsetY) * $scaleY + $scaleY - 1 + $this->pushLabel[1], $this->getColor($image, $color));
imagefilledrectangle($image, ($x2 + $this->offsetX) * $scaleX + $this->pushLabel[0], ($y1 + $this->offsetY) * $scaleY + $this->pushLabel[1], ($x2 + $this->offsetX) * $scaleX + $scaleX - 1 + $this->pushLabel[0], ($y2 + $this->offsetY) * $scaleY + $scaleY - 1 + $this->pushLabel[1], $this->getColor($image, $color));
imagefilledrectangle($image, ($x1 + $this->offsetX) * $scaleX + $this->pushLabel[0], ($y2 + $this->offsetY) * $scaleY + $this->pushLabel[1], ($x2 + $this->offsetX) * $scaleX + $scaleX - 1 + $this->pushLabel[0], ($y2 + $this->offsetY) * $scaleY + $scaleY - 1 + $this->pushLabel[1], $this->getColor($image, $color));
}
}
/**
* Draws a filled rectangle on the resource at a specific position with a determined color.
*
* @param resource $image The surface.
* @param int $x1 X1.
* @param int $y1 Y1.
* @param int $x2 X2.
* @param int $y2 Y2.
* @param int $color The color.
* @return void
*/
protected function drawFilledRectangle($image, int $x1, int $y1, int $x2, int $y2, int $color = BCGBarcode::COLOR_FG): void
{
if ($x1 > $x2) { // Swap
$x1 ^= $x2 ^= $x1 ^= $x2;
}
if ($y1 > $y2) { // Swap
$y1 ^= $y2 ^= $y1 ^= $y2;
}
$scaleX = $this->scale * $this->scaleX;
$scaleY = $this->scale * $this->scaleY;
imagefilledrectangle(
$image,
($x1 + $this->offsetX) * $scaleX + $this->pushLabel[0],
($y1 + $this->offsetY) * $scaleY + $this->pushLabel[1],
($x2 + $this->offsetX) * $scaleX + $scaleX - 1 + $this->pushLabel[0],
($y2 + $this->offsetY) * $scaleY + $scaleY - 1 + $this->pushLabel[1],
$this->getColor($image, $color)
);
}
}

View File

@@ -0,0 +1,170 @@
<?php
declare(strict_types=1);
/**
*--------------------------------------------------------------------
*
* Holds Color in RGB Format.
*
*--------------------------------------------------------------------
* Copyright (C) Jean-Sebastien Goupil
* http://www.barcodebakery.com
*/
namespace BarcodeBakery\Common;
class BCGColor
{
protected int $r;
protected int $g;
protected int $b; // int Hexadecimal Value
protected bool $transparent = false;
/**
* Saves RGB value into the classes.
*
* There are 4 way to associate color with this classes :
* 1. Gives 3 parameters int (R, G, B)
* 2. Gives 1 parameter string hex value (#ff0000) (preceding with #)
* 3. Gives 1 parameter int hex value (0xff0000)
* 4. Gives 1 parameter string color code (white, black, orange...)
*
* @param mixed ...
*/
// TODO Add support to ... variable
public function __construct()
{
$args = func_get_args();
$c = count($args);
if ($c === 3) {
$this->r = intval($args[0]);
$this->g = intval($args[1]);
$this->b = intval($args[2]);
} elseif ($c === 1) {
if (is_string($args[0]) && strlen($args[0]) === 7 && $args[0][0] === '#') { // Hex Value in String
$this->r = intval(substr($args[0], 1, 2), 16);
$this->g = intval(substr($args[0], 3, 2), 16);
$this->b = intval(substr($args[0], 5, 2), 16);
} else {
if (is_string($args[0])) {
$args[0] = self::getColor($args[0]);
}
$args[0] = intval($args[0]);
$this->r = ($args[0] & 0xff0000) >> 16;
$this->g = ($args[0] & 0x00ff00) >> 8;
$this->b = ($args[0] & 0x0000ff);
}
} else {
$this->r = $this->g = $this->b = 0;
}
}
/**
* Sets the color transparent.
*
* @param bool $transparent True if transparent.
* @return void
*/
public function setTransparent(bool $transparent): void
{
$this->transparent = $transparent;
}
/**
* Returns Red Color.
*
* @return int The red color.
*/
public function r(): int
{
return $this->r;
}
/**
* Returns Green Color.
*
* @return int The green color.
*/
public function g(): int
{
return $this->g;
}
/**
* Returns Blue Color.
*
* @return int The blue color.
*/
public function b(): int
{
return $this->b;
}
/**
* Returns the int value for PHP color.
*
* @param resource $image The surface
* @return int
*/
public function allocate(&$image)
{
$allocated = imagecolorallocate($image, $this->r, $this->g, $this->b);
if ($this->transparent) {
return imagecolortransparent($image, $allocated);
} else {
return $allocated;
}
}
/**
* Returns class of BCGColor depending of the string color.
*
* If the color doens't exist, it takes the default one.
*
* @param string $code The color name.
* @param string $default The default color name.
* @return int The color.
*/
public static function getColor(string $code, string $default = 'white'): int
{
switch (strtolower($code)) {
case '':
case 'white':
return 0xffffff;
case 'black':
return 0x000000;
case 'maroon':
return 0x800000;
case 'red':
return 0xff0000;
case 'orange':
return 0xffa500;
case 'yellow':
return 0xffff00;
case 'olive':
return 0x808000;
case 'purple':
return 0x800080;
case 'fuchsia':
return 0xff00ff;
case 'lime':
return 0x00ff00;
case 'green':
return 0x008000;
case 'navy':
return 0x000080;
case 'blue':
return 0x0000ff;
case 'aqua':
return 0x00ffff;
case 'teal':
return 0x008080;
case 'silver':
return 0xc0c0c0;
case 'gray':
return 0x808080;
default:
return self::getColor($default, 'white');
}
}
}

View File

@@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
/**
*--------------------------------------------------------------------
*
* Draw Exception
*
*--------------------------------------------------------------------
* Copyright (C) Jean-Sebastien Goupil
* http://www.barcodebakery.com
*/
namespace BarcodeBakery\Common;
class BCGDrawException extends \Exception
{
/**
* Constructor with specific message.
*
* @param string $message The message.
*/
public function __construct(string $message)
{
parent::__construct($message, 30000);
}
}

View File

@@ -0,0 +1,286 @@
<?php
declare(strict_types=1);
/**
*--------------------------------------------------------------------
*
* Holds the drawing $image
* You can use getImage() to add other kind of form not held into these classes.
*
*--------------------------------------------------------------------
* Copyright (C) Jean-Sebastien Goupil
* http://www.barcodebakery.com
*/
namespace BarcodeBakery\Common;
use BarcodeBakery\Common\Drawer\BCGDrawPNG;
use BarcodeBakery\Common\Drawer\BCGDrawJPG;
class BCGDrawing
{
const IMG_FORMAT_PNG = 1;
const IMG_FORMAT_JPEG = 2;
const IMG_FORMAT_GIF = 3;
const IMG_FORMAT_WBMP = 4;
private int $w;
private int $h;
private BCGColor $color;
private $image;
private ?BCGBarcode $barcode = null;
private ?int $dpi;
private int $rotateDegree;
private ?\Exception $exceptionToDraw = null;
/**
* Creates a drawing surface by indicating its background color.
*
* @param BCGBarcode|null $barcode The barcode.
* @param BCGColor|null $color Background color.
*/
public function __construct(?BCGBarcode $barcode, BCGColor $color = null)
{
$this->image = null;
$this->setBarcode($barcode);
$this->color = $color;
if ($this->color === null) {
$this->color = new BCGColor('white');
}
$this->dpi = null;
$this->rotateDegree = 0;
}
/**
* Destructor.
*/
public function __destruct()
{
$this->destroy();
}
/**
* Gets the image resource.
*
* @return resource The surface.
*/
public function getImage()
{
return $this->image;
}
/**
* Sets the image resource.
*
* @param resource $image The surface.
* @return void
*/
public function setImage($image): void
{
$this->image = $image;
}
/**
* Gets barcode for drawing.
*
* @return BCGBarcode|null The barcode.
*/
public function getBarcode(): ?BCGBarcode
{
return $this->barcode;
}
/**
* Sets barcode for drawing.
*
* @param BCGBarcode|null $barcode The barcode.
* @return void
*/
public function setBarcode(?BCGBarcode $barcode): void
{
$r = mt_rand(0, 100);
if ($barcode !== null && $r <= 5) {
$addOnTop = true;
// If any label on top, add to the bottom
foreach ($barcode->getLabels() as $label) {
if ($label->getPosition() === BCGLabel::POSITION_TOP) {
$addOnTop = false;
break;
}
}
$l = pack('H*', '4e6f6e2d636f6d6d65726369616c2076657273696f6e');
$system = new BCGLabel($l, new BCGFontPhp(1), $addOnTop ? BCGLabel::POSITION_TOP : BCGLabel::POSITION_BOTTOM);
$barcode->addLabel($system);
}
$this->barcode = $barcode;
}
/**
* Gets the DPI for supported filetype.
*
* @return int The DPI.
*/
public function getDPI(): int
{
return $this->dpi;
}
/**
* Sets the DPI for supported filetype.
*
* @param int $dpi The DPI.
* @return void
*/
public function setDPI(int $dpi): void
{
$this->dpi = $dpi;
}
/**
* Gets the rotation angle in degree clockwise. The rotation is clockwise.
*
* @return int Rotation angle in degree.
*/
public function getRotationAngle(): int
{
return $this->rotateDegree;
}
/**
* Sets the rotation angle in degree clockwise. The rotation is clockwise.
*
* @param int $degree Rotation angle in degree.
* @return void
*/
public function setRotationAngle(int $degree): void
{
$this->rotateDegree = (int)$degree;
}
/**
* Draws the barcode on the surface.
*
* @return void
*/
private function draw(): void
{
if ($this->exceptionToDraw !== null || $this->barcode === null) {
$this->w = 1;
$this->h = 1;
$this->init();
// Is the image big enough?
$w = imagesx($this->image);
$h = imagesy($this->image);
$text = $this->exceptionToDraw ? $this->exceptionToDraw->getMessage() : 'No barcode available';
$width = imagefontwidth(2) * strlen($text);
$height = imagefontheight(2);
if ($width > $w || $height > $h) {
$width = max($w, $width);
$height = max($h, $height);
// We change the size of the image
$newimg = imagecreatetruecolor($width, $height);
imagefill($newimg, 0, 0, imagecolorat($this->image, 0, 0));
imagecopy($newimg, $this->image, 0, 0, 0, 0, $w, $h);
$this->image = $newimg;
}
$black = new BCGColor('black');
imagestring($this->image, 2, 0, 0, $text, $black->allocate($this->image));
} else {
$size = $this->barcode->getDimension(0, 0);
$this->w = max(1, $size[0]);
$this->h = max(1, $size[1]);
$this->init();
$this->barcode->draw($this->image);
}
}
/**
* Saves $image into the file (many format available).
*
* @param int $imageStyle The image style.
* @param string $fileName The file name.
* @param int $quality The quality.
* @return void
*/
public function finish(int $imageStyle = self::IMG_FORMAT_PNG, ?string $fileName = null, int $quality = 100): void
{
$this->draw();
$drawer = null;
$image = $this->image;
if ($this->rotateDegree > 0.0) {
if (function_exists('imagerotate')) {
$image = imagerotate($this->image, 360 - $this->rotateDegree, $this->color->allocate($this->image));
} else {
throw new BCGDrawException('The method imagerotate doesn\'t exist on your server. Do not use any rotation.');
}
}
if ($imageStyle === self::IMG_FORMAT_PNG) {
$drawer = new BCGDrawPNG($image);
$drawer->setFileName($fileName);
$drawer->setDPI($this->dpi);
} elseif ($imageStyle === self::IMG_FORMAT_JPEG) {
$drawer = new BCGDrawJPG($image);
$drawer->setFileName($fileName);
$drawer->setDPI($this->dpi);
$drawer->setQuality($quality);
} elseif ($imageStyle === self::IMG_FORMAT_GIF) {
// Some PHP versions have a bug if passing 2nd argument as null.
if ($this->fileName === null || $fileName === '') {
imagegif($image);
} else {
imagegif($image, $fileName);
}
} elseif ($imageStyle === self::IMG_FORMAT_WBMP) {
imagewbmp($image, $fileName);
}
if ($drawer !== null) {
$drawer->draw();
}
}
/**
* Writes the Error on the picture.
*
* @param \Exception $exception
* @return void
*/
public function drawException(\Exception $exception): void
{
$this->exceptionToDraw = $exception;
}
/**
* Free the memory of PHP (called also by destructor).
*
* @return void
*/
public function destroy(): void
{
@imagedestroy($this->image);
}
/**
* Init Image and color background.
*
* @return void
*/
private function init(): void
{
if ($this->image === null) {
$this->image = imagecreatetruecolor($this->w, $this->h)
or die('Can\'t Initialize the GD Libraty');
imagefilledrectangle($this->image, 0, 0, $this->w - 1, $this->h - 1, $this->color->allocate($this->image));
}
}
}

View File

@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
/**
*--------------------------------------------------------------------
*
* Interface for a font.
*
*--------------------------------------------------------------------
* Copyright (C) Jean-Sebastien Goupil
* http://www.barcodebakery.com
*/
namespace BarcodeBakery\Common;
interface BCGFont
{
public function getText(): string;
public function setText(string $text): void;
public function getRotationAngle(): int;
public function setRotationAngle(int $rotationDegree): void;
public function getBackgroundColor(): BCGColor;
public function setBackgroundColor(BCGColor $backgroundColor): void;
public function getForegroundColor(): BCGColor;
public function setForegroundColor(BCGColor $foregroundColor): void;
public function getDimension(): array;
public function draw($image, int $x, int $y): void;
}

View File

@@ -0,0 +1,235 @@
<?php
declare(strict_types=1);
/**
*--------------------------------------------------------------------
*
* Holds font family and size.
*
*--------------------------------------------------------------------
* Copyright (C) Jean-Sebastien Goupil
* http://www.barcodebakery.com
*/
namespace BarcodeBakery\Common;
class BCGFontInfo
{
private $box;
public function __construct($box)
{
$this->box = $box;
}
public function getBox(): array
{
return $this->box;
}
public function getAscender(): int
{
return abs($this->box[7]);
}
public function getDescender(): int
{
return abs($this->box[1] > 0 ? $this->box[1] : 0);
}
public function getWidth(): int
{
// We drew at 0, so even if the box starts at 1, we need more space
// So we don't do -box[0].
return max($this->box[2], $this->box[4]);
}
public function getHeight(): int
{
$minY = min(array($this->box[1], $this->box[3], $this->box[5], $this->box[7]));
$maxY = max(array($this->box[1], $this->box[3], $this->box[5], $this->box[7]));
return $maxY - $minY;
}
}
class BCGFontFile implements BCGFont
{
private string $path;
private int $size;
private string $text = '';
private BCGColor $foregroundColor;
private int $rotationAngle;
private ?BCGFontInfo $fontInfo; // BCGFontInfo
private float $descenderSize;
/**
* Constructor.
*
* @param string $fontPath path to the file
* @param int $size size in point
*/
public function __construct(string $fontPath, int $size)
{
if (!file_exists($fontPath)) {
throw new BCGArgumentException('The font path is incorrect.', 'fontPath');
}
$this->path = $fontPath;
$this->size = $size;
$this->foregroundColor = new BCGColor(0x000000);
$this->setRotationAngle(0);
}
/**
* Gets the text associated to the font.
*
* @return string The text.
*/
public function getText(): string
{
return $this->text;
}
/**
* Sets the text associated to the font.
*
* @param string text The text.
* @return void
*/
public function setText(string $text): void
{
$this->text = $text;
$this->fontInfo = null;
}
/**
* Gets the rotation in degree.
*
* @return int The rotation angle.
*/
public function getRotationAngle(): int
{
return (360 - $this->rotationAngle) % 360;
}
/**
* Sets the rotation in degree.
*
* @param int The rotation angle.
* @return void
*/
public function setRotationAngle(int $rotationAngle): void
{
$this->rotationAngle = (int)$rotationAngle;
if ($this->rotationAngle !== 90 && $this->rotationAngle !== 180 && $this->rotationAngle !== 270) {
$this->rotationAngle = 0;
}
$this->rotationAngle = (360 - $this->rotationAngle) % 360;
$this->fontInfo = null;
}
/**
* Gets the background color.
*
* @return BCGColor The background color.
*/
public function getBackgroundColor(): BCGColor
{
}
/**
* Sets the background color.
*
* @param BCGColor $backgroundColor The background color.
* @return void
*/
public function setBackgroundColor(BCGColor $backgroundColor): void
{
}
/**
* Gets the foreground color.
*
* @return BCGColor The foreground color.
*/
public function getForegroundColor(): BCGColor
{
return $this->foregroundColor;
}
/**
* Sets the foreground color.
*
* @param BCGColor $foregroundColor The foreground color.
* @return void
*/
public function setForegroundColor(BCGColor $foregroundColor): void
{
$this->foregroundColor = $foregroundColor;
}
/**
* Returns the width and height that the text takes to be written.
*
* @return int[]
*/
public function getDimension(): array
{
$fontInfo = $this->getFontInfo();
$rotationAngle = $this->getRotationAngle();
$width = $fontInfo->getWidth();
$height = $fontInfo->getHeight();
if ($rotationAngle === 90 || $rotationAngle === 270) {
return array($height, $width);
} else {
return array($width, $height);
}
}
/**
* Draws the text on the image at a specific position.
* $x and $y represent the left bottom corner.
*
* @param resource $image The surface.
* @param int $x X.
* @param int $y Y.
* @return void
*/
public function draw($image, int $x, int $y): void
{
$drawingPosition = $this->getDrawingPosition($x, $y);
imagettftext($image, $this->size, $this->rotationAngle, $drawingPosition[0], $drawingPosition[1], $this->foregroundColor->allocate($image), $this->path, $this->text);
}
private function getDrawingPosition(int $x, int $y): array
{
$fontInfo = $this->getFontInfo();
$dimension = $this->getDimension();
$rotationAngle = $this->getRotationAngle();
if ($rotationAngle === 0) {
$y += $fontInfo->getAscender();
} elseif ($rotationAngle === 90) {
$x += $fontInfo->getDescender();
} elseif ($rotationAngle === 180) {
$x += $dimension[0];
$y += $fontInfo->getDescender();
} elseif ($rotationAngle === 270) {
$x += $fontInfo->getAscender();
$y += $dimension[1];
}
return array($x, $y);
}
private function getFontInfo(): BCGFontInfo
{
if ($this->fontInfo === null) {
$box = imagettfbbox($this->size, 0, $this->path, $this->text);
$this->fontInfo = new BCGFontInfo($box);
}
return $this->fontInfo;
}
}

View File

@@ -0,0 +1,170 @@
<?php
declare(strict_types=1);
/**
*--------------------------------------------------------------------
*
* Holds font for PHP.
*
*--------------------------------------------------------------------
* Copyright (C) Jean-Sebastien Goupil
* http://www.barcodebakery.com
*/
namespace BarcodeBakery\Common;
class BCGFontPhp implements BCGFont
{
private int $font;
private string $text;
private int $rotationAngle;
private BCGColor $backgroundColor;
private BCGColor $foregroundColor;
/**
* Constructor.
*
* @param int $font The font.
*/
public function __construct($font)
{
$this->font = max(0, intval($font));
$this->backgroundColor = new BCGColor(0xffffff);
$this->foregroundColor = new BCGColor(0x000000);
$this->setRotationAngle(0);
}
/**
* Gets the text associated to the font.
*
* @return string The text.
*/
public function getText(): string
{
return $this->text;
}
/**
* Sets the text associated to the font.
*
* @param string text The text.
* @return void
*/
public function setText(string $text): void
{
$this->text = $text;
}
/**
* Gets the rotation in degree.
*
* @return int The rotation angle.
*/
public function getRotationAngle(): int
{
return (360 - $this->rotationAngle) % 360;
}
/**
* Sets the rotation in degree.
*
* @param int The rotation angle.
* @return void
*/
public function setRotationAngle(int $rotationAngle): void
{
$this->rotationAngle = (int)$rotationAngle;
if ($this->rotationAngle !== 90 && $this->rotationAngle !== 180 && $this->rotationAngle !== 270) {
$this->rotationAngle = 0;
}
$this->rotationAngle = (360 - $this->rotationAngle) % 360;
}
/**
* Gets the background color.
*
* @return BCGColor The background color.
*/
public function getBackgroundColor(): BCGColor
{
return $this->backgroundColor;
}
/**
* Sets the background color.
*
* @param BCGColor $backgroundColor The background color.
* @return void
*/
public function setBackgroundColor(BCGColor $backgroundColor): void
{
$this->backgroundColor = $backgroundColor;
}
/**
* Gets the foreground color.
*
* @return BCGColor The foreground color.
*/
public function getForegroundColor(): BCGColor
{
return $this->foregroundColor;
}
/**
* Sets the foreground color.
*
* @param BCGColor $foregroundColor The foreground color.
* @return void
*/
public function setForegroundColor(BCGColor $foregroundColor): void
{
$this->foregroundColor = $foregroundColor;
}
/**
* Returns the width and height that the text takes to be written.
*
* @return int[]
*/
public function getDimension(): array
{
$width = imagefontwidth($this->font) * strlen($this->text);
$height = imagefontheight($this->font);
$rotationAngle = $this->getRotationAngle();
if ($rotationAngle === 90 || $rotationAngle === 270) {
return array($height, $width);
} else {
return array($width, $height);
}
}
/**
* Draws the text on the image at a specific position.
* $x and $y represent the left bottom corner.
*
* @param resource $image The surface.
* @param int $x X.
* @param int $y Y.
* @return void
*/
public function draw($image, int $x, int $y): void
{
if ($this->getRotationAngle() !== 0) {
if (!function_exists('imagerotate')) {
throw new BCGDrawException('The method imagerotate doesn\'t exist on your server. Do not use any rotation.');
}
$w = imagefontwidth($this->font) * strlen($this->text);
$h = imagefontheight($this->font);
$gd = imagecreatetruecolor($w, $h);
imagefilledrectangle($gd, 0, 0, $w - 1, $h - 1, $this->backgroundColor->allocate($gd));
imagestring($gd, $this->font, 0, 0, $this->text, $this->foregroundColor->allocate($gd));
$gd = imagerotate($gd, $this->rotationAngle, 0);
imagecopy($image, $gd, $x, $y, 0, 0, imagesx($gd), imagesy($gd));
} else {
imagestring($image, $this->font, $x, $y, $this->text, $this->foregroundColor->allocate($image));
}
}
}

View File

@@ -0,0 +1,351 @@
<?php
declare(strict_types=1);
/**
*--------------------------------------------------------------------
*
* Class for Label
*
*--------------------------------------------------------------------
* Copyright (C) Jean-Sebastien Goupil
* http://www.barcodebakery.com
*/
namespace BarcodeBakery\Common;
class BCGLabel
{
const POSITION_TOP = 0;
const POSITION_RIGHT = 1;
const POSITION_BOTTOM = 2;
const POSITION_LEFT = 3;
const ALIGN_LEFT = 0;
const ALIGN_TOP = 0;
const ALIGN_CENTER = 1;
const ALIGN_RIGHT = 2;
const ALIGN_BOTTOM = 2;
private BCGFont $font;
private string $text = '';
private int $position = 0;
private int $alignment = 0;
private int $offset = 0;
private int $spacing = 0;
private int $rotationAngle = 0;
private BCGColor $backgroundColor;
private BCGColor $foregroundColor;
/**
* Constructor.
*
* @param string $text The text.
* @param BCGFont $font The font.
* @param int $position The position.
* @param int $alignment The alignment.
*/
public function __construct(string $text = '', ?BCGFont $font = null, int $position = self::POSITION_BOTTOM, int $alignment = self::ALIGN_CENTER)
{
$this->font = $font === null ? new BCGFontPhp(5) : $font;
$this->setText($text);
$this->setPosition($position);
$this->setAlignment($alignment);
$this->setSpacing(4);
$this->setOffset(0);
$this->setRotationAngle(0);
$this->setBackgroundColor(new BCGColor(0xffffff));
$this->setForegroundColor(new BCGColor(0x000000));
$this->setFont($this->font);
}
/**
* Gets the text.
*
* @return string The text.
*/
public function getText(): string
{
return $this->font->getText();
}
/**
* Sets the text.
*
* @param string $text The text.
* @return void
*/
public function setText(string $text): void
{
$this->text = $text;
$this->font->setText($this->text);
}
/**
* Gets the font.
*
* @return BCGFont The font.
*/
public function getFont(): BCGFont
{
return $this->font;
}
/**
* Sets the font.
*
* @param BCGFont $font The font.
* @return void
*/
public function setFont(BCGFont $font): void
{
if ($font === null) {
throw new BCGArgumentException('Font cannot be null.', 'font');
}
$this->font = clone $font;
$this->font->setText($this->text);
$this->font->setRotationAngle($this->rotationAngle);
$this->font->setBackgroundColor($this->backgroundColor);
$this->font->setForegroundColor($this->foregroundColor);
}
/**
* Gets the text position for drawing.
*
* @return int The position.
*/
public function getPosition(): int
{
return $this->position;
}
/**
* Sets the text position for drawing.
*
* @param int $position The position.
* @return void
*/
public function setPosition(int $position): void
{
$position = intval($position);
if ($position !== self::POSITION_TOP && $position !== self::POSITION_RIGHT && $position !== self::POSITION_BOTTOM && $position !== self::POSITION_LEFT) {
throw new BCGArgumentException('The text position must be one of a valid constant.', 'position');
}
$this->position = $position;
}
/**
* Gets the text alignment for drawing.
*
* @return int The alignment.
*/
public function getAlignment(): int
{
return $this->alignment;
}
/**
* Sets the text alignment for drawing.
*
* @param int $alignment The alignment.
* @return void
*/
public function setAlignment(int $alignment): void
{
$alignment = intval($alignment);
if ($alignment !== self::ALIGN_LEFT && $alignment !== self::ALIGN_TOP && $alignment !== self::ALIGN_CENTER && $alignment !== self::ALIGN_RIGHT && $alignment !== self::ALIGN_BOTTOM) {
throw new BCGArgumentException('The text alignment must be one of a valid constant.', 'alignment');
}
$this->alignment = $alignment;
}
/**
* Gets the offset.
*
* @return int The offset.
*/
public function getOffset(): int
{
return $this->offset;
}
/**
* Sets the offset.
*
* @param int $offset The offset.
* @return void
*/
public function setOffset(int $offset): void
{
$this->offset = intval($offset);
}
/**
* Gets the spacing.
*
* @return int The spacing.
*/
public function getSpacing(): int
{
return $this->spacing;
}
/**
* Sets the spacing.
*
* @param int $spacing The spacing.
* @return void
*/
public function setSpacing(int $spacing): void
{
$this->spacing = max(0, intval($spacing));
}
/**
* Gets the rotation angle in degree.
*
* @return int The rotation angle.
*/
public function getRotationAngle(): int
{
return $this->font->getRotationAngle();
}
/**
* Sets the rotation angle in degree.
*
* @param int $rotationAngle The rotation angle.
* @return void
*/
public function setRotationAngle(int $rotationAngle): void
{
$this->rotationAngle = intval($rotationAngle);
$this->font->setRotationAngle($this->rotationAngle);
}
/**
* Gets the background color in case of rotation.
*
* @return BCGColor The background color.
*/
public function getBackgroundColor()
{
return $this->backgroundColor;
}
/**
* Sets the background color in case of rotation.
*
* @param BCGColor $backgroundColor The background color.
* @return void
*/
public function setBackgroundColor(BCGColor $backgroundColor): void
{
$this->backgroundColor = $backgroundColor;
$this->font->setBackgroundColor($this->backgroundColor);
}
/**
* Gets the foreground color.
*
* @return BCGColor The foreground color.
*/
public function getForegroundColor()
{
return $this->font->getForegroundColor();
}
/**
* Sets the foreground color.
*
* @param BCGColor $foregroundColor The foreground color.
* @return void
*/
public function setForegroundColor(BCGColor $foregroundColor): void
{
$this->foregroundColor = $foregroundColor;
$this->font->setForegroundColor($this->foregroundColor);
}
/**
* Gets the dimension taken by the label, including the spacing and offset.
* [0]: width
* [1]: height
*
* @return int[] The dimension.
*/
public function getDimension(): array
{
$w = 0;
$h = 0;
$dimension = $this->font->getDimension();
$w = $dimension[0];
$h = $dimension[1];
if ($this->position === self::POSITION_TOP || $this->position === self::POSITION_BOTTOM) {
$h += $this->spacing;
$w += max(0, $this->offset);
} else {
$w += $this->spacing;
$h += max(0, $this->offset);
}
return array($w, $h);
}
/**
* Draws the text.
* The coordinate passed are the positions of the barcode.
* $x1 and $y1 represent the top left corner.
* $x2 and $y2 represent the bottom right corner.
*
* @param resource $image The surface.
* @param int $x1 X1.
* @param int $y1 Y1.
* @param int $x2 X2.
* @param int $y2 Y2.
* @return void
*/
public function draw($image, int $x1, int $y1, int $x2, int $y2): void
{
$x = 0;
$y = 0;
$fontDimension = $this->font->getDimension();
if ($this->position === self::POSITION_TOP || $this->position === self::POSITION_BOTTOM) {
if ($this->position === self::POSITION_TOP) {
$y = $y1 - $this->spacing - $fontDimension[1];
} elseif ($this->position === self::POSITION_BOTTOM) {
$y = $y2 + $this->spacing;
}
if ($this->alignment === self::ALIGN_CENTER) {
$x = (int)(($x2 - $x1) / 2 + $x1 - $fontDimension[0] / 2 + $this->offset);
} elseif ($this->alignment === self::ALIGN_LEFT) {
$x = $x1 + $this->offset;
} else {
$x = $x2 + $this->offset - $fontDimension[0];
}
} else {
if ($this->position === self::POSITION_LEFT) {
$x = $x1 - $this->spacing - $fontDimension[0];
} elseif ($this->position === self::POSITION_RIGHT) {
$x = $x2 + $this->spacing;
}
if ($this->alignment === self::ALIGN_CENTER) {
$y = (int)(($y2 - $y1) / 2 + $y1 - $fontDimension[1] / 2 + $this->offset);
} elseif ($this->alignment === self::ALIGN_TOP) {
$y = $y1 + $this->offset;
} else {
$y = $y2 + $this->offset - $fontDimension[1];
}
}
$this->font->setText($this->text);
$this->font->draw($image, $x, $y);
}
}

View File

@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
/**
*--------------------------------------------------------------------
*
* Parse Exception
*
*--------------------------------------------------------------------
* Copyright (C) Jean-Sebastien Goupil
* http://www.barcodebakery.com
*/
namespace BarcodeBakery\Common;
class BCGParseException extends \Exception
{
protected string $barcode;
/**
* Constructor with specific message for a barcode.
*
* @param string $barcode The barcode name.
* @param string $message The message.
*/
public function __construct(string $barcode, string $message)
{
$this->barcode = $barcode;
parent::__construct($message, 10000);
}
}

View File

@@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
/**
*--------------------------------------------------------------------
*
* Base class to draw images
*
*--------------------------------------------------------------------
* Copyright (C) Jean-Sebastien Goupil
* http://www.barcodebakery.com
*/
namespace BarcodeBakery\Common\Drawer;
abstract class BCGDraw
{
protected $image;
protected ?string $fileName;
/**
* Constructor.
*
* @param resource $image The surface.
*/
protected function __construct($image)
{
$this->image = $image;
}
/**
* Sets the file name.
*
* @param string|null $fileName The file name.
* @return void
*/
public function setFileName(?string $fileName): void
{
$this->fileName = $fileName;
}
/**
* Method needed to draw the image based on its specification (JPG, GIF, etc.).
*
* @return void
*/
abstract public function draw(): void;
}

View File

@@ -0,0 +1,116 @@
<?php
declare(strict_types=1);
/**
*--------------------------------------------------------------------
*
* Image Class to draw JPG images with possibility to set DPI
*
*--------------------------------------------------------------------
* Copyright (C) Jean-Sebastien Goupil
* http://www.barcodebakery.com
*/
namespace BarcodeBakery\Common\Drawer;
if (!function_exists('file_put_contents')) {
function file_put_contents($fileName, $data)
{
$f = @fopen($fileName, 'w');
if (!$f) {
return false;
} else {
$bytes = fwrite($f, $data);
fclose($f);
return $bytes;
}
}
}
class BCGDrawJPG extends BCGDraw
{
private int $dpi;
private int $quality;
/**
* Constructor.
*
* @param resource $image The surface.
*/
public function __construct($image)
{
parent::__construct($image);
}
/**
* Sets the DPI.
*
* @param int $dpi The DPI.
* @return void
*/
public function setDPI(int $dpi): void
{
if (is_int($dpi)) {
$this->dpi = max(1, $dpi);
} else {
$this->dpi = null;
}
}
/**
* Sets the quality of the JPG.
*
* @param int $quality The quality.
* @return void
*/
public function setQuality(int $quality): void
{
$this->quality = $quality;
}
/**
* Draws the JPG on the screen or in a file.
*
* @return void
*/
public function draw(): void
{
ob_start();
imagejpeg($this->image, null, $this->quality);
$bin = ob_get_contents();
ob_end_clean();
$this->setInternalProperties($bin);
if (empty($this->fileName)) {
echo $bin;
} else {
file_put_contents($this->fileName, $bin);
}
}
private function setInternalProperties(&$bin): void
{
$this->internalSetDPI($bin);
$this->internalSetC($bin);
}
private function internalSetDPI(&$bin): void
{
if ($this->dpi !== null) {
$bin = substr_replace($bin, pack("Cnn", 0x01, $this->dpi, $this->dpi), 13, 5);
}
}
private function internalSetC(&$bin): void
{
if (strcmp(substr($bin, 0, 4), pack('H*', 'FFD8FFE0')) === 0) {
$offset = 4 + (ord($bin[4]) << 8 | ord($bin[5]));
$firstPart = substr($bin, 0, $offset);
$secondPart = substr($bin, $offset);
$cr = pack('H*', 'FFFE004447656E657261746564207769746820426172636F64652042616B65727920666F722050485020687474703A2F2F7777772E626172636F646562616B6572792E636F6D');
$bin = $firstPart;
$bin .= $cr;
$bin .= $secondPart;
}
}
}

View File

@@ -0,0 +1,220 @@
<?php
declare(strict_types=1);
/**
*--------------------------------------------------------------------
*
* Image Class to draw PNG images with possibility to set DPI
*
*--------------------------------------------------------------------
* Copyright (C) Jean-Sebastien Goupil
* http://www.barcodebakery.com
*/
namespace BarcodeBakery\Common\Drawer;
if (!function_exists('file_put_contents')) {
function file_put_contents($fileName, $data)
{
$f = @fopen($fileName, 'w');
if (!$f) {
return false;
} else {
$bytes = fwrite($f, $data);
fclose($f);
return $bytes;
}
}
}
class BCGDrawPNG extends BCGDraw
{
private ?int $dpi;
/**
* Constructor.
*
* @param resource $image The surface.
*/
public function __construct($image)
{
parent::__construct($image);
}
/**
* Sets the DPI.
*
* @param int|null $dpi The dpi.
* @return void
*/
public function setDPI(?int $dpi): void
{
if (is_numeric($dpi)) {
$this->dpi = max(1, $dpi);
} else {
$this->dpi = null;
}
}
/**
* Draws the PNG on the screen or in a file.
*
* @return void
*/
public function draw(): void
{
ob_start();
imagepng($this->image);
$bin = ob_get_contents();
ob_end_clean();
$this->setInternalProperties($bin);
if (empty($this->fileName)) {
echo $bin;
} else {
file_put_contents($this->fileName, $bin);
}
}
private function setInternalProperties(&$bin): void
{
// Scan all the ChunkType
if (strcmp(substr($bin, 0, 8), pack('H*', '89504E470D0A1A0A')) === 0) {
$chunks = $this->detectChunks($bin);
$this->internalSetDPI($bin, $chunks);
$this->internalSetC($bin, $chunks);
}
}
private function detectChunks($bin)
{
$data = substr($bin, 8);
$chunks = array();
$c = strlen($data);
$offset = 0;
while ($offset < $c) {
$packed = unpack('Nsize/a4chunk', $data);
$size = $packed['size'];
$chunk = $packed['chunk'];
$chunks[] = array('offset' => $offset + 8, 'size' => $size, 'chunk' => $chunk);
$jump = $size + 12;
$offset += $jump;
$data = substr($data, $jump);
}
return $chunks;
}
private function internalSetDPI(&$bin, &$chunks): void
{
if ($this->dpi !== null) {
$meters = (int)($this->dpi * 39.37007874);
$found = -1;
$c = count($chunks);
for ($i = 0; $i < $c; $i++) {
// We already have a pHYs
if ($chunks[$i]['chunk'] === 'pHYs') {
$found = $i;
break;
}
}
$data = 'pHYs' . pack('NNC', $meters, $meters, 0x01);
$crc = self::crc($data, 13);
$cr = pack('Na13N', 9, $data, $crc);
// We didn't have a pHYs
if ($found === -1) {
// Don't do anything if we have a bad PNG
if ($c >= 2 && $chunks[0]['chunk'] === 'IHDR') {
array_splice($chunks, 1, 0, array(array('offset' => 33, 'size' => 9, 'chunk' => 'pHYs')));
// Push the data
for ($i = 2; $i < $c; $i++) {
$chunks[$i]['offset'] += 21;
}
$firstPart = substr($bin, 0, 33);
$secondPart = substr($bin, 33);
$bin = $firstPart;
$bin .= $cr;
$bin .= $secondPart;
}
} else {
$bin = substr_replace($bin, $cr, $chunks[$i]['offset'], 21);
}
}
}
private function internalSetC(&$bin, &$chunks): void
{
if (count($chunks) >= 2 && $chunks[0]['chunk'] === 'IHDR') {
$firstPart = substr($bin, 0, 33);
$secondPart = substr($bin, 33);
$cr = pack('H*', '0000004C74455874436F707972696768740047656E657261746564207769746820426172636F64652042616B65727920666F722050485020687474703A2F2F7777772E626172636F646562616B6572792E636F6DC57F50A1');
$bin = $firstPart;
$bin .= $cr;
$bin .= $secondPart;
}
// Chunks is dirty!! But we are done.
}
private static array $crcTable = array();
private static bool $crcTableComputed = false;
private static function make_crcTable(): void
{
for ($n = 0; $n < 256; $n++) {
$c = $n;
for ($k = 0; $k < 8; $k++) {
if (($c & 1) === 1) {
$c = 0xedb88320 ^ (self::SHR($c, 1));
} else {
$c = self::SHR($c, 1);
}
}
self::$crcTable[$n] = $c;
}
self::$crcTableComputed = true;
}
private static function SHR($x, $n): int
{
$mask = 0x40000000;
if ($x < 0) {
$x &= 0x7FFFFFFF;
$mask = $mask >> ($n - 1);
return ($x >> $n) | $mask;
}
return (int)$x >> (int)$n;
}
private static function update_crc($crc, $buf, $len): int
{
$c = $crc;
if (!self::$crcTableComputed) {
self::make_crcTable();
}
for ($n = 0; $n < $len; $n++) {
$c = self::$crcTable[($c ^ ord($buf[$n])) & 0xff] ^ (self::SHR($c, 8));
}
return $c;
}
private static function crc($data, $len): int
{
return self::update_crc(-1, $data, $len) ^ -1;
}
}

View File

@@ -0,0 +1,102 @@
<?php
declare(strict_types=1);
/**
*--------------------------------------------------------------------
*
* Entry about an AI.
*
*--------------------------------------------------------------------
* Copyright (C) Jean-Sebastien Goupil
* http://www.barcodebakery.com
*/
namespace BarcodeBakery\Common\GS1;
class AIData
{
private string $ai;
private int $kindOfData;
private int $minLength;
private int $maxLength;
private bool $checksum;
/**
* Constructor creating an entry for an AI.
*
* @param string $ai The AI.
* @param int $kindOfData The type of data.
* @param int $minLength The minimum length.
* @param int $maxLength The maximum length.
* @param bool $checksum Indicates if a checksum is present.
* @param string $description The description of the AI.
*/
function __construct(string $ai, int $kindOfData, int $minLength, int $maxLength, bool $checksum, string $description)
{
$this->ai = $ai;
$this->kindOfData = $kindOfData;
$this->minLength = $minLength;
$this->maxLength = $maxLength;
$this->checksum = $checksum;
$this->description = $description;
}
/**
* Gets the AI.
*
* @return string
*/
public function getAI(): string
{
return $this->ai;
}
/**
* Gets the type of data.
*
* @return int
*/
public function getKindOfData(): int
{
return $this->kindOfData;
}
/**
* Gets the minimum length.
*
* @return int
*/
public function getMinLength(): int
{
return $this->minLength;
}
/**
* Gets the maximum length.
*
* @return int
*/
public function getMaxLength(): int
{
return $this->maxLength;
}
/**
* Indicates if a checksum is required.
*
* @return bool
*/
public function getChecksum(): bool
{
return $this->checksum;
}
/**
* The description of the AI.
*
* @return string
*/
public function getDescription(): string
{
return $this->description;
}
}

View File

@@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
/**
*--------------------------------------------------------------------
*
* GS1 Kind of data.
*
*--------------------------------------------------------------------
* Copyright (C) Jean-Sebastien Goupil
* http://www.barcodebakery.com
*/
namespace BarcodeBakery\Common\GS1;
/**
* GS1 Kind of data.
*/
class KindOfData
{
/**
* The content is only numeric.
*/
const NUMERIC = 1;
/**
* The content contains number and letters.
*/
const ALPHA_NUMERIC = 2;
/**
* The content is of a date format yymmdd.
*/
const DATE = 3;
/**
* The content is of a date and time format yymmddhhii or yymmddhhiiss.
*/
const DATETIME = 4;
}

View File

@@ -0,0 +1,206 @@
<?php
declare(strict_types=1);
/**
*--------------------------------------------------------------------
*
* Enable to join 2 BCGDrawing or 2 image object to make only one image.
* There are some options for alignment.
*
*--------------------------------------------------------------------
* Copyright (C) Jean-Sebastien Goupil
* http://www.barcodebakery.com
*/
namespace BarcodeBakery\Common;
class JoinDraw
{
const ALIGN_RIGHT = 0;
const ALIGN_BOTTOM = 0;
const ALIGN_LEFT = 1;
const ALIGN_TOP = 1;
const ALIGN_CENTER = 2;
const POSITION_RIGHT = 0;
const POSITION_BOTTOM = 1;
const POSITION_LEFT = 2;
const POSITION_TOP = 3;
private $image1;
private $image2;
private $alignement;
private $position;
private $space;
private $image;
/**
* Construct the JoinDrawing Object.
* - $image1 and $image2 have to be BCGDrawing object or image object.
* - $space is the space between the two graphics in pixel.
* - $position is the position of the $image2 depending the $image1.
* - $alignment is the alignment of the $image2 if this one is smaller than $image1;
* if $image2 is bigger than $image1, the $image1 will be positionned on the opposite side specified.
*
* @param mixed $image1 The image 1.
* @param mixed $image2 The image 2.
* @param BCGColor $background The bacground color.
* @param int $space The spacing.
* @param int $position The position.
* @param int $alignment The alignment.
*/
public function __construct($image1, $image2, BCGColor $background, int $space = 10, int $position = self::POSITION_RIGHT, int $alignment = self::ALIGN_TOP)
{
if ($image1 instanceof BCGDrawing) {
$this->image1 = $image1->getImage();
} else {
$this->image1 = $image1;
}
if ($image2 instanceof BCGDrawing) {
$this->image2 = $image2->getImage();
} else {
$this->image2 = $image2;
}
$this->background = $background;
$this->space = (int)$space;
$this->position = (int)$position;
$this->alignment = (int)$alignment;
$this->createIm();
}
/**
* Destroys the image.
*/
public function __destruct(): void
{
imagedestroy($this->image);
}
/**
* Finds the position where the barcode should be aligned.
*
* @param int $size1 The size 1.
* @param int $size2 The size 2.
* @param int $ailgnment The alignment.
* @return int The position.
*/
private function findPosition(int $size1, int $size2, int $alignment): int
{
$rsize1 = max($size1, $size2);
$rsize2 = min($size1, $size2);
if ($alignment === self::ALIGN_LEFT) { // Or TOP
return 0;
} elseif ($alignment === self::ALIGN_CENTER) {
return $rsize1 / 2 - $rsize2 / 2;
} else { // RIGHT or TOP
return $rsize1 - $rsize2;
}
}
/**
* Change the alignments.
*
* @param int $alignment The alignment.
* @return int The alignment.
*/
private function changeAlignment(int $alignment): int
{
if ($alignment === 0) {
return 1;
} elseif ($alignment === 1) {
return 0;
} else {
return 2;
}
}
/**
* Creates the image.
*
* @return void
*/
private function createIm(): void
{
$w1 = imagesx($this->image1);
$w2 = imagesx($this->image2);
$h1 = imagesy($this->image1);
$h2 = imagesy($this->image2);
if ($this->position === self::POSITION_LEFT || $this->position === self::POSITION_RIGHT) {
$w = $w1 + $w2 + $this->space;
$h = max($h1, $h2);
} else {
$w = max($w1, $w2);
$h = $h1 + $h2 + $this->space;
}
$this->image = imagecreatetruecolor($w, $h);
imagefill($this->image, 0, 0, $this->background->allocate($this->image));
// We start defining position of images
if ($this->position === self::POSITION_TOP) {
if ($w1 > $w2) {
$posX1 = 0;
$posX2 = $this->findPosition($w1, $w2, $this->alignment);
} else {
$a = $this->changeAlignment($this->alignment);
$posX1 = $this->findPosition($w1, $w2, $a);
$posX2 = 0;
}
$posY2 = 0;
$posY1 = $h2 + $this->space;
} elseif ($this->position === self::POSITION_LEFT) {
if ($w1 > $w2) {
$posY1 = 0;
$posY2 = $this->findPosition($h1, $h2, $this->alignment);
} else {
$a = $this->changeAlignment($this->alignment);
$posY2 = 0;
$posY1 = $this->findPosition($h1, $h2, $a);
}
$posX2 = 0;
$posX1 = $w2 + $this->space;
} elseif ($this->position === self::POSITION_BOTTOM) {
if ($w1 > $w2) {
$posX2 = $this->findPosition($w1, $w2, $this->alignment);
$posX1 = 0;
} else {
$a = $this->changeAlignment($this->alignment);
$posX2 = 0;
$posX1 = $this->findPosition($w1, $w2, $a);
}
$posY1 = 0;
$posY2 = $h1 + $this->space;
} else { // defaults to RIGHT
if ($w1 > $w2) {
$posY2 = $this->findPosition($h1, $h2, $this->alignment);
$posY1 = 0;
} else {
$a = $this->changeAlignment($this->alignment);
$posY2 = 0;
$posY1 = $this->findPosition($h1, $h2, $a);
}
$posX1 = 0;
$posX2 = $w1 + $this->space;
}
imagecopy($this->image, $this->image1, $posX1, $posY1, 0, 0, $w1, $h1);
imagecopy($this->image, $this->image2, $posX2, $posY2, 0, 0, $w2, $h2);
}
/**
* Returns the new $image created.
*
* @return resource The surface.
*/
public function getImage()
{
return $this->image;
}
}