Bug 5194: The company name is not displayed on invoices if the logo is set. Fixed.
[fa-stable.git] / reporting / includes / barcodes.php
index 4454ec997255512af2d5883215f324b7b79f3e7a..4b88fff846d47c6b49d0901f7c45cc8fd33db242 100644 (file)
@@ -79,9 +79,9 @@ class TCPDFBarcode {
         * <li>$arrcode["bcode"][$k]["h"] bar height in units.</li>
         * <li>$arrcode["bcode"][$k]["p"] bar top position (0 = top, 1 = middle)</li></ul>
         * @param string $code code to print
-        * @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>
+        * @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>EAN2 : 2-Digits UPC-Based Extension</li><li>EAN5 : 5-Digits UPC-Based Extension</li><li>EAN8 : EAN 8</li><li>EAN13 : EAN 13</li><li>UPCA : UPC-A</li><li>UPCE : UPC-E</li><li>POSTNET : POSTNET</li><li>CODABAR : CODABAR</li></ul>
         */
-       function TCPDFBarcode($code, $type) {
+       function __construct($code, $type) {
                $this->setBarcode($code, $type);
        }
        
@@ -96,7 +96,7 @@ class TCPDFBarcode {
        /** 
         * Set the barcode.
         * @param string $code code to print
-        * @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>
+        * @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>EAN2 : 2-Digits UPC-Based Extension</li><li>EAN5 : 5-Digits UPC-Based Extension</li><li>EAN8 : EAN 8</li><li>EAN13 : EAN 13</li><li>UPCA : UPC-A</li><li>UPCE : UPC-E</li><li>POSTNET : POSTNET</li><li>CODABAR : CODABAR</li></ul>
         * @return array
         */
        function setBarcode($code, $type) {
@@ -133,12 +133,28 @@ class TCPDFBarcode {
                                $arrcode = $this->barcode_c128($code, "C");
                                break;
                        }
-                       case "EAN13": { // EAN 13
-                               $arrcode = $this->barcode_ean13($code, 13);
+                       case 'EAN2': { // 2-Digits UPC-Based Extension
+                               $arrcode = $this->barcode_eanext($code, 2);
                                break;
                        }
-                       case "UPCA": { // UPC-A
-                               $arrcode = $this->barcode_ean13($code, 12);
+                       case 'EAN5': { // 5-Digits UPC-Based Extension
+                               $arrcode = $this->barcode_eanext($code, 5);
+                               break;
+                       }
+                       case 'EAN8': { // EAN 8
+                               $arrcode = $this->barcode_eanupc($code, 8);
+                               break;
+                       }
+                       case 'EAN13': { // EAN 13
+                               $arrcode = $this->barcode_eanupc($code, 13);
+                               break;
+                       }
+                       case 'UPCA': { // UPC-A
+                               $arrcode = $this->barcode_eanupc($code, 12);
+                               break;
+                       }
+                       case 'UPCE': { // UPC-E
+                               $arrcode = $this->barcode_eanupc($code, 6);
                                break;
                        }
                        case "POSTNET": { // POSTNET
@@ -227,7 +243,7 @@ class TCPDFBarcode {
                $bararray = array("code" => $code, "maxw" => 0, "maxh" => 1, "bcode" => array());
                $k = 0;
                for($i=0; $i < strlen($code); $i++) {
-                       $char = $code{$i};
+                       $char = $code[$i];
                        if(!isset($chr[$char])) {
                                // invalid character
                                return false;
@@ -238,7 +254,7 @@ class TCPDFBarcode {
                                } else {
                                        $t = false; // space
                                }
-                               $w = $chr[$char]{$j};
+                               $w = $chr[$char][$j];
                                $bararray["bcode"][$k] = array("t" => $t, "w" => $w, "h" => 1, "p" => 0);
                                $bararray["maxw"] += $w;
                                $k++;
@@ -292,10 +308,10 @@ class TCPDFBarcode {
                        chr(124) => '%Q', chr(125) => '%R', chr(126) => '%S', chr(127) => '%T');
                $code_ext = '';
                for ($i = 0 ; $i < strlen($code); $i++) {
-                       if (ord($code{$i}) > 127) {
+                       if (ord($code[$i]) > 127) {
                                return false;
                        }
-                       $code_ext .= $encode[$code{$i}];
+                       $code_ext .= $encode[$code[$i]];
                }
                return $code_ext;
        }
@@ -314,7 +330,7 @@ class TCPDFBarcode {
                        'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%');
                $sum = 0;
                for ($i=0 ; $i < strlen($code); $i++) {
-                       $k = array_keys($chars, $code{$i});
+                       $k = array_keys($chars, $code[$i]);
                        $sum += $k[0];
                }
                $j = ($sum % 43);
@@ -353,8 +369,8 @@ class TCPDFBarcode {
                $bararray = array("code" => $code, "maxw" => 0, "maxh" => 1, "bcode" => array());
                $k = 0;
                for($i=0; $i < strlen($code); $i=$i+2) {
-                       $char_bar = $code{$i};
-                       $char_space = $code{$i+1};
+                       $char_bar = $code[$i];
+                       $char_space = $code[$i+1];
                        if((!isset($chr[$char_bar])) OR (!isset($chr[$char_space]))) {
                                // invalid character
                                return false;
@@ -362,7 +378,7 @@ class TCPDFBarcode {
                        // create a bar-space sequence
                        $seq = "";
                        for($s=0; $s < strlen($chr[$char_bar]); $s++){
-                               $seq .= $chr[$char_bar]{$s} . $chr[$char_space]{$s};
+                               $seq .= $chr[$char_bar][$s] . $chr[$char_space][$s];
                        }
                        for($j=0; $j < strlen($seq); $j++) {
                                if (($j % 2) == 0) {
@@ -370,7 +386,7 @@ class TCPDFBarcode {
                                } else {
                                        $t = false; // space
                                }
-                               $w = $seq{$j};
+                               $w = $seq[$j];
                                $bararray["bcode"][$k] = array("t" => $t, "w" => $w, "h" => 1, "p" => 0);
                                $bararray["maxw"] += $w;
                                $k++;
@@ -525,7 +541,7 @@ class TCPDFBarcode {
                                }
                                $new_code = "";
                                for ($i=0; $i < (strlen($code) / 2); $i++) {
-                                       $new_code .= chr(intval($code{(2 * $i)}.$code{(2 * $i + 1)}));
+                                       $new_code .= chr(intval($code[(2 * $i)].$code[(2 * $i + 1)]));
                                }
                                $code = $new_code;
                                break;
@@ -537,7 +553,7 @@ class TCPDFBarcode {
                // calculate check character
                $sum = $startid;
                for ($i=0; $i < strlen($code); $i++) {
-                       $sum +=  (strpos($keys, $code{$i}) * ($i+1));
+                       $sum +=  (strpos($keys, $code[$i]) * ($i+1));
                }
                $check = ($sum % 103);
                
@@ -547,9 +563,9 @@ class TCPDFBarcode {
                $k = 0;
                $len = strlen($code);
                for($i=0; $i < $len; $i++) {
-                       $ck = strpos($keys, $code{$i});
+                       $ck = strpos($keys, $code[$i]);
                        if (($i == 0) OR ($i > ($len-4))) {
-                               $seq = $chr[ord($code{$i})];
+                               $seq = $chr[ord($code[$i])];
                        } elseif(($ck >= 0) AND isset($chr[$ck])) {
                                        $seq = $chr[$ck];
                        } else {
@@ -562,7 +578,7 @@ class TCPDFBarcode {
                                } else {
                                        $t = false; // space
                                }
-                               $w = $seq{$j};
+                               $w = $seq[$j];
                                $bararray["bcode"][$k] = array("t" => $t, "w" => $w, "h" => 1, "p" => 0);
                                $bararray["maxw"] += $w;
                                $k++;
@@ -570,49 +586,84 @@ class TCPDFBarcode {
                }
                return $bararray;               
        }
-       
+
        /**
         * EAN13 and UPC-A barcodes.
-        * @param string $code code to represent.
-        * @param string $len barcode type: 13 = EAN13, 12 = UPC-A
+        * EAN13: European Article Numbering international retail product code
+        * UPC-A: Universal product code seen on almost all retail products in the USA and Canada
+        * UPC-E: Short version of UPC symbol
+        * @param $code (string) code to represent.
+        * @param $len (string) barcode type: 6 = UPC-E, 8 = EAN8, 13 = EAN13, 12 = UPC-A
         * @return array barcode representation.
-        * @access protected
+        * @protected
         */
-       function barcode_ean13($code, $len=13) {
+       protected function barcode_eanupc($code, $len=13) {
+               $upce = false;
+               if ($len == 6) {
+                       $len = 12; // UPC-A
+                       $upce = true; // UPC-E mode
+               }
+               $data_len = $len - 1;
                //Padding
-               $code = str_pad($code, $len-1, '0', STR_PAD_LEFT);
-               if($len == 12) {
-                       $code = '0'.$code;
+               $code = str_pad($code, $data_len, '0', STR_PAD_LEFT);
+               $code_len = strlen($code);
+               // calculate check digit
+               $sum_a = 0;
+               for ($i = 1; $i < $data_len; $i+=2) {
+                       $sum_a += $code[$i];
                }
-               // add check digit
-               if(strlen($code) == 12) {
-                       $sum=0;
-                       for($i=1;$i<=11;$i+=2) {
-                               $sum += (3 * $code{$i});
-                       }
-                       for($i=0; $i <= 10; $i+=2) {
-                               $sum += ($code{$i});
-                       }
-                       $r = $sum % 10;
-                       if($r > 0) {
-                               $r = (10 - $r);
-                       }
+               if ($len > 12) {
+                       $sum_a *= 3;
+               }
+               $sum_b = 0;
+               for ($i = 0; $i < $data_len; $i+=2) {
+                       $sum_b += ($code[$i]);
+               }
+               if ($len < 13) {
+                       $sum_b *= 3;
+               }
+               $r = ($sum_a + $sum_b) % 10;
+               if($r > 0) {
+                       $r = (10 - $r);
+               }
+               if ($code_len == $data_len) {
+                       // add check digit
                        $code .= $r;
-               } else { // test checkdigit
-                       $sum = 0;
-                       for($i=1; $i <= 11; $i+=2) {
-                               $sum += (3 * $code{$i});
-                       }
-                       for($i=0; $i <= 10; $i+=2) {
-                               $sum += $code{$i};
-                       }
-                       if ((($sum + $code{12}) % 10) != 0) {
-                               return false;
+               } elseif ($r !== intval($code[$data_len])) {
+                       // wrong checkdigit
+                       return false;
+               }
+               if ($len == 12) {
+                       // UPC-A
+                       $code = '0'.$code;
+                       ++$len;
+               }
+               if ($upce) {
+                       // convert UPC-A to UPC-E
+                       $tmp = substr($code, 4, 3);
+                       if (($tmp == '000') OR ($tmp == '100') OR ($tmp == '200')) {
+                               // manufacturer code ends in 000, 100, or 200
+                               $upce_code = substr($code, 2, 2).substr($code, 9, 3).substr($code, 4, 1);
+                       } else {
+                               $tmp = substr($code, 5, 2);
+                               if ($tmp == '00') {
+                                       // manufacturer code ends in 00
+                                       $upce_code = substr($code, 2, 3).substr($code, 10, 2).'3';
+                               } else {
+                                       $tmp = substr($code, 6, 1);
+                                       if ($tmp == '0') {
+                                               // manufacturer code ends in 0
+                                               $upce_code = substr($code, 2, 4).substr($code, 11, 1).'4';
+                                       } else {
+                                               // manufacturer code does not end in zero
+                                               $upce_code = substr($code, 2, 5).substr($code, 11, 1);
+                                       }
+                               }
                        }
                }
                //Convert digits to bars
                $codes = array(
-                       'A'=>array(
+                       'A'=>array( // left odd parity
                                '0'=>'0001101',
                                '1'=>'0011001',
                                '2'=>'0010011',
@@ -623,7 +674,7 @@ class TCPDFBarcode {
                                '7'=>'0111011',
                                '8'=>'0110111',
                                '9'=>'0001011'),
-                       'B'=>array(
+                       'B'=>array( // left even parity
                                '0'=>'0100111',
                                '1'=>'0110011',
                                '2'=>'0011011',
@@ -634,7 +685,7 @@ class TCPDFBarcode {
                                '7'=>'0010001',
                                '8'=>'0001001',
                                '9'=>'0010111'),
-                       'C'=>array(
+                       'C'=>array( // right
                                '0'=>'1110010',
                                '1'=>'1100110',
                                '2'=>'1101100',
@@ -658,38 +709,78 @@ class TCPDFBarcode {
                        '8'=>array('A','B','A','B','B','A'),
                        '9'=>array('A','B','B','A','B','A')
                );
-               
-               $bararray = array("code" => $code, "maxw" => 0, "maxh" => 1, "bcode" => array());
+               $upce_parities = array();
+               $upce_parities[0] = array(
+                       '0'=>array('B','B','B','A','A','A'),
+                       '1'=>array('B','B','A','B','A','A'),
+                       '2'=>array('B','B','A','A','B','A'),
+                       '3'=>array('B','B','A','A','A','B'),
+                       '4'=>array('B','A','B','B','A','A'),
+                       '5'=>array('B','A','A','B','B','A'),
+                       '6'=>array('B','A','A','A','B','B'),
+                       '7'=>array('B','A','B','A','B','A'),
+                       '8'=>array('B','A','B','A','A','B'),
+                       '9'=>array('B','A','A','B','A','B')
+               );
+               $upce_parities[1] = array(
+                       '0'=>array('A','A','A','B','B','B'),
+                       '1'=>array('A','A','B','A','B','B'),
+                       '2'=>array('A','A','B','B','A','B'),
+                       '3'=>array('A','A','B','B','B','A'),
+                       '4'=>array('A','B','A','A','B','B'),
+                       '5'=>array('A','B','B','A','A','B'),
+                       '6'=>array('A','B','B','B','A','A'),
+                       '7'=>array('A','B','A','B','A','B'),
+                       '8'=>array('A','B','A','B','B','A'),
+                       '9'=>array('A','B','B','A','B','A')
+               );
                $k = 0;
-               $seq = '101';
-               $p = $parities[$code{0}];
-               for($i=1; $i < 7; $i++) {
-                       $seq .= $codes[$p[$i-1]][$code{$i}];
-               }
-               $seq .= '01010';
-               for($i=7; $i < 13; $i++) {
-                       $seq .= $codes['C'][$code{$i}];
+               $seq = '101'; // left guard bar
+               if ($upce) {
+                       $bararray = array('code' => $upce_code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
+                       $p = $upce_parities[$code[1]][$r];
+                       for ($i = 0; $i < 6; ++$i) {
+                               $seq .= $codes[$p[$i]][$upce_code[$i]];
+                       }
+                       $seq .= '010101'; // right guard bar
+               } else {
+                       $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
+                       $half_len = intval(ceil($len / 2));
+                       if ($len == 8) {
+                               for ($i = 0; $i < $half_len; ++$i) {
+                                       $seq .= $codes['A'][$code[$i]];
+                               }
+                       } else {
+                               $p = $parities[$code[0]];
+                               for ($i = 1; $i < $half_len; ++$i) {
+                                       $seq .= $codes[$p[$i-1]][$code[$i]];
+                               }
+                       }
+                       $seq .= '01010'; // center guard bar
+                       for ($i = $half_len; $i < $len; ++$i) {
+                               $seq .= $codes['C'][$code[$i]];
+                       }
+                       $seq .= '101'; // right guard bar
                }
-               $seq .= '101';
-               $len = strlen($seq);
+               $clen = strlen($seq);
                $w = 0;
-               for($i=0; $i < $len; $i++) {
+               for ($i = 0; $i < $clen; ++$i) {
                        $w += 1;
-                       if (($i == ($len - 1)) OR (($i < ($len - 1)) AND ($seq{$i} != $seq{($i+1)}))) {
-                               if ($seq{$i} == '1') {
+                       if (($i == ($clen - 1)) OR (($i < ($clen - 1)) AND ($seq[$i] != $seq[($i+1)]))) {
+                               if ($seq[$i] == '1') {
                                        $t = true; // bar
                                } else {
                                        $t = false; // space
                                }
-                               $bararray["bcode"][$k] = array("t" => $t, "w" => $w, "h" => 1, "p" => 0);
-                               $bararray["maxw"] += $w;
-                               $k++;
+                               $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
+                               $bararray['maxw'] += $w;
+                               ++$k;
                                $w = 0;
                        }
                }
                return $bararray;
        }
-       
+
        /**
         * POSTNET barcodes.
         * @param string $code zip code to represent. Must be a string containing a zip code of the form DDDDD or DDDDD-DDDD.
@@ -718,7 +809,7 @@ class TCPDFBarcode {
                // calculate checksum
                $sum = 0;
                for($i=0; $i < $len; $i++) {
-                       $sum += intval($code{$i});
+                       $sum += intval($code[$i]);
                }
                if(($sum % 10) == 0) {
                        return false;
@@ -731,7 +822,7 @@ class TCPDFBarcode {
                $bararray["maxw"] += 2;
                for ($i=0; $i < $len; $i++) {
                        for ($j=0; $j < 5; $j++) {
-                               $h = $barlen[$code{$i}][$j];
+                               $h = $barlen[$code[$i]][$j];
                                $p = floor(1 / $h);
                                $bararray["bcode"][$k++] = array("t" => 1, "w" => 1, "h" => $h, "p" => $p);
                                $bararray["bcode"][$k++] = array("t" => 0, "w" => 1, "h" => 2, "p" => 0);
@@ -781,17 +872,17 @@ class TCPDFBarcode {
                $code = "A".strtoupper($code)."A";
                $len = strlen($code);
                for($i=0; $i < $len; $i++) {
-                       if (!isset($chr[$code{$i}])) {
+                       if (!isset($chr[$code[$i]])) {
                                return false;
                        }
-                       $seq = $chr[$code{$i}];
+                       $seq = $chr[$code[$i]];
                        for($j=0; $j < 8; $j++) {
                                if (($j % 2) == 0) {
                                        $t = true; // bar
                                } else {
                                        $t = false; // space
                                }
-                               $w = $seq{$j};
+                               $w = $seq[$j];
                                $bararray["bcode"][$k] = array("t" => $t, "w" => $w, "h" => 1, "p" => 0);
                                $bararray["maxw"] += $w;
                                $k++;