BCGBarcode.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. <?php
  2. /**
  3. *--------------------------------------------------------------------
  4. *
  5. * Base class for Barcode 1D and 2D
  6. *
  7. *--------------------------------------------------------------------
  8. * Copyright (C) Jean-Sebastien Goupil
  9. * http://www.barcodephp.com
  10. */
  11. include_once('BCGColor.php');
  12. include_once('BCGLabel.php');
  13. include_once('BCGArgumentException.php');
  14. include_once('BCGDrawException.php');
  15. abstract class BCGBarcode {
  16. const COLOR_BG = 0;
  17. const COLOR_FG = 1;
  18. protected $colorFg, $colorBg; // Color Foreground, Barckground
  19. protected $scale; // Scale of the graphic, default: 1
  20. protected $offsetX, $offsetY; // Position where to start the drawing
  21. protected $labels = array(); // Array of BCGLabel
  22. protected $pushLabel = array(0, 0); // Push for the label, left and top
  23. /**
  24. * Constructor.
  25. */
  26. protected function __construct() {
  27. $this->setOffsetX(0);
  28. $this->setOffsetY(0);
  29. $this->setForegroundColor(0x000000);
  30. $this->setBackgroundColor(0xffffff);
  31. $this->setScale(1);
  32. }
  33. /**
  34. * Parses the text before displaying it.
  35. *
  36. * @param mixed $text
  37. */
  38. public function parse($text) {
  39. }
  40. /**
  41. * Gets the foreground color of the barcode.
  42. *
  43. * @return BCGColor
  44. */
  45. public function getForegroundColor() {
  46. return $this->colorFg;
  47. }
  48. /**
  49. * Sets the foreground color of the barcode. It could be a BCGColor
  50. * value or simply a language code (white, black, yellow...) or hex value.
  51. *
  52. * @param mixed $code
  53. */
  54. public function setForegroundColor($code) {
  55. if ($code instanceof BCGColor) {
  56. $this->colorFg = $code;
  57. } else {
  58. $this->colorFg = new BCGColor($code);
  59. }
  60. }
  61. /**
  62. * Gets the background color of the barcode.
  63. *
  64. * @return BCGColor
  65. */
  66. public function getBackgroundColor() {
  67. return $this->colorBg;
  68. }
  69. /**
  70. * Sets the background color of the barcode. It could be a BCGColor
  71. * value or simply a language code (white, black, yellow...) or hex value.
  72. *
  73. * @param mixed $code
  74. */
  75. public function setBackgroundColor($code) {
  76. if ($code instanceof BCGColor) {
  77. $this->colorBg = $code;
  78. } else {
  79. $this->colorBg = new BCGColor($code);
  80. }
  81. foreach ($this->labels as $label) {
  82. $label->setBackgroundColor($this->colorBg);
  83. }
  84. }
  85. /**
  86. * Sets the color.
  87. *
  88. * @param mixed $fg
  89. * @param mixed $bg
  90. */
  91. public function setColor($fg, $bg) {
  92. $this->setForegroundColor($fg);
  93. $this->setBackgroundColor($bg);
  94. }
  95. /**
  96. * Gets the scale of the barcode.
  97. *
  98. * @return int
  99. */
  100. public function getScale() {
  101. return $this->scale;
  102. }
  103. /**
  104. * Sets the scale of the barcode in pixel.
  105. * If the scale is lower than 1, an exception is raised.
  106. *
  107. * @param int $scale
  108. */
  109. public function setScale($scale) {
  110. $scale = intval($scale);
  111. if ($scale <= 0) {
  112. throw new BCGArgumentException('The scale must be larger than 0.', 'scale');
  113. }
  114. $this->scale = $scale;
  115. }
  116. /**
  117. * Abstract method that draws the barcode on the resource.
  118. *
  119. * @param resource $im
  120. */
  121. public abstract function draw($im);
  122. /**
  123. * Returns the maximal size of a barcode.
  124. * [0]->width
  125. * [1]->height
  126. *
  127. * @param int $w
  128. * @param int $h
  129. * @return int[]
  130. */
  131. public function getDimension($w, $h) {
  132. $labels = $this->getBiggestLabels(false);
  133. $pixelsAround = array(0, 0, 0, 0); // TRBL
  134. if (isset($labels[BCGLabel::POSITION_TOP])) {
  135. $dimension = $labels[BCGLabel::POSITION_TOP]->getDimension();
  136. $pixelsAround[0] += $dimension[1];
  137. }
  138. if (isset($labels[BCGLabel::POSITION_RIGHT])) {
  139. $dimension = $labels[BCGLabel::POSITION_RIGHT]->getDimension();
  140. $pixelsAround[1] += $dimension[0];
  141. }
  142. if (isset($labels[BCGLabel::POSITION_BOTTOM])) {
  143. $dimension = $labels[BCGLabel::POSITION_BOTTOM]->getDimension();
  144. $pixelsAround[2] += $dimension[1];
  145. }
  146. if (isset($labels[BCGLabel::POSITION_LEFT])) {
  147. $dimension = $labels[BCGLabel::POSITION_LEFT]->getDimension();
  148. $pixelsAround[3] += $dimension[0];
  149. }
  150. $finalW = ($w + $this->offsetX) * $this->scale;
  151. $finalH = ($h + $this->offsetY) * $this->scale;
  152. // This section will check if a top/bottom label is too big for its width and left/right too big for its height
  153. $reversedLabels = $this->getBiggestLabels(true);
  154. foreach ($reversedLabels as $label) {
  155. $dimension = $label->getDimension();
  156. $alignment = $label->getAlignment();
  157. if ($label->getPosition() === BCGLabel::POSITION_LEFT || $label->getPosition() === BCGLabel::POSITION_RIGHT) {
  158. if ($alignment === BCGLabel::ALIGN_TOP) {
  159. $pixelsAround[2] = max($pixelsAround[2], $dimension[1] - $finalH);
  160. } elseif ($alignment === BCGLabel::ALIGN_CENTER) {
  161. $temp = ceil(($dimension[1] - $finalH) / 2);
  162. $pixelsAround[0] = max($pixelsAround[0], $temp);
  163. $pixelsAround[2] = max($pixelsAround[2], $temp);
  164. } elseif ($alignment === BCGLabel::ALIGN_BOTTOM) {
  165. $pixelsAround[0] = max($pixelsAround[0], $dimension[1] - $finalH);
  166. }
  167. } else {
  168. if ($alignment === BCGLabel::ALIGN_LEFT) {
  169. $pixelsAround[1] = max($pixelsAround[1], $dimension[0] - $finalW);
  170. } elseif ($alignment === BCGLabel::ALIGN_CENTER) {
  171. $temp = ceil(($dimension[0] - $finalW) / 2);
  172. $pixelsAround[1] = max($pixelsAround[1], $temp);
  173. $pixelsAround[3] = max($pixelsAround[3], $temp);
  174. } elseif ($alignment === BCGLabel::ALIGN_RIGHT) {
  175. $pixelsAround[3] = max($pixelsAround[3], $dimension[0] - $finalW);
  176. }
  177. }
  178. }
  179. $this->pushLabel[0] = $pixelsAround[3];
  180. $this->pushLabel[1] = $pixelsAround[0];
  181. $finalW = ($w + $this->offsetX) * $this->scale + $pixelsAround[1] + $pixelsAround[3];
  182. $finalH = ($h + $this->offsetY) * $this->scale + $pixelsAround[0] + $pixelsAround[2];
  183. return array($finalW, $finalH);
  184. }
  185. /**
  186. * Gets the X offset.
  187. *
  188. * @return int
  189. */
  190. public function getOffsetX() {
  191. return $this->offsetX;
  192. }
  193. /**
  194. * Sets the X offset.
  195. *
  196. * @param int $offsetX
  197. */
  198. public function setOffsetX($offsetX) {
  199. $offsetX = intval($offsetX);
  200. if ($offsetX < 0) {
  201. throw new BCGArgumentException('The offset X must be 0 or larger.', 'offsetX');
  202. }
  203. $this->offsetX = $offsetX;
  204. }
  205. /**
  206. * Gets the Y offset.
  207. *
  208. * @return int
  209. */
  210. public function getOffsetY() {
  211. return $this->offsetY;
  212. }
  213. /**
  214. * Sets the Y offset.
  215. *
  216. * @param int $offsetY
  217. */
  218. public function setOffsetY($offsetY) {
  219. $offsetY = intval($offsetY);
  220. if ($offsetY < 0) {
  221. throw new BCGArgumentException('The offset Y must be 0 or larger.', 'offsetY');
  222. }
  223. $this->offsetY = $offsetY;
  224. }
  225. /**
  226. * Adds the label to the drawing.
  227. *
  228. * @param BCGLabel $label
  229. */
  230. public function addLabel(BCGLabel $label) {
  231. $label->setBackgroundColor($this->colorBg);
  232. $this->labels[] = $label;
  233. }
  234. /**
  235. * Removes the label from the drawing.
  236. *
  237. * @param BCGLabel $label
  238. */
  239. public function removeLabel(BCGLabel $label) {
  240. $remove = -1;
  241. $c = count($this->labels);
  242. for ($i = 0; $i < $c; $i++) {
  243. if ($this->labels[$i] === $label) {
  244. $remove = $i;
  245. break;
  246. }
  247. }
  248. if ($remove > -1) {
  249. array_splice($this->labels, $remove, 1);
  250. }
  251. }
  252. /**
  253. * Clears the labels.
  254. */
  255. public function clearLabels() {
  256. $this->labels = array();
  257. }
  258. /**
  259. * Draws the text.
  260. * The coordinate passed are the positions of the barcode.
  261. * $x1 and $y1 represent the top left corner.
  262. * $x2 and $y2 represent the bottom right corner.
  263. *
  264. * @param resource $im
  265. * @param int $x1
  266. * @param int $y1
  267. * @param int $x2
  268. * @param int $y2
  269. */
  270. protected function drawText($im, $x1, $y1, $x2, $y2) {
  271. foreach ($this->labels as $label) {
  272. $label->draw($im,
  273. ($x1 + $this->offsetX) * $this->scale + $this->pushLabel[0],
  274. ($y1 + $this->offsetY) * $this->scale + $this->pushLabel[1],
  275. ($x2 + $this->offsetX) * $this->scale + $this->pushLabel[0],
  276. ($y2 + $this->offsetY) * $this->scale + $this->pushLabel[1]);
  277. }
  278. }
  279. /**
  280. * Draws 1 pixel on the resource at a specific position with a determined color.
  281. *
  282. * @param resource $im
  283. * @param int $x
  284. * @param int $y
  285. * @param int $color
  286. */
  287. protected function drawPixel($im, $x, $y, $color = self::COLOR_FG) {
  288. $xR = ($x + $this->offsetX) * $this->scale + $this->pushLabel[0];
  289. $yR = ($y + $this->offsetY) * $this->scale + $this->pushLabel[1];
  290. // We always draw a rectangle
  291. imagefilledrectangle($im,
  292. $xR,
  293. $yR,
  294. $xR + $this->scale - 1,
  295. $yR + $this->scale - 1,
  296. $this->getColor($im, $color));
  297. }
  298. /**
  299. * Draws an empty rectangle on the resource at a specific position with a determined color.
  300. *
  301. * @param resource $im
  302. * @param int $x1
  303. * @param int $y1
  304. * @param int $x2
  305. * @param int $y2
  306. * @param int $color
  307. */
  308. protected function drawRectangle($im, $x1, $y1, $x2, $y2, $color = self::COLOR_FG) {
  309. if ($this->scale === 1) {
  310. imagefilledrectangle($im,
  311. ($x1 + $this->offsetX) + $this->pushLabel[0],
  312. ($y1 + $this->offsetY) + $this->pushLabel[1],
  313. ($x2 + $this->offsetX) + $this->pushLabel[0],
  314. ($y2 + $this->offsetY) + $this->pushLabel[1],
  315. $this->getColor($im, $color));
  316. } else {
  317. imagefilledrectangle($im, ($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($im, $color));
  318. imagefilledrectangle($im, ($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($im, $color));
  319. imagefilledrectangle($im, ($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($im, $color));
  320. imagefilledrectangle($im, ($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($im, $color));
  321. }
  322. }
  323. /**
  324. * Draws a filled rectangle on the resource at a specific position with a determined color.
  325. *
  326. * @param resource $im
  327. * @param int $x1
  328. * @param int $y1
  329. * @param int $x2
  330. * @param int $y2
  331. * @param int $color
  332. */
  333. protected function drawFilledRectangle($im, $x1, $y1, $x2, $y2, $color = self::COLOR_FG) {
  334. if ($x1 > $x2) { // Swap
  335. $x1 ^= $x2 ^= $x1 ^= $x2;
  336. }
  337. if ($y1 > $y2) { // Swap
  338. $y1 ^= $y2 ^= $y1 ^= $y2;
  339. }
  340. imagefilledrectangle($im,
  341. ($x1 + $this->offsetX) * $this->scale + $this->pushLabel[0],
  342. ($y1 + $this->offsetY) * $this->scale + $this->pushLabel[1],
  343. ($x2 + $this->offsetX) * $this->scale + $this->pushLabel[0] + $this->scale - 1,
  344. ($y2 + $this->offsetY) * $this->scale + $this->pushLabel[1] + $this->scale - 1,
  345. $this->getColor($im, $color));
  346. }
  347. /**
  348. * Allocates the color based on the integer.
  349. *
  350. * @param resource $im
  351. * @param int $color
  352. * @return resource
  353. */
  354. protected function getColor($im, $color) {
  355. if ($color === self::COLOR_BG) {
  356. return $this->colorBg->allocate($im);
  357. } else {
  358. return $this->colorFg->allocate($im);
  359. }
  360. }
  361. /**
  362. * Returning the biggest label widths for LEFT/RIGHT and heights for TOP/BOTTOM.
  363. *
  364. * @param bool $reversed
  365. * @return BCGLabel[]
  366. */
  367. private function getBiggestLabels($reversed = false) {
  368. $searchLR = $reversed ? 1 : 0;
  369. $searchTB = $reversed ? 0 : 1;
  370. $labels = array();
  371. foreach ($this->labels as $label) {
  372. $position = $label->getPosition();
  373. if (isset($labels[$position])) {
  374. $savedDimension = $labels[$position]->getDimension();
  375. $dimension = $label->getDimension();
  376. if ($position === BCGLabel::POSITION_LEFT || $position === BCGLabel::POSITION_RIGHT) {
  377. if ($dimension[$searchLR] > $savedDimension[$searchLR]) {
  378. $labels[$position] = $label;
  379. }
  380. } else {
  381. if ($dimension[$searchTB] > $savedDimension[$searchTB]) {
  382. $labels[$position] = $label;
  383. }
  384. }
  385. } else {
  386. $labels[$position] = $label;
  387. }
  388. }
  389. return $labels;
  390. }
  391. }
  392. ?>