1. Import
This commit is contained in:
@@ -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/
|
||||
@@ -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": "*"
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user