1<?php
2
3namespace Mpdf\Barcode;
4
5/**
6 * UPC-Based Extentions
7 * 2-Digit Ext.: Used to indicate magazines and newspaper issue numbers
8 * 5-Digit Ext.: Used to mark suggested retail price of books
9 */
10class EanExt extends \Mpdf\Barcode\AbstractBarcode implements \Mpdf\Barcode\BarcodeInterface
11{
12
13	/**
14	 * @param string $code
15	 * @param int $length
16	 * @param float $leftMargin
17	 * @param float $rightMargin
18	 * @param float $xDim
19	 * @param float $barHeight
20	 * @param float $separatorMargin
21	 */
22	public function __construct($code, $length, $leftMargin, $rightMargin, $xDim, $barHeight, $separatorMargin)
23	{
24		$this->init($code, $length);
25
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)
30		$this->data['sepM'] = $separatorMargin; // SEPARATION margin =  x X-dim (http://web.archive.org/web/19990501035133/http://www.uc-council.org/d36-d.htm)
31	}
32
33	/**
34	 * @param string $code
35	 * @param int $length
36	 */
37	private function init($code, $length = 5)
38	{
39		// Padding
40		$code = str_pad($code, $length, '0', STR_PAD_LEFT);
41
42		// Calculate check digit
43		if ($length == 2) {
44			$r = $code % 4;
45		} elseif ($length == 5) {
46			$r = (3 * ($code[0] + $code[2] + $code[4])) + (9 * ($code[1] + $code[3]));
47			$r %= 10;
48		} else {
49			throw new \Mpdf\Barcode\BarcodeException(sprintf('Invalid EAN barcode value "%s"', $code));
50		}
51
52		// Convert digits to bars
53		$codes = [
54			'A' => [ // left odd parity
55				'0' => '0001101',
56				'1' => '0011001',
57				'2' => '0010011',
58				'3' => '0111101',
59				'4' => '0100011',
60				'5' => '0110001',
61				'6' => '0101111',
62				'7' => '0111011',
63				'8' => '0110111',
64				'9' => '0001011'],
65			'B' => [ // left even parity
66				'0' => '0100111',
67				'1' => '0110011',
68				'2' => '0011011',
69				'3' => '0100001',
70				'4' => '0011101',
71				'5' => '0111001',
72				'6' => '0000101',
73				'7' => '0010001',
74				'8' => '0001001',
75				'9' => '0010111']
76		];
77		$parities = [];
78		$parities[2] = [
79			'0' => ['A', 'A'],
80			'1' => ['A', 'B'],
81			'2' => ['B', 'A'],
82			'3' => ['B', 'B']
83		];
84		$parities[5] = [
85			'0' => ['B', 'B', 'A', 'A', 'A'],
86			'1' => ['B', 'A', 'B', 'A', 'A'],
87			'2' => ['B', 'A', 'A', 'B', 'A'],
88			'3' => ['B', 'A', 'A', 'A', 'B'],
89			'4' => ['A', 'B', 'B', 'A', 'A'],
90			'5' => ['A', 'A', 'B', 'B', 'A'],
91			'6' => ['A', 'A', 'A', 'B', 'B'],
92			'7' => ['A', 'B', 'A', 'B', 'A'],
93			'8' => ['A', 'B', 'A', 'A', 'B'],
94			'9' => ['A', 'A', 'B', 'A', 'B']
95		];
96		$p = $parities[$length][$r];
97		$seq = '1011'; // left guard bar
98		$seq .= $codes[$p[0]][$code[0]];
99		for ($i = 1; $i < $length; ++$i) {
100			$seq .= '01'; // separator
101			$seq .= $codes[$p[$i]][$code[$i]];
102		}
103
104		$bararray = ['code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => []];
105
106		$this->data = $this->binseqToArray($seq, $bararray);
107	}
108
109	public function getType()
110	{
111		return 'EAN EXT';
112	}
113
114}
115