1<?php
2
3namespace jucksearm\barcode\lib;
4
5use jucksearm\barcode\lib\Barcode2D;
6
7class DatamatrixFactory
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, 'DATAMATRIX');
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->margin > 0) {
157			$scale['frame'] = $this->size - ($this->_borderPx * 2);
158			$scale['margin'] = round($this->size * ($this->margin / 100));
159			$scale['area'] = $scale['frame'] - (($scale['margin'] * 2));
160			$scale['size'] = floor($scale['area'] / $bcd['num_cols']);
161			$scale['posX'] = $scale['margin'] + floor(($scale['area'] - ($bcd['num_cols'] * $scale['size'])) / 2);
162			$scale['posY'] = $scale['posX'];
163		} else {
164			$scale['frame'] = $this->size;
165			$scale['margin'] = 0;
166			$scale['area'] = $this->size;
167			$scale['size'] = floor($scale['area'] / $bcd['num_cols']);
168			$scale['posX'] = floor(($scale['frame'] - ($bcd['num_cols'] * $scale['size'])) / 2);
169			$scale['posY'] = $scale['posX'];
170		}
171
172		if ($this->size < $scale['frame'])
173			throw new \Exception('This size not render.');
174
175		return (object) $scale;
176	}
177
178	public function getDatamatrixHtmlData()
179	{
180		$bcd = $this->barcode->getBarcodeArray();
181		$color = $this->hexColor;
182		$scale = $this->scale;
183
184		if ($this->margin > 0) {
185			$datamatrixData = '<div style="position:absolute; border: solid '.$this->_borderPx.'px '.$this->hexColor.'; width:'.($this->size - 2).'px; height:'.($this->size - 2).'px">';
186		} else {
187			$datamatrixData = '<div style="position:absolute; width:'.$this->size.'px; height:'.$this->size.'px">';
188		}
189
190		$datamatrixData .= '<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";
191
192		$w = $scale->size;
193		$h = $scale->size;
194
195		// print bars
196		$y = 0;
197		// for each row
198		for ($r = 0; $r < $bcd['num_rows']; ++$r) {
199			$x = 0;
200			// for each column
201			for ($c = 0; $c < $bcd['num_cols']; ++$c) {
202				if ($bcd['bcode'][$r][$c] == 1) {
203					// draw a single barcode cell
204					$datamatrixData .= '<div style="background-color:'.$color.';width:'.$w.'px;height:'.$h.'px;position:absolute;left:'.$x.'px;top:'.$y.'px;">&nbsp;</div>'."\n";
205				}
206				$x += $w;
207			}
208			$y += $h;
209		}
210
211		$datamatrixData .= '</div>'."\n";
212
213		$datamatrixData .= '</div>'."\n";
214
215		return $datamatrixData;
216	}
217
218	public function getDatamatrixPngData()
219	{
220		$bcd = $this->barcode->getBarcodeArray();
221		$this->_borderPx = 0;
222		$color = $this->rgbColor;
223		$scale = $this->scale;
224
225		$w = $bcd['num_cols'] * $scale->size;
226		$h = $bcd['num_rows'] * $scale->size;
227
228		if (function_exists('imagecreate')) {
229			$png = imagecreate($w, $h);
230			$bgcol = imagecolorallocate($png, 255, 255, 255);
231			imagecolortransparent($png, $bgcol);
232			$fgcol = imagecolorallocate($png, $color[0], $color[1], $color[2]);
233		} else {
234			return false;
235		}
236
237		// print bars
238		$y = 0;
239		// for each row
240		for ($r = 0; $r < $bcd['num_rows']; ++$r) {
241			$x = 0;
242			// for each column
243			for ($c = 0; $c < $bcd['num_cols']; ++$c) {
244				if ($bcd['bcode'][$r][$c] == 1) {
245					imagefilledrectangle($png, $x, $y, ($x + $scale->size - 1), ($y + $scale->size - 1), $fgcol);
246				}
247				$x += $scale->size;
248			}
249			$y += $scale->size;
250		}
251
252		$frame = imagecreatetruecolor($this->size, $this->size);
253		$blank = imagecreate($this->size, $this->size);
254		imagecolorallocate($blank, 255, 255, 255);
255		imagecopyresampled($frame, $blank, 0, 0, 0, 0, imagesx($blank), imagesy($blank), imagesx($blank), imagesy($blank));
256		imagedestroy($blank);
257		imagecopyresampled($frame, $png, $scale->posX, $scale->posY, 0, 0, imagesx($png), imagesy($png), imagesx($png), imagesy($png));
258		imagedestroy($png);
259
260		if ($this->file === null) {
261			ob_start();
262			imagepng($frame);
263			$datamatrixData = ob_get_clean();
264		} else {
265			preg_match("/\.png$/", $this->file, $output);
266			if (count($output) == 0)
267				throw new \Exception('Incorrect file extension format.');
268
269			$filePath = explode(DIRECTORY_SEPARATOR, $this->file);
270			if (count($filePath) == 1 ) {
271				$savePath = dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'tmp'.DIRECTORY_SEPARATOR.$this->file;
272			} else {
273				$savePath = $this->file;
274			}
275
276			if (!@imagepng($frame, $savePath))
277				throw new \Exception('Not found save path.');
278
279			$datamatrixData = file_get_contents($savePath);
280		}
281
282		imagedestroy($frame);
283
284		return $datamatrixData;
285	}
286
287	public function getDatamatrixSvgData()
288	{
289		$bcd = $this->barcode->getBarcodeArray();
290		$color = $this->hexColor;
291		$scale = $this->scale;
292
293		$w = $bcd['num_cols'] * $scale->size;
294		$h = $bcd['num_rows'] * $scale->size;
295
296		$repstr = array("\0" => '', '&' => '&amp;', '<' => '&lt;', '>' => '&gt;');
297		$datamatrixData = '<'.'?'.'xml version="1.0" standalone="no"'.'?'.'>'."\n";
298		$datamatrixData .= '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'."\n";
299		$datamatrixData .= '<svg width="'.$this->size.'" height="'.$this->size.'" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">'."\n";
300		$datamatrixData .= "\t".'<desc>'.strtr($bcd['code'], $repstr).'</desc>'."\n";
301
302		if ($this->margin > 0) {
303			$datamatrixData .= "\t".'<g id="border" fill="none" stroke="'.$color.'">'."\n";
304			$datamatrixData .= "\t\t".'<rect height="'.$this->size.'" width="'.$this->size.'" y="0" x="0" />'."\n";
305			$datamatrixData .= "\t".'</g>'."\n";
306		}
307
308		$datamatrixData .= "\t".'<g id="bars" fill="'.$color.'" stroke="none">'."\n";
309		// print bars
310		$y = $scale->posY;
311		// for each row
312		for ($r = 0; $r < $bcd['num_rows']; ++$r) {
313			$x = $scale->posX;
314			// for each column
315			for ($c = 0; $c < $bcd['num_cols']; ++$c) {
316				if ($bcd['bcode'][$r][$c] == 1) {
317					// draw a single barcode cell
318					$datamatrixData .= "\t\t".'<rect x="'.$x.'" y="'.$y.'" width="'.$scale->size.'" height="'.$scale->size.'" />'."\n";
319				}
320				$x += $scale->size;
321			}
322			$y += $scale->size;
323		}
324		$datamatrixData .= "\t".'</g>'."\n";
325
326		$datamatrixData .= '</svg>'."\n";
327
328		if ($this->file != null) {
329			preg_match("/\.svg$/", $this->file, $output);
330			if (count($output) == 0)
331				throw new \Exception('Incorrect file extension format.');
332
333			$filePath = explode(DIRECTORY_SEPARATOR, $this->file);
334			if (count($filePath) == 1 ) {
335				$savePath = dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'tmp'.DIRECTORY_SEPARATOR.$this->file;
336			} else {
337				$savePath = $this->file;
338			}
339
340			if (!@file_put_contents($savePath, $datamatrixData))
341				throw new \Exception('Not found save path.');
342		}
343
344		return $datamatrixData;
345	}
346
347	public function renderHTML()
348	{
349		$datamatrixData = $this->getDatamatrixHtmlData();
350
351		header('Content-Type: text/html');
352		header('Content-Length: '.strlen($datamatrixData));
353		header('Cache-Control: no-cache');
354		header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
355
356		echo $datamatrixData;
357	}
358
359	public function renderPNG()
360	{
361		$datamatrixData = $this->getDatamatrixPngData();
362
363		header('Content-Type: image/png');
364		header('Content-Length: '.strlen($datamatrixData));
365		header('Cache-Control: no-cache');
366		header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
367
368		echo $datamatrixData;
369	}
370
371	public function renderSVG()
372	{
373		$datamatrixData = $this->getDatamatrixSvgData();
374
375		header('Content-Type: image/svg+xml');
376		header('Content-Length: '.strlen($datamatrixData));
377		header('Cache-Control: no-cache');
378		header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
379
380		echo $datamatrixData;
381	}
382}