PageRenderTime 63ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 1ms

/barcodes.php

https://github.com/felipegirotti/2D-3D-Barcodes-Generator
PHP | 2709 lines | 2132 code | 56 blank | 521 comment | 298 complexity | 663df485ef7d628a29cdaca2c4bc7185 MD5 | raw file
  1. <?php
  2. //============================================================+
  3. // File name : barcodes.php
  4. // @author DNS
  5. class DNS2DBarcode {
  6. /**
  7. * Array representation of barcode.
  8. * @protected
  9. */
  10. protected $barcode_array = false;
  11. /**
  12. *path to save png in getBarcodePNGPath
  13. * @var <type>
  14. */
  15. public $save_path;
  16. /**
  17. * Return an array representations of barcode.
  18. * @return array
  19. */
  20. public function getBarcodeArray() {
  21. return $this->barcode_array;
  22. }
  23. /**
  24. * <li>$arrcode['code'] code to be printed on text label</li>
  25. * <li>$arrcode['num_rows'] required number of rows</li>
  26. * <li>$arrcode['num_cols'] required number of columns</li>
  27. * <li>$arrcode['bcode'][$r][$c] value of the cell is $r row and $c column (0 = transparent, 1 = black)</li></ul>
  28. * @param $code (string) code to print
  29. * @param $type (string) type of barcode: <ul><li>DATAMATRIX : Datamatrix (ISO/IEC 16022)</li><li>PDF417 : PDF417 (ISO/IEC 15438:2006)</li><li>PDF417,a,e,t,s,f,o0,o1,o2,o3,o4,o5,o6 : PDF417 with parameters: a = aspect ratio (width/height); e = error correction level (0-8); t = total number of macro segments; s = macro segment index (0-99998); f = file ID; o0 = File Name (text); o1 = Segment Count (numeric); o2 = Time Stamp (numeric); o3 = Sender (text); o4 = Addressee (text); o5 = File Size (numeric); o6 = Checksum (numeric). NOTES: Parameters t, s and f are required for a Macro Control Block, all other parametrs are optional. To use a comma character ',' on text options, replace it with the character 255: "\xff".</li><li>QRCODE : QRcode Low error correction</li><li>QRCODE,L : QRcode Low error correction</li><li>QRCODE,M : QRcode Medium error correction</li><li>QRCODE,Q : QRcode Better error correction</li><li>QRCODE,H : QR-CODE Best error correction</li><li>RAW: raw mode - comma-separad list of array rows</li><li>RAW2: raw mode - array rows are surrounded by square parenthesis.</li><li>TEST : Test matrix</li></ul>
  30. * Send barcode as SVG image object to the standard output.
  31. * @param $w (int) Width of a single rectangle element in user units.
  32. * @param $h (int) Height of a single rectangle element in user units.
  33. * @param $color (string) Foreground color (in SVG format) for bar elements (background is transparent).
  34. * @public
  35. */
  36. public function getBarcodeSVG($code, $type, $w=3, $h=3, $color='black') {
  37. //set barcode code and type
  38. $this->setBarcode($code, $type);
  39. // send headers
  40. $code = $this->getBarcodeSVGcode($w, $h, $color);
  41. header('Content-Type: application/svg+xml');
  42. header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1
  43. header('Pragma: public');
  44. header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past
  45. header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
  46. header('Content-Disposition: inline; filename="' . md5($code) . '.svg";');
  47. //header('Content-Length: '.strlen($code));
  48. echo $code;
  49. }
  50. /**
  51. * Return a SVG string representation of barcode.
  52. * <li>$arrcode['code'] code to be printed on text label</li>
  53. * <li>$arrcode['num_rows'] required number of rows</li>
  54. * <li>$arrcode['num_cols'] required number of columns</li>
  55. * <li>$arrcode['bcode'][$r][$c] value of the cell is $r row and $c column (0 = transparent, 1 = black)</li></ul>
  56. * @param $code (string) code to print
  57. * @param $type (string) type of barcode: <ul><li>DATAMATRIX : Datamatrix (ISO/IEC 16022)</li><li>PDF417 : PDF417 (ISO/IEC 15438:2006)</li><li>PDF417,a,e,t,s,f,o0,o1,o2,o3,o4,o5,o6 : PDF417 with parameters: a = aspect ratio (width/height); e = error correction level (0-8); t = total number of macro segments; s = macro segment index (0-99998); f = file ID; o0 = File Name (text); o1 = Segment Count (numeric); o2 = Time Stamp (numeric); o3 = Sender (text); o4 = Addressee (text); o5 = File Size (numeric); o6 = Checksum (numeric). NOTES: Parameters t, s and f are required for a Macro Control Block, all other parametrs are optional. To use a comma character ',' on text options, replace it with the character 255: "\xff".</li><li>QRCODE : QRcode Low error correction</li><li>QRCODE,L : QRcode Low error correction</li><li>QRCODE,M : QRcode Medium error correction</li><li>QRCODE,Q : QRcode Better error correction</li><li>QRCODE,H : QR-CODE Best error correction</li><li>RAW: raw mode - comma-separad list of array rows</li><li>RAW2: raw mode - array rows are surrounded by square parenthesis.</li><li>TEST : Test matrix</li></ul>
  58. * @param $w (int) Width of a single rectangle element in user units.
  59. * @param $h (int) Height of a single rectangle element in user units.
  60. * @param $color (string) Foreground color (in SVG format) for bar elements (background is transparent).
  61. * @return string SVG code.
  62. * @public
  63. */
  64. public function getBarcodeSVGcode($code, $type, $w=3, $h=3, $color='black') {
  65. //set barcode code and type
  66. $this->setBarcode($code, $type);
  67. // replace table for special characters
  68. $repstr = array("\0" => '', '&' => '&amp;', '<' => '&lt;', '>' => '&gt;');
  69. $svg = '<' . '?' . 'xml version="1.0" standalone="no"' . '?' . '>' . "\n";
  70. $svg .= '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' . "\n";
  71. $svg .= '<svg width="' . round(($this->barcode_array['num_cols'] * $w), 3) . '" height="' . round(($this->barcode_array['num_rows'] * $h), 3) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">' . "\n";
  72. $svg .= "\t" . '<desc>' . strtr($this->barcode_array['code'], $repstr) . '</desc>' . "\n";
  73. $svg .= "\t" . '<g id="elements" fill="' . $color . '" stroke="none">' . "\n";
  74. // print barcode elements
  75. $y = 0;
  76. // for each row
  77. for ($r = 0; $r < $this->barcode_array['num_rows']; ++$r) {
  78. $x = 0;
  79. // for each column
  80. for ($c = 0; $c < $this->barcode_array['num_cols']; ++$c) {
  81. if ($this->barcode_array['bcode'][$r][$c] == 1) {
  82. // draw a single barcode cell
  83. $svg .= "\t\t" . '<rect x="' . $x . '" y="' . $y . '" width="' . $w . '" height="' . $h . '" />' . "\n";
  84. }
  85. $x += $w;
  86. }
  87. $y += $h;
  88. }
  89. $svg .= "\t" . '</g>' . "\n";
  90. $svg .= '</svg>' . "\n";
  91. return $svg;
  92. }
  93. /**
  94. * Return an HTML representation of barcode.
  95. * <li>$arrcode['code'] code to be printed on text label</li>
  96. * <li>$arrcode['num_rows'] required number of rows</li>
  97. * <li>$arrcode['num_cols'] required number of columns</li>
  98. * <li>$arrcode['bcode'][$r][$c] value of the cell is $r row and $c column (0 = transparent, 1 = black)</li></ul>
  99. * @param $code (string) code to print
  100. * @param $type (string) type of barcode: <ul><li>DATAMATRIX : Datamatrix (ISO/IEC 16022)</li><li>PDF417 : PDF417 (ISO/IEC 15438:2006)</li><li>PDF417,a,e,t,s,f,o0,o1,o2,o3,o4,o5,o6 : PDF417 with parameters: a = aspect ratio (width/height); e = error correction level (0-8); t = total number of macro segments; s = macro segment index (0-99998); f = file ID; o0 = File Name (text); o1 = Segment Count (numeric); o2 = Time Stamp (numeric); o3 = Sender (text); o4 = Addressee (text); o5 = File Size (numeric); o6 = Checksum (numeric). NOTES: Parameters t, s and f are required for a Macro Control Block, all other parametrs are optional. To use a comma character ',' on text options, replace it with the character 255: "\xff".</li><li>QRCODE : QRcode Low error correction</li><li>QRCODE,L : QRcode Low error correction</li><li>QRCODE,M : QRcode Medium error correction</li><li>QRCODE,Q : QRcode Better error correction</li><li>QRCODE,H : QR-CODE Best error correction</li><li>RAW: raw mode - comma-separad list of array rows</li><li>RAW2: raw mode - array rows are surrounded by square parenthesis.</li><li>TEST : Test matrix</li></ul>
  101. * @param $w (int) Width of a single rectangle element in pixels.
  102. * @param $h (int) Height of a single rectangle element in pixels.
  103. * @param $color (string) Foreground color for bar elements (background is transparent).
  104. * @return string HTML code.
  105. * @public
  106. */
  107. public function getBarcodeHTML($code, $type, $w=10, $h=10, $color='black') {
  108. //set barcode code and type
  109. $this->setBarcode($code, $type);
  110. $html = '<div style="font-size:0;position:relative;width:' . ($w * $this->barcode_array['num_cols']) . 'px;height:' . ($h * $this->barcode_array['num_rows']) . 'px;">' . "\n";
  111. // print barcode elements
  112. $y = 0;
  113. // for each row
  114. for ($r = 0; $r < $this->barcode_array['num_rows']; ++$r) {
  115. $x = 0;
  116. // for each column
  117. for ($c = 0; $c < $this->barcode_array['num_cols']; ++$c) {
  118. if ($this->barcode_array['bcode'][$r][$c] == 1) {
  119. // draw a single barcode cell
  120. $html .= '<div style="background-color:' . $color . ';width:' . $w . 'px;height:' . $h . 'px;position:absolute;left:' . $x . 'px;top:' . $y . 'px;">&nbsp;</div>' . "\n";
  121. }
  122. $x += $w;
  123. }
  124. $y += $h;
  125. }
  126. $html .= '</div>' . "\n";
  127. return $html;
  128. }
  129. /**
  130. * Return a PNG image representation of barcode (requires GD or Imagick library).
  131. * <li>$arrcode['code'] code to be printed on text label</li>
  132. * <li>$arrcode['num_rows'] required number of rows</li>
  133. * <li>$arrcode['num_cols'] required number of columns</li>
  134. * <li>$arrcode['bcode'][$r][$c] value of the cell is $r row and $c column (0 = transparent, 1 = black)</li></ul>
  135. * @param $code (string) code to print
  136. * @param $type (string) type of barcode: <ul><li>DATAMATRIX : Datamatrix (ISO/IEC 16022)</li><li>PDF417 : PDF417 (ISO/IEC 15438:2006)</li><li>PDF417,a,e,t,s,f,o0,o1,o2,o3,o4,o5,o6 : PDF417 with parameters: a = aspect ratio (width/height); e = error correction level (0-8); t = total number of macro segments; s = macro segment index (0-99998); f = file ID; o0 = File Name (text); o1 = Segment Count (numeric); o2 = Time Stamp (numeric); o3 = Sender (text); o4 = Addressee (text); o5 = File Size (numeric); o6 = Checksum (numeric). NOTES: Parameters t, s and f are required for a Macro Control Block, all other parametrs are optional. To use a comma character ',' on text options, replace it with the character 255: "\xff".</li><li>QRCODE : QRcode Low error correction</li><li>QRCODE,L : QRcode Low error correction</li><li>QRCODE,M : QRcode Medium error correction</li><li>QRCODE,Q : QRcode Better error correction</li><li>QRCODE,H : QR-CODE Best error correction</li><li>RAW: raw mode - comma-separad list of array rows</li><li>RAW2: raw mode - array rows are surrounded by square parenthesis.</li><li>TEST : Test matrix</li></ul>
  137. * @param $w (int) Width of a single rectangle element in pixels.
  138. * @param $h (int) Height of a single rectangle element in pixels.
  139. * @param $color (array) RGB (0-255) foreground color for bar elements (background is transparent).
  140. * @return image or false in case of error.
  141. * @public
  142. */
  143. public function getBarcodePNG($code, $type, $w=3, $h=3, $color=array(0, 0, 0)) {
  144. //set barcode code and type
  145. $this->setBarcode($code, $type);
  146. // calculate image size
  147. $width = ($this->barcode_array['num_cols'] * $w);
  148. $height = ($this->barcode_array['num_rows'] * $h);
  149. if (function_exists('imagecreate')) {
  150. // GD library
  151. $imagick = false;
  152. $png = imagecreate($width, $height);
  153. $bgcol = imagecolorallocate($png, 255, 255, 255);
  154. imagecolortransparent($png, $bgcol);
  155. $fgcol = imagecolorallocate($png, $color[0], $color[1], $color[2]);
  156. } elseif (extension_loaded('imagick')) {
  157. $imagick = true;
  158. $bgcol = new imagickpixel('rgb(255,255,255');
  159. $fgcol = new imagickpixel('rgb(' . $color[0] . ',' . $color[1] . ',' . $color[2] . ')');
  160. $png = new Imagick();
  161. $png->newImage($width, $height, 'none', 'png');
  162. $bar = new imagickdraw();
  163. $bar->setfillcolor($fgcol);
  164. } else {
  165. return false;
  166. }
  167. // print barcode elements
  168. $y = 0;
  169. // for each row
  170. for ($r = 0; $r < $this->barcode_array['num_rows']; ++$r) {
  171. $x = 0;
  172. // for each column
  173. for ($c = 0; $c < $this->barcode_array['num_cols']; ++$c) {
  174. if ($this->barcode_array['bcode'][$r][$c] == 1) {
  175. // draw a single barcode cell
  176. if ($imagick) {
  177. $bar->rectangle($x, $y, ($x + $w), ($y + $h));
  178. } else {
  179. imagefilledrectangle($png, $x, $y, ($x + $w), ($y + $h), $fgcol);
  180. }
  181. }
  182. $x += $w;
  183. }
  184. $y += $h;
  185. }
  186. // send headers
  187. header('Content-Type: image/png');
  188. header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1
  189. header('Pragma: public');
  190. header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past
  191. header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
  192. if ($imagick) {
  193. $png->drawimage($bar);
  194. echo $png;
  195. } else {
  196. imagepng($png);
  197. imagedestroy($png);
  198. }
  199. }
  200. /**
  201. * Return a .png file path which create in server
  202. * <li>$arrcode['code'] code to be printed on text label</li>
  203. * <li>$arrcode['num_rows'] required number of rows</li>
  204. * <li>$arrcode['num_cols'] required number of columns</li>
  205. * <li>$arrcode['bcode'][$r][$c] value of the cell is $r row and $c column (0 = transparent, 1 = black)</li></ul>
  206. * @param $code (string) code to print
  207. * @param $type (string) type of barcode: <ul><li>DATAMATRIX : Datamatrix (ISO/IEC 16022)</li><li>PDF417 : PDF417 (ISO/IEC 15438:2006)</li><li>PDF417,a,e,t,s,f,o0,o1,o2,o3,o4,o5,o6 : PDF417 with parameters: a = aspect ratio (width/height); e = error correction level (0-8); t = total number of macro segments; s = macro segment index (0-99998); f = file ID; o0 = File Name (text); o1 = Segment Count (numeric); o2 = Time Stamp (numeric); o3 = Sender (text); o4 = Addressee (text); o5 = File Size (numeric); o6 = Checksum (numeric). NOTES: Parameters t, s and f are required for a Macro Control Block, all other parametrs are optional. To use a comma character ',' on text options, replace it with the character 255: "\xff".</li><li>QRCODE : QRcode Low error correction</li><li>QRCODE,L : QRcode Low error correction</li><li>QRCODE,M : QRcode Medium error correction</li><li>QRCODE,Q : QRcode Better error correction</li><li>QRCODE,H : QR-CODE Best error correction</li><li>RAW: raw mode - comma-separad list of array rows</li><li>RAW2: raw mode - array rows are surrounded by square parenthesis.</li><li>TEST : Test matrix</li></ul>
  208. * @param $w (int) Width of a single rectangle element in pixels.
  209. * @param $h (int) Height of a single rectangle element in pixels.
  210. * @param $color (array) RGB (0-255) foreground color for bar elements (background is transparent).
  211. * @return path of image whice created
  212. * @public
  213. */
  214. public function getBarcodePNGPath($code, $type, $w=3, $h=3, $color=array(0, 0, 0)) {
  215. //set barcode code and type
  216. $this->setBarcode($code, $type);
  217. // calculate image size
  218. $width = ($this->barcode_array['num_cols'] * $w);
  219. $height = ($this->barcode_array['num_rows'] * $h);
  220. if (function_exists('imagecreate')) {
  221. // GD library
  222. $imagick = false;
  223. $png = imagecreate($width, $height);
  224. $bgcol = imagecolorallocate($png, 255, 255, 255);
  225. imagecolortransparent($png, $bgcol);
  226. $fgcol = imagecolorallocate($png, $color[0], $color[1], $color[2]);
  227. } elseif (extension_loaded('imagick')) {
  228. $imagick = true;
  229. $bgcol = new imagickpixel('rgb(255,255,255');
  230. $fgcol = new imagickpixel('rgb(' . $color[0] . ',' . $color[1] . ',' . $color[2] . ')');
  231. $png = new Imagick();
  232. $png->newImage($width, $height, 'none', 'png');
  233. $bar = new imagickdraw();
  234. $bar->setfillcolor($fgcol);
  235. } else {
  236. return false;
  237. }
  238. // print barcode elements
  239. $y = 0;
  240. // for each row
  241. for ($r = 0; $r < $this->barcode_array['num_rows']; ++$r) {
  242. $x = 0;
  243. // for each column
  244. for ($c = 0; $c < $this->barcode_array['num_cols']; ++$c) {
  245. if ($this->barcode_array['bcode'][$r][$c] == 1) {
  246. // draw a single barcode cell
  247. if ($imagick) {
  248. $bar->rectangle($x, $y, ($x + $w), ($y + $h));
  249. } else {
  250. imagefilledrectangle($png, $x, $y, ($x + $w), ($y + $h), $fgcol);
  251. }
  252. }
  253. $x += $w;
  254. }
  255. $y += $h;
  256. }
  257. $save_file = $this->checkfile($this->save_path.$code . ".png");
  258. if ($imagick) {
  259. $png->drawimage($bar);
  260. //echo $png;
  261. }
  262. if (ImagePng($png, $save_file)) {
  263. imagedestroy($png);
  264. return $save_file;
  265. } else {
  266. imagedestroy($png);
  267. return $code;
  268. }
  269. }
  270. /**
  271. * Set the barcode.
  272. * @param $code (string) code to print
  273. * @param $type (string) type of barcode: <ul><li>DATAMATRIX : Datamatrix (ISO/IEC 16022)</li><li>PDF417 : PDF417 (ISO/IEC 15438:2006)</li><li>PDF417,a,e,t,s,f,o0,o1,o2,o3,o4,o5,o6 : PDF417 with parameters: a = aspect ratio (width/height); e = error correction level (0-8); t = total number of macro segments; s = macro segment index (0-99998); f = file ID; o0 = File Name (text); o1 = Segment Count (numeric); o2 = Time Stamp (numeric); o3 = Sender (text); o4 = Addressee (text); o5 = File Size (numeric); o6 = Checksum (numeric). NOTES: Parameters t, s and f are required for a Macro Control Block, all other parametrs are optional. To use a comma character ',' on text options, replace it with the character 255: "\xff".</li><li>QRCODE : QRcode Low error correction</li><li>QRCODE,L : QRcode Low error correction</li><li>QRCODE,M : QRcode Medium error correction</li><li>QRCODE,Q : QRcode Better error correction</li><li>QRCODE,H : QR-CODE Best error correction</li><li>RAW: raw mode - comma-separad list of array rows</li><li>RAW2: raw mode - array rows are surrounded by square parenthesis.</li><li>TEST : Test matrix</li></ul>
  274. * @return array
  275. */
  276. public function setBarcode($code, $type) {
  277. $mode = explode(',', $type);
  278. $qrtype = strtoupper($mode[0]);
  279. switch ($qrtype) {
  280. case 'DATAMATRIX': { // DATAMATRIX (ISO/IEC 16022)
  281. require_once(dirname(__FILE__) . '/datamatrix.php');
  282. $qrcode = new Datamatrix($code);
  283. $this->barcode_array = $qrcode->getBarcodeArray();
  284. $this->barcode_array['code'] = $code;
  285. break;
  286. }
  287. case 'PDF417': { // PDF417 (ISO/IEC 15438:2006)
  288. require_once(dirname(__FILE__) . '/pdf417.php');
  289. if (!isset($mode[1]) OR ($mode[1] === '')) {
  290. $aspectratio = 2; // default aspect ratio (width / height)
  291. } else {
  292. $aspectratio = floatval($mode[1]);
  293. }
  294. if (!isset($mode[2]) OR ($mode[2] === '')) {
  295. $ecl = -1; // default error correction level (auto)
  296. } else {
  297. $ecl = intval($mode[2]);
  298. }
  299. // set macro block
  300. $macro = array();
  301. if (isset($mode[3]) AND ($mode[3] !== '') AND isset($mode[4]) AND ($mode[4] !== '') AND isset($mode[5]) AND ($mode[5] !== '')) {
  302. $macro['segment_total'] = intval($mode[3]);
  303. $macro['segment_index'] = intval($mode[4]);
  304. $macro['file_id'] = strtr($mode[5], "\xff", ',');
  305. for ($i = 0; $i < 7; ++$i) {
  306. $o = $i + 6;
  307. if (isset($mode[$o]) AND ($mode[$o] !== '')) {
  308. // add option
  309. $macro['option_' . $i] = strtr($mode[$o], "\xff", ',');
  310. }
  311. }
  312. }
  313. $qrcode = new PDF417($code, $ecl, $aspectratio, $macro);
  314. $this->barcode_array = $qrcode->getBarcodeArray();
  315. $this->barcode_array['code'] = $code;
  316. break;
  317. }
  318. case 'QRCODE': { // QR-CODE
  319. require_once(dirname(__FILE__) . '/qrcode.php');
  320. if (!isset($mode[1]) OR (!in_array($mode[1], array('L', 'M', 'Q', 'H')))) {
  321. $mode[1] = 'L'; // Ddefault: Low error correction
  322. }
  323. $qrcode = new QRcode($code, strtoupper($mode[1]));
  324. $this->barcode_array = $qrcode->getBarcodeArray();
  325. $this->barcode_array['code'] = $code;
  326. break;
  327. }
  328. case 'RAW':
  329. case 'RAW2': { // RAW MODE
  330. // remove spaces
  331. $code = preg_replace('/[\s]*/si', '', $code);
  332. if (strlen($code) < 3) {
  333. break;
  334. }
  335. if ($qrtype == 'RAW') {
  336. // comma-separated rows
  337. $rows = explode(',', $code);
  338. } else { // RAW2
  339. // rows enclosed in square parentheses
  340. $code = substr($code, 1, -1);
  341. $rows = explode('][', $code);
  342. }
  343. $this->barcode_array['num_rows'] = count($rows);
  344. $this->barcode_array['num_cols'] = strlen($rows[0]);
  345. $this->barcode_array['bcode'] = array();
  346. foreach ($rows as $r) {
  347. $this->barcode_array['bcode'][] = str_split($r, 1);
  348. }
  349. $this->barcode_array['code'] = $code;
  350. break;
  351. }
  352. default: {
  353. $this->barcode_array = false;
  354. }
  355. }
  356. }
  357. public function checkfile($path) {
  358. if (file_exists($path)) {
  359. $base_name = pathinfo($path, PATHINFO_BASENAME);
  360. return $this->checkfile(str_replace($base_name, rand(0, 9999) . $base_name, $path));
  361. } else {
  362. return $path;
  363. }
  364. }
  365. }
  366. // end of class
  367. //============================================================+
  368. class DNS1DBarcode {
  369. /**
  370. * Array representation of barcode.
  371. * @protected
  372. */
  373. protected $barcode_array;
  374. /**
  375. *path to save png in getBarcodePNGPath
  376. * @var <type>
  377. */
  378. public $save_path;
  379. /**
  380. * This is the class constructor.
  381. * Return an array representations for common 1D barcodes:<ul>
  382. * <li>$arrcode['code'] code to be printed on text label</li>
  383. * <li>$arrcode['maxh'] max barcode height</li>
  384. * <li>$arrcode['maxw'] max barcode width</li>
  385. * <li>$arrcode['bcode'][$k] single bar or space in $k position</li>
  386. * <li>$arrcode['bcode'][$k]['t'] bar type: true = bar, false = space.</li>
  387. * <li>$arrcode['bcode'][$k]['w'] bar width in units.</li>
  388. * <li>$arrcode['bcode'][$k]['h'] bar height in units.</li>
  389. * <li>$arrcode['bcode'][$k]['p'] bar top position (0 = top, 1 = middle)</li></ul>
  390. * @param $code (string) code to print
  391. * @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>
  392. * @public
  393. */
  394. /**
  395. * Return an array representations of barcode.
  396. * @return array
  397. * @public
  398. */
  399. public function getBarcodeArray() {
  400. return $this->barcode_array;
  401. }
  402. /**
  403. * Send barcode as SVG image object to the standard output.
  404. * @param $code (string) code to print
  405. * @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>
  406. * @param $w (int) Minimum width of a single bar in user units.
  407. * @param $h (int) Height of barcode in user units.
  408. * @param $color (string) Foreground color (in SVG format) for bar elements (background is transparent).
  409. * @public
  410. */
  411. public function getBarcodeSVG($code, $type,$w=2, $h=30, $color='black') {
  412. $this->setBarcode($code, $type);
  413. // send headers
  414. $code = $this->getBarcodeSVGcode($w, $h, $color);
  415. header('Content-Type: application/svg+xml');
  416. header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1
  417. header('Pragma: public');
  418. header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past
  419. header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
  420. header('Content-Disposition: inline; filename="'.md5($code).'.svg";');
  421. //header('Content-Length: '.strlen($code));
  422. echo $code;
  423. }
  424. /**
  425. * Return a SVG string representation of barcode.
  426. * @param $code (string) code to print
  427. * @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>
  428. * @param $w (int) Minimum width of a single bar in user units.
  429. * @param $h (int) Height of barcode in user units.
  430. * @param $color (string) Foreground color (in SVG format) for bar elements (background is transparent).
  431. * @return string SVG code.
  432. * @public
  433. */
  434. public function getBarcodeSVGcode($code, $type,$w=2, $h=30, $color='black') {
  435. $this->setBarcode($code, $type);
  436. // replace table for special characters
  437. $repstr = array("\0" => '', '&' => '&amp;', '<' => '&lt;', '>' => '&gt;');
  438. $svg = '<'.'?'.'xml version="1.0" standalone="no"'.'?'.'>'."\n";
  439. $svg .= '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'."\n";
  440. $svg .= '<svg width="'.round(($this->barcode_array['maxw'] * $w), 3).'" height="'.$h.'" version="1.1" xmlns="http://www.w3.org/2000/svg">'."\n";
  441. $svg .= "\t".'<desc>'.strtr($this->barcode_array['code'], $repstr).'</desc>'."\n";
  442. $svg .= "\t".'<g id="bars" fill="'.$color.'" stroke="none">'."\n";
  443. // print bars
  444. $x = 0;
  445. foreach ($this->barcode_array['bcode'] as $k => $v) {
  446. $bw = round(($v['w'] * $w), 3);
  447. $bh = round(($v['h'] * $h / $this->barcode_array['maxh']), 3);
  448. if ($v['t']) {
  449. $y = round(($v['p'] * $h / $this->barcode_array['maxh']), 3);
  450. // draw a vertical bar
  451. $svg .= "\t\t".'<rect x="'.$x.'" y="'.$y.'" width="'.$bw.'" height="'.$bh.'" />'."\n";
  452. }
  453. $x += $bw;
  454. }
  455. $svg .= "\t".'</g>'."\n";
  456. $svg .= '</svg>'."\n";
  457. return $svg;
  458. }
  459. /**
  460. * Return an HTML representation of barcode.
  461. * @param $code (string) code to print
  462. * @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>
  463. * @param $w (int) Width of a single bar element in pixels.
  464. * @param $h (int) Height of a single bar element in pixels.
  465. * @param $color (string) Foreground color for bar elements (background is transparent).
  466. * @return string HTML code.
  467. * @public
  468. */
  469. public function getBarcodeHTML($code, $type,$w=2, $h=30, $color='black') {
  470. $this->setBarcode($code, $type);
  471. $html = '<div style="font-size:0;position:relative;">'."\n";
  472. $html = '<div style="font-size:0;position:relative;width:'.($this->barcode_array['maxw'] * $w).'px;height:'.($h).'px;">'."\n";
  473. // print bars
  474. $x = 0;
  475. foreach ($this->barcode_array['bcode'] as $k => $v) {
  476. $bw = round(($v['w'] * $w), 3);
  477. $bh = round(($v['h'] * $h / $this->barcode_array['maxh']), 3);
  478. if ($v['t']) {
  479. $y = round(($v['p'] * $h / $this->barcode_array['maxh']), 3);
  480. // draw a vertical bar
  481. $html .= '<div style="background-color:'.$color.';width:'.$bw.'px;height:'.$bh.'px;position:absolute;left:'.$x.'px;top:'.$y.'px;">&nbsp;</div>'."\n";
  482. }
  483. $x += $bw;
  484. }
  485. $html .= '</div>'."\n";
  486. return $html;
  487. }
  488. /**
  489. * Return a PNG image representation of barcode (requires GD or Imagick library).
  490. * @param $code (string) code to print
  491. * @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>
  492. * @param $w (int) Width of a single bar element in pixels.
  493. * @param $h (int) Height of a single bar element in pixels.
  494. * @param $color (array) RGB (0-255) foreground color for bar elements (background is transparent).
  495. * @return image or false in case of error.
  496. * @public
  497. */
  498. public function getBarcodePNG($code, $type,$w=2, $h=30, $color=array(0,0,0)) {
  499. $this->setBarcode($code, $type);
  500. // calculate image size
  501. $width = ($this->barcode_array['maxw'] * $w);
  502. $height = $h;
  503. if (function_exists('imagecreate')) {
  504. // GD library
  505. $imagick = false;
  506. $png = imagecreate($width, $height);
  507. $bgcol = imagecolorallocate($png, 255, 255, 255);
  508. imagecolortransparent($png, $bgcol);
  509. $fgcol = imagecolorallocate($png, $color[0], $color[1], $color[2]);
  510. } elseif (extension_loaded('imagick')) {
  511. $imagick = true;
  512. $bgcol = new imagickpixel('rgb(255,255,255');
  513. $fgcol = new imagickpixel('rgb('.$color[0].','.$color[1].','.$color[2].')');
  514. $png = new Imagick();
  515. $png->newImage($width, $height, 'none', 'png');
  516. $bar = new imagickdraw();
  517. $bar->setfillcolor($fgcol);
  518. } else {
  519. return false;
  520. }
  521. // print bars
  522. $x = 0;
  523. foreach ($this->barcode_array['bcode'] as $k => $v) {
  524. $bw = round(($v['w'] * $w), 3);
  525. $bh = round(($v['h'] * $h / $this->barcode_array['maxh']), 3);
  526. if ($v['t']) {
  527. $y = round(($v['p'] * $h / $this->barcode_array['maxh']), 3);
  528. // draw a vertical bar
  529. if ($imagick) {
  530. $bar->rectangle($x, $y, ($x + $bw), ($y + $bh));
  531. } else {
  532. imagefilledrectangle($png, $x, $y, ($x + $bw), ($y + $bh), $fgcol);
  533. }
  534. }
  535. $x += $bw;
  536. }
  537. // send headers
  538. header('Content-Type: image/png');
  539. header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1
  540. header('Pragma: public');
  541. header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past
  542. header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
  543. if ($imagick) {
  544. $png->drawimage($bar);
  545. echo $png;
  546. } else {
  547. imagepng($png);
  548. imagedestroy($png);
  549. }
  550. }
  551. /**
  552. * Return a .png file path which create in server
  553. * @param $code (string) code to print
  554. * @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>
  555. * @param $w (int) Width of a single bar element in pixels.
  556. * @param $h (int) Height of a single bar element in pixels.
  557. * @param $color (array) RGB (0-255) foreground color for bar elements (background is transparent).
  558. * @return image or false in case of error.
  559. * @public
  560. */
  561. public function getBarcodePNGPath($code, $type,$w=2, $h=30, $color=array(0,0,0)) {
  562. $this->setBarcode($code, $type);
  563. // calculate image size
  564. $width = ($this->barcode_array['maxw'] * $w);
  565. $height = $h;
  566. if (function_exists('imagecreate')) {
  567. // GD library
  568. $imagick = false;
  569. $png = imagecreate($width, $height);
  570. $bgcol = imagecolorallocate($png, 255, 255, 255);
  571. imagecolortransparent($png, $bgcol);
  572. $fgcol = imagecolorallocate($png, $color[0], $color[1], $color[2]);
  573. } elseif (extension_loaded('imagick')) {
  574. $imagick = true;
  575. $bgcol = new imagickpixel('rgb(255,255,255');
  576. $fgcol = new imagickpixel('rgb('.$color[0].','.$color[1].','.$color[2].')');
  577. $png = new Imagick();
  578. $png->newImage($width, $height, 'none', 'png');
  579. $bar = new imagickdraw();
  580. $bar->setfillcolor($fgcol);
  581. } else {
  582. return false;
  583. }
  584. // print bars
  585. $x = 0;
  586. foreach ($this->barcode_array['bcode'] as $k => $v) {
  587. $bw = round(($v['w'] * $w), 3);
  588. $bh = round(($v['h'] * $h / $this->barcode_array['maxh']), 3);
  589. if ($v['t']) {
  590. $y = round(($v['p'] * $h / $this->barcode_array['maxh']), 3);
  591. // draw a vertical bar
  592. if ($imagick) {
  593. $bar->rectangle($x, $y, ($x + $bw), ($y + $bh));
  594. } else {
  595. imagefilledrectangle($png, $x, $y, ($x + $bw), ($y + $bh), $fgcol);
  596. }
  597. }
  598. $x += $bw;
  599. }
  600. $save_file = $this->checkfile($this->save_path.$code . ".png");
  601. if ($imagick) {
  602. $png->drawimage($bar);
  603. //echo $png;
  604. }
  605. if (ImagePng($png, $save_file)) {
  606. imagedestroy($png);
  607. return $save_file;
  608. } else {
  609. imagedestroy($png);
  610. return $code;
  611. }
  612. }
  613. /**
  614. * Set the barcode.
  615. * @param $code (string) code to print
  616. * @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>
  617. * @return array barcode array
  618. * @public
  619. */
  620. public function setBarcode($code, $type) {
  621. switch (strtoupper($type)) {
  622. case 'C39': { // CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
  623. $arrcode = $this->barcode_code39($code, false, false);
  624. break;
  625. }
  626. case 'C39+': { // CODE 39 with checksum
  627. $arrcode = $this->barcode_code39($code, false, true);
  628. break;
  629. }
  630. case 'C39E': { // CODE 39 EXTENDED
  631. $arrcode = $this->barcode_code39($code, true, false);
  632. break;
  633. }
  634. case 'C39E+': { // CODE 39 EXTENDED + CHECKSUM
  635. $arrcode = $this->barcode_code39($code, true, true);
  636. break;
  637. }
  638. case 'C93': { // CODE 93 - USS-93
  639. $arrcode = $this->barcode_code93($code);
  640. break;
  641. }
  642. case 'S25': { // Standard 2 of 5
  643. $arrcode = $this->barcode_s25($code, false);
  644. break;
  645. }
  646. case 'S25+': { // Standard 2 of 5 + CHECKSUM
  647. $arrcode = $this->barcode_s25($code, true);
  648. break;
  649. }
  650. case 'I25': { // Interleaved 2 of 5
  651. $arrcode = $this->barcode_i25($code, false);
  652. break;
  653. }
  654. case 'I25+': { // Interleaved 2 of 5 + CHECKSUM
  655. $arrcode = $this->barcode_i25($code, true);
  656. break;
  657. }
  658. case 'C128': { // CODE 128
  659. $arrcode = $this->barcode_c128($code, '');
  660. break;
  661. }
  662. case 'C128A': { // CODE 128 A
  663. $arrcode = $this->barcode_c128($code, 'A');
  664. break;
  665. }
  666. case 'C128B': { // CODE 128 B
  667. $arrcode = $this->barcode_c128($code, 'B');
  668. break;
  669. }
  670. case 'C128C': { // CODE 128 C
  671. $arrcode = $this->barcode_c128($code, 'C');
  672. break;
  673. }
  674. case 'EAN2': { // 2-Digits UPC-Based Extention
  675. $arrcode = $this->barcode_eanext($code, 2);
  676. break;
  677. }
  678. case 'EAN5': { // 5-Digits UPC-Based Extention
  679. $arrcode = $this->barcode_eanext($code, 5);
  680. break;
  681. }
  682. case 'EAN8': { // EAN 8
  683. $arrcode = $this->barcode_eanupc($code, 8);
  684. break;
  685. }
  686. case 'EAN13': { // EAN 13
  687. $arrcode = $this->barcode_eanupc($code, 13);
  688. break;
  689. }
  690. case 'UPCA': { // UPC-A
  691. $arrcode = $this->barcode_eanupc($code, 12);
  692. break;
  693. }
  694. case 'UPCE': { // UPC-E
  695. $arrcode = $this->barcode_eanupc($code, 6);
  696. break;
  697. }
  698. case 'MSI': { // MSI (Variation of Plessey code)
  699. $arrcode = $this->barcode_msi($code, false);
  700. break;
  701. }
  702. case 'MSI+': { // MSI + CHECKSUM (modulo 11)
  703. $arrcode = $this->barcode_msi($code, true);
  704. break;
  705. }
  706. case 'POSTNET': { // POSTNET
  707. $arrcode = $this->barcode_postnet($code, false);
  708. break;
  709. }
  710. case 'PLANET': { // PLANET
  711. $arrcode = $this->barcode_postnet($code, true);
  712. break;
  713. }
  714. case 'RMS4CC': { // RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)
  715. $arrcode = $this->barcode_rms4cc($code, false);
  716. break;
  717. }
  718. case 'KIX': { // KIX (Klant index - Customer index)
  719. $arrcode = $this->barcode_rms4cc($code, true);
  720. break;
  721. }
  722. case 'IMB': { // IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200
  723. $arrcode = $this->barcode_imb($code);
  724. break;
  725. }
  726. case 'CODABAR': { // CODABAR
  727. $arrcode = $this->barcode_codabar($code);
  728. break;
  729. }
  730. case 'CODE11': { // CODE 11
  731. $arrcode = $this->barcode_code11($code);
  732. break;
  733. }
  734. case 'PHARMA': { // PHARMACODE
  735. $arrcode = $this->barcode_pharmacode($code);
  736. break;
  737. }
  738. case 'PHARMA2T': { // PHARMACODE TWO-TRACKS
  739. $arrcode = $this->barcode_pharmacode2t($code);
  740. break;
  741. }
  742. default: {
  743. $this->barcode_array = false;
  744. $arrcode = false;
  745. break;
  746. }
  747. }
  748. $this->barcode_array = $arrcode;
  749. }
  750. /**
  751. * CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
  752. * General-purpose code in very wide use world-wide
  753. * @param $code (string) code to represent.
  754. * @param $extended (boolean) if true uses the extended mode.
  755. * @param $checksum (boolean) if true add a checksum to the code.
  756. * @return array barcode representation.
  757. * @protected
  758. */
  759. protected function barcode_code39($code, $extended=false, $checksum=false) {
  760. $chr['0'] = '111331311';
  761. $chr['1'] = '311311113';
  762. $chr['2'] = '113311113';
  763. $chr['3'] = '313311111';
  764. $chr['4'] = '111331113';
  765. $chr['5'] = '311331111';
  766. $chr['6'] = '113331111';
  767. $chr['7'] = '111311313';
  768. $chr['8'] = '311311311';
  769. $chr['9'] = '113311311';
  770. $chr['A'] = '311113113';
  771. $chr['B'] = '113113113';
  772. $chr['C'] = '313113111';
  773. $chr['D'] = '111133113';
  774. $chr['E'] = '311133111';
  775. $chr['F'] = '113133111';
  776. $chr['G'] = '111113313';
  777. $chr['H'] = '311113311';
  778. $chr['I'] = '113113311';
  779. $chr['J'] = '111133311';
  780. $chr['K'] = '311111133';
  781. $chr['L'] = '113111133';
  782. $chr['M'] = '313111131';
  783. $chr['N'] = '111131133';
  784. $chr['O'] = '311131131';
  785. $chr['P'] = '113131131';
  786. $chr['Q'] = '111111333';
  787. $chr['R'] = '311111331';
  788. $chr['S'] = '113111331';
  789. $chr['T'] = '111131331';
  790. $chr['U'] = '331111113';
  791. $chr['V'] = '133111113';
  792. $chr['W'] = '333111111';
  793. $chr['X'] = '131131113';
  794. $chr['Y'] = '331131111';
  795. $chr['Z'] = '133131111';
  796. $chr['-'] = '131111313';
  797. $chr['.'] = '331111311';
  798. $chr[' '] = '133111311';
  799. $chr['$'] = '131313111';
  800. $chr['/'] = '131311131';
  801. $chr['+'] = '131113131';
  802. $chr['%'] = '111313131';
  803. $chr['*'] = '131131311';
  804. $code = strtoupper($code);
  805. if ($extended) {
  806. // extended mode
  807. $code = $this->encode_code39_ext($code);
  808. }
  809. if ($code === false) {
  810. return false;
  811. }
  812. if ($checksum) {
  813. // checksum
  814. $code .= $this->checksum_code39($code);
  815. }
  816. // add start and stop codes
  817. $code = '*'.$code.'*';
  818. $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
  819. $k = 0;
  820. $clen = strlen($code);
  821. for ($i = 0; $i < $clen; ++$i) {
  822. $char = $code{$i};
  823. if(!isset($chr[$char])) {
  824. // invalid character
  825. return false;
  826. }
  827. for ($j = 0; $j < 9; ++$j) {
  828. if (($j % 2) == 0) {
  829. $t = true; // bar
  830. } else {
  831. $t = false; // space
  832. }
  833. $w = $chr[$char]{$j};
  834. $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
  835. $bararray['maxw'] += $w;
  836. ++$k;
  837. }
  838. // intercharacter gap
  839. $bararray['bcode'][$k] = array('t' => false, 'w' => 1, 'h' => 1, 'p' => 0);
  840. $bararray['maxw'] += 1;
  841. ++$k;
  842. }
  843. return $bararray;
  844. }
  845. /**
  846. * Encode a string to be used for CODE 39 Extended mode.
  847. * @param $code (string) code to represent.
  848. * @return encoded string.
  849. * @protected
  850. */
  851. protected function encode_code39_ext($code) {
  852. $encode = array(
  853. chr(0) => '%U', chr(1) => '$A', chr(2) => '$B', chr(3) => '$C',
  854. chr(4) => '$D', chr(5) => '$E', chr(6) => '$F', chr(7) => '$G',
  855. chr(8) => '$H', chr(9) => '$I', chr(10) => '$J', chr(11) => '£K',
  856. chr(12) => '$L', chr(13) => '$M', chr(14) => '$N', chr(15) => '$O',
  857. chr(16) => '$P', chr(17) => '$Q', chr(18) => '$R', chr(19) => '$S',
  858. chr(20) => '$T', chr(21) => '$U', chr(22) => '$V', chr(23) => '$W',
  859. chr(24) => '$X', chr(25) => '$Y', chr(26) => '$Z', chr(27) => '%A',
  860. chr(28) => '%B', chr(29) => '%C', chr(30) => '%D', chr(31) => '%E',
  861. chr(32) => ' ', chr(33) => '/A', chr(34) => '/B', chr(35) => '/C',
  862. chr(36) => '/D', chr(37) => '/E', chr(38) => '/F', chr(39) => '/G',
  863. chr(40) => '/H', chr(41) => '/I', chr(42) => '/J', chr(43) => '/K',
  864. chr(44) => '/L', chr(45) => '-', chr(46) => '.', chr(47) => '/O',
  865. chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3',
  866. chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7',
  867. chr(56) => '8', chr(57) => '9', chr(58) => '/Z', chr(59) => '%F',
  868. chr(60) => '%G', chr(61) => '%H', chr(62) => '%I', chr(63) => '%J',
  869. chr(64) => '%V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C',
  870. chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G',
  871. chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K',
  872. chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O',
  873. chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S',
  874. chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W',
  875. chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => '%K',
  876. chr(92) => '%L', chr(93) => '%M', chr(94) => '%N', chr(95) => '%O',
  877. chr(96) => '%W', chr(97) => '+A', chr(98) => '+B', chr(99) => '+C',
  878. chr(100) => '+D', chr(101) => '+E', chr(102) => '+F', chr(103) => '+G',
  879. chr(104) => '+H', chr(105) => '+I', chr(106) => '+J', chr(107) => '+K',
  880. chr(108) => '+L', chr(109) => '+M', chr(110) => '+N', chr(111) => '+O',
  881. chr(112) => '+P', chr(113) => '+Q', chr(114) => '+R', chr(115) => '+S',
  882. chr(116) => '+T', chr(117) => '+U', chr(118) => '+V', chr(119) => '+W',
  883. chr(120) => '+X', chr(121) => '+Y', chr(122) => '+Z', chr(123) => '%P',
  884. chr(124) => '%Q', chr(125) => '%R', chr(126) => '%S', chr(127) => '%T');
  885. $code_ext = '';
  886. $clen = strlen($code);
  887. for ($i = 0 ; $i < $clen; ++$i) {
  888. if (ord($code{$i}) > 127) {
  889. return false;
  890. }
  891. $code_ext .= $encode[$code{$i}];
  892. }
  893. return $code_ext;
  894. }
  895. /**
  896. * Calculate CODE 39 checksum (modulo 43).
  897. * @param $code (string) code to represent.
  898. * @return char checksum.
  899. * @protected
  900. */
  901. protected function checksum_code39($code) {
  902. $chars = array(
  903. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  904. 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
  905. 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
  906. 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%');
  907. $sum = 0;
  908. $clen = strlen($code);
  909. for ($i = 0 ; $i < $clen; ++$i) {
  910. $k = array_keys($chars, $code{$i});
  911. $sum += $k[0];
  912. }
  913. $j = ($sum % 43);
  914. return $chars[$j];
  915. }
  916. /**
  917. * CODE 93 - USS-93
  918. * Compact code similar to Code 39
  919. * @param $code (string) code to represent.
  920. * @return array barcode representation.
  921. * @protected
  922. */
  923. protected function barcode_code93($code) {
  924. $chr[48] = '131112'; // 0
  925. $chr[49] = '111213'; // 1
  926. $chr[50] = '111312'; // 2
  927. $chr[51] = '111411'; // 3
  928. $chr[52] = '121113'; // 4
  929. $chr[53] = '121212'; // 5
  930. $chr[54] = '121311'; // 6
  931. $chr[55] = '111114'; // 7
  932. $chr[56] = '131211'; // 8
  933. $chr[57] = '141111'; // 9
  934. $chr[65] = '211113'; // A
  935. $chr[66] = '211212'; // B
  936. $chr[67] = '211311'; // C
  937. $chr[68] = '221112'; // D
  938. $chr[69] = '221211'; // E
  939. $chr[70] = '231111'; // F
  940. $chr[71] = '112113'; // G
  941. $chr[72] = '112212'; // H
  942. $chr[73] = '112311'; // I
  943. $chr[74] = '122112'; // J
  944. $chr[75] = '132111'; // K
  945. $chr[76] = '111123'; // L
  946. $chr[77] = '111222'; // M
  947. $chr[78] = '111321'; // N
  948. $chr[79] = '121122'; // O
  949. $chr[80] = '131121'; // P
  950. $chr[81] = '212112'; // Q
  951. $chr[82] = '212211'; // R
  952. $chr[83] = '211122'; // S
  953. $chr[84] = '211221'; // T
  954. $chr[85] = '221121'; // U
  955. $chr[86] = '222111'; // V
  956. $chr[87] = '112122'; // W
  957. $chr[88] = '112221'; // X
  958. $chr[89] = '122121'; // Y
  959. $chr[90] = '123111'; // Z
  960. $chr[45] = '121131'; // -
  961. $chr[46] = '311112'; // .
  962. $chr[32] = '311211'; //
  963. $chr[36] = '321111'; // $
  964. $chr[47] = '112131'; // /
  965. $chr[43] = '113121'; // +
  966. $chr[37] = '211131'; // %
  967. $chr[128] = '121221'; // ($)
  968. $chr[129] = '311121'; // (/)
  969. $chr[130] = '122211'; // (+)
  970. $chr[131] = '312111'; // (%)
  971. $chr[42] = '111141'; // start-stop
  972. $code = strtoupper($code);
  973. $encode = array(
  974. chr(0) => chr(131).'U', chr(1) => chr(128).'A', chr(2) => chr(128).'B', chr(3) => chr(128).'C',
  975. chr(4) => chr(128).'D', chr(5) => chr(128).'E', chr(6) => chr(128).'F', chr(7) => chr(128).'G',
  976. chr(8) => chr(128).'H', chr(9) => chr(128).'I', chr(10) => chr(128).'J', chr(11) => '£K',
  977. chr(12) => chr(128).'L', chr(13) => chr(128).'M', chr(14) => chr(128).'N', chr(15) => chr(128).'O',
  978. chr(16) => chr(128).'P', chr(17) => chr(128).'Q', chr(18) => chr(128).'R', chr(19) => chr(128).'S',
  979. chr(20) => chr(128).'T', chr(21) => chr(128).'U', chr(22) => chr(128).'V', chr(23) => chr(128).'W',
  980. chr(24) => chr(128).'X', chr(25) => chr(128).'Y', chr(26) => chr(128).'Z', chr(27) => chr(131).'A',
  981. chr(28) => chr(131).'B', chr(29) => chr(131).'C', chr(30) => chr(131).'D', chr(31) => chr(131).'E',
  982. chr(32) => ' ', chr(33) => chr(129).'A', chr(34) => chr(129).'B', chr(35) => chr(129).'C',
  983. chr(36) => chr(129).'D', chr(37) => chr(129).'E', chr(38) => chr(129).'F', chr(39) => chr(129).'G',
  984. chr(40) => chr(129).'H', chr(41) => chr(129).'I', chr(42) => chr(129).'J', chr(43) => chr(129).'K',
  985. chr(44) => chr(129).'L', chr(45) => '-', chr(46) => '.', chr(47) => chr(129).'O',
  986. chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3',
  987. chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7',
  988. chr(56) => '8', chr(57) => '9', chr(58) => chr(129).'Z', chr(59) => chr(131).'F',
  989. chr(60) => chr(131).'G', chr(61) => chr(131).'H', chr(62) => chr(131).'I', chr(63) => chr(131).'J',
  990. chr(64) => chr(131).'V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C',
  991. chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G',
  992. chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K',
  993. chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O',
  994. chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S',
  995. chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W',
  996. chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => chr(131).'K',
  997. chr(92) => chr(131).'L', chr(93) => chr(131).'M', chr(94) => chr(131).'N', chr(95) => chr(131).'O',
  998. chr(96) => chr(131).'W', chr(97) => chr(130).'A', chr(98) => chr(130).'B', chr(99) => chr(130).'C',
  999. chr(100) => chr(130).'D', chr(101) => chr(130).'E', chr(102) => chr(130).'F', chr(103) => chr(130).'G',
  1000. chr(104) => chr(130).'H', chr(105) => chr(130).'I', chr(106) => chr(130).'J', chr(107) => chr(130).'K',
  1001. chr(108) => chr(130).'L', chr(109) => chr(130).'M', chr(110) => chr(130).'N', chr(111) => chr(130).'O',
  1002. chr(112) => chr(130).'P', chr(113) => chr(130).'Q', chr(114) => chr(130).'R', chr(115) => chr(130).'S',
  1003. chr(116) => chr(130).'T', chr(117) => chr(130).'U', chr(118) => chr(130).'V', chr(119) => chr(130).'W',
  1004. chr(120) => chr(130).'X', chr(121) => chr(130).'Y', chr(122) => chr(130).'Z', chr(123) => chr(131).'P',
  1005. chr(124) => chr(131).'Q', chr(125) => chr(131).'R', chr(126) => chr(131).'S', chr(127) => chr(131).'T');
  1006. $code_ext = '';
  1007. $clen = strlen($code);
  1008. for ($i = 0 ; $i < $clen; ++$i) {
  1009. if (ord($code{$i}) > 127) {
  1010. return false;
  1011. }
  1012. $code_ext .= $encode[$code{$i}];
  1013. }
  1014. // checksum
  1015. $code_ext .= $this->checksum_code93($code_ext);
  1016. // add start and stop codes
  1017. $code = '*'.$code_ext.'*';
  1018. $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
  1019. $k = 0;
  1020. $clen = strlen($code);
  1021. for ($i = 0; $i < $clen; ++$i) {
  1022. $char = ord($code{$i});
  1023. if(!isset($chr[$char])) {
  1024. // invalid character
  1025. return false;
  1026. }
  1027. for ($j = 0; $j < 6; ++$j) {
  1028. if (($j % 2) == 0) {
  1029. $t = true; // bar
  1030. } else {
  1031. $t = false; // space
  1032. }
  1033. $w = $chr[$char]{$j};
  1034. $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
  1035. $bararray['maxw'] += $w;
  1036. ++$k;
  1037. }
  1038. }
  1039. $bararray['bcode'][$k] = array('t' => true, 'w' => 1, 'h' => 1, 'p' => 0);
  1040. $bararray['maxw'] += 1;
  1041. ++$k;
  1042. return $bararray;
  1043. }
  1044. /**
  1045. * Calculate CODE 93 checksum (modulo 47).
  1046. * @param $code (string) code to represent.
  1047. * @return string checksum code.
  1048. * @protected
  1049. */
  1050. protected function checksum_code93($code) {
  1051. $chars = array(
  1052. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  1053. 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
  1054. 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
  1055. 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%',
  1056. '<', '=', '>', '?');
  1057. // translate special characters
  1058. $code = strtr($code, chr(128).chr(131).chr(129).chr(130), '<=>?');
  1059. $len = strlen($code);
  1060. // calculate check digit C
  1061. $p = 1;
  1062. $check = 0;
  1063. for ($i = ($len - 1); $i >= 0; --$i) {
  1064. $k = array_keys($chars, $code{$i});
  1065. $check += ($k[0] * $p);
  1066. ++$p;
  1067. if ($p > 20) {
  1068. $p = 1;
  1069. }
  1070. }
  1071. $check %= 47;
  1072. $c = $chars[$check];
  1073. $code .= $c;
  1074. // calculate check digit K
  1075. $p = 1;
  1076. $check = 0;
  1077. for ($i = $len; $i >= 0; --$i) {
  1078. $k = array_keys($chars, $code{$i});
  1079. $check += ($k[0] * $p);
  1080. ++$p;
  1081. if ($p > 15) {
  1082. $p = 1;
  1083. }
  1084. }
  1085. $check %= 47;
  1086. $k = $chars[$check];
  1087. $checksum = $c.$k;
  1088. // resto respecial characters
  1089. $checksum = strtr($checksum, '<=>?', chr(128).chr(131).chr(129).chr(130));
  1090. return $checksum;
  1091. }
  1092. /**
  1093. * Checksum for standard 2 of 5 barcodes.
  1094. * @param $code (string) code to process.
  1095. * @return int checksum.
  1096. * @protected
  1097. */
  1098. protected function checksum_s25($code) {
  1099. $len = strlen($code);
  1100. $sum = 0;
  1101. for ($i = 0; $i < $len; $i+=2) {
  1102. $sum += $code{$i};
  1103. }
  1104. $sum *= 3;
  1105. for ($i = 1; $i < $len; $i+=2) {
  1106. $sum += ($code{$i});
  1107. }
  1108. $r = $sum % 10;
  1109. if($r > 0) {
  1110. $r = (10 - $r);
  1111. }
  1112. return $r;
  1113. }
  1114. /**
  1115. * MSI.
  1116. * Variation of Plessey code, with similar applications
  1117. * Contains digits (0 to 9) and encodes the data only in the width of bars.
  1118. * @param $code (string) code to represent.
  1119. * @param $checksum (boolean) if true add a checksum to the code (modulo 11)
  1120. * @return array barcode representation.
  1121. * @protected
  1122. */
  1123. protected function barcode_msi($code, $checksum=false) {
  1124. $chr['0'] = '100100100100';
  1125. $chr['1'] = '100100100110';
  1126. $chr['2'] = '100100110100';
  1127. $chr['3'] = '100100110110';
  1128. $chr['4'] = '100110100100';
  1129. $chr['5'] = '100110100110';
  1130. $chr['6'] = '100110110100';
  1131. $chr['7'] = '100110110110';
  1132. $chr['8'] = '110100100100';
  1133. $chr['9'] = '110100100110';
  1134. $chr['A'] = '110100110100';
  1135. $chr['B'] = '110100110110';
  1136. $chr['C'] = '110110100100';
  1137. $chr['D'] = '110110100110';
  1138. $chr['E'] = '110110110100';
  1139. $chr['F'] = '110110110110';
  1140. if ($checksum) {
  1141. // add checksum
  1142. $clen = strlen($code);
  1143. $p = 2;
  1144. $check = 0;
  1145. for ($i = ($clen - 1); $i >= 0; --$i) {
  1146. $check += (hexdec($code{$i}) * $p);
  1147. ++$p;
  1148. if ($p > 7) {
  1149. $p = 2;
  1150. }
  1151. }
  1152. $check %= 11;
  1153. if ($check > 0) {
  1154. $check = 11 - $check;
  1155. }
  1156. $code .= $check;
  1157. }
  1158. $seq = '110'; // left guard
  1159. $clen = strlen($code);
  1160. for ($i = 0; $i < $clen; ++$i) {
  1161. $digit = $code{$i};
  1162. if (!isset($chr[$digit])) {
  1163. // invalid character
  1164. return false;
  1165. }
  1166. $seq .= $chr[$digit];
  1167. }
  1168. $seq .= '1001'; // right guard
  1169. $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
  1170. return $this->binseq_to_array($seq, $bararray);
  1171. }
  1172. /**
  1173. * Standard 2 of 5 barcodes.
  1174. * Used in airline ticket marking, photofinishing
  1175. * Contains digits (0 to 9) and encodes the data only in the width of bars.
  1176. * @param $code (string) code to represent.
  1177. * @param $checksum (boolean) if true add a checksum to the code
  1178. * @return array barcode representation.
  1179. * @protected
  1180. */
  1181. protected function barcode_s25($code, $checksum=false) {
  1182. $chr['0'] = '10101110111010';
  1183. $chr['1'] = '11101010101110';
  1184. $chr['2'] = '10111010101110';
  1185. $chr['3'] = '11101110101010';
  1186. $chr['4'] = '10101110101110';
  1187. $chr['5'] = '11101011101010';
  1188. $chr['6'] = '10111011101010';
  1189. $chr['7'] = '10101011101110';
  1190. $chr['8'] = '10101110111010';
  1191. $chr['9'] = '10111010111010';
  1192. if ($checksum) {
  1193. // add checksum
  1194. $code .= $this->checksum_s25($code);
  1195. }
  1196. if((strlen($code) % 2) != 0) {
  1197. // add leading zero if code-length is odd
  1198. $code = '0'.$code;
  1199. }
  1200. $seq = '11011010';
  1201. $clen = strlen($code);
  1202. for ($i = 0; $i < $clen; ++$i) {
  1203. $digit = $code{$i};
  1204. if (!isset($chr[$digit])) {
  1205. // invalid character
  1206. return false;
  1207. }
  1208. $seq .= $chr[$digit];
  1209. }
  1210. $seq .= '1101011';
  1211. $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
  1212. return $this->binseq_to_array($seq, $bararray);
  1213. }
  1214. /**
  1215. * Convert binary barcode sequence to DNS1DBarcode barcode array.
  1216. * @param $seq (string) barcode as binary sequence.
  1217. * @param $bararray (array) barcode array.
  1218. * òparam array $bararray DNS1DBarcode barcode array to fill up
  1219. * @return array barcode representation.
  1220. * @protected
  1221. */
  1222. protected function binseq_to_array($seq, $bararray) {
  1223. $len = strlen($seq);
  1224. $w = 0;
  1225. $k = 0;
  1226. for ($i = 0; $i < $len; ++$i) {
  1227. $w += 1;
  1228. if (($i == ($len - 1)) OR (($i < ($len - 1)) AND ($seq{$i} != $seq{($i+1)}))) {
  1229. if ($seq{$i} == '1') {
  1230. $t = true; // bar
  1231. } else {
  1232. $t = false; // space
  1233. }
  1234. $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
  1235. $bararray['maxw'] += $w;
  1236. ++$k;
  1237. $w = 0;
  1238. }
  1239. }
  1240. return $bararray;
  1241. }
  1242. /**
  1243. * Interleaved 2 of 5 barcodes.
  1244. * Compact numeric code, widely used in industry, air cargo
  1245. * Contains digits (0 to 9) and encodes the data in the width of both bars and spaces.
  1246. * @param $code (string) code to represent.
  1247. * @param $checksum (boolean) if true add a checksum to the code
  1248. * @return array barcode representation.
  1249. * @protected
  1250. */
  1251. protected function barcode_i25($code, $checksum=false) {
  1252. $chr['0'] = '11221';
  1253. $chr['1'] = '21112';
  1254. $chr['2'] = '12112';
  1255. $chr['3'] = '22111';
  1256. $chr['4'] = '11212';
  1257. $chr['5'] = '21211';
  1258. $chr['6'] = '12211';
  1259. $chr['7'] = '11122';
  1260. $chr['8'] = '21121';
  1261. $chr['9'] = '12121';
  1262. $chr['A'] = '11';
  1263. $chr['Z'] = '21';
  1264. if ($checksum) {
  1265. // add checksum
  1266. $code .= $this->checksum_s25($code);
  1267. }
  1268. if((strlen($code) % 2) != 0) {
  1269. // add leading zero if code-length is odd
  1270. $code = '0'.$code;
  1271. }
  1272. // add start and stop codes
  1273. $code = 'AA'.strtolower($code).'ZA';
  1274. $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
  1275. $k = 0;
  1276. $clen = strlen($code);
  1277. for ($i = 0; $i < $clen; $i = ($i + 2)) {
  1278. $char_bar = $code{$i};
  1279. $char_space = $code{$i+1};
  1280. if((!isset($chr[$char_bar])) OR (!isset($chr[$char_space]))) {
  1281. // invalid character
  1282. return false;
  1283. }
  1284. // create a bar-space sequence
  1285. $seq = '';
  1286. $chrlen = strlen($chr[$char_bar]);
  1287. for ($s = 0; $s < $chrlen; $s++){
  1288. $seq .= $chr[$char_bar]{$s} . $chr[$char_space]{$s};
  1289. }
  1290. $seqlen = strlen($seq);
  1291. for ($j = 0; $j < $seqlen; ++$j) {
  1292. if (($j % 2) == 0) {
  1293. $t = true; // bar
  1294. } else {
  1295. $t = false; // space
  1296. }
  1297. $w = $seq{$j};
  1298. $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
  1299. $bararray['maxw'] += $w;
  1300. ++$k;
  1301. }
  1302. }
  1303. return $bararray;
  1304. }
  1305. /**
  1306. * C128 barcodes.
  1307. * Very capable code, excellent density, high reliability; in very wide use world-wide
  1308. * @param $code (string) code to represent.
  1309. * @param $type (string) barcode type: A, B, C or empty for automatic switch (AUTO mode)
  1310. * @return array barcode representation.
  1311. * @protected
  1312. */
  1313. protected function barcode_c128($code, $type='') {
  1314. $chr = array(
  1315. '212222', /* 00 */
  1316. '222122', /* 01 */
  1317. '222221', /* 02 */
  1318. '121223', /* 03 */
  1319. '121322', /* 04 */
  1320. '131222', /* 05 */
  1321. '122213', /* 06 */
  1322. '122312', /* 07 */
  1323. '132212', /* 08 */
  1324. '221213', /* 09 */
  1325. '221312', /* 10 */
  1326. '231212', /* 11 */
  1327. '112232', /* 12 */
  1328. '122132', /* 13 */
  1329. '122231', /* 14 */
  1330. '113222', /* 15 */
  1331. '123122', /* 16 */
  1332. '123221', /* 17 */
  1333. '223211', /* 18 */
  1334. '221132', /* 19 */
  1335. '221231', /* 20 */
  1336. '213212', /* 21 */
  1337. '223112', /* 22 */
  1338. '312131', /* 23 */
  1339. '311222', /* 24 */
  1340. '321122', /* 25 */
  1341. '321221', /* 26 */
  1342. '312212', /* 27 */
  1343. '322112', /* 28 */
  1344. '322211', /* 29 */
  1345. '212123', /* 30 */
  1346. '212321', /* 31 */
  1347. '232121', /* 32 */
  1348. '111323', /* 33 */
  1349. '131123', /* 34 */
  1350. '131321', /* 35 */
  1351. '112313', /* 36 */
  1352. '132113', /* 37 */
  1353. '132311', /* 38 */
  1354. '211313', /* 39 */
  1355. '231113', /* 40 */
  1356. '231311', /* 41 */
  1357. '112133', /* 42 */
  1358. '112331', /* 43 */
  1359. '132131', /* 44 */
  1360. '113123', /* 45 */
  1361. '113321', /* 46 */
  1362. '133121', /* 47 */
  1363. '313121', /* 48 */
  1364. '211331', /* 49 */
  1365. '231131', /* 50 */
  1366. '213113', /* 51 */
  1367. '213311', /* 52 */
  1368. '213131', /* 53 */
  1369. '311123', /* 54 */
  1370. '311321', /* 55 */
  1371. '331121', /* 56 */
  1372. '312113', /* 57 */
  1373. '312311', /* 58 */
  1374. '332111', /* 59 */
  1375. '314111', /* 60 */
  1376. '221411', /* 61 */
  1377. '431111', /* 62 */
  1378. '111224', /* 63 */
  1379. '111422', /* 64 */
  1380. '121124', /* 65 */
  1381. '121421', /* 66 */
  1382. '141122', /* 67 */
  1383. '141221', /* 68 */
  1384. '112214', /* 69 */
  1385. '112412', /* 70 */
  1386. '122114', /* 71 */
  1387. '122411', /* 72 */
  1388. '142112', /* 73 */
  1389. '142211', /* 74 */
  1390. '241211', /* 75 */
  1391. '221114', /* 76 */
  1392. '413111', /* 77 */
  1393. '241112', /* 78 */
  1394. '134111', /* 79 */
  1395. '111242', /* 80 */
  1396. '121142', /* 81 */
  1397. '121241', /* 82 */
  1398. '114212', /* 83 */
  1399. '124112', /* 84 */
  1400. '124211', /* 85 */
  1401. '411212', /* 86 */
  1402. '421112', /* 87 */
  1403. '421211', /* 88 */
  1404. '212141', /* 89 */
  1405. '214121', /* 90 */
  1406. '412121', /* 91 */
  1407. '111143', /* 92 */
  1408. '111341', /* 93 */
  1409. '131141', /* 94 */
  1410. '114113', /* 95 */
  1411. '114311', /* 96 */
  1412. '411113', /* 97 */
  1413. '411311', /* 98 */
  1414. '113141', /* 99 */
  1415. '114131', /* 100 */
  1416. '311141', /* 101 */
  1417. '411131', /* 102 */
  1418. '211412', /* 103 START A */
  1419. '211214', /* 104 START B */
  1420. '211232', /* 105 START C */
  1421. '233111', /* STOP */
  1422. '200000' /* END */
  1423. );
  1424. // ASCII characters for code A (ASCII 00 - 95)
  1425. $keys_a = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_';
  1426. $keys_a .= chr(0).chr(1).chr(2).chr(3).chr(4).chr(5).chr(6).chr(7).chr(8).chr(9);
  1427. $keys_a .= chr(10).chr(11).chr(12).chr(13).chr(14).chr(15).chr(16).chr(17).chr(18).chr(19);
  1428. $keys_a .= chr(20).chr(21).chr(22).chr(23).chr(24).chr(25).chr(26).chr(27).chr(28).chr(29);
  1429. $keys_a .= chr(30).chr(31);
  1430. // ASCII characters for code B (ASCII 32 - 127)
  1431. $keys_b = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'.chr(127);
  1432. // special codes
  1433. $fnc_a = array(241 => 102, 242 => 97, 243 => 96, 244 => 101);
  1434. $fnc_b = array(241 => 102, 242 => 97, 243 => 96, 244 => 100);
  1435. // array of symbols
  1436. $code_data = array();
  1437. // lenght of the code
  1438. $len = strlen($code);
  1439. switch(strtoupper($type)) {
  1440. case 'A': { // MODE A
  1441. $startid = 103;
  1442. for ($i = 0; $i < $len; ++$i) {
  1443. $char = $code{$i};
  1444. $char_id = ord($char);
  1445. if (($char_id >= 241) AND ($char_id <= 244)) {
  1446. $code_data[] = $fnc_a[$char_id];
  1447. } elseif (($char_id >= 0) AND ($char_id <= 95)) {
  1448. $code_data[] = strpos($keys_a, $char);
  1449. } else {
  1450. return false;
  1451. }
  1452. }
  1453. break;
  1454. }
  1455. case 'B': { // MODE B
  1456. $startid = 104;
  1457. for ($i = 0; $i < $len; ++$i) {
  1458. $char = $code{$i};
  1459. $char_id = ord($char);
  1460. if (($char_id >= 241) AND ($char_id <= 244)) {
  1461. $code_data[] = $fnc_b[$char_id];
  1462. } elseif (($char_id >= 32) AND ($char_id <= 127)) {
  1463. $code_data[] = strpos($keys_b, $char);
  1464. } else {
  1465. return false;
  1466. }
  1467. }
  1468. break;
  1469. }
  1470. case 'C': { // MODE C
  1471. $startid = 105;
  1472. if (ord($code{0}) == 241) {
  1473. $code_data[] = 102;
  1474. $code = substr($code, 1);
  1475. --$len;
  1476. }
  1477. if (($len % 2) != 0) {
  1478. // the length must be even
  1479. return false;
  1480. }
  1481. for ($i = 0; $i < $len; $i+=2) {
  1482. $chrnum = $code{$i}.$code{$i+1};
  1483. if (preg_match('/([0-9]{2})/', $chrnum) > 0) {
  1484. $code_data[] = intval($chrnum);
  1485. } else {
  1486. return false;
  1487. }
  1488. }
  1489. break;
  1490. }
  1491. default: { // MODE AUTO
  1492. // split code into sequences
  1493. $sequence = array();
  1494. // get numeric sequences (if any)
  1495. $numseq = array();
  1496. preg_match_all('/([0-9]{4,})/', $code, $numseq, PREG_OFFSET_CAPTURE);
  1497. if (isset($numseq[1]) AND !empty($numseq[1])) {
  1498. $end_offset = 0;
  1499. foreach ($numseq[1] as $val) {
  1500. $offset = $val[1];
  1501. if ($offset > $end_offset) {
  1502. // non numeric sequence
  1503. $sequence = array_merge($sequence, $this->get128ABsequence(substr($code, $end_offset, ($offset - $end_offset))));
  1504. }
  1505. // numeric sequence
  1506. $slen = strlen($val[0]);
  1507. if (($slen % 2) != 0) {
  1508. // the length must be even
  1509. --$slen;
  1510. }
  1511. $sequence[] = array('C', substr($code, $offset, $slen), $slen);
  1512. $end_offset = $offset + $slen;
  1513. }
  1514. if ($end_offset < $len) {
  1515. $sequence = array_merge($sequence, $this->get128ABsequence(substr($code, $end_offset)));
  1516. }
  1517. } else {
  1518. // text code (non C mode)
  1519. $sequence = array_merge($sequence, $this->get128ABsequence($code));
  1520. }
  1521. // process the sequence
  1522. foreach ($sequence as $key => $seq) {
  1523. switch($seq[0]) {
  1524. case 'A': {
  1525. if ($key == 0) {
  1526. $startid = 103;
  1527. } elseif ($sequence[($key - 1)][0] != 'A') {
  1528. if (($seq[2] == 1) AND ($key > 0) AND ($sequence[($key - 1)][0] == 'B') AND (!isset($sequence[($key - 1)][3]))) {
  1529. // single character shift
  1530. $code_data[] = 98;
  1531. // mark shift
  1532. $sequence[$key][3] = true;
  1533. } elseif (!isset($sequence[($key - 1)][3])) {
  1534. $code_data[] = 101;
  1535. }
  1536. }
  1537. for ($i = 0; $i < $seq[2]; ++$i) {
  1538. $char = $seq[1]{$i};
  1539. $char_id = ord($char);
  1540. if (($char_id >= 241) AND ($char_id <= 244)) {
  1541. $code_data[] = $fnc_a[$char_id];
  1542. } else {
  1543. $code_data[] = strpos($keys_a, $char);
  1544. }
  1545. }
  1546. break;
  1547. }
  1548. case 'B': {
  1549. if ($key == 0) {
  1550. $tmpchr = ord($seq[1]{0});
  1551. if (($seq[2] == 1) AND ($tmpchr >= 241) AND ($tmpchr <= 244) AND isset($sequence[($key + 1)]) AND ($sequence[($key + 1)][0] != 'B')) {
  1552. switch ($sequence[($key + 1)][0]) {
  1553. case 'A': {
  1554. $startid = 103;
  1555. $sequence[$key][0] = 'A';
  1556. $code_data[] = $fnc_a[$tmpchr];
  1557. break;
  1558. }
  1559. case 'C': {
  1560. $startid = 105;
  1561. $sequence[$key][0] = 'C';
  1562. $code_data[] = $fnc_a[$tmpchr];
  1563. break;
  1564. }
  1565. }
  1566. break;
  1567. } else {
  1568. $startid = 104;
  1569. }
  1570. } elseif ($sequence[($key - 1)][0] != 'B') {
  1571. if (($seq[2] == 1) AND ($key > 0) AND ($sequence[($key - 1)][0] == 'A') AND (!isset($sequence[($key - 1)][3]))) {
  1572. // single character shift
  1573. $code_data[] = 98;
  1574. // mark shift
  1575. $sequence[$key][3] = true;
  1576. } elseif (!isset($sequence[($key - 1)][3])) {
  1577. $code_data[] = 100;
  1578. }
  1579. }
  1580. for ($i = 0; $i < $seq[2]; ++$i) {
  1581. $char = $seq[1]{$i};
  1582. $char_id = ord($char);
  1583. if (($char_id >= 241) AND ($char_id <= 244)) {
  1584. $code_data[] = $fnc_b[$char_id];
  1585. } else {
  1586. $code_data[] = strpos($keys_b, $char);
  1587. }
  1588. }
  1589. break;
  1590. }
  1591. case 'C': {
  1592. if ($key == 0) {
  1593. $startid = 105;
  1594. } elseif ($sequence[($key - 1)][0] != 'C') {
  1595. $code_data[] = 99;
  1596. }
  1597. for ($i = 0; $i < $seq[2]; $i+=2) {
  1598. $chrnum = $seq[1]{$i}.$seq[1]{$i+1};
  1599. $code_data[] = intval($chrnum);
  1600. }
  1601. break;
  1602. }
  1603. }
  1604. }
  1605. }
  1606. }
  1607. // calculate check character
  1608. $sum = $startid;
  1609. foreach ($code_data as $key => $val) {
  1610. $sum += ($val * ($key + 1));
  1611. }
  1612. // add check character
  1613. $code_data[] = ($sum % 103);
  1614. // add stop sequence
  1615. $code_data[] = 106;
  1616. $code_data[] = 107;
  1617. // add start code at the beginning
  1618. array_unshift($code_data, $startid);
  1619. // build barcode array
  1620. $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
  1621. foreach ($code_data as $val) {
  1622. $seq = $chr[$val];
  1623. for ($j = 0; $j < 6; ++$j) {
  1624. if (($j % 2) == 0) {
  1625. $t = true; // bar
  1626. } else {
  1627. $t = false; // space
  1628. }
  1629. $w = $seq{$j};
  1630. $bararray['bcode'][] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
  1631. $bararray['maxw'] += $w;
  1632. }
  1633. }
  1634. return $bararray;
  1635. }
  1636. /**
  1637. * Split text code in A/B sequence for 128 code
  1638. * @param $code (string) code to split.
  1639. * @return array sequence
  1640. * @protected
  1641. */
  1642. protected function get128ABsequence($code) {
  1643. $len = strlen($code);
  1644. $sequence = array();
  1645. // get A sequences (if any)
  1646. $numseq = array();
  1647. preg_match_all('/([\0-\31])/', $code, $numseq, PREG_OFFSET_CAPTURE);
  1648. if (isset($numseq[1]) AND !empty($numseq[1])) {
  1649. $end_offset = 0;
  1650. foreach ($numseq[1] as $val) {
  1651. $offset = $val[1];
  1652. if ($offset > $end_offset) {
  1653. // B sequence
  1654. $sequence[] = array('B', substr($code, $end_offset, ($offset - $end_offset)), ($offset - $end_offset));
  1655. }
  1656. // A sequence
  1657. $slen = strlen($val[0]);
  1658. $sequence[] = array('A', substr($code, $offset, $slen), $slen);
  1659. $end_offset = $offset + $slen;
  1660. }
  1661. if ($end_offset < $len) {
  1662. $sequence[] = array('B', substr($code, $end_offset), ($len - $end_offset));
  1663. }
  1664. } else {
  1665. // only B sequence
  1666. $sequence[] = array('B', $code, $len);
  1667. }
  1668. return $sequence;
  1669. }
  1670. /**
  1671. * EAN13 and UPC-A barcodes.
  1672. * EAN13: European Article Numbering international retail product code
  1673. * UPC-A: Universal product code seen on almost all retail products in the USA and Canada
  1674. * UPC-E: Short version of UPC symbol
  1675. * @param $code (string) code to represent.
  1676. * @param $len (string) barcode type: 6 = UPC-E, 8 = EAN8, 13 = EAN13, 12 = UPC-A
  1677. * @return array barcode representation.
  1678. * @protected
  1679. */
  1680. protected function barcode_eanupc($code, $len=13) {
  1681. $upce = false;
  1682. if ($len == 6) {
  1683. $len = 12; // UPC-A
  1684. $upce = true; // UPC-E mode
  1685. }
  1686. $data_len = $len - 1;
  1687. //Padding
  1688. $code = str_pad($code, $data_len, '0', STR_PAD_LEFT);
  1689. $code_len = strlen($code);
  1690. // calculate check digit
  1691. $sum_a = 0;
  1692. for ($i = 1; $i < $data_len; $i+=2) {
  1693. $sum_a += $code{$i};
  1694. }
  1695. if ($len > 12) {
  1696. $sum_a *= 3;
  1697. }
  1698. $sum_b = 0;
  1699. for ($i = 0; $i < $data_len; $i+=2) {
  1700. $sum_b += ($code{$i});
  1701. }
  1702. if ($len < 13) {
  1703. $sum_b *= 3;
  1704. }
  1705. $r = ($sum_a + $sum_b) % 10;
  1706. if($r > 0) {
  1707. $r = (10 - $r);
  1708. }
  1709. if ($code_len == $data_len) {
  1710. // add check digit
  1711. $code .= $r;
  1712. } elseif ($r !== intval($code{$data_len})) {
  1713. // wrong checkdigit
  1714. return false;
  1715. }
  1716. if ($len == 12) {
  1717. // UPC-A
  1718. $code = '0'.$code;
  1719. ++$len;
  1720. }
  1721. if ($upce) {
  1722. // convert UPC-A to UPC-E
  1723. $tmp = substr($code, 4, 3);
  1724. if (($tmp == '000') OR ($tmp == '100') OR ($tmp == '200')) {
  1725. // manufacturer code ends in 000, 100, or 200
  1726. $upce_code = substr($code, 2, 2).substr($code, 9, 3).substr($code, 4, 1);
  1727. } else {
  1728. $tmp = substr($code, 5, 2);
  1729. if ($tmp == '00') {
  1730. // manufacturer code ends in 00
  1731. $upce_code = substr($code, 2, 3).substr($code, 10, 2).'3';
  1732. } else {
  1733. $tmp = substr($code, 6, 1);
  1734. if ($tmp == '0') {
  1735. // manufacturer code ends in 0
  1736. $upce_code = substr($code, 2, 4).substr($code, 11, 1).'4';
  1737. } else {
  1738. // manufacturer code does not end in zero
  1739. $upce_code = substr($code, 2, 5).substr($code, 11, 1);
  1740. }
  1741. }
  1742. }
  1743. }
  1744. //Convert digits to bars
  1745. $codes = array(
  1746. 'A'=>array( // left odd parity
  1747. '0'=>'0001101',
  1748. '1'=>'0011001',
  1749. '2'=>'0010011',
  1750. '3'=>'0111101',
  1751. '4'=>'0100011',
  1752. '5'=>'0110001',
  1753. '6'=>'0101111',
  1754. '7'=>'0111011',
  1755. '8'=>'0110111',
  1756. '9'=>'0001011'),
  1757. 'B'=>array( // left even parity
  1758. '0'=>'0100111',
  1759. '1'=>'0110011',
  1760. '2'=>'0011011',
  1761. '3'=>'0100001',
  1762. '4'=>'0011101',
  1763. '5'=>'0111001',
  1764. '6'=>'0000101',
  1765. '7'=>'0010001',
  1766. '8'=>'0001001',
  1767. '9'=>'0010111'),
  1768. 'C'=>array( // right
  1769. '0'=>'1110010',
  1770. '1'=>'1100110',
  1771. '2'=>'1101100',
  1772. '3'=>'1000010',
  1773. '4'=>'1011100',
  1774. '5'=>'1001110',
  1775. '6'=>'1010000',
  1776. '7'=>'1000100',
  1777. '8'=>'1001000',
  1778. '9'=>'1110100')
  1779. );
  1780. $parities = array(
  1781. '0'=>array('A','A','A','A','A','A'),
  1782. '1'=>array('A','A','B','A','B','B'),
  1783. '2'=>array('A','A','B','B','A','B'),
  1784. '3'=>array('A','A','B','B','B','A'),
  1785. '4'=>array('A','B','A','A','B','B'),
  1786. '5'=>array('A','B','B','A','A','B'),
  1787. '6'=>array('A','B','B','B','A','A'),
  1788. '7'=>array('A','B','A','B','A','B'),
  1789. '8'=>array('A','B','A','B','B','A'),
  1790. '9'=>array('A','B','B','A','B','A')
  1791. );
  1792. $upce_parities = array();
  1793. $upce_parities[0] = array(
  1794. '0'=>array('B','B','B','A','A','A'),
  1795. '1'=>array('B','B','A','B','A','A'),
  1796. '2'=>array('B','B','A','A','B','A'),
  1797. '3'=>array('B','B','A','A','A','B'),
  1798. '4'=>array('B','A','B','B','A','A'),
  1799. '5'=>array('B','A','A','B','B','A'),
  1800. '6'=>array('B','A','A','A','B','B'),
  1801. '7'=>array('B','A','B','A','B','A'),
  1802. '8'=>array('B','A','B','A','A','B'),
  1803. '9'=>array('B','A','A','B','A','B')
  1804. );
  1805. $upce_parities[1] = array(
  1806. '0'=>array('A','A','A','B','B','B'),
  1807. '1'=>array('A','A','B','A','B','B'),
  1808. '2'=>array('A','A','B','B','A','B'),
  1809. '3'=>array('A','A','B','B','B','A'),
  1810. '4'=>array('A','B','A','A','B','B'),
  1811. '5'=>array('A','B','B','A','A','B'),
  1812. '6'=>array('A','B','B','B','A','A'),
  1813. '7'=>array('A','B','A','B','A','B'),
  1814. '8'=>array('A','B','A','B','B','A'),
  1815. '9'=>array('A','B','B','A','B','A')
  1816. );
  1817. $k = 0;
  1818. $seq = '101'; // left guard bar
  1819. if ($upce) {
  1820. $bararray = array('code' => $upce_code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
  1821. $p = $upce_parities[$code{1}][$r];
  1822. for ($i = 0; $i < 6; ++$i) {
  1823. $seq .= $codes[$p[$i]][$upce_code{$i}];
  1824. }
  1825. $seq .= '010101'; // right guard bar
  1826. } else {
  1827. $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
  1828. $half_len = ceil($len / 2);
  1829. if ($len == 8) {
  1830. for ($i = 0; $i < $half_len; ++$i) {
  1831. $seq .= $codes['A'][$code{$i}];
  1832. }
  1833. } else {
  1834. $p = $parities[$code{0}];
  1835. for ($i = 1; $i < $half_len; ++$i) {
  1836. $seq .= $codes[$p[$i-1]][$code{$i}];
  1837. }
  1838. }
  1839. $seq .= '01010'; // center guard bar
  1840. for ($i = $half_len; $i < $len; ++$i) {
  1841. $seq .= $codes['C'][$code{$i}];
  1842. }
  1843. $seq .= '101'; // right guard bar
  1844. }
  1845. $clen = strlen($seq);
  1846. $w = 0;
  1847. for ($i = 0; $i < $clen; ++$i) {
  1848. $w += 1;
  1849. if (($i == ($clen - 1)) OR (($i < ($clen - 1)) AND ($seq{$i} != $seq{($i+1)}))) {
  1850. if ($seq{$i} == '1') {
  1851. $t = true; // bar
  1852. } else {
  1853. $t = false; // space
  1854. }
  1855. $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
  1856. $bararray['maxw'] += $w;
  1857. ++$k;
  1858. $w = 0;
  1859. }
  1860. }
  1861. return $bararray;
  1862. }
  1863. /**
  1864. * UPC-Based Extentions
  1865. * 2-Digit Ext.: Used to indicate magazines and newspaper issue numbers
  1866. * 5-Digit Ext.: Used to mark suggested retail price of books
  1867. * @param $code (string) code to represent.
  1868. * @param $len (string) barcode type: 2 = 2-Digit, 5 = 5-Digit
  1869. * @return array barcode representation.
  1870. * @protected
  1871. */
  1872. protected function barcode_eanext($code, $len=5) {
  1873. //Padding
  1874. $code = str_pad($code, $len, '0', STR_PAD_LEFT);
  1875. // calculate check digit
  1876. if ($len == 2) {
  1877. $r = $code % 4;
  1878. } elseif ($len == 5) {
  1879. $r = (3 * ($code{0} + $code{2} + $code{4})) + (9 * ($code{1} + $code{3}));
  1880. $r %= 10;
  1881. } else {
  1882. return false;
  1883. }
  1884. //Convert digits to bars
  1885. $codes = array(
  1886. 'A'=>array( // left odd parity
  1887. '0'=>'0001101',
  1888. '1'=>'0011001',
  1889. '2'=>'0010011',
  1890. '3'=>'0111101',
  1891. '4'=>'0100011',
  1892. '5'=>'0110001',
  1893. '6'=>'0101111',
  1894. '7'=>'0111011',
  1895. '8'=>'0110111',
  1896. '9'=>'0001011'),
  1897. 'B'=>array( // left even parity
  1898. '0'=>'0100111',
  1899. '1'=>'0110011',
  1900. '2'=>'0011011',
  1901. '3'=>'0100001',
  1902. '4'=>'0011101',
  1903. '5'=>'0111001',
  1904. '6'=>'0000101',
  1905. '7'=>'0010001',
  1906. '8'=>'0001001',
  1907. '9'=>'0010111')
  1908. );
  1909. $parities = array();
  1910. $parities[2] = array(
  1911. '0'=>array('A','A'),
  1912. '1'=>array('A','B'),
  1913. '2'=>array('B','A'),
  1914. '3'=>array('B','B')
  1915. );
  1916. $parities[5] = array(
  1917. '0'=>array('B','B','A','A','A'),
  1918. '1'=>array('B','A','B','A','A'),
  1919. '2'=>array('B','A','A','B','A'),
  1920. '3'=>array('B','A','A','A','B'),
  1921. '4'=>array('A','B','B','A','A'),
  1922. '5'=>array('A','A','B','B','A'),
  1923. '6'=>array('A','A','A','B','B'),
  1924. '7'=>array('A','B','A','B','A'),
  1925. '8'=>array('A','B','A','A','B'),
  1926. '9'=>array('A','A','B','A','B')
  1927. );
  1928. $p = $parities[$len][$r];
  1929. $seq = '1011'; // left guard bar
  1930. $seq .= $codes[$p[0]][$code{0}];
  1931. for ($i = 1; $i < $len; ++$i) {
  1932. $seq .= '01'; // separator
  1933. $seq .= $codes[$p[$i]][$code{$i}];
  1934. }
  1935. $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
  1936. return $this->binseq_to_array($seq, $bararray);
  1937. }
  1938. /**
  1939. * POSTNET and PLANET barcodes.
  1940. * Used by U.S. Postal Service for automated mail sorting
  1941. * @param $code (string) zip code to represent. Must be a string containing a zip code of the form DDDDD or DDDDD-DDDD.
  1942. * @param $planet (boolean) if true print the PLANET barcode, otherwise print POSTNET
  1943. * @return array barcode representation.
  1944. * @protected
  1945. */
  1946. protected function barcode_postnet($code, $planet=false) {
  1947. // bar lenght
  1948. if ($planet) {
  1949. $barlen = Array(
  1950. 0 => Array(1,1,2,2,2),
  1951. 1 => Array(2,2,2,1,1),
  1952. 2 => Array(2,2,1,2,1),
  1953. 3 => Array(2,2,1,1,2),
  1954. 4 => Array(2,1,2,2,1),
  1955. 5 => Array(2,1,2,1,2),
  1956. 6 => Array(2,1,1,2,2),
  1957. 7 => Array(1,2,2,2,1),
  1958. 8 => Array(1,2,2,1,2),
  1959. 9 => Array(1,2,1,2,2)
  1960. );
  1961. } else {
  1962. $barlen = Array(
  1963. 0 => Array(2,2,1,1,1),
  1964. 1 => Array(1,1,1,2,2),
  1965. 2 => Array(1,1,2,1,2),
  1966. 3 => Array(1,1,2,2,1),
  1967. 4 => Array(1,2,1,1,2),
  1968. 5 => Array(1,2,1,2,1),
  1969. 6 => Array(1,2,2,1,1),
  1970. 7 => Array(2,1,1,1,2),
  1971. 8 => Array(2,1,1,2,1),
  1972. 9 => Array(2,1,2,1,1)
  1973. );
  1974. }
  1975. $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 2, 'bcode' => array());
  1976. $k = 0;
  1977. $code = str_replace('-', '', $code);
  1978. $code = str_replace(' ', '', $code);
  1979. $len = strlen($code);
  1980. // calculate checksum
  1981. $sum = 0;
  1982. for ($i = 0; $i < $len; ++$i) {
  1983. $sum += intval($code{$i});
  1984. }
  1985. $chkd = ($sum % 10);
  1986. if($chkd > 0) {
  1987. $chkd = (10 - $chkd);
  1988. }
  1989. $code .= $chkd;
  1990. $len = strlen($code);
  1991. // start bar
  1992. $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0);
  1993. $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
  1994. $bararray['maxw'] += 2;
  1995. for ($i = 0; $i < $len; ++$i) {
  1996. for ($j = 0; $j < 5; ++$j) {
  1997. $h = $barlen[$code{$i}][$j];
  1998. $p = floor(1 / $h);
  1999. $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
  2000. $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
  2001. $bararray['maxw'] += 2;
  2002. }
  2003. }
  2004. // end bar
  2005. $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0);
  2006. $bararray['maxw'] += 1;
  2007. return $bararray;
  2008. }
  2009. /**
  2010. * RMS4CC - CBC - KIX
  2011. * RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code) - KIX (Klant index - Customer index)
  2012. * RM4SCC is the name of the barcode symbology used by the Royal Mail for its Cleanmail service.
  2013. * @param $code (string) code to print
  2014. * @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 code.
  2015. * @return array barcode representation.
  2016. * @protected
  2017. */
  2018. protected function barcode_rms4cc($code, $kix=false) {
  2019. $notkix = !$kix;
  2020. // bar mode
  2021. // 1 = pos 1, length 2
  2022. // 2 = pos 1, length 3
  2023. // 3 = pos 2, length 1
  2024. // 4 = pos 2, length 2
  2025. $barmode = array(
  2026. '0' => array(3,3,2,2),
  2027. '1' => array(3,4,1,2),
  2028. '2' => array(3,4,2,1),
  2029. '3' => array(4,3,1,2),
  2030. '4' => array(4,3,2,1),
  2031. '5' => array(4,4,1,1),
  2032. '6' => array(3,1,4,2),
  2033. '7' => array(3,2,3,2),
  2034. '8' => array(3,2,4,1),
  2035. '9' => array(4,1,3,2),
  2036. 'A' => array(4,1,4,1),
  2037. 'B' => array(4,2,3,1),
  2038. 'C' => array(3,1,2,4),
  2039. 'D' => array(3,2,1,4),
  2040. 'E' => array(3,2,2,3),
  2041. 'F' => array(4,1,1,4),
  2042. 'G' => array(4,1,2,3),
  2043. 'H' => array(4,2,1,3),
  2044. 'I' => array(1,3,4,2),
  2045. 'J' => array(1,4,3,2),
  2046. 'K' => array(1,4,4,1),
  2047. 'L' => array(2,3,3,2),
  2048. 'M' => array(2,3,4,1),
  2049. 'N' => array(2,4,3,1),
  2050. 'O' => array(1,3,2,4),
  2051. 'P' => array(1,4,1,4),
  2052. 'Q' => array(1,4,2,3),
  2053. 'R' => array(2,3,1,4),
  2054. 'S' => array(2,3,2,3),
  2055. 'T' => array(2,4,1,3),
  2056. 'U' => array(1,1,4,4),
  2057. 'V' => array(1,2,3,4),
  2058. 'W' => array(1,2,4,3),
  2059. 'X' => array(2,1,3,4),
  2060. 'Y' => array(2,1,4,3),
  2061. 'Z' => array(2,2,3,3)
  2062. );
  2063. $code = strtoupper($code);
  2064. $len = strlen($code);
  2065. $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array());
  2066. if ($notkix) {
  2067. // table for checksum calculation (row,col)
  2068. $checktable = array(
  2069. '0' => array(1,1),
  2070. '1' => array(1,2),
  2071. '2' => array(1,3),
  2072. '3' => array(1,4),
  2073. '4' => array(1,5),
  2074. '5' => array(1,0),
  2075. '6' => array(2,1),
  2076. '7' => array(2,2),
  2077. '8' => array(2,3),
  2078. '9' => array(2,4),
  2079. 'A' => array(2,5),
  2080. 'B' => array(2,0),
  2081. 'C' => array(3,1),
  2082. 'D' => array(3,2),
  2083. 'E' => array(3,3),
  2084. 'F' => array(3,4),
  2085. 'G' => array(3,5),
  2086. 'H' => array(3,0),
  2087. 'I' => array(4,1),
  2088. 'J' => array(4,2),
  2089. 'K' => array(4,3),
  2090. 'L' => array(4,4),
  2091. 'M' => array(4,5),
  2092. 'N' => array(4,0),
  2093. 'O' => array(5,1),
  2094. 'P' => array(5,2),
  2095. 'Q' => array(5,3),
  2096. 'R' => array(5,4),
  2097. 'S' => array(5,5),
  2098. 'T' => array(5,0),
  2099. 'U' => array(0,1),
  2100. 'V' => array(0,2),
  2101. 'W' => array(0,3),
  2102. 'X' => array(0,4),
  2103. 'Y' => array(0,5),
  2104. 'Z' => array(0,0)
  2105. );
  2106. $row = 0;
  2107. $col = 0;
  2108. for ($i = 0; $i < $len; ++$i) {
  2109. $row += $checktable[$code{$i}][0];
  2110. $col += $checktable[$code{$i}][1];
  2111. }
  2112. $row %= 6;
  2113. $col %= 6;
  2114. $chk = array_keys($checktable, array($row,$col));
  2115. $code .= $chk[0];
  2116. ++$len;
  2117. }
  2118. $k = 0;
  2119. if ($notkix) {
  2120. // start bar
  2121. $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0);
  2122. $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
  2123. $bararray['maxw'] += 2;
  2124. }
  2125. for ($i = 0; $i < $len; ++$i) {
  2126. for ($j = 0; $j < 4; ++$j) {
  2127. switch ($barmode[$code{$i}][$j]) {
  2128. case 1: {
  2129. $p = 0;
  2130. $h = 2;
  2131. break;
  2132. }
  2133. case 2: {
  2134. $p = 0;
  2135. $h = 3;
  2136. break;
  2137. }
  2138. case 3: {
  2139. $p = 1;
  2140. $h = 1;
  2141. break;
  2142. }
  2143. case 4: {
  2144. $p = 1;
  2145. $h = 2;
  2146. break;
  2147. }
  2148. }
  2149. $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
  2150. $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
  2151. $bararray['maxw'] += 2;
  2152. }
  2153. }
  2154. if ($notkix) {
  2155. // stop bar
  2156. $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 3, 'p' => 0);
  2157. $bararray['maxw'] += 1;
  2158. }
  2159. return $bararray;
  2160. }
  2161. /**
  2162. * CODABAR barcodes.
  2163. * Older code often used in library systems, sometimes in blood banks
  2164. * @param $code (string) code to represent.
  2165. * @return array barcode representation.
  2166. * @protected
  2167. */
  2168. protected function barcode_codabar($code) {
  2169. $chr = array(
  2170. '0' => '11111221',
  2171. '1' => '11112211',
  2172. '2' => '11121121',
  2173. '3' => '22111111',
  2174. '4' => '11211211',
  2175. '5' => '21111211',
  2176. '6' => '12111121',
  2177. '7' => '12112111',
  2178. '8' => '12211111',
  2179. '9' => '21121111',
  2180. '-' => '11122111',
  2181. '$' => '11221111',
  2182. ':' => '21112121',
  2183. '/' => '21211121',
  2184. '.' => '21212111',
  2185. '+' => '11222221',
  2186. 'A' => '11221211',
  2187. 'B' => '12121121',
  2188. 'C' => '11121221',
  2189. 'D' => '11122211'
  2190. );
  2191. $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
  2192. $k = 0;
  2193. $w = 0;
  2194. $seq = '';
  2195. $code = 'A'.strtoupper($code).'A';
  2196. $len = strlen($code);
  2197. for ($i = 0; $i < $len; ++$i) {
  2198. if (!isset($chr[$code{$i}])) {
  2199. return false;
  2200. }
  2201. $seq = $chr[$code{$i}];
  2202. for ($j = 0; $j < 8; ++$j) {
  2203. if (($j % 2) == 0) {
  2204. $t = true; // bar
  2205. } else {
  2206. $t = false; // space
  2207. }
  2208. $w = $seq{$j};
  2209. $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
  2210. $bararray['maxw'] += $w;
  2211. ++$k;
  2212. }
  2213. }
  2214. return $bararray;
  2215. }
  2216. /**
  2217. * CODE11 barcodes.
  2218. * Used primarily for labeling telecommunications equipment
  2219. * @param $code (string) code to represent.
  2220. * @return array barcode representation.
  2221. * @protected
  2222. */
  2223. protected function barcode_code11($code) {
  2224. $chr = array(
  2225. '0' => '111121',
  2226. '1' => '211121',
  2227. '2' => '121121',
  2228. '3' => '221111',
  2229. '4' => '112121',
  2230. '5' => '212111',
  2231. '6' => '122111',
  2232. '7' => '111221',
  2233. '8' => '211211',
  2234. '9' => '211111',
  2235. '-' => '112111',
  2236. 'S' => '112211'
  2237. );
  2238. $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
  2239. $k = 0;
  2240. $w = 0;
  2241. $seq = '';
  2242. $len = strlen($code);
  2243. // calculate check digit C
  2244. $p = 1;
  2245. $check = 0;
  2246. for ($i = ($len - 1); $i >= 0; --$i) {
  2247. $digit = $code{$i};
  2248. if ($digit == '-') {
  2249. $dval = 10;
  2250. } else {
  2251. $dval = intval($digit);
  2252. }
  2253. $check += ($dval * $p);
  2254. ++$p;
  2255. if ($p > 10) {
  2256. $p = 1;
  2257. }
  2258. }
  2259. $check %= 11;
  2260. if ($check == 10) {
  2261. $check = '-';
  2262. }
  2263. $code .= $check;
  2264. if ($len > 10) {
  2265. // calculate check digit K
  2266. $p = 1;
  2267. $check = 0;
  2268. for ($i = $len; $i >= 0; --$i) {
  2269. $digit = $code{$i};
  2270. if ($digit == '-') {
  2271. $dval = 10;
  2272. } else {
  2273. $dval = intval($digit);
  2274. }
  2275. $check += ($dval * $p);
  2276. ++$p;
  2277. if ($p > 9) {
  2278. $p = 1;
  2279. }
  2280. }
  2281. $check %= 11;
  2282. $code .= $check;
  2283. ++$len;
  2284. }
  2285. $code = 'S'.$code.'S';
  2286. $len += 3;
  2287. for ($i = 0; $i < $len; ++$i) {
  2288. if (!isset($chr[$code{$i}])) {
  2289. return false;
  2290. }
  2291. $seq = $chr[$code{$i}];
  2292. for ($j = 0; $j < 6; ++$j) {
  2293. if (($j % 2) == 0) {
  2294. $t = true; // bar
  2295. } else {
  2296. $t = false; // space
  2297. }
  2298. $w = $seq{$j};
  2299. $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
  2300. $bararray['maxw'] += $w;
  2301. ++$k;
  2302. }
  2303. }
  2304. return $bararray;
  2305. }
  2306. /**
  2307. * Pharmacode
  2308. * Contains digits (0 to 9)
  2309. * @param $code (string) code to represent.
  2310. * @return array barcode representation.
  2311. * @protected
  2312. */
  2313. protected function barcode_pharmacode($code) {
  2314. $seq = '';
  2315. $code = intval($code);
  2316. while ($code > 0) {
  2317. if (($code % 2) == 0) {
  2318. $seq .= '11100';
  2319. $code -= 2;
  2320. } else {
  2321. $seq .= '100';
  2322. $code -= 1;
  2323. }
  2324. $code /= 2;
  2325. }
  2326. $seq = substr($seq, 0, -2);
  2327. $seq = strrev($seq);
  2328. $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
  2329. return $this->binseq_to_array($seq, $bararray);
  2330. }
  2331. /**
  2332. * Pharmacode two-track
  2333. * Contains digits (0 to 9)
  2334. * @param $code (string) code to represent.
  2335. * @return array barcode representation.
  2336. * @protected
  2337. */
  2338. protected function barcode_pharmacode2t($code) {
  2339. $seq = '';
  2340. $code = intval($code);
  2341. do {
  2342. switch ($code % 3) {
  2343. case 0: {
  2344. $seq .= '3';
  2345. $code = ($code - 3) / 3;
  2346. break;
  2347. }
  2348. case 1: {
  2349. $seq .= '1';
  2350. $code = ($code - 1) / 3;
  2351. break;
  2352. }
  2353. case 2: {
  2354. $seq .= '2';
  2355. $code = ($code - 2) / 3;
  2356. break;
  2357. }
  2358. }
  2359. } while($code != 0);
  2360. $seq = strrev($seq);
  2361. $k = 0;
  2362. $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 2, 'bcode' => array());
  2363. $len = strlen($seq);
  2364. for ($i = 0; $i < $len; ++$i) {
  2365. switch ($seq{$i}) {
  2366. case '1': {
  2367. $p = 1;
  2368. $h = 1;
  2369. break;
  2370. }
  2371. case '2': {
  2372. $p = 0;
  2373. $h = 1;
  2374. break;
  2375. }
  2376. case '3': {
  2377. $p = 0;
  2378. $h = 2;
  2379. break;
  2380. }
  2381. }
  2382. $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
  2383. $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
  2384. $bararray['maxw'] += 2;
  2385. }
  2386. unset($bararray['bcode'][($k - 1)]);
  2387. --$bararray['maxw'];
  2388. return $bararray;
  2389. }
  2390. /**
  2391. * IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200
  2392. * (requires PHP bcmath extension)
  2393. * Intelligent Mail barcode is a 65-bar code for use on mail in the United States.
  2394. * The fields are described as follows:<ul><li>The Barcode Identifier shall be assigned by USPS to encode the presort identification that is currently printed in human readable form on the optional endorsement line (OEL) as well as for future USPS use. This shall be two digits, with the second digit in the range of 0–4. The allowable encoding ranges shall be 00–04, 10–14, 20–24, 30–34, 40–44, 50–54, 60–64, 70–74, 80–84, and 90–94.</li><li>The Service Type Identifier shall be assigned by USPS for any combination of services requested on the mailpiece. The allowable encoding range shall be 000http://it2.php.net/manual/en/function.dechex.php–999. Each 3-digit value shall correspond to a particular mail class with a particular combination of service(s). Each service program, such as OneCode Confirm and OneCode ACS, shall provide the list of Service Type Identifier values.</li><li>The Mailer or Customer Identifier shall be assigned by USPS as a unique, 6 or 9 digit number that identifies a business entity. The allowable encoding range for the 6 digit Mailer ID shall be 000000- 899999, while the allowable encoding range for the 9 digit Mailer ID shall be 900000000-999999999.</li><li>The Serial or Sequence Number shall be assigned by the mailer for uniquely identifying and tracking mailpieces. The allowable encoding range shall be 000000000–999999999 when used with a 6 digit Mailer ID and 000000-999999 when used with a 9 digit Mailer ID. e. The Delivery Point ZIP Code shall be assigned by the mailer for routing the mailpiece. This shall replace POSTNET for routing the mailpiece to its final delivery point. The length may be 0, 5, 9, or 11 digits. The allowable encoding ranges shall be no ZIP Code, 00000–99999, 000000000–999999999, and 00000000000–99999999999.</li></ul>
  2395. * @param $code (string) code to print, separate the ZIP (routing code) from the rest using a minus char '-' (BarcodeID_ServiceTypeID_MailerID_SerialNumber-RoutingCode)
  2396. * @return array barcode representation.
  2397. * @protected
  2398. */
  2399. protected function barcode_imb($code) {
  2400. $asc_chr = array(4,0,2,6,3,5,1,9,8,7,1,2,0,6,4,8,2,9,5,3,0,1,3,7,4,6,8,9,2,0,5,1,9,4,3,8,6,7,1,2,4,3,9,5,7,8,3,0,2,1,4,0,9,1,7,0,2,4,6,3,7,1,9,5,8);
  2401. $dsc_chr = array(7,1,9,5,8,0,2,4,6,3,5,8,9,7,3,0,6,1,7,4,6,8,9,2,5,1,7,5,4,3,8,7,6,0,2,5,4,9,3,0,1,6,8,2,0,4,5,9,6,7,5,2,6,3,8,5,1,9,8,7,4,0,2,6,3);
  2402. $asc_pos = array(3,0,8,11,1,12,8,11,10,6,4,12,2,7,9,6,7,9,2,8,4,0,12,7,10,9,0,7,10,5,7,9,6,8,2,12,1,4,2,0,1,5,4,6,12,1,0,9,4,7,5,10,2,6,9,11,2,12,6,7,5,11,0,3,2);
  2403. $dsc_pos = array(2,10,12,5,9,1,5,4,3,9,11,5,10,1,6,3,4,1,10,0,2,11,8,6,1,12,3,8,6,4,4,11,0,6,1,9,11,5,3,7,3,10,7,11,8,2,10,3,5,8,0,3,12,11,8,4,5,1,3,0,7,12,9,8,10);
  2404. $code_arr = explode('-', $code);
  2405. $tracking_number = $code_arr[0];
  2406. if (isset($code_arr[1])) {
  2407. $routing_code = $code_arr[1];
  2408. } else {
  2409. $routing_code = '';
  2410. }
  2411. // Conversion of Routing Code
  2412. switch (strlen($routing_code)) {
  2413. case 0: {
  2414. $binary_code = 0;
  2415. break;
  2416. }
  2417. case 5: {
  2418. $binary_code = bcadd($routing_code, '1');
  2419. break;
  2420. }
  2421. case 9: {
  2422. $binary_code = bcadd($routing_code, '100001');
  2423. break;
  2424. }
  2425. case 11: {
  2426. $binary_code = bcadd($routing_code, '1000100001');
  2427. break;
  2428. }
  2429. default: {
  2430. return false;
  2431. break;
  2432. }
  2433. }
  2434. $binary_code = bcmul($binary_code, 10);
  2435. $binary_code = bcadd($binary_code, $tracking_number{0});
  2436. $binary_code = bcmul($binary_code, 5);
  2437. $binary_code = bcadd($binary_code, $tracking_number{1});
  2438. $binary_code .= substr($tracking_number, 2, 18);
  2439. // convert to hexadecimal
  2440. $binary_code = $this->dec_to_hex($binary_code);
  2441. // pad to get 13 bytes
  2442. $binary_code = str_pad($binary_code, 26, '0', STR_PAD_LEFT);
  2443. // convert string to array of bytes
  2444. $binary_code_arr = chunk_split($binary_code, 2, "\r");
  2445. $binary_code_arr = substr($binary_code_arr, 0, -1);
  2446. $binary_code_arr = explode("\r", $binary_code_arr);
  2447. // calculate frame check sequence
  2448. $fcs = $this->imb_crc11fcs($binary_code_arr);
  2449. // exclude first 2 bits from first byte
  2450. $first_byte = sprintf('%2s', dechex((hexdec($binary_code_arr[0]) << 2) >> 2));
  2451. $binary_code_102bit = $first_byte.substr($binary_code, 2);
  2452. // convert binary data to codewords
  2453. $codewords = array();
  2454. $data = $this->hex_to_dec($binary_code_102bit);
  2455. $codewords[0] = bcmod($data, 636) * 2;
  2456. $data = bcdiv($data, 636);
  2457. for ($i = 1; $i < 9; ++$i) {
  2458. $codewords[$i] = bcmod($data, 1365);
  2459. $data = bcdiv($data, 1365);
  2460. }
  2461. $codewords[9] = $data;
  2462. if (($fcs >> 10) == 1) {
  2463. $codewords[9] += 659;
  2464. }
  2465. // generate lookup tables
  2466. $table2of13 = $this->imb_tables(2, 78);
  2467. $table5of13 = $this->imb_tables(5, 1287);
  2468. // convert codewords to characters
  2469. $characters = array();
  2470. $bitmask = 512;
  2471. foreach($codewords as $k => $val) {
  2472. if ($val <= 1286) {
  2473. $chrcode = $table5of13[$val];
  2474. } else {
  2475. $chrcode = $table2of13[($val - 1287)];
  2476. }
  2477. if (($fcs & $bitmask) > 0) {
  2478. // bitwise invert
  2479. $chrcode = ((~$chrcode) & 8191);
  2480. }
  2481. $characters[] = $chrcode;
  2482. $bitmask /= 2;
  2483. }
  2484. $characters = array_reverse($characters);
  2485. // build bars
  2486. $k = 0;
  2487. $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array());
  2488. for ($i = 0; $i < 65; ++$i) {
  2489. $asc = (($characters[$asc_chr[$i]] & pow(2, $asc_pos[$i])) > 0);
  2490. $dsc = (($characters[$dsc_chr[$i]] & pow(2, $dsc_pos[$i])) > 0);
  2491. if ($asc AND $dsc) {
  2492. // full bar (F)
  2493. $p = 0;
  2494. $h = 3;
  2495. } elseif ($asc) {
  2496. // ascender (A)
  2497. $p = 0;
  2498. $h = 2;
  2499. } elseif ($dsc) {
  2500. // descender (D)
  2501. $p = 1;
  2502. $h = 2;
  2503. } else {
  2504. // tracker (T)
  2505. $p = 1;
  2506. $h = 1;
  2507. }
  2508. $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
  2509. $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
  2510. $bararray['maxw'] += 2;
  2511. }
  2512. unset($bararray['bcode'][($k - 1)]);
  2513. --$bararray['maxw'];
  2514. return $bararray;
  2515. }
  2516. /**
  2517. * Convert large integer number to hexadecimal representation.
  2518. * (requires PHP bcmath extension)
  2519. * @param $number (string) number to convert specified as a string
  2520. * @return string hexadecimal representation
  2521. */
  2522. public function dec_to_hex($number) {
  2523. $i = 0;
  2524. $hex = array();
  2525. if($number == 0) {
  2526. return '00';
  2527. }
  2528. while($number > 0) {
  2529. if($number == 0) {
  2530. array_push($hex, '0');
  2531. } else {
  2532. array_push($hex, strtoupper(dechex(bcmod($number, '16'))));
  2533. $number = bcdiv($number, '16', 0);
  2534. }
  2535. }
  2536. $hex = array_reverse($hex);
  2537. return implode($hex);
  2538. }
  2539. /**
  2540. * Convert large hexadecimal number to decimal representation (string).
  2541. * (requires PHP bcmath extension)
  2542. * @param $hex (string) hexadecimal number to convert specified as a string
  2543. * @return string hexadecimal representation
  2544. */
  2545. public function hex_to_dec($hex) {
  2546. $dec = 0;
  2547. $bitval = 1;
  2548. $len = strlen($hex);
  2549. for($pos = ($len - 1); $pos >= 0; --$pos) {
  2550. $dec = bcadd($dec, bcmul(hexdec($hex{$pos}), $bitval));
  2551. $bitval = bcmul($bitval, 16);
  2552. }
  2553. return $dec;
  2554. }
  2555. /**
  2556. * Intelligent Mail Barcode calculation of Frame Check Sequence
  2557. * @param $code_arr (string) array of hexadecimal values (13 bytes holding 102 bits right justified).
  2558. * @return int 11 bit Frame Check Sequence as integer (decimal base)
  2559. * @protected
  2560. */
  2561. protected function imb_crc11fcs($code_arr) {
  2562. $genpoly = 0x0F35; // generator polynomial
  2563. $fcs = 0x07FF; // Frame Check Sequence
  2564. // do most significant byte skipping the 2 most significant bits
  2565. $data = hexdec($code_arr[0]) << 5;
  2566. for ($bit = 2; $bit < 8; ++$bit) {
  2567. if (($fcs ^ $data) & 0x400) {
  2568. $fcs = ($fcs << 1) ^ $genpoly;
  2569. } else {
  2570. $fcs = ($fcs << 1);
  2571. }
  2572. $fcs &= 0x7FF;
  2573. $data <<= 1;
  2574. }
  2575. // do rest of bytes
  2576. for ($byte = 1; $byte < 13; ++$byte) {
  2577. $data = hexdec($code_arr[$byte]) << 3;
  2578. for ($bit = 0; $bit < 8; ++$bit) {
  2579. if (($fcs ^ $data) & 0x400) {
  2580. $fcs = ($fcs << 1) ^ $genpoly;
  2581. } else {
  2582. $fcs = ($fcs << 1);
  2583. }
  2584. $fcs &= 0x7FF;
  2585. $data <<= 1;
  2586. }
  2587. }
  2588. return $fcs;
  2589. }
  2590. /**
  2591. * Reverse unsigned short value
  2592. * @param $num (int) value to reversr
  2593. * @return int reversed value
  2594. * @protected
  2595. */
  2596. protected function imb_reverse_us($num) {
  2597. $rev = 0;
  2598. for ($i = 0; $i < 16; ++$i) {
  2599. $rev <<= 1;
  2600. $rev |= ($num & 1);
  2601. $num >>= 1;
  2602. }
  2603. return $rev;
  2604. }
  2605. /**
  2606. * generate Nof13 tables used for Intelligent Mail Barcode
  2607. * @param $n (int) is the type of table: 2 for 2of13 table, 5 for 5of13table
  2608. * @param $size (int) size of table (78 for n=2 and 1287 for n=5)
  2609. * @return array requested table
  2610. * @protected
  2611. */
  2612. protected function imb_tables($n, $size) {
  2613. $table = array();
  2614. $lli = 0; // LUT lower index
  2615. $lui = $size - 1; // LUT upper index
  2616. for ($count = 0; $count < 8192; ++$count) {
  2617. $bit_count = 0;
  2618. for ($bit_index = 0; $bit_index < 13; ++$bit_index) {
  2619. $bit_count += intval(($count & (1 << $bit_index)) != 0);
  2620. }
  2621. // if we don't have the right number of bits on, go on to the next value
  2622. if ($bit_count == $n) {
  2623. $reverse = ($this->imb_reverse_us($count) >> 3);
  2624. // if the reverse is less than count, we have already visited this pair before
  2625. if ($reverse >= $count) {
  2626. // If count is symmetric, place it at the first free slot from the end of the list.
  2627. // Otherwise, place it at the first free slot from the beginning of the list AND place $reverse ath the next free slot from the beginning of the list
  2628. if ($reverse == $count) {
  2629. $table[$lui] = $count;
  2630. --$lui;
  2631. } else {
  2632. $table[$lli] = $count;
  2633. ++$lli;
  2634. $table[$lli] = $reverse;
  2635. ++$lli;
  2636. }
  2637. }
  2638. }
  2639. }
  2640. return $table;
  2641. }
  2642. public function checkfile($path) {
  2643. if (file_exists($path)) {
  2644. $base_name = pathinfo($path, PATHINFO_BASENAME);
  2645. return $this->checkfile(str_replace($base_name, rand(0, 9999) . $base_name, $path));
  2646. } else {
  2647. return $path;
  2648. }
  2649. }
  2650. } // end of class
  2651. //============================================================+
  2652. // END OF FILE
  2653. //============================================================+