PageRenderTime 63ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/library/tcpdf/barcodes.php

https://bitbucket.org/marcor/gazie
PHP | 2201 lines | 1774 code | 38 blank | 389 comment | 236 complexity | 65c705bbc5382a9d21d210fa2461b63c MD5 | raw file
Possible License(s): LGPL-2.1, LGPL-3.0, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. //============================================================+
  3. // File name : barcodes.php
  4. // Version : 1.0.017
  5. // Begin : 2008-06-09
  6. // Last Update : 2011-06-01
  7. // Author : Nicola Asuni - Tecnick.com S.r.l - Via Della Pace, 11 - 09044 - Quartucciu (CA) - ITALY - www.tecnick.com - info@tecnick.com
  8. // License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html)
  9. // -------------------------------------------------------------------
  10. // Copyright (C) 2008-2011 Nicola Asuni - Tecnick.com S.r.l.
  11. //
  12. // This file is part of TCPDF software library.
  13. //
  14. // TCPDF is free software: you can redistribute it and/or modify it
  15. // under the terms of the GNU Lesser General Public License as
  16. // published by the Free Software Foundation, either version 3 of the
  17. // License, or (at your option) any later version.
  18. //
  19. // TCPDF is distributed in the hope that it will be useful, but
  20. // WITHOUT ANY WARRANTY; without even the implied warranty of
  21. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  22. // See the GNU Lesser General Public License for more details.
  23. //
  24. // You should have received a copy of the GNU Lesser General Public License
  25. // along with TCPDF. If not, see <http://www.gnu.org/licenses/>.
  26. //
  27. // See LICENSE.TXT file for more information.
  28. // -------------------------------------------------------------------
  29. //
  30. // Description : PHP class to creates array representations for
  31. // common 1D barcodes to be used with TCPDF.
  32. //
  33. //============================================================+
  34. /**
  35. * @file
  36. * PHP class to creates array representations for common 1D barcodes to be used with TCPDF.
  37. * @package com.tecnick.tcpdf
  38. * @author Nicola Asuni
  39. * @version 1.0.017
  40. */
  41. /**
  42. * @class TCPDFBarcode
  43. * PHP class to creates array representations for common 1D barcodes to be used with TCPDF (http://www.tcpdf.org).<br>
  44. * @package com.tecnick.tcpdf
  45. * @version 1.0.017
  46. * @author Nicola Asuni
  47. */
  48. class TCPDFBarcode {
  49. /**
  50. * Array representation of barcode.
  51. * @protected
  52. */
  53. protected $barcode_array;
  54. /**
  55. * This is the class constructor.
  56. * Return an array representations for common 1D barcodes:<ul>
  57. * <li>$arrcode['code'] code to be printed on text label</li>
  58. * <li>$arrcode['maxh'] max barcode height</li>
  59. * <li>$arrcode['maxw'] max barcode width</li>
  60. * <li>$arrcode['bcode'][$k] single bar or space in $k position</li>
  61. * <li>$arrcode['bcode'][$k]['t'] bar type: true = bar, false = space.</li>
  62. * <li>$arrcode['bcode'][$k]['w'] bar width in units.</li>
  63. * <li>$arrcode['bcode'][$k]['h'] bar height in units.</li>
  64. * <li>$arrcode['bcode'][$k]['p'] bar top position (0 = top, 1 = middle)</li></ul>
  65. * @param $code (string) code to print
  66. * @param $type (string) type of barcode: <ul><li>C39 : CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.</li><li>C39+ : CODE 39 with checksum</li><li>C39E : CODE 39 EXTENDED</li><li>C39E+ : CODE 39 EXTENDED + CHECKSUM</li><li>C93 : CODE 93 - USS-93</li><li>S25 : Standard 2 of 5</li><li>S25+ : Standard 2 of 5 + CHECKSUM</li><li>I25 : Interleaved 2 of 5</li><li>I25+ : Interleaved 2 of 5 + CHECKSUM</li><li>C128 : CODE 128</li><li>C128A : CODE 128 A</li><li>C128B : CODE 128 B</li><li>C128C : CODE 128 C</li><li>EAN2 : 2-Digits UPC-Based Extention</li><li>EAN5 : 5-Digits UPC-Based Extention</li><li>EAN8 : EAN 8</li><li>EAN13 : EAN 13</li><li>UPCA : UPC-A</li><li>UPCE : UPC-E</li><li>MSI : MSI (Variation of Plessey code)</li><li>MSI+ : MSI + CHECKSUM (modulo 11)</li><li>POSTNET : POSTNET</li><li>PLANET : PLANET</li><li>RMS4CC : RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)</li><li>KIX : KIX (Klant index - Customer index)</li><li>IMB: Intelligent Mail Barcode - Onecode - USPS-B-3200</li><li>CODABAR : CODABAR</li><li>CODE11 : CODE 11</li><li>PHARMA : PHARMACODE</li><li>PHARMA2T : PHARMACODE TWO-TRACKS</li></ul>
  67. * @public
  68. */
  69. public function __construct($code, $type) {
  70. $this->setBarcode($code, $type);
  71. }
  72. /**
  73. * Return an array representations of barcode.
  74. * @return array
  75. * @public
  76. */
  77. public function getBarcodeArray() {
  78. return $this->barcode_array;
  79. }
  80. /**
  81. * Send barcode as SVG image object to the standard output.
  82. * @param $w (int) Minimum width of a single bar in user units.
  83. * @param $h (int) Height of barcode in user units.
  84. * @param $color (string) Foreground color (in SVG format) for bar elements (background is transparent).
  85. * @public
  86. */
  87. public function getBarcodeSVG($w=2, $h=30, $color='black') {
  88. // send XML headers
  89. $code = $this->getBarcodeSVGcode($w, $h, $color);
  90. header('Content-Type: application/svg+xml');
  91. header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1
  92. header('Pragma: public');
  93. header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past
  94. header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
  95. header('Content-Disposition: inline; filename="'.md5($code).'.svg";');
  96. //header('Content-Length: '.strlen($code));
  97. echo $code;
  98. }
  99. /**
  100. * Return a SVG string representation of barcode.
  101. * @param $w (int) Minimum width of a single bar in user units.
  102. * @param $h (int) Height of barcode in user units.
  103. * @param $color (string) Foreground color (in SVG format) for bar elements (background is transparent).
  104. * @return string SVG code.
  105. * @public
  106. */
  107. public function getBarcodeSVGcode($w=2, $h=30, $color='black') {
  108. // replace table for special characters
  109. $repstr = array("\0" => '', '&' => '&amp;', '<' => '&lt;', '>' => '&gt;');
  110. $svg = '<'.'?'.'xml version="1.0" standalone="no"'.'?'.'>'."\n";
  111. $svg .= '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'."\n";
  112. $svg .= '<svg width="'.round(($this->barcode_array['maxw'] * $w), 3).'" height="'.$h.'" version="1.1" xmlns="http://www.w3.org/2000/svg">'."\n";
  113. $svg .= "\t".'<desc>'.strtr($this->barcode_array['code'], $repstr).'</desc>'."\n";
  114. $svg .= "\t".'<g id="bars" fill="'.$color.'" stroke="none">'."\n";
  115. // print bars
  116. $x = 0;
  117. foreach ($this->barcode_array['bcode'] as $k => $v) {
  118. $bw = round(($v['w'] * $w), 3);
  119. $bh = round(($v['h'] * $h / $this->barcode_array['maxh']), 3);
  120. if ($v['t']) {
  121. $y = round(($v['p'] * $h / $this->barcode_array['maxh']), 3);
  122. // draw a vertical bar
  123. $svg .= "\t\t".'<rect x="'.$x.'" y="'.$y.'" width="'.$bw.'" height="'.$bh.'" />'."\n";
  124. }
  125. $x += $bw;
  126. }
  127. $svg .= "\t".'</g>'."\n";
  128. $svg .= '</svg>'."\n";
  129. return $svg;
  130. }
  131. /**
  132. * Set the barcode.
  133. * @param $code (string) code to print
  134. * @param $type (string) type of barcode: <ul><li>C39 : CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.</li><li>C39+ : CODE 39 with checksum</li><li>C39E : CODE 39 EXTENDED</li><li>C39E+ : CODE 39 EXTENDED + CHECKSUM</li><li>C93 : CODE 93 - USS-93</li><li>S25 : Standard 2 of 5</li><li>S25+ : Standard 2 of 5 + CHECKSUM</li><li>I25 : Interleaved 2 of 5</li><li>I25+ : Interleaved 2 of 5 + CHECKSUM</li><li>C128 : CODE 128</li><li>C128A : CODE 128 A</li><li>C128B : CODE 128 B</li><li>C128C : CODE 128 C</li><li>EAN2 : 2-Digits UPC-Based Extention</li><li>EAN5 : 5-Digits UPC-Based Extention</li><li>EAN8 : EAN 8</li><li>EAN13 : EAN 13</li><li>UPCA : UPC-A</li><li>UPCE : UPC-E</li><li>MSI : MSI (Variation of Plessey code)</li><li>MSI+ : MSI + CHECKSUM (modulo 11)</li><li>POSTNET : POSTNET</li><li>PLANET : PLANET</li><li>RMS4CC : RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)</li><li>KIX : KIX (Klant index - Customer index)</li><li>IMB: Intelligent Mail Barcode - Onecode - USPS-B-3200</li><li>CODABAR : CODABAR</li><li>CODE11 : CODE 11</li><li>PHARMA : PHARMACODE</li><li>PHARMA2T : PHARMACODE TWO-TRACKS</li></ul>
  135. * @return array barcode array
  136. * @public
  137. */
  138. public function setBarcode($code, $type) {
  139. switch (strtoupper($type)) {
  140. case 'C39': { // CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
  141. $arrcode = $this->barcode_code39($code, false, false);
  142. break;
  143. }
  144. case 'C39+': { // CODE 39 with checksum
  145. $arrcode = $this->barcode_code39($code, false, true);
  146. break;
  147. }
  148. case 'C39E': { // CODE 39 EXTENDED
  149. $arrcode = $this->barcode_code39($code, true, false);
  150. break;
  151. }
  152. case 'C39E+': { // CODE 39 EXTENDED + CHECKSUM
  153. $arrcode = $this->barcode_code39($code, true, true);
  154. break;
  155. }
  156. case 'C93': { // CODE 93 - USS-93
  157. $arrcode = $this->barcode_code93($code);
  158. break;
  159. }
  160. case 'S25': { // Standard 2 of 5
  161. $arrcode = $this->barcode_s25($code, false);
  162. break;
  163. }
  164. case 'S25+': { // Standard 2 of 5 + CHECKSUM
  165. $arrcode = $this->barcode_s25($code, true);
  166. break;
  167. }
  168. case 'I25': { // Interleaved 2 of 5
  169. $arrcode = $this->barcode_i25($code, false);
  170. break;
  171. }
  172. case 'I25+': { // Interleaved 2 of 5 + CHECKSUM
  173. $arrcode = $this->barcode_i25($code, true);
  174. break;
  175. }
  176. case 'C128': { // CODE 128
  177. $arrcode = $this->barcode_c128($code, '');
  178. break;
  179. }
  180. case 'C128A': { // CODE 128 A
  181. $arrcode = $this->barcode_c128($code, 'A');
  182. break;
  183. }
  184. case 'C128B': { // CODE 128 B
  185. $arrcode = $this->barcode_c128($code, 'B');
  186. break;
  187. }
  188. case 'C128C': { // CODE 128 C
  189. $arrcode = $this->barcode_c128($code, 'C');
  190. break;
  191. }
  192. case 'EAN2': { // 2-Digits UPC-Based Extention
  193. $arrcode = $this->barcode_eanext($code, 2);
  194. break;
  195. }
  196. case 'EAN5': { // 5-Digits UPC-Based Extention
  197. $arrcode = $this->barcode_eanext($code, 5);
  198. break;
  199. }
  200. case 'EAN8': { // EAN 8
  201. $arrcode = $this->barcode_eanupc($code, 8);
  202. break;
  203. }
  204. case 'EAN13': { // EAN 13
  205. $arrcode = $this->barcode_eanupc($code, 13);
  206. break;
  207. }
  208. case 'UPCA': { // UPC-A
  209. $arrcode = $this->barcode_eanupc($code, 12);
  210. break;
  211. }
  212. case 'UPCE': { // UPC-E
  213. $arrcode = $this->barcode_eanupc($code, 6);
  214. break;
  215. }
  216. case 'MSI': { // MSI (Variation of Plessey code)
  217. $arrcode = $this->barcode_msi($code, false);
  218. break;
  219. }
  220. case 'MSI+': { // MSI + CHECKSUM (modulo 11)
  221. $arrcode = $this->barcode_msi($code, true);
  222. break;
  223. }
  224. case 'POSTNET': { // POSTNET
  225. $arrcode = $this->barcode_postnet($code, false);
  226. break;
  227. }
  228. case 'PLANET': { // PLANET
  229. $arrcode = $this->barcode_postnet($code, true);
  230. break;
  231. }
  232. case 'RMS4CC': { // RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)
  233. $arrcode = $this->barcode_rms4cc($code, false);
  234. break;
  235. }
  236. case 'KIX': { // KIX (Klant index - Customer index)
  237. $arrcode = $this->barcode_rms4cc($code, true);
  238. break;
  239. }
  240. case 'IMB': { // IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200
  241. $arrcode = $this->barcode_imb($code);
  242. break;
  243. }
  244. case 'CODABAR': { // CODABAR
  245. $arrcode = $this->barcode_codabar($code);
  246. break;
  247. }
  248. case 'CODE11': { // CODE 11
  249. $arrcode = $this->barcode_code11($code);
  250. break;
  251. }
  252. case 'PHARMA': { // PHARMACODE
  253. $arrcode = $this->barcode_pharmacode($code);
  254. break;
  255. }
  256. case 'PHARMA2T': { // PHARMACODE TWO-TRACKS
  257. $arrcode = $this->barcode_pharmacode2t($code);
  258. break;
  259. }
  260. default: {
  261. $this->barcode_array = false;
  262. $arrcode = false;
  263. break;
  264. }
  265. }
  266. $this->barcode_array = $arrcode;
  267. }
  268. /**
  269. * CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
  270. * General-purpose code in very wide use world-wide
  271. * @param $code (string) code to represent.
  272. * @param $extended (boolean) if true uses the extended mode.
  273. * @param $checksum (boolean) if true add a checksum to the code.
  274. * @return array barcode representation.
  275. * @protected
  276. */
  277. protected function barcode_code39($code, $extended=false, $checksum=false) {
  278. $chr['0'] = '111221211';
  279. $chr['1'] = '211211112';
  280. $chr['2'] = '112211112';
  281. $chr['3'] = '212211111';
  282. $chr['4'] = '111221112';
  283. $chr['5'] = '211221111';
  284. $chr['6'] = '112221111';
  285. $chr['7'] = '111211212';
  286. $chr['8'] = '211211211';
  287. $chr['9'] = '112211211';
  288. $chr['A'] = '211112112';
  289. $chr['B'] = '112112112';
  290. $chr['C'] = '212112111';
  291. $chr['D'] = '111122112';
  292. $chr['E'] = '211122111';
  293. $chr['F'] = '112122111';
  294. $chr['G'] = '111112212';
  295. $chr['H'] = '211112211';
  296. $chr['I'] = '112112211';
  297. $chr['J'] = '111122211';
  298. $chr['K'] = '211111122';
  299. $chr['L'] = '112111122';
  300. $chr['M'] = '212111121';
  301. $chr['N'] = '111121122';
  302. $chr['O'] = '211121121';
  303. $chr['P'] = '112121121';
  304. $chr['Q'] = '111111222';
  305. $chr['R'] = '211111221';
  306. $chr['S'] = '112111221';
  307. $chr['T'] = '111121221';
  308. $chr['U'] = '221111112';
  309. $chr['V'] = '122111112';
  310. $chr['W'] = '222111111';
  311. $chr['X'] = '121121112';
  312. $chr['Y'] = '221121111';
  313. $chr['Z'] = '122121111';
  314. $chr['-'] = '121111212';
  315. $chr['.'] = '221111211';
  316. $chr[' '] = '122111211';
  317. $chr['$'] = '121212111';
  318. $chr['/'] = '121211121';
  319. $chr['+'] = '121112121';
  320. $chr['%'] = '111212121';
  321. $chr['*'] = '121121211';
  322. $code = strtoupper($code);
  323. if ($extended) {
  324. // extended mode
  325. $code = $this->encode_code39_ext($code);
  326. }
  327. if ($code === false) {
  328. return false;
  329. }
  330. if ($checksum) {
  331. // checksum
  332. $code .= $this->checksum_code39($code);
  333. }
  334. // add start and stop codes
  335. $code = '*'.$code.'*';
  336. $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
  337. $k = 0;
  338. $clen = strlen($code);
  339. for ($i = 0; $i < $clen; ++$i) {
  340. $char = $code{$i};
  341. if(!isset($chr[$char])) {
  342. // invalid character
  343. return false;
  344. }
  345. for ($j = 0; $j < 9; ++$j) {
  346. if (($j % 2) == 0) {
  347. $t = true; // bar
  348. } else {
  349. $t = false; // space
  350. }
  351. $w = $chr[$char]{$j};
  352. $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
  353. $bararray['maxw'] += $w;
  354. ++$k;
  355. }
  356. $bararray['bcode'][$k] = array('t' => false, 'w' => 1, 'h' => 1, 'p' => 0);
  357. $bararray['maxw'] += 1;
  358. ++$k;
  359. }
  360. return $bararray;
  361. }
  362. /**
  363. * Encode a string to be used for CODE 39 Extended mode.
  364. * @param $code (string) code to represent.
  365. * @return encoded string.
  366. * @protected
  367. */
  368. protected function encode_code39_ext($code) {
  369. $encode = array(
  370. chr(0) => '%U', chr(1) => '$A', chr(2) => '$B', chr(3) => '$C',
  371. chr(4) => '$D', chr(5) => '$E', chr(6) => '$F', chr(7) => '$G',
  372. chr(8) => '$H', chr(9) => '$I', chr(10) => '$J', chr(11) => '£K',
  373. chr(12) => '$L', chr(13) => '$M', chr(14) => '$N', chr(15) => '$O',
  374. chr(16) => '$P', chr(17) => '$Q', chr(18) => '$R', chr(19) => '$S',
  375. chr(20) => '$T', chr(21) => '$U', chr(22) => '$V', chr(23) => '$W',
  376. chr(24) => '$X', chr(25) => '$Y', chr(26) => '$Z', chr(27) => '%A',
  377. chr(28) => '%B', chr(29) => '%C', chr(30) => '%D', chr(31) => '%E',
  378. chr(32) => ' ', chr(33) => '/A', chr(34) => '/B', chr(35) => '/C',
  379. chr(36) => '/D', chr(37) => '/E', chr(38) => '/F', chr(39) => '/G',
  380. chr(40) => '/H', chr(41) => '/I', chr(42) => '/J', chr(43) => '/K',
  381. chr(44) => '/L', chr(45) => '-', chr(46) => '.', chr(47) => '/O',
  382. chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3',
  383. chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7',
  384. chr(56) => '8', chr(57) => '9', chr(58) => '/Z', chr(59) => '%F',
  385. chr(60) => '%G', chr(61) => '%H', chr(62) => '%I', chr(63) => '%J',
  386. chr(64) => '%V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C',
  387. chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G',
  388. chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K',
  389. chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O',
  390. chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S',
  391. chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W',
  392. chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => '%K',
  393. chr(92) => '%L', chr(93) => '%M', chr(94) => '%N', chr(95) => '%O',
  394. chr(96) => '%W', chr(97) => '+A', chr(98) => '+B', chr(99) => '+C',
  395. chr(100) => '+D', chr(101) => '+E', chr(102) => '+F', chr(103) => '+G',
  396. chr(104) => '+H', chr(105) => '+I', chr(106) => '+J', chr(107) => '+K',
  397. chr(108) => '+L', chr(109) => '+M', chr(110) => '+N', chr(111) => '+O',
  398. chr(112) => '+P', chr(113) => '+Q', chr(114) => '+R', chr(115) => '+S',
  399. chr(116) => '+T', chr(117) => '+U', chr(118) => '+V', chr(119) => '+W',
  400. chr(120) => '+X', chr(121) => '+Y', chr(122) => '+Z', chr(123) => '%P',
  401. chr(124) => '%Q', chr(125) => '%R', chr(126) => '%S', chr(127) => '%T');
  402. $code_ext = '';
  403. $clen = strlen($code);
  404. for ($i = 0 ; $i < $clen; ++$i) {
  405. if (ord($code{$i}) > 127) {
  406. return false;
  407. }
  408. $code_ext .= $encode[$code{$i}];
  409. }
  410. return $code_ext;
  411. }
  412. /**
  413. * Calculate CODE 39 checksum (modulo 43).
  414. * @param $code (string) code to represent.
  415. * @return char checksum.
  416. * @protected
  417. */
  418. protected function checksum_code39($code) {
  419. $chars = array(
  420. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  421. 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
  422. 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
  423. 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%');
  424. $sum = 0;
  425. $clen = strlen($code);
  426. for ($i = 0 ; $i < $clen; ++$i) {
  427. $k = array_keys($chars, $code{$i});
  428. $sum += $k[0];
  429. }
  430. $j = ($sum % 43);
  431. return $chars[$j];
  432. }
  433. /**
  434. * CODE 93 - USS-93
  435. * Compact code similar to Code 39
  436. * @param $code (string) code to represent.
  437. * @return array barcode representation.
  438. * @protected
  439. */
  440. protected function barcode_code93($code) {
  441. $chr[48] = '131112'; // 0
  442. $chr[49] = '111213'; // 1
  443. $chr[50] = '111312'; // 2
  444. $chr[51] = '111411'; // 3
  445. $chr[52] = '121113'; // 4
  446. $chr[53] = '121212'; // 5
  447. $chr[54] = '121311'; // 6
  448. $chr[55] = '111114'; // 7
  449. $chr[56] = '131211'; // 8
  450. $chr[57] = '141111'; // 9
  451. $chr[65] = '211113'; // A
  452. $chr[66] = '211212'; // B
  453. $chr[67] = '211311'; // C
  454. $chr[68] = '221112'; // D
  455. $chr[69] = '221211'; // E
  456. $chr[70] = '231111'; // F
  457. $chr[71] = '112113'; // G
  458. $chr[72] = '112212'; // H
  459. $chr[73] = '112311'; // I
  460. $chr[74] = '122112'; // J
  461. $chr[75] = '132111'; // K
  462. $chr[76] = '111123'; // L
  463. $chr[77] = '111222'; // M
  464. $chr[78] = '111321'; // N
  465. $chr[79] = '121122'; // O
  466. $chr[80] = '131121'; // P
  467. $chr[81] = '212112'; // Q
  468. $chr[82] = '212211'; // R
  469. $chr[83] = '211122'; // S
  470. $chr[84] = '211221'; // T
  471. $chr[85] = '221121'; // U
  472. $chr[86] = '222111'; // V
  473. $chr[87] = '112122'; // W
  474. $chr[88] = '112221'; // X
  475. $chr[89] = '122121'; // Y
  476. $chr[90] = '123111'; // Z
  477. $chr[45] = '121131'; // -
  478. $chr[46] = '311112'; // .
  479. $chr[32] = '311211'; //
  480. $chr[36] = '321111'; // $
  481. $chr[47] = '112131'; // /
  482. $chr[43] = '113121'; // +
  483. $chr[37] = '211131'; // %
  484. $chr[128] = '121221'; // ($)
  485. $chr[129] = '311121'; // (/)
  486. $chr[130] = '122211'; // (+)
  487. $chr[131] = '312111'; // (%)
  488. $chr[42] = '111141'; // start-stop
  489. $code = strtoupper($code);
  490. $encode = array(
  491. chr(0) => chr(131).'U', chr(1) => chr(128).'A', chr(2) => chr(128).'B', chr(3) => chr(128).'C',
  492. chr(4) => chr(128).'D', chr(5) => chr(128).'E', chr(6) => chr(128).'F', chr(7) => chr(128).'G',
  493. chr(8) => chr(128).'H', chr(9) => chr(128).'I', chr(10) => chr(128).'J', chr(11) => '£K',
  494. chr(12) => chr(128).'L', chr(13) => chr(128).'M', chr(14) => chr(128).'N', chr(15) => chr(128).'O',
  495. chr(16) => chr(128).'P', chr(17) => chr(128).'Q', chr(18) => chr(128).'R', chr(19) => chr(128).'S',
  496. chr(20) => chr(128).'T', chr(21) => chr(128).'U', chr(22) => chr(128).'V', chr(23) => chr(128).'W',
  497. chr(24) => chr(128).'X', chr(25) => chr(128).'Y', chr(26) => chr(128).'Z', chr(27) => chr(131).'A',
  498. chr(28) => chr(131).'B', chr(29) => chr(131).'C', chr(30) => chr(131).'D', chr(31) => chr(131).'E',
  499. chr(32) => ' ', chr(33) => chr(129).'A', chr(34) => chr(129).'B', chr(35) => chr(129).'C',
  500. chr(36) => chr(129).'D', chr(37) => chr(129).'E', chr(38) => chr(129).'F', chr(39) => chr(129).'G',
  501. chr(40) => chr(129).'H', chr(41) => chr(129).'I', chr(42) => chr(129).'J', chr(43) => chr(129).'K',
  502. chr(44) => chr(129).'L', chr(45) => '-', chr(46) => '.', chr(47) => chr(129).'O',
  503. chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3',
  504. chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7',
  505. chr(56) => '8', chr(57) => '9', chr(58) => chr(129).'Z', chr(59) => chr(131).'F',
  506. chr(60) => chr(131).'G', chr(61) => chr(131).'H', chr(62) => chr(131).'I', chr(63) => chr(131).'J',
  507. chr(64) => chr(131).'V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C',
  508. chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G',
  509. chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K',
  510. chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O',
  511. chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S',
  512. chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W',
  513. chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => chr(131).'K',
  514. chr(92) => chr(131).'L', chr(93) => chr(131).'M', chr(94) => chr(131).'N', chr(95) => chr(131).'O',
  515. chr(96) => chr(131).'W', chr(97) => chr(130).'A', chr(98) => chr(130).'B', chr(99) => chr(130).'C',
  516. chr(100) => chr(130).'D', chr(101) => chr(130).'E', chr(102) => chr(130).'F', chr(103) => chr(130).'G',
  517. chr(104) => chr(130).'H', chr(105) => chr(130).'I', chr(106) => chr(130).'J', chr(107) => chr(130).'K',
  518. chr(108) => chr(130).'L', chr(109) => chr(130).'M', chr(110) => chr(130).'N', chr(111) => chr(130).'O',
  519. chr(112) => chr(130).'P', chr(113) => chr(130).'Q', chr(114) => chr(130).'R', chr(115) => chr(130).'S',
  520. chr(116) => chr(130).'T', chr(117) => chr(130).'U', chr(118) => chr(130).'V', chr(119) => chr(130).'W',
  521. chr(120) => chr(130).'X', chr(121) => chr(130).'Y', chr(122) => chr(130).'Z', chr(123) => chr(131).'P',
  522. chr(124) => chr(131).'Q', chr(125) => chr(131).'R', chr(126) => chr(131).'S', chr(127) => chr(131).'T');
  523. $code_ext = '';
  524. $clen = strlen($code);
  525. for ($i = 0 ; $i < $clen; ++$i) {
  526. if (ord($code{$i}) > 127) {
  527. return false;
  528. }
  529. $code_ext .= $encode[$code{$i}];
  530. }
  531. // checksum
  532. $code_ext .= $this->checksum_code93($code_ext);
  533. // add start and stop codes
  534. $code = '*'.$code_ext.'*';
  535. $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
  536. $k = 0;
  537. $clen = strlen($code);
  538. for ($i = 0; $i < $clen; ++$i) {
  539. $char = ord($code{$i});
  540. if(!isset($chr[$char])) {
  541. // invalid character
  542. return false;
  543. }
  544. for ($j = 0; $j < 6; ++$j) {
  545. if (($j % 2) == 0) {
  546. $t = true; // bar
  547. } else {
  548. $t = false; // space
  549. }
  550. $w = $chr[$char]{$j};
  551. $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
  552. $bararray['maxw'] += $w;
  553. ++$k;
  554. }
  555. }
  556. $bararray['bcode'][$k] = array('t' => true, 'w' => 1, 'h' => 1, 'p' => 0);
  557. $bararray['maxw'] += 1;
  558. ++$k;
  559. return $bararray;
  560. }
  561. /**
  562. * Calculate CODE 93 checksum (modulo 47).
  563. * @param $code (string) code to represent.
  564. * @return string checksum code.
  565. * @protected
  566. */
  567. protected function checksum_code93($code) {
  568. $chars = array(
  569. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  570. 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
  571. 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
  572. 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%',
  573. '<', '=', '>', '?');
  574. // translate special characters
  575. $code = strtr($code, chr(128).chr(131).chr(129).chr(130), '<=>?');
  576. $len = strlen($code);
  577. // calculate check digit C
  578. $p = 1;
  579. $check = 0;
  580. for ($i = ($len - 1); $i >= 0; --$i) {
  581. $k = array_keys($chars, $code{$i});
  582. $check += ($k[0] * $p);
  583. ++$p;
  584. if ($p > 20) {
  585. $p = 1;
  586. }
  587. }
  588. $check %= 47;
  589. $c = $chars[$check];
  590. $code .= $c;
  591. // calculate check digit K
  592. $p = 1;
  593. $check = 0;
  594. for ($i = $len; $i >= 0; --$i) {
  595. $k = array_keys($chars, $code{$i});
  596. $check += ($k[0] * $p);
  597. ++$p;
  598. if ($p > 15) {
  599. $p = 1;
  600. }
  601. }
  602. $check %= 47;
  603. $k = $chars[$check];
  604. $checksum = $c.$k;
  605. // resto respecial characters
  606. $checksum = strtr($checksum, '<=>?', chr(128).chr(131).chr(129).chr(130));
  607. return $checksum;
  608. }
  609. /**
  610. * Checksum for standard 2 of 5 barcodes.
  611. * @param $code (string) code to process.
  612. * @return int checksum.
  613. * @protected
  614. */
  615. protected function checksum_s25($code) {
  616. $len = strlen($code);
  617. $sum = 0;
  618. for ($i = 0; $i < $len; $i+=2) {
  619. $sum += $code{$i};
  620. }
  621. $sum *= 3;
  622. for ($i = 1; $i < $len; $i+=2) {
  623. $sum += ($code{$i});
  624. }
  625. $r = $sum % 10;
  626. if($r > 0) {
  627. $r = (10 - $r);
  628. }
  629. return $r;
  630. }
  631. /**
  632. * MSI.
  633. * Variation of Plessey code, with similar applications
  634. * Contains digits (0 to 9) and encodes the data only in the width of bars.
  635. * @param $code (string) code to represent.
  636. * @param $checksum (boolean) if true add a checksum to the code (modulo 11)
  637. * @return array barcode representation.
  638. * @protected
  639. */
  640. protected function barcode_msi($code, $checksum=false) {
  641. $chr['0'] = '100100100100';
  642. $chr['1'] = '100100100110';
  643. $chr['2'] = '100100110100';
  644. $chr['3'] = '100100110110';
  645. $chr['4'] = '100110100100';
  646. $chr['5'] = '100110100110';
  647. $chr['6'] = '100110110100';
  648. $chr['7'] = '100110110110';
  649. $chr['8'] = '110100100100';
  650. $chr['9'] = '110100100110';
  651. $chr['A'] = '110100110100';
  652. $chr['B'] = '110100110110';
  653. $chr['C'] = '110110100100';
  654. $chr['D'] = '110110100110';
  655. $chr['E'] = '110110110100';
  656. $chr['F'] = '110110110110';
  657. if ($checksum) {
  658. // add checksum
  659. $clen = strlen($code);
  660. $p = 2;
  661. $check = 0;
  662. for ($i = ($clen - 1); $i >= 0; --$i) {
  663. $check += (hexdec($code{$i}) * $p);
  664. ++$p;
  665. if ($p > 7) {
  666. $p = 2;
  667. }
  668. }
  669. $check %= 11;
  670. if ($check > 0) {
  671. $check = 11 - $check;
  672. }
  673. $code .= $check;
  674. }
  675. $seq = '110'; // left guard
  676. $clen = strlen($code);
  677. for ($i = 0; $i < $clen; ++$i) {
  678. $digit = $code{$i};
  679. if (!isset($chr[$digit])) {
  680. // invalid character
  681. return false;
  682. }
  683. $seq .= $chr[$digit];
  684. }
  685. $seq .= '1001'; // right guard
  686. $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
  687. return $this->binseq_to_array($seq, $bararray);
  688. }
  689. /**
  690. * Standard 2 of 5 barcodes.
  691. * Used in airline ticket marking, photofinishing
  692. * Contains digits (0 to 9) and encodes the data only in the width of bars.
  693. * @param $code (string) code to represent.
  694. * @param $checksum (boolean) if true add a checksum to the code
  695. * @return array barcode representation.
  696. * @protected
  697. */
  698. protected function barcode_s25($code, $checksum=false) {
  699. $chr['0'] = '10101110111010';
  700. $chr['1'] = '11101010101110';
  701. $chr['2'] = '10111010101110';
  702. $chr['3'] = '11101110101010';
  703. $chr['4'] = '10101110101110';
  704. $chr['5'] = '11101011101010';
  705. $chr['6'] = '10111011101010';
  706. $chr['7'] = '10101011101110';
  707. $chr['8'] = '10101110111010';
  708. $chr['9'] = '10111010111010';
  709. if ($checksum) {
  710. // add checksum
  711. $code .= $this->checksum_s25($code);
  712. }
  713. if((strlen($code) % 2) != 0) {
  714. // add leading zero if code-length is odd
  715. $code = '0'.$code;
  716. }
  717. $seq = '11011010';
  718. $clen = strlen($code);
  719. for ($i = 0; $i < $clen; ++$i) {
  720. $digit = $code{$i};
  721. if (!isset($chr[$digit])) {
  722. // invalid character
  723. return false;
  724. }
  725. $seq .= $chr[$digit];
  726. }
  727. $seq .= '1101011';
  728. $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
  729. return $this->binseq_to_array($seq, $bararray);
  730. }
  731. /**
  732. * Convert binary barcode sequence to TCPDF barcode array.
  733. * @param $seq (string) barcode as binary sequence.
  734. * @param $bararray (array) barcode array.
  735. * òparam array $bararray TCPDF barcode array to fill up
  736. * @return array barcode representation.
  737. * @protected
  738. */
  739. protected function binseq_to_array($seq, $bararray) {
  740. $len = strlen($seq);
  741. $w = 0;
  742. $k = 0;
  743. for ($i = 0; $i < $len; ++$i) {
  744. $w += 1;
  745. if (($i == ($len - 1)) OR (($i < ($len - 1)) AND ($seq{$i} != $seq{($i+1)}))) {
  746. if ($seq{$i} == '1') {
  747. $t = true; // bar
  748. } else {
  749. $t = false; // space
  750. }
  751. $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
  752. $bararray['maxw'] += $w;
  753. ++$k;
  754. $w = 0;
  755. }
  756. }
  757. return $bararray;
  758. }
  759. /**
  760. * Interleaved 2 of 5 barcodes.
  761. * Compact numeric code, widely used in industry, air cargo
  762. * Contains digits (0 to 9) and encodes the data in the width of both bars and spaces.
  763. * @param $code (string) code to represent.
  764. * @param $checksum (boolean) if true add a checksum to the code
  765. * @return array barcode representation.
  766. * @protected
  767. */
  768. protected function barcode_i25($code, $checksum=false) {
  769. $chr['0'] = '11221';
  770. $chr['1'] = '21112';
  771. $chr['2'] = '12112';
  772. $chr['3'] = '22111';
  773. $chr['4'] = '11212';
  774. $chr['5'] = '21211';
  775. $chr['6'] = '12211';
  776. $chr['7'] = '11122';
  777. $chr['8'] = '21121';
  778. $chr['9'] = '12121';
  779. $chr['A'] = '11';
  780. $chr['Z'] = '21';
  781. if ($checksum) {
  782. // add checksum
  783. $code .= $this->checksum_s25($code);
  784. }
  785. if((strlen($code) % 2) != 0) {
  786. // add leading zero if code-length is odd
  787. $code = '0'.$code;
  788. }
  789. // add start and stop codes
  790. $code = 'AA'.strtolower($code).'ZA';
  791. $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
  792. $k = 0;
  793. $clen = strlen($code);
  794. for ($i = 0; $i < $clen; $i = ($i + 2)) {
  795. $char_bar = $code{$i};
  796. $char_space = $code{$i+1};
  797. if((!isset($chr[$char_bar])) OR (!isset($chr[$char_space]))) {
  798. // invalid character
  799. return false;
  800. }
  801. // create a bar-space sequence
  802. $seq = '';
  803. $chrlen = strlen($chr[$char_bar]);
  804. for ($s = 0; $s < $chrlen; $s++){
  805. $seq .= $chr[$char_bar]{$s} . $chr[$char_space]{$s};
  806. }
  807. $seqlen = strlen($seq);
  808. for ($j = 0; $j < $seqlen; ++$j) {
  809. if (($j % 2) == 0) {
  810. $t = true; // bar
  811. } else {
  812. $t = false; // space
  813. }
  814. $w = $seq{$j};
  815. $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
  816. $bararray['maxw'] += $w;
  817. ++$k;
  818. }
  819. }
  820. return $bararray;
  821. }
  822. /**
  823. * C128 barcodes.
  824. * Very capable code, excellent density, high reliability; in very wide use world-wide
  825. * @param $code (string) code to represent.
  826. * @param $type (string) barcode type: A, B, C or empty for automatic switch (AUTO mode)
  827. * @return array barcode representation.
  828. * @protected
  829. */
  830. protected function barcode_c128($code, $type='') {
  831. $chr = array(
  832. '212222', /* 00 */
  833. '222122', /* 01 */
  834. '222221', /* 02 */
  835. '121223', /* 03 */
  836. '121322', /* 04 */
  837. '131222', /* 05 */
  838. '122213', /* 06 */
  839. '122312', /* 07 */
  840. '132212', /* 08 */
  841. '221213', /* 09 */
  842. '221312', /* 10 */
  843. '231212', /* 11 */
  844. '112232', /* 12 */
  845. '122132', /* 13 */
  846. '122231', /* 14 */
  847. '113222', /* 15 */
  848. '123122', /* 16 */
  849. '123221', /* 17 */
  850. '223211', /* 18 */
  851. '221132', /* 19 */
  852. '221231', /* 20 */
  853. '213212', /* 21 */
  854. '223112', /* 22 */
  855. '312131', /* 23 */
  856. '311222', /* 24 */
  857. '321122', /* 25 */
  858. '321221', /* 26 */
  859. '312212', /* 27 */
  860. '322112', /* 28 */
  861. '322211', /* 29 */
  862. '212123', /* 30 */
  863. '212321', /* 31 */
  864. '232121', /* 32 */
  865. '111323', /* 33 */
  866. '131123', /* 34 */
  867. '131321', /* 35 */
  868. '112313', /* 36 */
  869. '132113', /* 37 */
  870. '132311', /* 38 */
  871. '211313', /* 39 */
  872. '231113', /* 40 */
  873. '231311', /* 41 */
  874. '112133', /* 42 */
  875. '112331', /* 43 */
  876. '132131', /* 44 */
  877. '113123', /* 45 */
  878. '113321', /* 46 */
  879. '133121', /* 47 */
  880. '313121', /* 48 */
  881. '211331', /* 49 */
  882. '231131', /* 50 */
  883. '213113', /* 51 */
  884. '213311', /* 52 */
  885. '213131', /* 53 */
  886. '311123', /* 54 */
  887. '311321', /* 55 */
  888. '331121', /* 56 */
  889. '312113', /* 57 */
  890. '312311', /* 58 */
  891. '332111', /* 59 */
  892. '314111', /* 60 */
  893. '221411', /* 61 */
  894. '431111', /* 62 */
  895. '111224', /* 63 */
  896. '111422', /* 64 */
  897. '121124', /* 65 */
  898. '121421', /* 66 */
  899. '141122', /* 67 */
  900. '141221', /* 68 */
  901. '112214', /* 69 */
  902. '112412', /* 70 */
  903. '122114', /* 71 */
  904. '122411', /* 72 */
  905. '142112', /* 73 */
  906. '142211', /* 74 */
  907. '241211', /* 75 */
  908. '221114', /* 76 */
  909. '413111', /* 77 */
  910. '241112', /* 78 */
  911. '134111', /* 79 */
  912. '111242', /* 80 */
  913. '121142', /* 81 */
  914. '121241', /* 82 */
  915. '114212', /* 83 */
  916. '124112', /* 84 */
  917. '124211', /* 85 */
  918. '411212', /* 86 */
  919. '421112', /* 87 */
  920. '421211', /* 88 */
  921. '212141', /* 89 */
  922. '214121', /* 90 */
  923. '412121', /* 91 */
  924. '111143', /* 92 */
  925. '111341', /* 93 */
  926. '131141', /* 94 */
  927. '114113', /* 95 */
  928. '114311', /* 96 */
  929. '411113', /* 97 */
  930. '411311', /* 98 */
  931. '113141', /* 99 */
  932. '114131', /* 100 */
  933. '311141', /* 101 */
  934. '411131', /* 102 */
  935. '211412', /* 103 START A */
  936. '211214', /* 104 START B */
  937. '211232', /* 105 START C */
  938. '233111', /* STOP */
  939. '200000' /* END */
  940. );
  941. // ASCII characters for code A (ASCII 00 - 95)
  942. $keys_a = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_';
  943. $keys_a .= chr(0).chr(1).chr(2).chr(3).chr(4).chr(5).chr(6).chr(7).chr(8).chr(9);
  944. $keys_a .= chr(10).chr(11).chr(12).chr(13).chr(14).chr(15).chr(16).chr(17).chr(18).chr(19);
  945. $keys_a .= chr(20).chr(21).chr(22).chr(23).chr(24).chr(25).chr(26).chr(27).chr(28).chr(29);
  946. $keys_a .= chr(30).chr(31);
  947. // ASCII characters for code B (ASCII 32 - 127)
  948. $keys_b = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'.chr(127);
  949. // special codes
  950. $fnc_a = array(241 => 102, 242 => 97, 243 => 96, 244 => 101);
  951. $fnc_b = array(241 => 102, 242 => 97, 243 => 96, 244 => 100);
  952. // array of symbols
  953. $code_data = array();
  954. // lenght of the code
  955. $len = strlen($code);
  956. switch(strtoupper($type)) {
  957. case 'A': { // MODE A
  958. $startid = 103;
  959. for ($i = 0; $i < $len; ++$i) {
  960. $char = $code{$i};
  961. $char_id = ord($char);
  962. if (($char_id >= 241) AND ($char_id <= 244)) {
  963. $code_data[] = $fnc_a[$char_id];
  964. } elseif (($char_id >= 0) AND ($char_id <= 95)) {
  965. $code_data[] = strpos($keys_a, $char);
  966. } else {
  967. return false;
  968. }
  969. }
  970. break;
  971. }
  972. case 'B': { // MODE B
  973. $startid = 104;
  974. for ($i = 0; $i < $len; ++$i) {
  975. $char = $code{$i};
  976. $char_id = ord($char);
  977. if (($char_id >= 241) AND ($char_id <= 244)) {
  978. $code_data[] = $fnc_b[$char_id];
  979. } elseif (($char_id >= 32) AND ($char_id <= 127)) {
  980. $code_data[] = strpos($keys_b, $char);
  981. } else {
  982. return false;
  983. }
  984. }
  985. break;
  986. }
  987. case 'C': { // MODE C
  988. $startid = 105;
  989. if (ord($code{0}) == 241) {
  990. $code_data[] = 102;
  991. $code = substr($code, 1);
  992. --$len;
  993. }
  994. if (($len % 2) != 0) {
  995. // the length must be even
  996. return false;
  997. }
  998. for ($i = 0; $i < $len; $i+=2) {
  999. $chrnum = $code{$i}.$code{$i+1};
  1000. if (preg_match('/([0-9]{2})/', $chrnum) > 0) {
  1001. $code_data[] = intval($chrnum);
  1002. } else {
  1003. return false;
  1004. }
  1005. }
  1006. break;
  1007. }
  1008. default: { // MODE AUTO
  1009. // split code into sequences
  1010. $sequence = array();
  1011. // get numeric sequences (if any)
  1012. $numseq = array();
  1013. preg_match_all('/([0-9]{4,})/', $code, $numseq, PREG_OFFSET_CAPTURE);
  1014. if (isset($numseq[1]) AND !empty($numseq[1])) {
  1015. $end_offset = 0;
  1016. foreach ($numseq[1] as $val) {
  1017. $offset = $val[1];
  1018. if ($offset > $end_offset) {
  1019. // non numeric sequence
  1020. $sequence = array_merge($sequence, $this->get128ABsequence(substr($code, $end_offset, ($offset - $end_offset))));
  1021. }
  1022. // numeric sequence
  1023. $slen = strlen($val[0]);
  1024. if (($slen % 2) != 0) {
  1025. // the length must be even
  1026. --$slen;
  1027. }
  1028. $sequence[] = array('C', substr($code, $offset, $slen), $slen);
  1029. $end_offset = $offset + $slen;
  1030. }
  1031. if ($end_offset < $len) {
  1032. $sequence = array_merge($sequence, $this->get128ABsequence(substr($code, $end_offset)));
  1033. }
  1034. } else {
  1035. // text code (non C mode)
  1036. $sequence = array_merge($sequence, $this->get128ABsequence($code));
  1037. }
  1038. // process the sequence
  1039. foreach ($sequence as $key => $seq) {
  1040. switch($seq[0]) {
  1041. case 'A': {
  1042. if ($key == 0) {
  1043. $startid = 103;
  1044. } elseif ($sequence[($key - 1)][0] != 'A') {
  1045. if (($seq[2] == 1) AND ($key > 0) AND ($sequence[($key - 1)][0] == 'B') AND (!isset($sequence[($key - 1)][3]))) {
  1046. // single character shift
  1047. $code_data[] = 98;
  1048. // mark shift
  1049. $sequence[$key][3] = true;
  1050. } elseif (!isset($sequence[($key - 1)][3])) {
  1051. $code_data[] = 101;
  1052. }
  1053. }
  1054. for ($i = 0; $i < $seq[2]; ++$i) {
  1055. $char = $seq[1]{$i};
  1056. $char_id = ord($char);
  1057. if (($char_id >= 241) AND ($char_id <= 244)) {
  1058. $code_data[] = $fnc_a[$char_id];
  1059. } else {
  1060. $code_data[] = strpos($keys_a, $char);
  1061. }
  1062. }
  1063. break;
  1064. }
  1065. case 'B': {
  1066. if ($key == 0) {
  1067. $tmpchr = ord($seq[1]{0});
  1068. if (($seq[2] == 1) AND ($tmpchr >= 241) AND ($tmpchr <= 244) AND isset($sequence[($key + 1)]) AND ($sequence[($key + 1)][0] != 'B')) {
  1069. switch ($sequence[($key + 1)][0]) {
  1070. case 'A': {
  1071. $startid = 103;
  1072. $sequence[$key][0] = 'A';
  1073. $code_data[] = $fnc_a[$tmpchr];
  1074. break;
  1075. }
  1076. case 'C': {
  1077. $startid = 105;
  1078. $sequence[$key][0] = 'C';
  1079. $code_data[] = $fnc_a[$tmpchr];
  1080. break;
  1081. }
  1082. }
  1083. break;
  1084. } else {
  1085. $startid = 104;
  1086. }
  1087. } elseif ($sequence[($key - 1)][0] != 'B') {
  1088. if (($seq[2] == 1) AND ($key > 0) AND ($sequence[($key - 1)][0] == 'A') AND (!isset($sequence[($key - 1)][3]))) {
  1089. // single character shift
  1090. $code_data[] = 98;
  1091. // mark shift
  1092. $sequence[$key][3] = true;
  1093. } elseif (!isset($sequence[($key - 1)][3])) {
  1094. $code_data[] = 100;
  1095. }
  1096. }
  1097. for ($i = 0; $i < $seq[2]; ++$i) {
  1098. $char = $seq[1]{$i};
  1099. $char_id = ord($char);
  1100. if (($char_id >= 241) AND ($char_id <= 244)) {
  1101. $code_data[] = $fnc_b[$char_id];
  1102. } else {
  1103. $code_data[] = strpos($keys_b, $char);
  1104. }
  1105. }
  1106. break;
  1107. }
  1108. case 'C': {
  1109. if ($key == 0) {
  1110. $startid = 105;
  1111. } elseif ($sequence[($key - 1)][0] != 'C') {
  1112. $code_data[] = 99;
  1113. }
  1114. for ($i = 0; $i < $seq[2]; $i+=2) {
  1115. $chrnum = $seq[1]{$i}.$seq[1]{$i+1};
  1116. $code_data[] = intval($chrnum);
  1117. }
  1118. break;
  1119. }
  1120. }
  1121. }
  1122. }
  1123. }
  1124. // calculate check character
  1125. $sum = $startid;
  1126. foreach ($code_data as $key => $val) {
  1127. $sum += ($val * ($key + 1));
  1128. }
  1129. // add check character
  1130. $code_data[] = ($sum % 103);
  1131. // add stop sequence
  1132. $code_data[] = 106;
  1133. $code_data[] = 107;
  1134. // add start code at the beginning
  1135. array_unshift($code_data, $startid);
  1136. // build barcode array
  1137. $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
  1138. foreach ($code_data as $val) {
  1139. $seq = $chr[$val];
  1140. for ($j = 0; $j < 6; ++$j) {
  1141. if (($j % 2) == 0) {
  1142. $t = true; // bar
  1143. } else {
  1144. $t = false; // space
  1145. }
  1146. $w = $seq{$j};
  1147. $bararray['bcode'][] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
  1148. $bararray['maxw'] += $w;
  1149. }
  1150. }
  1151. return $bararray;
  1152. }
  1153. /**
  1154. * Split text code in A/B sequence for 128 code
  1155. * @param $code (string) code to split.
  1156. * @return array sequence
  1157. * @protected
  1158. */
  1159. protected function get128ABsequence($code) {
  1160. $len = strlen($code);
  1161. $sequence = array();
  1162. // get A sequences (if any)
  1163. $numseq = array();
  1164. preg_match_all('/([\0-\31])/', $code, $numseq, PREG_OFFSET_CAPTURE);
  1165. if (isset($numseq[1]) AND !empty($numseq[1])) {
  1166. $end_offset = 0;
  1167. foreach ($numseq[1] as $val) {
  1168. $offset = $val[1];
  1169. if ($offset > $end_offset) {
  1170. // B sequence
  1171. $sequence[] = array('B', substr($code, $end_offset, ($offset - $end_offset)), ($offset - $end_offset));
  1172. }
  1173. // A sequence
  1174. $slen = strlen($val[0]);
  1175. $sequence[] = array('A', substr($code, $offset, $slen), $slen);
  1176. $end_offset = $offset + $slen;
  1177. }
  1178. if ($end_offset < $len) {
  1179. $sequence[] = array('B', substr($code, $end_offset), ($len - $end_offset));
  1180. }
  1181. } else {
  1182. // only B sequence
  1183. $sequence[] = array('B', $code, $len);
  1184. }
  1185. return $sequence;
  1186. }
  1187. /**
  1188. * EAN13 and UPC-A barcodes.
  1189. * EAN13: European Article Numbering international retail product code
  1190. * UPC-A: Universal product code seen on almost all retail products in the USA and Canada
  1191. * UPC-E: Short version of UPC symbol
  1192. * @param $code (string) code to represent.
  1193. * @param $len (string) barcode type: 6 = UPC-E, 8 = EAN8, 13 = EAN13, 12 = UPC-A
  1194. * @return array barcode representation.
  1195. * @protected
  1196. */
  1197. protected function barcode_eanupc($code, $len=13) {
  1198. $upce = false;
  1199. if ($len == 6) {
  1200. $len = 12; // UPC-A
  1201. $upce = true; // UPC-E mode
  1202. }
  1203. $data_len = $len - 1;
  1204. //Padding
  1205. $code = str_pad($code, $data_len, '0', STR_PAD_LEFT);
  1206. $code_len = strlen($code);
  1207. // calculate check digit
  1208. $sum_a = 0;
  1209. for ($i = 1; $i < $data_len; $i+=2) {
  1210. $sum_a += $code{$i};
  1211. }
  1212. if ($len > 12) {
  1213. $sum_a *= 3;
  1214. }
  1215. $sum_b = 0;
  1216. for ($i = 0; $i < $data_len; $i+=2) {
  1217. $sum_b += ($code{$i});
  1218. }
  1219. if ($len < 13) {
  1220. $sum_b *= 3;
  1221. }
  1222. $r = ($sum_a + $sum_b) % 10;
  1223. if($r > 0) {
  1224. $r = (10 - $r);
  1225. }
  1226. if ($code_len == $data_len) {
  1227. // add check digit
  1228. $code .= $r;
  1229. } elseif ($r !== intval($code{$data_len})) {
  1230. // wrong checkdigit
  1231. return false;
  1232. }
  1233. if ($len == 12) {
  1234. // UPC-A
  1235. $code = '0'.$code;
  1236. ++$len;
  1237. }
  1238. if ($upce) {
  1239. // convert UPC-A to UPC-E
  1240. $tmp = substr($code, 4, 3);
  1241. if (($tmp == '000') OR ($tmp == '100') OR ($tmp == '200')) {
  1242. // manufacturer code ends in 000, 100, or 200
  1243. $upce_code = substr($code, 2, 2).substr($code, 9, 3).substr($code, 4, 1);
  1244. } else {
  1245. $tmp = substr($code, 5, 2);
  1246. if ($tmp == '00') {
  1247. // manufacturer code ends in 00
  1248. $upce_code = substr($code, 2, 3).substr($code, 10, 2).'3';
  1249. } else {
  1250. $tmp = substr($code, 6, 1);
  1251. if ($tmp == '0') {
  1252. // manufacturer code ends in 0
  1253. $upce_code = substr($code, 2, 4).substr($code, 11, 1).'4';
  1254. } else {
  1255. // manufacturer code does not end in zero
  1256. $upce_code = substr($code, 2, 5).substr($code, 11, 1);
  1257. }
  1258. }
  1259. }
  1260. }
  1261. //Convert digits to bars
  1262. $codes = array(
  1263. 'A'=>array( // left odd parity
  1264. '0'=>'0001101',
  1265. '1'=>'0011001',
  1266. '2'=>'0010011',
  1267. '3'=>'0111101',
  1268. '4'=>'0100011',
  1269. '5'=>'0110001',
  1270. '6'=>'0101111',
  1271. '7'=>'0111011',
  1272. '8'=>'0110111',
  1273. '9'=>'0001011'),
  1274. 'B'=>array( // left even parity
  1275. '0'=>'0100111',
  1276. '1'=>'0110011',
  1277. '2'=>'0011011',
  1278. '3'=>'0100001',
  1279. '4'=>'0011101',
  1280. '5'=>'0111001',
  1281. '6'=>'0000101',
  1282. '7'=>'0010001',
  1283. '8'=>'0001001',
  1284. '9'=>'0010111'),
  1285. 'C'=>array( // right
  1286. '0'=>'1110010',
  1287. '1'=>'1100110',
  1288. '2'=>'1101100',
  1289. '3'=>'1000010',
  1290. '4'=>'1011100',
  1291. '5'=>'1001110',
  1292. '6'=>'1010000',
  1293. '7'=>'1000100',
  1294. '8'=>'1001000',
  1295. '9'=>'1110100')
  1296. );
  1297. $parities = array(
  1298. '0'=>array('A','A','A','A','A','A'),
  1299. '1'=>array('A','A','B','A','B','B'),
  1300. '2'=>array('A','A','B','B','A','B'),
  1301. '3'=>array('A','A','B','B','B','A'),
  1302. '4'=>array('A','B','A','A','B','B'),
  1303. '5'=>array('A','B','B','A','A','B'),
  1304. '6'=>array('A','B','B','B','A','A'),
  1305. '7'=>array('A','B','A','B','A','B'),
  1306. '8'=>array('A','B','A','B','B','A'),
  1307. '9'=>array('A','B','B','A','B','A')
  1308. );
  1309. $upce_parities = array();
  1310. $upce_parities[0] = array(
  1311. '0'=>array('B','B','B','A','A','A'),
  1312. '1'=>array('B','B','A','B','A','A'),
  1313. '2'=>array('B','B','A','A','B','A'),
  1314. '3'=>array('B','B','A','A','A','B'),
  1315. '4'=>array('B','A','B','B','A','A'),
  1316. '5'=>array('B','A','A','B','B','A'),
  1317. '6'=>array('B','A','A','A','B','B'),
  1318. '7'=>array('B','A','B','A','B','A'),
  1319. '8'=>array('B','A','B','A','A','B'),
  1320. '9'=>array('B','A','A','B','A','B')
  1321. );
  1322. $upce_parities[1] = array(
  1323. '0'=>array('A','A','A','B','B','B'),
  1324. '1'=>array('A','A','B','A','B','B'),
  1325. '2'=>array('A','A','B','B','A','B'),
  1326. '3'=>array('A','A','B','B','B','A'),
  1327. '4'=>array('A','B','A','A','B','B'),
  1328. '5'=>array('A','B','B','A','A','B'),
  1329. '6'=>array('A','B','B','B','A','A'),
  1330. '7'=>array('A','B','A','B','A','B'),
  1331. '8'=>array('A','B','A','B','B','A'),
  1332. '9'=>array('A','B','B','A','B','A')
  1333. );
  1334. $k = 0;
  1335. $seq = '101'; // left guard bar
  1336. if ($upce) {
  1337. $bararray = array('code' => $upce_code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
  1338. $p = $upce_parities[$code{1}][$r];
  1339. for ($i = 0; $i < 6; ++$i) {
  1340. $seq .= $codes[$p[$i]][$upce_code{$i}];
  1341. }
  1342. $seq .= '010101'; // right guard bar
  1343. } else {
  1344. $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
  1345. $half_len = ceil($len / 2);
  1346. if ($len == 8) {
  1347. for ($i = 0; $i < $half_len; ++$i) {
  1348. $seq .= $codes['A'][$code{$i}];
  1349. }
  1350. } else {
  1351. $p = $parities[$code{0}];
  1352. for ($i = 1; $i < $half_len; ++$i) {
  1353. $seq .= $codes[$p[$i-1]][$code{$i}];
  1354. }
  1355. }
  1356. $seq .= '01010'; // center guard bar
  1357. for ($i = $half_len; $i < $len; ++$i) {
  1358. $seq .= $codes['C'][$code{$i}];
  1359. }
  1360. $seq .= '101'; // right guard bar
  1361. }
  1362. $clen = strlen($seq);
  1363. $w = 0;
  1364. for ($i = 0; $i < $clen; ++$i) {
  1365. $w += 1;
  1366. if (($i == ($clen - 1)) OR (($i < ($clen - 1)) AND ($seq{$i} != $seq{($i+1)}))) {
  1367. if ($seq{$i} == '1') {
  1368. $t = true; // bar
  1369. } else {
  1370. $t = false; // space
  1371. }
  1372. $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
  1373. $bararray['maxw'] += $w;
  1374. ++$k;
  1375. $w = 0;
  1376. }
  1377. }
  1378. return $bararray;
  1379. }
  1380. /**
  1381. * UPC-Based Extentions
  1382. * 2-Digit Ext.: Used to indicate magazines and newspaper issue numbers
  1383. * 5-Digit Ext.: Used to mark suggested retail price of books
  1384. * @param $code (string) code to represent.
  1385. * @param $len (string) barcode type: 2 = 2-Digit, 5 = 5-Digit
  1386. * @return array barcode representation.
  1387. * @protected
  1388. */
  1389. protected function barcode_eanext($code, $len=5) {
  1390. //Padding
  1391. $code = str_pad($code, $len, '0', STR_PAD_LEFT);
  1392. // calculate check digit
  1393. if ($len == 2) {
  1394. $r = $code % 4;
  1395. } elseif ($len == 5) {
  1396. $r = (3 * ($code{0} + $code{2} + $code{4})) + (9 * ($code{1} + $code{3}));
  1397. $r %= 10;
  1398. } else {
  1399. return false;
  1400. }
  1401. //Convert digits to bars
  1402. $codes = array(
  1403. 'A'=>array( // left odd parity
  1404. '0'=>'0001101',
  1405. '1'=>'0011001',
  1406. '2'=>'0010011',
  1407. '3'=>'0111101',
  1408. '4'=>'0100011',
  1409. '5'=>'0110001',
  1410. '6'=>'0101111',
  1411. '7'=>'0111011',
  1412. '8'=>'0110111',
  1413. '9'=>'0001011'),
  1414. 'B'=>array( // left even parity
  1415. '0'=>'0100111',
  1416. '1'=>'0110011',
  1417. '2'=>'0011011',
  1418. '3'=>'0100001',
  1419. '4'=>'0011101',
  1420. '5'=>'0111001',
  1421. '6'=>'0000101',
  1422. '7'=>'0010001',
  1423. '8'=>'0001001',
  1424. '9'=>'0010111')
  1425. );
  1426. $parities = array();
  1427. $parities[2] = array(
  1428. '0'=>array('A','A'),
  1429. '1'=>array('A','B'),
  1430. '2'=>array('B','A'),
  1431. '3'=>array('B','B')
  1432. );
  1433. $parities[5] = array(
  1434. '0'=>array('B','B','A','A','A'),
  1435. '1'=>array('B','A','B','A','A'),
  1436. '2'=>array('B','A','A','B','A'),
  1437. '3'=>array('B','A','A','A','B'),
  1438. '4'=>array('A','B','B','A','A'),
  1439. '5'=>array('A','A','B','B','A'),
  1440. '6'=>array('A','A','A','B','B'),
  1441. '7'=>array('A','B','A','B','A'),
  1442. '8'=>array('A','B','A','A','B'),
  1443. '9'=>array('A','A','B','A','B')
  1444. );
  1445. $p = $parities[$len][$r];
  1446. $seq = '1011'; // left guard bar
  1447. $seq .= $codes[$p[0]][$code{0}];
  1448. for ($i = 1; $i < $len; ++$i) {
  1449. $seq .= '01'; // separator
  1450. $seq .= $codes[$p[$i]][$code{$i}];
  1451. }
  1452. $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
  1453. return $this->binseq_to_array($seq, $bararray);
  1454. }
  1455. /**
  1456. * POSTNET and PLANET barcodes.
  1457. * Used by U.S. Postal Service for automated mail sorting
  1458. * @param $code (string) zip code to represent. Must be a string containing a zip code of the form DDDDD or DDDDD-DDDD.
  1459. * @param $planet (boolean) if true print the PLANET barcode, otherwise print POSTNET
  1460. * @return array barcode representation.
  1461. * @protected
  1462. */
  1463. protected function barcode_postnet($code, $planet=false) {
  1464. // bar lenght
  1465. if ($planet) {
  1466. $barlen = Array(
  1467. 0 => Array(1,1,2,2,2),
  1468. 1 => Array(2,2,2,1,1),
  1469. 2 => Array(2,2,1,2,1),
  1470. 3 => Array(2,2,1,1,2),
  1471. 4 => Array(2,1,2,2,1),
  1472. 5 => Array(2,1,2,1,2),
  1473. 6 => Array(2,1,1,2,2),
  1474. 7 => Array(1,2,2,2,1),
  1475. 8 => Array(1,2,2,1,2),
  1476. 9 => Array(1,2,1,2,2)
  1477. );
  1478. } else {
  1479. $barlen = Array(
  1480. 0 => Array(2,2,1,1,1),
  1481. 1 => Array(1,1,1,2,2),
  1482. 2 => Array(1,1,2,1,2),
  1483. 3 => Array(1,1,2,2,1),
  1484. 4 => Array(1,2,1,1,2),
  1485. 5 => Array(1,2,1,2,1),
  1486. 6 => Array(1,2,2,1,1),
  1487. 7 => Array(2,1,1,1,2),
  1488. 8 => Array(2,1,1,2,1),
  1489. 9 => Array(2,1,2,1,1)
  1490. );
  1491. }
  1492. $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 2, 'bcode' => array());
  1493. $k = 0;
  1494. $code = str_replace('-', '', $code);
  1495. $code = str_replace(' ', '', $code);
  1496. $len = strlen($code);
  1497. // calculate checksum
  1498. $sum = 0;
  1499. for ($i = 0; $i < $len; ++$i) {
  1500. $sum += intval($code{$i});
  1501. }
  1502. $chkd = ($sum % 10);
  1503. if($chkd > 0) {
  1504. $chkd = (10 - $chkd);
  1505. }
  1506. $code .= $chkd;
  1507. $len = strlen($code);
  1508. // start bar
  1509. $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0);
  1510. $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
  1511. $bararray['maxw'] += 2;
  1512. for ($i = 0; $i < $len; ++$i) {
  1513. for ($j = 0; $j < 5; ++$j) {
  1514. $h = $barlen[$code{$i}][$j];
  1515. $p = floor(1 / $h);
  1516. $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
  1517. $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
  1518. $bararray['maxw'] += 2;
  1519. }
  1520. }
  1521. // end bar
  1522. $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0);
  1523. $bararray['maxw'] += 1;
  1524. return $bararray;
  1525. }
  1526. /**
  1527. * RMS4CC - CBC - KIX
  1528. * RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code) - KIX (Klant index - Customer index)
  1529. * RM4SCC is the name of the barcode symbology used by the Royal Mail for its Cleanmail service.
  1530. * @param $code (string) code to print
  1531. * @param $kix (boolean) if true prints the KIX variation (doesn't use the start and end symbols, and the checksum) - in this case the house number must be sufficed with an X and placed at the end of the c…

Large files files are truncated, but you can click here to view the full file