2 //============================================================+
3 // File name : barcodes.php
5 // Last Update : 2008-07-16
7 // License : GNU LGPL (http://www.gnu.org/copyleft/lesser.html)
8 // ----------------------------------------------------------------------------
9 // Copyright (C) 2008 Nicola Asuni - Tecnick.com S.r.l.
11 // This program is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU Lesser General Public License as published by
13 // the Free Software Foundation, either version 2.1 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU Lesser General Public License for more details.
21 // You should have received a copy of the GNU Lesser General Public License
22 // along with this program. If not, see <http://www.gnu.org/licenses/>.
24 // See LICENSE.TXT file for more information.
25 // ----------------------------------------------------------------------------
27 // Description : PHP class to creates array representations for
28 // common 1D barcodes to be used with TCPDF.
30 // Author: Nicola Asuni
36 // 09044 Quartucciu (CA)
40 //============================================================+
43 * PHP class to creates array representations for common 1D barcodes to be used with TCPDF.
44 * @package com.tecnick.tcpdf
45 * @abstract Functions for generating string representation of common 1D barcodes.
46 * @author Nicola Asuni
47 * @copyright 2008 Nicola Asuni - Tecnick.com S.r.l (www.tecnick.com) Via Della Pace, 11 - 09044 - Quartucciu (CA) - ITALY - www.tecnick.com - info@tecnick.com
48 * @link http://www.tcpdf.org
49 * @license http://www.gnu.org/copyleft/lesser.html LGPL
54 * PHP class to creates array representations for common 1D barcodes to be used with TCPDF (http://www.tcpdf.org).<br>
56 * @package com.tecnick.tcpdf
58 * @author Nicola Asuni
59 * @link http://www.tcpdf.org
60 * @license http://www.gnu.org/copyleft/lesser.html LGPL
65 * @var array representation of barcode.
71 * This is the class constructor.
72 * Return an array representations for common 1D barcodes:<ul>
73 * <li>$arrcode["code"] code to be printed on text label</li>
74 * <li>$arrcode["maxh"] max bar height</li>
75 * <li>$arrcode["maxw"] max bar width</li>
76 * <li>$arrcode["bcode"][$k] single bar or space in $k position</li>
77 * <li>$arrcode["bcode"][$k]["t"] bar type: true = bar, false = space.</li>
78 * <li>$arrcode["bcode"][$k]["w"] bar width in units.</li>
79 * <li>$arrcode["bcode"][$k]["h"] bar height in units.</li>
80 * <li>$arrcode["bcode"][$k]["p"] bar top position (0 = top, 1 = middle)</li></ul>
81 * @param string $code code to print
82 * @param string $type type of barcode: <ul><li>C39 : CODE 39</li><li>C39+ : CODE 39 with checksum</li><li>C39E : CODE 39 EXTENDED</li><li>C39E+ : CODE 39 EXTENDED with checksum</li><li>I25 : Interleaved 2 of 5</li><li>C128A : CODE 128 A</li><li>C128B : CODE 128 B</li><li>C128C : CODE 128 C</li><li>EAN13 : EAN 13</li><li>UPCA : UPC-A</li><li>POSTNET : POSTNET</li><li>CODABAR : CODABAR</li></ul>
84 function TCPDFBarcode($code, $type) {
85 $this->setBarcode($code, $type);
89 * Return an array representations of barcode.
92 function getBarcodeArray() {
93 return $this->barcode_array;
98 * @param string $code code to print
99 * @param string $type type of barcode: <ul><li>C39 : CODE 39</li><li>C39+ : CODE 39 with checksum</li><li>C39E : CODE 39 EXTENDED</li><li>C39E+ : CODE 39 EXTENDED with checksum</li><li>I25 : Interleaved 2 of 5</li><li>C128A : CODE 128 A</li><li>C128B : CODE 128 B</li><li>C128C : CODE 128 C</li><li>EAN13 : EAN 13</li><li>UPCA : UPC-A</li><li>POSTNET : POSTNET</li><li>CODABAR : CODABAR</li></ul>
102 function setBarcode($code, $type) {
103 switch (strtoupper($type)) {
104 case "C39": { // CODE 39
105 $arrcode = $this->barcode_code39($code, false, false);
108 case "C39+": { // CODE 39 with checksum
109 $arrcode = $this->barcode_code39($code, false, true);
112 case "C39E": { // CODE 39 EXTENDED
113 $arrcode = $this->barcode_code39($code, true, false);
116 case "C39E+": { // CODE 39 EXTENDED with checksum
117 $arrcode = $this->barcode_code39($code, true, true);
120 case "I25": { // Interleaved 2 of 5
121 $arrcode = $this->barcode_i25($code);
124 case "C128A": { // CODE 128 A
125 $arrcode = $this->barcode_c128($code, "A");
128 case "C128B": { // CODE 128 B
129 $arrcode = $this->barcode_c128($code, "B");
132 case "C128C": { // CODE 128 C
133 $arrcode = $this->barcode_c128($code, "C");
136 case "EAN13": { // EAN 13
137 $arrcode = $this->barcode_ean13($code, 13);
140 case "UPCA": { // UPC-A
141 $arrcode = $this->barcode_ean13($code, 12);
144 case "POSTNET": { // POSTNET
145 $arrcode = $this->barcode_postnet($code);
148 case "CODABAR": { // CODABAR
149 $arrcode = $this->barcode_codabar($code);
153 $this->barcode_array = false;
156 $this->barcode_array = $arrcode;
161 * @param string $code code to represent.
162 * @param boolean $checksum if true add a checksum to the code
163 * @return array barcode representation.
166 function barcode_code39($code, $extended=false, $checksum=false) {
167 $chr['0'] = '111221211';
168 $chr['1'] = '211211112';
169 $chr['2'] = '112211112';
170 $chr['3'] = '212211111';
171 $chr['4'] = '111221112';
172 $chr['5'] = '211221111';
173 $chr['6'] = '112221111';
174 $chr['7'] = '111211212';
175 $chr['8'] = '211211211';
176 $chr['9'] = '112211211';
177 $chr['A'] = '211112112';
178 $chr['B'] = '112112112';
179 $chr['C'] = '212112111';
180 $chr['D'] = '111122112';
181 $chr['E'] = '211122111';
182 $chr['F'] = '112122111';
183 $chr['G'] = '111112212';
184 $chr['H'] = '211112211';
185 $chr['I'] = '112112211';
186 $chr['J'] = '111122211';
187 $chr['K'] = '211111122';
188 $chr['L'] = '112111122';
189 $chr['M'] = '212111121';
190 $chr['N'] = '111121122';
191 $chr['O'] = '211121121';
192 $chr['P'] = '112121121';
193 $chr['Q'] = '111111222';
194 $chr['R'] = '211111221';
195 $chr['S'] = '112111221';
196 $chr['T'] = '111121221';
197 $chr['U'] = '221111112';
198 $chr['V'] = '122111112';
199 $chr['W'] = '222111111';
200 $chr['X'] = '121121112';
201 $chr['Y'] = '221121111';
202 $chr['Z'] = '122121111';
203 $chr['-'] = '121111212';
204 $chr['.'] = '221111211';
205 $chr[' '] = '122111211';
206 $chr['*'] = '121121211';
207 $chr['$'] = '121212111';
208 $chr['/'] = '121211121';
209 $chr['+'] = '121112121';
210 $chr['%'] = '111212121';
212 $code = strtoupper($code);
215 $code = $this->encode_code39_ext($code);
217 if ($code === false) {
222 $code .= $this->checksum_code39($code);
224 // add start and stop codes
225 $code = "*".$code."*";
227 $bararray = array("code" => $code, "maxw" => 0, "maxh" => 1, "bcode" => array());
229 for($i=0; $i < strlen($code); $i++) {
231 if(!isset($chr[$char])) {
235 for($j=0; $j < 9; $j++) {
241 $w = $chr[$char]{$j};
242 $bararray["bcode"][$k] = array("t" => $t, "w" => $w, "h" => 1, "p" => 0);
243 $bararray["maxw"] += $w;
246 $bararray["bcode"][$k] = array("t" => false, "w" => 1, "h" => 1, "p" => 0);
247 $bararray["maxw"] += 1;
254 * Encode a string to be used for CODE 39 Extended mode.
255 * @param string $code code to represent.
256 * @return encoded string.
259 function encode_code39_ext($code) {
261 chr(0) => '%U', chr(1) => '$A', chr(2) => '$B', chr(3) => '$C',
262 chr(4) => '$D', chr(5) => '$E', chr(6) => '$F', chr(7) => '$G',
263 chr(8) => '$H', chr(9) => '$I', chr(10) => '$J', chr(11) => '£K',
264 chr(12) => '$L', chr(13) => '$M', chr(14) => '$N', chr(15) => '$O',
265 chr(16) => '$P', chr(17) => '$Q', chr(18) => '$R', chr(19) => '$S',
266 chr(20) => '$T', chr(21) => '$U', chr(22) => '$V', chr(23) => '$W',
267 chr(24) => '$X', chr(25) => '$Y', chr(26) => '$Z', chr(27) => '%A',
268 chr(28) => '%B', chr(29) => '%C', chr(30) => '%D', chr(31) => '%E',
269 chr(32) => ' ', chr(33) => '/A', chr(34) => '/B', chr(35) => '/C',
270 chr(36) => '/D', chr(37) => '/E', chr(38) => '/F', chr(39) => '/G',
271 chr(40) => '/H', chr(41) => '/I', chr(42) => '/J', chr(43) => '/K',
272 chr(44) => '/L', chr(45) => '-', chr(46) => '.', chr(47) => '/O',
273 chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3',
274 chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7',
275 chr(56) => '8', chr(57) => '9', chr(58) => '/Z', chr(59) => '%F',
276 chr(60) => '%G', chr(61) => '%H', chr(62) => '%I', chr(63) => '%J',
277 chr(64) => '%V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C',
278 chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G',
279 chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K',
280 chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O',
281 chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S',
282 chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W',
283 chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => '%K',
284 chr(92) => '%L', chr(93) => '%M', chr(94) => '%N', chr(95) => '%O',
285 chr(96) => '%W', chr(97) => '+A', chr(98) => '+B', chr(99) => '+C',
286 chr(100) => '+D', chr(101) => '+E', chr(102) => '+F', chr(103) => '+G',
287 chr(104) => '+H', chr(105) => '+I', chr(106) => '+J', chr(107) => '+K',
288 chr(108) => '+L', chr(109) => '+M', chr(110) => '+N', chr(111) => '+O',
289 chr(112) => '+P', chr(113) => '+Q', chr(114) => '+R', chr(115) => '+S',
290 chr(116) => '+T', chr(117) => '+U', chr(118) => '+V', chr(119) => '+W',
291 chr(120) => '+X', chr(121) => '+Y', chr(122) => '+Z', chr(123) => '%P',
292 chr(124) => '%Q', chr(125) => '%R', chr(126) => '%S', chr(127) => '%T');
294 for ($i = 0 ; $i < strlen($code); $i++) {
295 if (ord($code{$i}) > 127) {
298 $code_ext .= $encode[$code{$i}];
304 * Calculate CODE 39 checksum (modulo 43).
305 * @param string $code code to represent.
306 * @return char checksum.
309 function checksum_code39($code) {
311 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
312 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
313 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
314 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%');
316 for ($i=0 ; $i < strlen($code); $i++) {
317 $k = array_keys($chars, $code{$i});
325 * Interleaved 2 of 5 barcodes.
326 * Contains digits (0 to 9) and encodes the data in the width of both bars and spaces.
327 * @param string $code code to represent.
328 * @param boolean $checksum if true add a checksum to the code
329 * @return array barcode representation.
332 function barcode_i25($code) {
346 if((strlen($code) % 2) != 0) {
347 // add leading zero if code-length is odd
350 // add start and stop codes
351 $code = 'AA'.strtolower($code).'ZA';
353 $bararray = array("code" => $code, "maxw" => 0, "maxh" => 1, "bcode" => array());
355 for($i=0; $i < strlen($code); $i=$i+2) {
356 $char_bar = $code{$i};
357 $char_space = $code{$i+1};
358 if((!isset($chr[$char_bar])) OR (!isset($chr[$char_space]))) {
362 // create a bar-space sequence
364 for($s=0; $s < strlen($chr[$char_bar]); $s++){
365 $seq .= $chr[$char_bar]{$s} . $chr[$char_space]{$s};
367 for($j=0; $j < strlen($seq); $j++) {
374 $bararray["bcode"][$k] = array("t" => $t, "w" => $w, "h" => 1, "p" => 0);
375 $bararray["maxw"] += $w;
385 * @param string $code code to represent.
386 * @param string $type barcode type: A, B or C
387 * @return array barcode representation.
390 function barcode_c128($code, $type="B") {
495 '211412', /* 103 START A */
496 '211214', /* 104 START B */
497 '211232', /* 105 START C */
502 switch(strtoupper($type)) {
505 $keys = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_';
506 for($i = 0; $i < 32; $i++) {
513 $keys = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'.chr(127);
519 if ((strlen($code) % 2) != 0) {
520 //echo "The length of barcode value must be even ($code). You must pad the number with zeros.\n";
523 for($i = 0; $i <= 99; $i++) {
527 for ($i=0; $i < (strlen($code) / 2); $i++) {
528 $new_code .= chr(intval($code{(2 * $i)}.$code{(2 * $i + 1)}));
537 // calculate check character
539 for ($i=0; $i < strlen($code); $i++) {
540 $sum += (strpos($keys, $code{$i}) * ($i+1));
542 $check = ($sum % 103);
544 // add start, check and stop codes
545 $code = chr($startid).$code.chr($check).chr(106).chr(107);
546 $bararray = array("code" => $code, "maxw" => 0, "maxh" => 1, "bcode" => array());
548 $len = strlen($code);
549 for($i=0; $i < $len; $i++) {
550 $ck = strpos($keys, $code{$i});
551 if (($i == 0) OR ($i > ($len-4))) {
552 $seq = $chr[ord($code{$i})];
553 } elseif(($ck >= 0) AND isset($chr[$ck])) {
559 for($j=0; $j < 6; $j++) {
566 $bararray["bcode"][$k] = array("t" => $t, "w" => $w, "h" => 1, "p" => 0);
567 $bararray["maxw"] += $w;
575 * EAN13 and UPC-A barcodes.
576 * @param string $code code to represent.
577 * @param string $len barcode type: 13 = EAN13, 12 = UPC-A
578 * @return array barcode representation.
581 function barcode_ean13($code, $len=13) {
583 $code = str_pad($code, $len-1, '0', STR_PAD_LEFT);
588 if(strlen($code) == 12) {
590 for($i=1;$i<=11;$i+=2) {
591 $sum += (3 * $code{$i});
593 for($i=0; $i <= 10; $i+=2) {
601 } else { // test checkdigit
603 for($i=1; $i <= 11; $i+=2) {
604 $sum += (3 * $code{$i});
606 for($i=0; $i <= 10; $i+=2) {
609 if ((($sum + $code{12}) % 10) != 0) {
613 //Convert digits to bars
650 '0'=>array('A','A','A','A','A','A'),
651 '1'=>array('A','A','B','A','B','B'),
652 '2'=>array('A','A','B','B','A','B'),
653 '3'=>array('A','A','B','B','B','A'),
654 '4'=>array('A','B','A','A','B','B'),
655 '5'=>array('A','B','B','A','A','B'),
656 '6'=>array('A','B','B','B','A','A'),
657 '7'=>array('A','B','A','B','A','B'),
658 '8'=>array('A','B','A','B','B','A'),
659 '9'=>array('A','B','B','A','B','A')
662 $bararray = array("code" => $code, "maxw" => 0, "maxh" => 1, "bcode" => array());
665 $p = $parities[$code{0}];
666 for($i=1; $i < 7; $i++) {
667 $seq .= $codes[$p[$i-1]][$code{$i}];
670 for($i=7; $i < 13; $i++) {
671 $seq .= $codes['C'][$code{$i}];
676 for($i=0; $i < $len; $i++) {
678 if (($i == ($len - 1)) OR (($i < ($len - 1)) AND ($seq{$i} != $seq{($i+1)}))) {
679 if ($seq{$i} == '1') {
684 $bararray["bcode"][$k] = array("t" => $t, "w" => $w, "h" => 1, "p" => 0);
685 $bararray["maxw"] += $w;
695 * @param string $code zip code to represent. Must be a string containing a zip code of the form DDDDD or DDDDD-DDDD.
696 * @return array barcode representation.
699 function barcode_postnet($code) {
702 0 => Array(2,2,1,1,1),
703 1 => Array(1,1,1,2,2),
704 2 => Array(1,1,2,1,2),
705 3 => Array(1,1,2,2,1),
706 4 => Array(1,2,1,1,2),
707 5 => Array(1,2,1,2,1),
708 6 => Array(1,2,2,1,1),
709 7 => Array(2,1,1,1,2),
710 8 => Array(2,1,1,2,1),
711 9 => Array(2,1,2,1,1)
713 $bararray = array("code" => $code, "maxw" => 0, "maxh" => 2, "bcode" => array());
715 $code = str_replace("-", "", $code);
716 $code = str_replace(" ", "", $code);
717 $len = strlen($code);
718 // calculate checksum
720 for($i=0; $i < $len; $i++) {
721 $sum += intval($code{$i});
723 if(($sum % 10) == 0) {
726 $code .= "".(10 - ($sum % 10))."";
727 $len = strlen($code);
729 $bararray["bcode"][$k++] = array("t" => 1, "w" => 1, "h" => 2, "p" => 0);
730 $bararray["bcode"][$k++] = array("t" => 0, "w" => 1, "h" => 2, "p" => 0);
731 $bararray["maxw"] += 2;
732 for ($i=0; $i < $len; $i++) {
733 for ($j=0; $j < 5; $j++) {
734 $h = $barlen[$code{$i}][$j];
736 $bararray["bcode"][$k++] = array("t" => 1, "w" => 1, "h" => $h, "p" => $p);
737 $bararray["bcode"][$k++] = array("t" => 0, "w" => 1, "h" => 2, "p" => 0);
738 $bararray["maxw"] += 2;
742 $bararray["bcode"][$k++] = array("t" => 1, "w" => 1, "h" => 2, "p" => 0);
743 $bararray["maxw"] += 1;
749 * @param string $code code to represent.
750 * @return array barcode representation.
753 function barcode_codabar($code) {
777 $bararray = array("code" => $code, "maxw" => 0, "maxh" => 1, "bcode" => array());
781 $code = "A".strtoupper($code)."A";
782 $len = strlen($code);
783 for($i=0; $i < $len; $i++) {
784 if (!isset($chr[$code{$i}])) {
787 $seq = $chr[$code{$i}];
788 for($j=0; $j < 8; $j++) {
795 $bararray["bcode"][$k] = array("t" => $t, "w" => $w, "h" => 1, "p" => 0);
796 $bararray["maxw"] += $w;
805 //============================================================+
807 //============================================================+