|
1 <?php |
|
2 /** |
|
3 * Zend Framework |
|
4 * |
|
5 * LICENSE |
|
6 * |
|
7 * This source file is subject to the new BSD license that is bundled |
|
8 * with this package in the file LICENSE.txt. |
|
9 * It is also available through the world-wide-web at this URL: |
|
10 * http://framework.zend.com/license/new-bsd |
|
11 * If you did not receive a copy of the license and are unable to |
|
12 * obtain it through the world-wide-web, please send an email |
|
13 * to license@zend.com so we can send you a copy immediately. |
|
14 * |
|
15 * @category Zend |
|
16 * @package Zend_Barcode |
|
17 * @subpackage Object |
|
18 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
19 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
20 * @version $Id: Code25.php 20096 2010-01-06 02:05:09Z bkarwin $ |
|
21 */ |
|
22 |
|
23 /** |
|
24 * @see Zend_Barcode_Object_ObjectAbstract |
|
25 */ |
|
26 require_once 'Zend/Barcode/Object/ObjectAbstract.php'; |
|
27 |
|
28 /** |
|
29 * @see Zend_Validate_Barcode |
|
30 */ |
|
31 require_once 'Zend/Validate/Barcode.php'; |
|
32 |
|
33 /** |
|
34 * Class for generate Code128 barcode |
|
35 * |
|
36 * @category Zend |
|
37 * @package Zend_Barcode |
|
38 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
39 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
40 */ |
|
41 class Zend_Barcode_Object_Code128 extends Zend_Barcode_Object_ObjectAbstract |
|
42 { |
|
43 /** |
|
44 * Drawing of checksum |
|
45 * (even if it's sometime optional, most of time it's required) |
|
46 * @var boolean |
|
47 */ |
|
48 protected $_withChecksum = true; |
|
49 |
|
50 /** |
|
51 * @var array |
|
52 */ |
|
53 protected $_convertedText = array(); |
|
54 |
|
55 protected $_codingMap = array( |
|
56 0 => "11011001100", 1 => "11001101100", 2 => "11001100110", |
|
57 3 => "10010011000", 4 => "10010001100", 5 => "10001001100", |
|
58 6 => "10011001000", 7 => "10011000100", 8 => "10001100100", |
|
59 9 => "11001001000", 10 => "11001000100", 11 => "11000100100", |
|
60 12 => "10110011100", 13 => "10011011100", 14 => "10011001110", |
|
61 15 => "10111001100", 16 => "10011101100", 17 => "10011100110", |
|
62 18 => "11001110010", 19 => "11001011100", 20 => "11001001110", |
|
63 21 => "11011100100", 22 => "11001110100", 23 => "11101101110", |
|
64 24 => "11101001100", 25 => "11100101100", 26 => "11100100110", |
|
65 27 => "11101100100", 28 => "11100110100", 29 => "11100110010", |
|
66 30 => "11011011000", 31 => "11011000110", 32 => "11000110110", |
|
67 33 => "10100011000", 34 => "10001011000", 35 => "10001000110", |
|
68 36 => "10110001000", 37 => "10001101000", 38 => "10001100010", |
|
69 39 => "11010001000", 40 => "11000101000", 41 => "11000100010", |
|
70 42 => "10110111000", 43 => "10110001110", 44 => "10001101110", |
|
71 45 => "10111011000", 46 => "10111000110", 47 => "10001110110", |
|
72 48 => "11101110110", 49 => "11010001110", 50 => "11000101110", |
|
73 51 => "11011101000", 52 => "11011100010", 53 => "11011101110", |
|
74 54 => "11101011000", 55 => "11101000110", 56 => "11100010110", |
|
75 57 => "11101101000", 58 => "11101100010", 59 => "11100011010", |
|
76 60 => "11101111010", 61 => "11001000010", 62 => "11110001010", |
|
77 63 => "10100110000", 64 => "10100001100", 65 => "10010110000", |
|
78 66 => "10010000110", 67 => "10000101100", 68 => "10000100110", |
|
79 69 => "10110010000", 70 => "10110000100", 71 => "10011010000", |
|
80 72 => "10011000010", 73 => "10000110100", 74 => "10000110010", |
|
81 75 => "11000010010", 76 => "11001010000", 77 => "11110111010", |
|
82 78 => "11000010100", 79 => "10001111010", 80 => "10100111100", |
|
83 81 => "10010111100", 82 => "10010011110", 83 => "10111100100", |
|
84 84 => "10011110100", 85 => "10011110010", 86 => "11110100100", |
|
85 87 => "11110010100", 88 => "11110010010", 89 => "11011011110", |
|
86 90 => "11011110110", 91 => "11110110110", 92 => "10101111000", |
|
87 93 => "10100011110", 94 => "10001011110", 95 => "10111101000", |
|
88 96 => "10111100010", 97 => "11110101000", 98 => "11110100010", |
|
89 99 => "10111011110", 100 => "10111101110", 101 => "11101011110", |
|
90 102 => "11110101110", |
|
91 103 => "11010000100", 104 => "11010010000", 105 => "11010011100", |
|
92 106 => "1100011101011"); |
|
93 |
|
94 /** |
|
95 * Character sets ABC |
|
96 * @var array |
|
97 */ |
|
98 protected $_charSets = array( |
|
99 'A' => array( |
|
100 ' ', '!', '"', '#', '$', '%', '&', "'", |
|
101 '(', ')', '*', '+', ',', '-', '.', '/', |
|
102 '0', '1', '2', '3', '4', '5', '6', '7', |
|
103 '8', '9', ':', ';', '<', '=', '>', '?', |
|
104 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', |
|
105 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', |
|
106 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', |
|
107 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', |
|
108 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
|
109 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, |
|
110 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, |
|
111 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, |
|
112 'FNC3', 'FNC2', 'SHIFT', 'Code C', 'Code B', 'FNC4', 'FNC1', |
|
113 'START A', 'START B', 'START C', 'STOP'), |
|
114 'B' => array( |
|
115 ' ', '!', '"', '#', '$', '%', '&', "'", |
|
116 '(', ')', '*', '+', ',', '-', '.', '/', |
|
117 '0', '1', '2', '3', '4', '5', '6', '7', |
|
118 '8', '9', ':', ';', '<', '=', '>', '?', |
|
119 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', |
|
120 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', |
|
121 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', |
|
122 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', |
|
123 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', |
|
124 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', |
|
125 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', |
|
126 'x', 'y', 'z', '{', '|', '}', '~', 0x7F, |
|
127 'FNC3', 'FNC2', 'SHIFT', 'Code C', 'FNC4', 'Code A', 'FNC1', |
|
128 'START A', 'START B', 'START C', 'STOP',), |
|
129 'C' => array( |
|
130 '00', '01', '02', '03', '04', '05', '06', '07', '08', '09', |
|
131 '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', |
|
132 '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', |
|
133 '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', |
|
134 '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', |
|
135 '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', |
|
136 '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', |
|
137 '70', '71', '72', '73', '74', '75', '76', '77', '78', '79', |
|
138 '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', |
|
139 '90', '91', '92', '93', '94', '95', '96', '97', '98', '99', |
|
140 'Code B', 'Code A', 'FNC1', 'START A', 'START B', 'START C', 'STOP')); |
|
141 /*'A' => array( |
|
142 ' '=>0, '!'=>1, '"'=>2, '#'=>3, '$'=>4, '%'=>5, '&'=>6, "'"=>7, |
|
143 '('=>8, ')'=>9, '*'=>10, '+'=>11, ','=>12, '-'=>13, '.'=>14, '/'=>15, |
|
144 '0'=>16, '1'=>17, '2'=>18, '3'=>19, '4'=>20, '5'=>21, '6'=>22, '7'=>23, |
|
145 '8'=>24, '9'=>25, ':'=>26, ';'=>27, '<'=>28, '='=>29, '>'=>30, '?'=>31, |
|
146 '@'=>32, 'A'=>33, 'B'=>34, 'C'=>35, 'D'=>36, 'E'=>37, 'F'=>38, 'G'=>39, |
|
147 'H'=>40, 'I'=>41, 'J'=>42, 'K'=>43, 'L'=>44, 'M'=>45, 'N'=>46, 'O'=>47, |
|
148 'P'=>48, 'Q'=>49, 'R'=>50, 'S'=>51, 'T'=>52, 'U'=>53, 'V'=>54, 'W'=>55, |
|
149 'X'=>56, 'Y'=>57, 'Z'=>58, '['=>59, '\\'=>60, ']'=>61, '^'=>62, '_'=>63, |
|
150 0x00=>64, 0x01=>65, 0x02=>66, 0x03=>67, 0x04=>68, 0x05=>69, 0x06=>70, 0x07=>71, |
|
151 0x08=>72, 0x09=>73, 0x0A=>74, 0x0B=>75, 0x0C=>76, 0x0D=>77, 0x0E=>78, 0x0F=>79, |
|
152 0x10=>80, 0x11=>81, 0x12=>82, 0x13=>83, 0x14=>84, 0x15=>85, 0x16=>86, 0x17=>87, |
|
153 0x18=>88, 0x19=>89, 0x1A=>90, 0x1B=>91, 0x1C=>92, 0x1D=>93, 0x1E=>94, 0x1F=>95, |
|
154 'FNC3'=>96, 'FNC2'=>97, 'SHIFT'=>98, 'Code C'=>99, 'Code B'=>100, 'FNC4'=>101, 'FNC1'=>102, 'START A'=>103, |
|
155 'START B'=>104, 'START C'=>105, 'STOP'=>106), |
|
156 'B' => array( |
|
157 ' '=>0, '!'=>1, '"'=>2, '#'=>3, '$'=>4, '%'=>5, '&'=>6, "'"=>7, |
|
158 '('=>8, ')'=>9, '*'=>10, '+'=>11, ','=>12, '-'=>13, '.'=>14, '/'=>15, |
|
159 '0'=>16, '1'=>17, '2'=>18, '3'=>19, '4'=>20, '5'=>21, '6'=>22, '7'=>23, |
|
160 '8'=>24, '9'=>25, ':'=>26, ';'=>27, '<'=>28, '='=>29, '>'=>30, '?'=>31, |
|
161 '@'=>32, 'A'=>33, 'B'=>34, 'C'=>35, 'D'=>36, 'E'=>37, 'F'=>38, 'G'=>39, |
|
162 'H'=>40, 'I'=>41, 'J'=>42, 'K'=>43, 'L'=>44, 'M'=>45, 'N'=>46, 'O'=>47, |
|
163 'P'=>48, 'Q'=>49, 'R'=>50, 'S'=>51, 'T'=>52, 'U'=>53, 'V'=>54, 'W'=>55, |
|
164 'X'=>56, 'Y'=>57, 'Z'=>58, '['=>59, '\\'=>60, ']'=>61, '^'=>62, '_'=>63, |
|
165 '`' =>64, 'a'=>65, 'b'=>66, 'c'=>67, 'd'=>68, 'e'=>69, 'f'=>70, 'g'=>71, |
|
166 'h'=>72, 'i'=>73, 'j'=>74, 'k'=>75, 'l'=>76, 'm'=>77, 'n'=>78, 'o'=>79, |
|
167 'p'=>80, 'q'=>81, 'r'=>82, 's'=>83, 't'=>84, 'u'=>85, 'v'=>86, 'w'=>87, |
|
168 'x'=>88, 'y'=>89, 'z'=>90, '{'=>91, '|'=>92, '}'=>93, '~'=>94, 0x7F=>95, |
|
169 'FNC3'=>96, 'FNC2'=>97, 'SHIFT'=>98, 'Code C'=>99, 'FNC4'=>100, 'Code A'=>101, 'FNC1'=>102, 'START A'=>103, |
|
170 'START B'=>104, 'START C'=>105, 'STOP'=>106,), |
|
171 'C' => array( |
|
172 '00'=>0, '01'=>1, '02'=>2, '03'=>3, '04'=>4, '05'=>5, '06'=>6, '07'=>7, '08'=>8, '09'=>9, |
|
173 '10'=>10, '11'=>11, '12'=>12, '13'=>13, '14'=>14, '15'=>15, '16'=>16, '17'=>17, '18'=>18, '19'=>19, |
|
174 '20'=>20, '21'=>21, '22'=>22, '23'=>23, '24'=>24, '25'=>25, '26'=>26, '27'=>27, '28'=>28, '29'=>29, |
|
175 '30'=>30, '31'=>31, '32'=>32, '33'=>33, '34'=>34, '35'=>35, '36'=>36, '37'=>37, '38'=>38, '39'=>39, |
|
176 '40'=>40, '41'=>41, '42'=>42, '43'=>43, '44'=>44, '45'=>45, '46'=>46, '47'=>47, '48'=>48, '49'=>49, |
|
177 '50'=>50, '51'=>51, '52'=>52, '53'=>53, '54'=>54, '55'=>55, '56'=>56, '57'=>57, '58'=>58, '59'=>59, |
|
178 '60'=>60, '61'=>61, '62'=>62, '63'=>63, '64'=>64, '65'=>65, '66'=>66, '67'=>67, '68'=>68, '69'=>69, |
|
179 '70'=>70, '71'=>71, '72'=>72, '73'=>73, '74'=>74, '75'=>75, '76'=>76, '77'=>77, '78'=>78, '79'=>79, |
|
180 '80'=>80, '81'=>81, '82'=>82, '83'=>83, '84'=>84, '85'=>85, '86'=>86, '87'=>87, '88'=>88, '89'=>89, |
|
181 '90'=>90, '91'=>91, '92'=>92, '93'=>93, '94'=>94, '95'=>95, '96'=>96, '97'=>97, '98'=>98, '99'=>99, |
|
182 'Code B'=>100, 'Code A'=>101, 'FNC1'=>102, 'START A'=>103, 'START B'=>104, 'START C'=>105, 'STOP'=>106));*/ |
|
183 |
|
184 /** |
|
185 * Width of the barcode (in pixels) |
|
186 * @return integer |
|
187 */ |
|
188 protected function _calculateBarcodeWidth() |
|
189 { |
|
190 $quietZone = $this->getQuietZone(); |
|
191 // Each characters contain 11 bars... |
|
192 $characterLength = 11 * $this->_barThinWidth * $this->_factor; |
|
193 $convertedChars = count($this->_convertToBarcodeChars($this->getText())); |
|
194 if ($this->_withChecksum) { |
|
195 $convertedChars++; |
|
196 } |
|
197 $encodedData = $convertedChars * $characterLength; |
|
198 // ...except the STOP character (13) |
|
199 $encodedData += $characterLength + 2 * $this->_barThinWidth * $this->_factor; |
|
200 $width = $quietZone + $encodedData + $quietZone; |
|
201 return $width; |
|
202 } |
|
203 |
|
204 /** |
|
205 * Partial check of code128 barcode |
|
206 * @return void |
|
207 */ |
|
208 protected function _checkParams() |
|
209 { |
|
210 } |
|
211 |
|
212 /** |
|
213 * Prepare array to draw barcode |
|
214 * @return array |
|
215 */ |
|
216 protected function _prepareBarcode() |
|
217 { |
|
218 $barcodeTable = array(); |
|
219 |
|
220 $convertedChars = $this->_convertToBarcodeChars($this->getText()); |
|
221 |
|
222 if ($this->_withChecksum) { |
|
223 $convertedChars[] = $this->getChecksum($this->getText()); |
|
224 } |
|
225 |
|
226 // STOP CHARACTER |
|
227 $convertedChars[] = 106; |
|
228 |
|
229 foreach ($convertedChars as $barcodeChar) { |
|
230 $barcodePattern = $this->_codingMap[$barcodeChar]; |
|
231 foreach (str_split($barcodePattern) as $c) { |
|
232 $barcodeTable[] = array($c, 1, 0, 1); |
|
233 } |
|
234 } |
|
235 return $barcodeTable; |
|
236 } |
|
237 |
|
238 /** |
|
239 * Checks if the next $length chars of $string starting at $pos are numeric. |
|
240 * Returns false if the end of the string is reached. |
|
241 * @param $string String to search |
|
242 * @param $pos Starting position |
|
243 * @param $length Length to search |
|
244 * @return bool |
|
245 */ |
|
246 protected static function _isDigit($string, $pos, $length = 2) |
|
247 { |
|
248 if ($pos + $length > strlen($string)) { |
|
249 return false; |
|
250 } |
|
251 |
|
252 for ($i = $pos; $i < $pos + $length; $i++) { |
|
253 if (!is_numeric($string[$i])) { |
|
254 return false; |
|
255 } |
|
256 } |
|
257 return true; |
|
258 } |
|
259 |
|
260 /** |
|
261 * Convert string to barcode string |
|
262 * @return array |
|
263 */ |
|
264 protected function _convertToBarcodeChars($string) |
|
265 { |
|
266 $string = (string) $string; |
|
267 if (!strlen($string)) { |
|
268 return array(); |
|
269 } |
|
270 |
|
271 if (isset($this->_convertedText[md5($string)])) { |
|
272 return $this->_convertedText[md5($string)]; |
|
273 } |
|
274 |
|
275 $currentCharset = null; |
|
276 $sum = 0; |
|
277 $fak = 0; |
|
278 $result = array(); |
|
279 |
|
280 for ($pos = 0; $pos < strlen($string); $pos++) { |
|
281 $char = $string[$pos]; |
|
282 $code = null; |
|
283 |
|
284 if (self::_isDigit($string, $pos, 4) && $currentCharset != 'C' |
|
285 || self::_isDigit($string, $pos, 2) && $currentCharset == 'C') { |
|
286 /** |
|
287 * Switch to C if the next 4 chars are numeric or stay C if the next 2 |
|
288 * chars are numeric |
|
289 */ |
|
290 if ($currentCharset != 'C') { |
|
291 if ($pos == 0) { |
|
292 $code = array_search("START C", $this->_charSets['C']); |
|
293 } else { |
|
294 $code = array_search("Code C", $this->_charSets[$currentCharset]); |
|
295 } |
|
296 $result[] = $code; |
|
297 $currentCharset = 'C'; |
|
298 } |
|
299 } else if (in_array($char, $this->_charSets['B']) && $currentCharset != 'B' |
|
300 && !(in_array($char, $this->_charSets['A']) && $currentCharset == 'A')) { |
|
301 /** |
|
302 * Switch to B as B contains the char and B is not the current charset. |
|
303 */ |
|
304 if ($pos == 0) { |
|
305 $code = array_search("START B", $this->_charSets['B']); |
|
306 } else { |
|
307 $code = array_search("Code B", $this->_charSets[$currentCharset]); |
|
308 } |
|
309 $result[] = $code; |
|
310 $currentCharset = 'B'; |
|
311 } else if (array_key_exists($char, $this->_charSets['A']) && $currentCharset != 'A' |
|
312 && !(array_key_exists($char, $this->_charSets['B']) && $currentCharset == 'B')) { |
|
313 /** |
|
314 * Switch to C as C contains the char and C is not the current charset. |
|
315 */ |
|
316 if ($pos == 0) { |
|
317 $code = array_search("START A", $this->_charSets['A']); |
|
318 } else { |
|
319 $code =array_search("Code A", $this->_charSets[$currentCharset]); |
|
320 } |
|
321 $result[] = $code; |
|
322 $currentCharset = 'A'; |
|
323 } |
|
324 |
|
325 if ($currentCharset == 'C') { |
|
326 $code = array_search(substr($string, $pos, 2), $this->_charSets['C']); |
|
327 $pos++; //Two chars from input |
|
328 } else { |
|
329 $code = array_search($string[$pos], $this->_charSets[$currentCharset]); |
|
330 } |
|
331 $result[] = $code; |
|
332 } |
|
333 |
|
334 $this->_convertedText[md5($string)] = $result; |
|
335 return $result; |
|
336 } |
|
337 |
|
338 /** |
|
339 * Set text to encode |
|
340 * @param string $value |
|
341 * @return Zend_Barcode_Object |
|
342 */ |
|
343 public function setText($value) |
|
344 { |
|
345 $this->_text = $value; |
|
346 return $this; |
|
347 } |
|
348 |
|
349 /** |
|
350 * Retrieve text to encode |
|
351 * @return string |
|
352 */ |
|
353 public function getText() |
|
354 { |
|
355 return $this->_text; |
|
356 } |
|
357 |
|
358 /** |
|
359 * Get barcode checksum |
|
360 * |
|
361 * @param string $text |
|
362 * @return int |
|
363 */ |
|
364 public function getChecksum($text) |
|
365 { |
|
366 $tableOfChars = $this->_convertToBarcodeChars($text); |
|
367 |
|
368 $sum = $tableOfChars[0]; |
|
369 unset($tableOfChars[0]); |
|
370 |
|
371 $k = 1; |
|
372 foreach ($tableOfChars as $char) { |
|
373 $sum += ($k++) * $char; |
|
374 } |
|
375 |
|
376 $checksum = $sum % 103; |
|
377 |
|
378 return $checksum; |
|
379 } |
|
380 |
|
381 /** |
|
382 * Standard validation for most of barcode objects |
|
383 * @param string $value |
|
384 * @param array $options |
|
385 */ |
|
386 protected function _validateText($value, $options = array()) |
|
387 { |
|
388 // @TODO: add code128 validator |
|
389 return true; |
|
390 } |
|
391 } |