1<?php 2 3namespace Mpdf\Barcode; 4 5/** 6 * CODE 93 - USS-93 7 * Compact code similar to Code 39 8 */ 9class Code93 extends \Mpdf\Barcode\AbstractBarcode implements \Mpdf\Barcode\BarcodeInterface 10{ 11 12 /** 13 * @param string $code 14 */ 15 public function __construct($code, $quiet_zone_left = null, $quiet_zone_right = null) 16 { 17 $this->init($code); 18 19 $this->data['nom-X'] = 0.381; // Nominal value for X-dim (bar width) in mm (2 X min. spec.) 20 $this->data['nom-H'] = 10; // Nominal value for Height of Full bar in mm (non-spec.) 21 $this->data['lightmL'] = ($quiet_zone_left !== null ? $quiet_zone_left : 10); // LEFT light margin = x X-dim (spec.) 22 $this->data['lightmR'] = ($quiet_zone_right !== null ? $quiet_zone_right : 10); // RIGHT light margin = x X-dim (spec.) 23 $this->data['lightTB'] = 0; // TOP/BOTTOM light margin = x X-dim (non-spec.) 24 } 25 26 /** 27 * @param string $code 28 */ 29 private function init($code) 30 { 31 $chr = [ 32 48 => '131112', // 0 33 49 => '111213', // 1 34 50 => '111312', // 2 35 51 => '111411', // 3 36 52 => '121113', // 4 37 53 => '121212', // 5 38 54 => '121311', // 6 39 55 => '111114', // 7 40 56 => '131211', // 8 41 57 => '141111', // 9 42 65 => '211113', // A 43 66 => '211212', // B 44 67 => '211311', // C 45 68 => '221112', // D 46 69 => '221211', // E 47 70 => '231111', // F 48 71 => '112113', // G 49 72 => '112212', // H 50 73 => '112311', // I 51 74 => '122112', // J 52 75 => '132111', // K 53 76 => '111123', // L 54 77 => '111222', // M 55 78 => '111321', // N 56 79 => '121122', // O 57 80 => '131121', // P 58 81 => '212112', // Q 59 82 => '212211', // R 60 83 => '211122', // S 61 84 => '211221', // T 62 85 => '221121', // U 63 86 => '222111', // V 64 87 => '112122', // W 65 88 => '112221', // X 66 89 => '122121', // Y 67 90 => '123111', // Z 68 45 => '121131', // - 69 46 => '311112', // . 70 32 => '311211', // 71 36 => '321111', // $ 72 47 => '112131', // / 73 43 => '113121', // + 74 37 => '211131', // % 75 128 => '121221', // ($) 76 129 => '311121', // (/) 77 130 => '122211', // (+) 78 131 => '312111', // (%) 79 42 => '111141', // start-stop 80 ]; 81 82 $code = strtoupper($code); 83 $encode = [ 84 chr(0) => chr(131) . 'U', chr(1) => chr(128) . 'A', chr(2) => chr(128) . 'B', chr(3) => chr(128) . 'C', 85 chr(4) => chr(128) . 'D', chr(5) => chr(128) . 'E', chr(6) => chr(128) . 'F', chr(7) => chr(128) . 'G', 86 chr(8) => chr(128) . 'H', chr(9) => chr(128) . 'I', chr(10) => chr(128) . 'J', chr(11) => '£K', 87 chr(12) => chr(128) . 'L', chr(13) => chr(128) . 'M', chr(14) => chr(128) . 'N', chr(15) => chr(128) . 'O', 88 chr(16) => chr(128) . 'P', chr(17) => chr(128) . 'Q', chr(18) => chr(128) . 'R', chr(19) => chr(128) . 'S', 89 chr(20) => chr(128) . 'T', chr(21) => chr(128) . 'U', chr(22) => chr(128) . 'V', chr(23) => chr(128) . 'W', 90 chr(24) => chr(128) . 'X', chr(25) => chr(128) . 'Y', chr(26) => chr(128) . 'Z', chr(27) => chr(131) . 'A', 91 chr(28) => chr(131) . 'B', chr(29) => chr(131) . 'C', chr(30) => chr(131) . 'D', chr(31) => chr(131) . 'E', 92 chr(32) => ' ', chr(33) => chr(129) . 'A', chr(34) => chr(129) . 'B', chr(35) => chr(129) . 'C', 93 chr(36) => chr(129) . 'D', chr(37) => chr(129) . 'E', chr(38) => chr(129) . 'F', chr(39) => chr(129) . 'G', 94 chr(40) => chr(129) . 'H', chr(41) => chr(129) . 'I', chr(42) => chr(129) . 'J', chr(43) => chr(129) . 'K', 95 chr(44) => chr(129) . 'L', chr(45) => '-', chr(46) => '.', chr(47) => chr(129) . 'O', 96 chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3', 97 chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7', 98 chr(56) => '8', chr(57) => '9', chr(58) => chr(129) . 'Z', chr(59) => chr(131) . 'F', 99 chr(60) => chr(131) . 'G', chr(61) => chr(131) . 'H', chr(62) => chr(131) . 'I', chr(63) => chr(131) . 'J', 100 chr(64) => chr(131) . 'V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C', 101 chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G', 102 chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K', 103 chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O', 104 chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S', 105 chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W', 106 chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => chr(131) . 'K', 107 chr(92) => chr(131) . 'L', chr(93) => chr(131) . 'M', chr(94) => chr(131) . 'N', chr(95) => chr(131) . 'O', 108 chr(96) => chr(131) . 'W', chr(97) => chr(130) . 'A', chr(98) => chr(130) . 'B', chr(99) => chr(130) . 'C', 109 chr(100) => chr(130) . 'D', chr(101) => chr(130) . 'E', chr(102) => chr(130) . 'F', chr(103) => chr(130) . 'G', 110 chr(104) => chr(130) . 'H', chr(105) => chr(130) . 'I', chr(106) => chr(130) . 'J', chr(107) => chr(130) . 'K', 111 chr(108) => chr(130) . 'L', chr(109) => chr(130) . 'M', chr(110) => chr(130) . 'N', chr(111) => chr(130) . 'O', 112 chr(112) => chr(130) . 'P', chr(113) => chr(130) . 'Q', chr(114) => chr(130) . 'R', chr(115) => chr(130) . 'S', 113 chr(116) => chr(130) . 'T', chr(117) => chr(130) . 'U', chr(118) => chr(130) . 'V', chr(119) => chr(130) . 'W', 114 chr(120) => chr(130) . 'X', chr(121) => chr(130) . 'Y', chr(122) => chr(130) . 'Z', chr(123) => chr(131) . 'P', 115 chr(124) => chr(131) . 'Q', chr(125) => chr(131) . 'R', chr(126) => chr(131) . 'S', chr(127) => chr(131) . 'T' 116 ]; 117 118 $code_ext = ''; 119 $clen = strlen($code); 120 121 for ($i = 0; $i < $clen; ++$i) { 122 if (ord($code[$i]) > 127) { 123 throw new \Mpdf\Barcode\BarcodeException(sprintf('Invalid character "%s" in CODE93 barcode value "%s"', $code[$i], $code)); 124 } 125 $code_ext .= $encode[$code[$i]]; 126 } 127 128 // checksum 129 $code_ext .= $this->checksum($code_ext); 130 131 // add start and stop codes 132 $code = '*' . $code_ext . '*'; 133 $bararray = ['code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => []]; 134 $k = 0; 135 $clen = strlen($code); 136 137 for ($i = 0; $i < $clen; ++$i) { 138 $char = ord($code[$i]); 139 if (!isset($chr[$char])) { 140 // invalid character 141 throw new \Mpdf\Barcode\BarcodeException(sprintf('Invalid CODE93 barcode value "%s"', $code)); 142 } 143 for ($j = 0; $j < 6; ++$j) { 144 if (($j % 2) == 0) { 145 $t = true; // bar 146 } else { 147 $t = false; // space 148 } 149 $w = $chr[$char][$j]; 150 $bararray['bcode'][$k] = ['t' => $t, 'w' => $w, 'h' => 1, 'p' => 0]; 151 $bararray['maxw'] += $w; 152 ++$k; 153 } 154 } 155 156 $bararray['bcode'][$k] = ['t' => true, 'w' => 1, 'h' => 1, 'p' => 0]; 157 $bararray['maxw'] += 1; 158 159 $this->data = $bararray; 160 } 161 162 /** 163 * Calculate CODE 93 checksum (modulo 47). 164 * 165 * @param string $code 166 * @return string 167 */ 168 protected function checksum($code) 169 { 170 $chars = [ 171 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 172 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 173 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 174 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%', 175 '<', '=', '>', '?' 176 ]; 177 178 // translate special characters 179 $code = strtr($code, chr(128) . chr(131) . chr(129) . chr(130), '<=>?'); 180 $len = strlen($code); 181 182 // calculate check digit C 183 $p = 1; 184 $check = 0; 185 for ($i = ($len - 1); $i >= 0; --$i) { 186 $k = array_keys($chars, $code[$i]); 187 $check += ($k[0] * $p); 188 ++$p; 189 if ($p > 20) { 190 $p = 1; 191 } 192 } 193 $check %= 47; 194 $c = $chars[$check]; 195 $code .= $c; 196 197 // calculate check digit K 198 $p = 1; 199 $check = 0; 200 for ($i = $len; $i >= 0; --$i) { 201 $k = array_keys($chars, $code[$i]); 202 $check += ($k[0] * $p); 203 ++$p; 204 if ($p > 15) { 205 $p = 1; 206 } 207 } 208 $check %= 47; 209 $k = $chars[$check]; 210 $checksum = $c . $k; 211 212 // resto respecial characters 213 $checksum = strtr($checksum, '<=>?', chr(128) . chr(131) . chr(129) . chr(130)); 214 215 return $checksum; 216 } 217 218 /** 219 * @inheritdoc 220 */ 221 public function getType() 222 { 223 return 'CODE93'; 224 } 225 226} 227