BCGcode93.barcode.php 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. <?php
  2. /**
  3. *--------------------------------------------------------------------
  4. *
  5. * Sub-Class - Code 93
  6. *
  7. * !! Warning !!
  8. * If you display the checksum on the barcode, you may obtain
  9. * some garbage since some characters are not displayable.
  10. *
  11. *--------------------------------------------------------------------
  12. * Copyright (C) Jean-Sebastien Goupil
  13. * http://www.barcodephp.com
  14. */
  15. include_once('BCGParseException.php');
  16. include_once('BCGBarcode1D.php');
  17. class BCGcode93 extends BCGBarcode1D {
  18. const EXTENDED_1 = 43;
  19. const EXTENDED_2 = 44;
  20. const EXTENDED_3 = 45;
  21. const EXTENDED_4 = 46;
  22. private $starting, $ending;
  23. private $indcheck, $data;
  24. /**
  25. * Constructor.
  26. */
  27. public function __construct() {
  28. parent::__construct();
  29. $this->starting = $this->ending = 47; /* * */
  30. $this->keys = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%', '($)', '(%)', '(/)', '(+)', '(*)');
  31. $this->code = array(
  32. '020001', /* 0 */
  33. '000102', /* 1 */
  34. '000201', /* 2 */
  35. '000300', /* 3 */
  36. '010002', /* 4 */
  37. '010101', /* 5 */
  38. '010200', /* 6 */
  39. '000003', /* 7 */
  40. '020100', /* 8 */
  41. '030000', /* 9 */
  42. '100002', /* A */
  43. '100101', /* B */
  44. '100200', /* C */
  45. '110001', /* D */
  46. '110100', /* E */
  47. '120000', /* F */
  48. '001002', /* G */
  49. '001101', /* H */
  50. '001200', /* I */
  51. '011001', /* J */
  52. '021000', /* K */
  53. '000012', /* L */
  54. '000111', /* M */
  55. '000210', /* N */
  56. '010011', /* O */
  57. '020010', /* P */
  58. '101001', /* Q */
  59. '101100', /* R */
  60. '100011', /* S */
  61. '100110', /* T */
  62. '110010', /* U */
  63. '111000', /* V */
  64. '001011', /* W */
  65. '001110', /* X */
  66. '011010', /* Y */
  67. '012000', /* Z */
  68. '010020', /* - */
  69. '200001', /* . */
  70. '200100', /* */
  71. '210000', /* $ */
  72. '001020', /* / */
  73. '002010', /* + */
  74. '100020', /* % */
  75. '010110', /*($)*/
  76. '201000', /*(%)*/
  77. '200010', /*(/)*/
  78. '011100', /*(+)*/
  79. '000030' /*(*)*/
  80. );
  81. }
  82. /**
  83. * Parses the text before displaying it.
  84. *
  85. * @param mixed $text
  86. */
  87. public function parse($text) {
  88. $this->text = $text;
  89. $data = array();
  90. $indcheck = array();
  91. $c = strlen($this->text);
  92. for ($i = 0; $i < $c; $i++) {
  93. $pos = array_search($this->text[$i], $this->keys);
  94. if ($pos === false) {
  95. // Search in extended?
  96. $extended = self::getExtendedVersion($this->text[$i]);
  97. if ($extended === false) {
  98. throw new BCGParseException('code93', 'The character \'' . $this->text[$i] . '\' is not allowed.');
  99. } else {
  100. $extc = strlen($extended);
  101. for ($j = 0; $j < $extc; $j++) {
  102. $v = $extended[$j];
  103. if ($v === '$') {
  104. $indcheck[] = self::EXTENDED_1;
  105. $data[] = $this->code[self::EXTENDED_1];
  106. } elseif ($v === '%') {
  107. $indcheck[] = self::EXTENDED_2;
  108. $data[] = $this->code[self::EXTENDED_2];
  109. } elseif ($v === '/') {
  110. $indcheck[] = self::EXTENDED_3;
  111. $data[] = $this->code[self::EXTENDED_3];
  112. } elseif ($v === '+') {
  113. $indcheck[] = self::EXTENDED_4;
  114. $data[] = $this->code[self::EXTENDED_4];
  115. } else {
  116. $pos2 = array_search($v, $this->keys);
  117. $indcheck[] = $pos2;
  118. $data[] = $this->code[$pos2];
  119. }
  120. }
  121. }
  122. } else {
  123. $indcheck[] = $pos;
  124. $data[] = $this->code[$pos];
  125. }
  126. }
  127. $this->setData(array($indcheck, $data));
  128. $this->addDefaultLabel();
  129. }
  130. /**
  131. * Draws the barcode.
  132. *
  133. * @param resource $im
  134. */
  135. public function draw($im) {
  136. // Starting *
  137. $this->drawChar($im, $this->code[$this->starting], true);
  138. $c = count($this->data);
  139. for ($i = 0; $i < $c; $i++) {
  140. $this->drawChar($im, $this->data[$i], true);
  141. }
  142. // Checksum
  143. $c = count($this->checksumValue);
  144. for ($i = 0; $i < $c; $i++) {
  145. $this->drawChar($im, $this->code[$this->checksumValue[$i]], true);
  146. }
  147. // Ending *
  148. $this->drawChar($im, $this->code[$this->ending], true);
  149. // Draw a Final Bar
  150. $this->drawChar($im, '0', true);
  151. $this->drawText($im, 0, 0, $this->positionX, $this->thickness);
  152. }
  153. /**
  154. * Returns the maximal size of a barcode.
  155. *
  156. * @param int $w
  157. * @param int $h
  158. * @return int[]
  159. */
  160. public function getDimension($w, $h) {
  161. $startlength = 9;
  162. $textlength = 9 * count($this->data);
  163. $checksumlength = 2 * 9;
  164. $endlength = 9 + 1; // + final bar
  165. $w += $startlength + $textlength + $checksumlength + $endlength;
  166. $h += $this->thickness;
  167. return parent::getDimension($w, $h);
  168. }
  169. /**
  170. * Validates the input.
  171. */
  172. protected function validate() {
  173. $c = count($this->data);
  174. if ($c === 0) {
  175. throw new BCGParseException('code93', 'No data has been entered.');
  176. }
  177. parent::validate();
  178. }
  179. /**
  180. * Overloaded method to calculate checksum.
  181. */
  182. protected function calculateChecksum() {
  183. // Checksum
  184. // First CheckSUM "C"
  185. // The "C" checksum character is the modulo 47 remainder of the sum of the weighted
  186. // value of the data characters. The weighting value starts at "1" for the right-most
  187. // data character, 2 for the second to last, 3 for the third-to-last, and so on up to 20.
  188. // After 20, the sequence wraps around back to 1.
  189. // Second CheckSUM "K"
  190. // Same as CheckSUM "C" but we count the CheckSum "C" at the end
  191. // After 15, the sequence wraps around back to 1.
  192. $sequence_multiplier = array(20, 15);
  193. $this->checksumValue = array();
  194. $indcheck = $this->indcheck;
  195. for ($z = 0; $z < 2; $z++) {
  196. $checksum = 0;
  197. for ($i = count($indcheck), $j = 0; $i > 0; $i--, $j++) {
  198. $multiplier = $i % $sequence_multiplier[$z];
  199. if ($multiplier === 0) {
  200. $multiplier = $sequence_multiplier[$z];
  201. }
  202. $checksum += $indcheck[$j] * $multiplier;
  203. }
  204. $this->checksumValue[$z] = $checksum % 47;
  205. $indcheck[] = $this->checksumValue[$z];
  206. }
  207. }
  208. /**
  209. * Overloaded method to display the checksum.
  210. */
  211. protected function processChecksum() {
  212. if ($this->checksumValue === false) { // Calculate the checksum only once
  213. $this->calculateChecksum();
  214. }
  215. if ($this->checksumValue !== false) {
  216. $ret = '';
  217. $c = count($this->checksumValue);
  218. for ($i = 0; $i < $c; $i++) {
  219. $ret .= $this->keys[$this->checksumValue[$i]];
  220. }
  221. return $ret;
  222. }
  223. return false;
  224. }
  225. /**
  226. * Saves data into the classes.
  227. *
  228. * This method will save data, calculate real column number
  229. * (if -1 was selected), the real error level (if -1 was
  230. * selected)... It will add Padding to the end and generate
  231. * the error codes.
  232. *
  233. * @param array $data
  234. */
  235. private function setData($data) {
  236. $this->indcheck = $data[0];
  237. $this->data = $data[1];
  238. $this->calculateChecksum();
  239. }
  240. /**
  241. * Returns the extended reprensentation of the character.
  242. *
  243. * @param string $char
  244. * @return string
  245. */
  246. private static function getExtendedVersion($char) {
  247. $o = ord($char);
  248. if ($o === 0) {
  249. return '%U';
  250. } elseif ($o >= 1 && $o <= 26) {
  251. return '$' . chr($o + 64);
  252. } elseif (($o >= 33 && $o <= 44) || $o === 47 || $o === 48) {
  253. return '/' . chr($o + 32);
  254. } elseif ($o >= 97 && $o <= 122) {
  255. return '+' . chr($o - 32);
  256. } elseif ($o >= 27 && $o <= 31) {
  257. return '%' . chr($o + 38);
  258. } elseif ($o >= 59 && $o <= 63) {
  259. return '%' . chr($o + 11);
  260. } elseif ($o >= 91 && $o <= 95) {
  261. return '%' . chr($o - 16);
  262. } elseif ($o >= 123 && $o <= 127) {
  263. return '%' . chr($o - 43);
  264. } elseif ($o === 64) {
  265. return '%V';
  266. } elseif ($o === 96) {
  267. return '%W';
  268. } elseif ($o > 127) {
  269. return false;
  270. } else {
  271. return $char;
  272. }
  273. }
  274. }
  275. ?>