1<?php
2
3namespace jucksearm\barcode\lib;
4
5use jucksearm\barcode\lib\Barcode2D;
6
7class PDF417Factory
8{
9	private $_attributes;
10	private $_borderPx = 1;
11	private $_marginPx = 5;
12	private $_scalePx = 1;
13
14	public function __construct()
15	{
16		$this->_attributes = [
17			'code'   => null,
18			'file'   => null,
19			'size'   => 100,
20			'margin' => 1,
21			'color'  => '000',
22		];
23	}
24
25	public function __set($name, $value)
26	{
27		$setter = 'set' . $name;
28        if (method_exists($this, $setter)) {
29            // set property
30            $this->$setter($value);
31
32            return;
33         }
34	}
35
36	public function __get($name)
37	{
38		$getter = 'get' . $name;
39        if (method_exists($this, $getter)) {
40            // read property
41            return $this->$getter();
42        }
43	}
44
45	public function setAttribute($name, $value)
46	{
47		if ($value === null) return;
48
49		$this->_attributes[$name] = $value;
50	}
51
52	public function getAttribute($name)
53	{
54		return $this->_attributes[$name];
55	}
56
57	public function setAttributes($attrs = [])
58	{
59		array_merge($this->_attributes, $attrs);
60	}
61
62	public function getAttributes()
63	{
64		return $this->_attributes;
65	}
66
67	public function setCode($value)
68	{
69		$this->setAttribute('code', $value);
70		return $this;
71	}
72
73	public function getCode()
74	{
75		return $this->getAttribute('code');
76	}
77
78	public function setFile($value)
79	{
80		$this->setAttribute('file', $value);
81		return $this;
82	}
83
84	public function getFile()
85	{
86		return $this->getAttribute('file');
87	}
88
89	public function setSize($value)
90	{
91		$this->setAttribute('size', $value);
92		return $this;
93	}
94
95	public function getSize()
96	{
97		return $this->getAttribute('size') * $this->_scalePx;
98	}
99
100	public function setMargin($value)
101	{
102		$this->setAttribute('margin', $value);
103		return $this;
104	}
105
106	public function getMargin()
107	{
108		return $this->getAttribute('margin');
109	}
110
111	public function setColor($value)
112	{
113		$this->setAttribute('color', $value);
114		return $this;
115	}
116
117	public function getColor()
118	{
119		return $this->getAttribute('color');
120	}
121
122	public function getBarcode()
123	{
124		return new Barcode2D($this->code, 'PDF417');
125	}
126
127	public function getHexColor()
128	{
129		$color = $this->color;
130
131		return '#'.$color;
132	}
133
134	public function getRgbColor()
135	{
136		$color = $this->color;
137
138		if (strlen($color) > 3) {
139			$r = hexdec(substr($color, 0, 2));
140			$g = hexdec(substr($color, 2, 2));
141			$b = hexdec(substr($color, 4, 2));
142		} else {
143			$r = hexdec(substr($color, 0, 1).substr($color, 0, 1));
144			$g = hexdec(substr($color, 1, 1).substr($color, 1, 1));
145			$b = hexdec(substr($color, 2, 1).substr($color, 2, 1));
146		}
147
148		return [$r, $g, $b];
149	}
150
151	private function getScale()
152	{
153		$scale = [];
154		$bcd = $this->barcode->getBarcodeArray();
155
156		if ($this->size < $bcd['num_cols'])
157			throw new \Exception('This size not render.');
158
159		if ($this->margin > 0) {
160			$scale['frameX'] = $this->size - ($this->_borderPx * 2);
161			$scale['margin'] = round($this->size * ($this->margin / 100));
162			$scale['area'] = $scale['frameX'] - (($scale['margin'] * 2));
163			$scale['size'] = floor($scale['area'] / $bcd['num_cols']);
164			$scale['posX'] = $scale['margin'] + floor(($scale['area'] - ($bcd['num_cols'] * $scale['size'])) / 2);
165			$scale['posY'] = $scale['posX'];
166			$scale['frameY'] = ($bcd['num_rows'] * $scale['size']) + ($scale['posY'] * 2);
167		} else {
168			$scale['frameX'] = $this->size;
169			$scale['margin'] = 0;
170			$scale['area'] = $this->size;
171			$scale['size'] = floor($scale['area'] / $bcd['num_cols']);
172			$scale['posX'] = floor(($scale['frameX'] - ($bcd['num_cols'] * $scale['size'])) / 2);
173			$scale['posY'] = $scale['posX'];
174			$scale['frameY'] = ($bcd['num_rows'] * $scale['size']) + ($scale['posY'] * 2);
175		}
176// exit;
177
178
179		return (object) $scale;
180	}
181
182	public function getPDF417HtmlData()
183	{
184		$bcd = $this->barcode->getBarcodeArray();
185		$color = $this->hexColor;
186		$scale = $this->scale;
187
188		if ($this->margin > 0) {
189			$pdf417Data = '<div style="position:absolute; border: solid '.$this->_borderPx.'px '.$this->hexColor.'; width:'.$scale->frameX.'px; height:'.$scale->frameY.'px">';
190		} else {
191			$pdf417Data = '<div style="position:absolute; width:'.$scale->frameX.'px; height:'.$scale->frameY.'px">';
192		}
193
194		$pdf417Data .= '<div style="font-size:0;position:absolute; width:'.($scale->size * $bcd['num_cols']).'px;height:'.($scale->size * $bcd['num_rows']).'px; top:'.$scale->posY.'px; left:'.$scale->posX.'px" z-index:1;>'."\n";
195
196		$w = $scale->size;
197		$h = $scale->size;
198
199		// print bars
200		$y = 0;
201		// for each row
202		for ($r = 0; $r < $bcd['num_rows']; ++$r) {
203			$x = 0;
204			// for each column
205			for ($c = 0; $c < $bcd['num_cols']; ++$c) {
206				if ($bcd['bcode'][$r][$c] == 1) {
207					// draw a single barcode cell
208					$pdf417Data .= '<div style="background-color:'.$color.';width:'.$w.'px;height:'.$h.'px;position:absolute;left:'.$x.'px;top:'.$y.'px;">&nbsp;</div>'."\n";
209				}
210				$x += $w;
211			}
212			$y += $h;
213		}
214
215		$pdf417Data .= '</div>'."\n";
216
217		$pdf417Data .= '</div>'."\n";
218
219		return $pdf417Data;
220	}
221
222	public function getPDF417PngData()
223	{
224		$bcd = $this->barcode->getBarcodeArray();
225		$this->_borderPx = 0;
226		$color = $this->rgbColor;
227		$scale = $this->scale;
228
229		$w = $bcd['num_cols'] * $scale->size;
230		$h = $bcd['num_rows'] * $scale->size;
231
232		if (function_exists('imagecreate')) {
233			$png = imagecreate($w, $h);
234			$bgcol = imagecolorallocate($png, 255, 255, 255);
235			imagecolortransparent($png, $bgcol);
236			$fgcol = imagecolorallocate($png, $color[0], $color[1], $color[2]);
237		} else {
238			return false;
239		}
240
241		// print bars
242		$y = 0;
243		// for each row
244		for ($r = 0; $r < $bcd['num_rows']; ++$r) {
245			$x = 0;
246			// for each column
247			for ($c = 0; $c < $bcd['num_cols']; ++$c) {
248				if ($bcd['bcode'][$r][$c] == 1) {
249					imagefilledrectangle($png, $x, $y, ($x + $scale->size - 1), ($y + $scale->size - 1), $fgcol);
250				}
251				$x += $scale->size;
252			}
253			$y += $scale->size;
254		}
255
256		$frame = imagecreatetruecolor($scale->frameX, $scale->frameY);
257		$blank = imagecreate($this->size, $this->size);
258		imagecolorallocate($blank, 255, 255, 255);
259		imagecopyresampled($frame, $blank, 0, 0, 0, 0, imagesx($blank), imagesy($blank), imagesx($blank), imagesy($blank));
260		imagedestroy($blank);
261		imagecopyresampled($frame, $png, $scale->posX, $scale->posY, 0, 0, imagesx($png), imagesy($png), imagesx($png), imagesy($png));
262		imagedestroy($png);
263
264		if ($this->file === null) {
265			ob_start();
266			imagepng($frame);
267			$pdf417Data = ob_get_clean();
268		} else {
269			preg_match("/\.png$/", $this->file, $output);
270			if (count($output) == 0)
271				throw new \Exception('Incorrect file extension format.');
272
273			$filePath = explode(DIRECTORY_SEPARATOR, $this->file);
274			if (count($filePath) == 1 ) {
275				$savePath = dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'tmp'.DIRECTORY_SEPARATOR.$this->file;
276			} else {
277				$savePath = $this->file;
278			}
279
280			if (!@imagepng($frame, $savePath))
281				throw new \Exception('Not found save path.');
282
283			$pdf417Data = file_get_contents($savePath);
284		}
285
286		imagedestroy($frame);
287
288		return $pdf417Data;
289	}
290
291	public function getPDF417SvgData()
292	{
293		$bcd = $this->barcode->getBarcodeArray();
294		$color = $this->hexColor;
295		$scale = $this->scale;
296
297		$w = $bcd['num_cols'] * $scale->size;
298		$h = $bcd['num_rows'] * $scale->size;
299
300		$repstr = array("\0" => '', '&' => '&amp;', '<' => '&lt;', '>' => '&gt;');
301		$pdf417Data = '<'.'?'.'xml version="1.0" standalone="no"'.'?'.'>'."\n";
302		$pdf417Data .= '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'."\n";
303		$pdf417Data .= '<svg width="'.$scale->frameX.'" height="'.$scale->frameY.'" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">'."\n";
304		$pdf417Data .= "\t".'<desc>'.strtr($bcd['code'], $repstr).'</desc>'."\n";
305
306		if ($this->margin > 0) {
307			$pdf417Data .= "\t".'<g id="border" fill="none" stroke="'.$color.'">'."\n";
308			$pdf417Data .= "\t\t".'<rect height="'.$scale->frameY.'" width="'.$scale->frameX.'" y="0" x="0" />'."\n";
309			$pdf417Data .= "\t".'</g>'."\n";
310		}
311
312		$pdf417Data .= "\t".'<g id="bars" fill="'.$color.'" stroke="none">'."\n";
313		// print bars
314		$y = $scale->posY;
315		// for each row
316		for ($r = 0; $r < $bcd['num_rows']; ++$r) {
317			$x = $scale->posX;
318			// for each column
319			for ($c = 0; $c < $bcd['num_cols']; ++$c) {
320				if ($bcd['bcode'][$r][$c] == 1) {
321					// draw a single barcode cell
322					$pdf417Data .= "\t\t".'<rect x="'.$x.'" y="'.$y.'" width="'.$scale->size.'" height="'.$scale->size.'" />'."\n";
323				}
324				$x += $scale->size;
325			}
326			$y += $scale->size;
327		}
328		$pdf417Data .= "\t".'</g>'."\n";
329
330		$pdf417Data .= '</svg>'."\n";
331
332		if ($this->file != null) {
333			preg_match("/\.svg$/", $this->file, $output);
334			if (count($output) == 0)
335				throw new \Exception('Incorrect file extension format.');
336
337			$filePath = explode(DIRECTORY_SEPARATOR, $this->file);
338			if (count($filePath) == 1 ) {
339				$savePath = dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'tmp'.DIRECTORY_SEPARATOR.$this->file;
340			} else {
341				$savePath = $this->file;
342			}
343
344			if (!@file_put_contents($savePath, $pdf417Data))
345				throw new \Exception('Not found save path.');
346		}
347
348		return $pdf417Data;
349	}
350
351	public function renderHTML()
352	{
353		$pdf417Data = $this->getPDF417HtmlData();
354
355		header('Content-Type: text/html');
356		header('Content-Length: '.strlen($pdf417Data));
357		header('Cache-Control: no-cache');
358		header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
359
360		echo $pdf417Data;
361	}
362
363	public function renderPNG()
364	{
365		$pdf417Data = $this->getPDF417PngData();
366
367		header('Content-Type: image/png');
368		header('Content-Length: '.strlen($pdf417Data));
369		header('Cache-Control: no-cache');
370		header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
371
372		echo $pdf417Data;
373	}
374
375	public function renderSVG()
376	{
377		$pdf417Data = $this->getPDF417SvgData();
378
379		header('Content-Type: image/svg+xml');
380		header('Content-Length: '.strlen($pdf417Data));
381		header('Cache-Control: no-cache');
382		header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
383
384		echo $pdf417Data;
385	}
386}