composer package updates
[openemr.git] / vendor / mpdf / mpdf / src / Barcode / EanUpc.php
blobaabf8e959a609a2f3753b4595ff73a7db629c9ba
1 <?php
3 namespace Mpdf\Barcode;
5 /**
6 * EAN13 and UPC-A barcodes.
7 * EAN13: European Article Numbering international retail product code
8 * UPC-A: Universal product code seen on almost all retail products in the USA and Canada
9 * UPC-E: Short version of UPC symbol
11 class EanUpc extends \Mpdf\Barcode\AbstractBarcode implements \Mpdf\Barcode\BarcodeInterface
14 /**
15 * @param string $code
16 * @param int $length
17 * @param float $leftMargin
18 * @param float $rightMargin
19 * @param float $xDim
20 * @param float $barHeight
22 public function __construct($code, $length, $leftMargin, $rightMargin, $xDim, $barHeight)
24 $this->init($code, $length);
26 $this->data['lightmL'] = $leftMargin; // LEFT light margin = x X-dim (http://www.gs1uk.org)
27 $this->data['lightmR'] = $rightMargin; // RIGHT light margin = x X-dim (http://www.gs1uk.org)
28 $this->data['nom-X'] = $xDim; // Nominal value for X-dim in mm (http://www.gs1uk.org)
29 $this->data['nom-H'] = $barHeight; // Nominal bar height in mm incl. numerals (http://www.gs1uk.org)
32 /**
33 * @param string $code
34 * @param int $length
36 private function init($code, $length)
38 $upce = false;
39 $checkdigit = false;
41 if ($length == 6) {
42 $length = 12; // UPC-A
43 $upce = true; // UPC-E mode
45 $dataLength = $length - 1;
47 // Padding
48 $code = str_pad($code, $dataLength, '0', STR_PAD_LEFT);
49 $codeLength = strlen($code);
51 // Calculate check digit
52 $sum_a = 0;
53 for ($i = 1; $i < $dataLength; $i += 2) {
54 $sum_a += $code[$i];
57 if ($length > 12) {
58 $sum_a *= 3;
60 $sum_b = 0;
61 for ($i = 0; $i < $dataLength; $i += 2) {
62 $sum_b += ($code[$i]);
65 if ($length < 13) {
66 $sum_b *= 3;
69 $r = ($sum_a + $sum_b) % 10;
70 if ($r > 0) {
71 $r = (10 - $r);
74 if ($codeLength == $dataLength) {
75 // Add check digit
76 $code .= $r;
77 $checkdigit = $r;
78 } elseif ($r !== (int) $code[$dataLength]) {
79 // Wrong checkdigit
80 throw new \Mpdf\Barcode\BarcodeException('Invalid EAN UPC barcode value');
83 if ($length == 12) {
84 // UPC-A
85 $code = '0' . $code;
86 ++$length;
89 if ($upce) {
90 // Convert UPC-A to UPC-E
91 $tmp = substr($code, 4, 3);
92 $prodCode = (int) substr($code, 7, 5); // product code
93 $invalidUpce = false;
94 if (($tmp == '000') or ($tmp == '100') or ($tmp == '200')) {
95 // Manufacturer code ends in 000, 100, or 200
96 $upceCode = substr($code, 2, 2) . substr($code, 9, 3) . substr($code, 4, 1);
97 if ($prodCode > 999) {
98 $invalidUpce = true;
100 } else {
101 $tmp = substr($code, 5, 2);
102 if ($tmp == '00') {
103 // Manufacturer code ends in 00
104 $upceCode = substr($code, 2, 3) . substr($code, 10, 2) . '3';
105 if ($prodCode > 99) {
106 $invalidUpce = true;
108 } else {
109 $tmp = substr($code, 6, 1);
110 if ($tmp == '0') {
111 // Manufacturer code ends in 0
112 $upceCode = substr($code, 2, 4) . substr($code, 11, 1) . '4';
113 if ($prodCode > 9) {
114 $invalidUpce = true;
116 } else {
117 // Manufacturer code does not end in zero
118 $upceCode = substr($code, 2, 5) . substr($code, 11, 1);
119 if ($prodCode > 9) {
120 $invalidUpce = true;
125 if ($invalidUpce) {
126 throw new \Mpdf\Barcode\BarcodeException('UPC-A cannot produce a valid UPC-E barcode');
130 // Convert digits to bars
131 $codes = [
132 'A' => [// left odd parity
133 '0' => '0001101',
134 '1' => '0011001',
135 '2' => '0010011',
136 '3' => '0111101',
137 '4' => '0100011',
138 '5' => '0110001',
139 '6' => '0101111',
140 '7' => '0111011',
141 '8' => '0110111',
142 '9' => '0001011'],
143 'B' => [// left even parity
144 '0' => '0100111',
145 '1' => '0110011',
146 '2' => '0011011',
147 '3' => '0100001',
148 '4' => '0011101',
149 '5' => '0111001',
150 '6' => '0000101',
151 '7' => '0010001',
152 '8' => '0001001',
153 '9' => '0010111'],
154 'C' => [// right
155 '0' => '1110010',
156 '1' => '1100110',
157 '2' => '1101100',
158 '3' => '1000010',
159 '4' => '1011100',
160 '5' => '1001110',
161 '6' => '1010000',
162 '7' => '1000100',
163 '8' => '1001000',
164 '9' => '1110100']
167 $parities = [
168 '0' => ['A', 'A', 'A', 'A', 'A', 'A'],
169 '1' => ['A', 'A', 'B', 'A', 'B', 'B'],
170 '2' => ['A', 'A', 'B', 'B', 'A', 'B'],
171 '3' => ['A', 'A', 'B', 'B', 'B', 'A'],
172 '4' => ['A', 'B', 'A', 'A', 'B', 'B'],
173 '5' => ['A', 'B', 'B', 'A', 'A', 'B'],
174 '6' => ['A', 'B', 'B', 'B', 'A', 'A'],
175 '7' => ['A', 'B', 'A', 'B', 'A', 'B'],
176 '8' => ['A', 'B', 'A', 'B', 'B', 'A'],
177 '9' => ['A', 'B', 'B', 'A', 'B', 'A']
180 $upceParities = [];
181 $upceParities[0] = [
182 '0' => ['B', 'B', 'B', 'A', 'A', 'A'],
183 '1' => ['B', 'B', 'A', 'B', 'A', 'A'],
184 '2' => ['B', 'B', 'A', 'A', 'B', 'A'],
185 '3' => ['B', 'B', 'A', 'A', 'A', 'B'],
186 '4' => ['B', 'A', 'B', 'B', 'A', 'A'],
187 '5' => ['B', 'A', 'A', 'B', 'B', 'A'],
188 '6' => ['B', 'A', 'A', 'A', 'B', 'B'],
189 '7' => ['B', 'A', 'B', 'A', 'B', 'A'],
190 '8' => ['B', 'A', 'B', 'A', 'A', 'B'],
191 '9' => ['B', 'A', 'A', 'B', 'A', 'B']
194 $upceParities[1] = [
195 '0' => ['A', 'A', 'A', 'B', 'B', 'B'],
196 '1' => ['A', 'A', 'B', 'A', 'B', 'B'],
197 '2' => ['A', 'A', 'B', 'B', 'A', 'B'],
198 '3' => ['A', 'A', 'B', 'B', 'B', 'A'],
199 '4' => ['A', 'B', 'A', 'A', 'B', 'B'],
200 '5' => ['A', 'B', 'B', 'A', 'A', 'B'],
201 '6' => ['A', 'B', 'B', 'B', 'A', 'A'],
202 '7' => ['A', 'B', 'A', 'B', 'A', 'B'],
203 '8' => ['A', 'B', 'A', 'B', 'B', 'A'],
204 '9' => ['A', 'B', 'B', 'A', 'B', 'A']
207 $k = 0;
208 $seq = '101'; // left guard bar
210 if ($upce && isset($upceCode)) {
211 $bararray = ['code' => $upceCode, 'maxw' => 0, 'maxh' => 1, 'bcode' => []];
212 $p = $upceParities[$code{1}][$r];
213 for ($i = 0; $i < 6; ++$i) {
214 $seq .= $codes[$p[$i]][$upceCode[$i]];
216 $seq .= '010101'; // right guard bar
217 } else {
218 $bararray = ['code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => []];
219 $halfLen = ceil($length / 2);
220 if ($length == 8) {
221 for ($i = 0; $i < $halfLen; ++$i) {
222 $seq .= $codes['A'][$code[$i]];
224 } else {
225 $p = $parities[$code{0}];
226 for ($i = 1; $i < $halfLen; ++$i) {
227 $seq .= $codes[$p[$i - 1]][$code[$i]];
230 $seq .= '01010'; // center guard bar
231 for ($i = $halfLen; $i < $length; ++$i) {
232 $seq .= $codes['C'][$code[(int) $i]];
234 $seq .= '101'; // right guard bar
237 $clen = strlen($seq);
238 $w = 0;
239 for ($i = 0; $i < $clen; ++$i) {
240 $w += 1;
241 if (($i == ($clen - 1)) or (($i < ($clen - 1)) and ($seq[$i] != $seq[($i + 1)]))) {
242 if ($seq[$i] == '1') {
243 $t = true; // bar
244 } else {
245 $t = false; // space
247 $bararray['bcode'][$k] = ['t' => $t, 'w' => $w, 'h' => 1, 'p' => 0];
248 $bararray['maxw'] += $w;
249 ++$k;
250 $w = 0;
253 $bararray['checkdigit'] = $checkdigit;
255 $this->data = $bararray;
259 * @inheritdoc
261 public function getType()
263 return 'EANUPC';