1<?php
2/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
3
4/**
5 * Image_Barcode2_Driver_Upce class
6 *
7 * Renders UPC-E barcodes
8 *
9 * PHP versions 5
10 *
11 * LICENSE: This source file is subject to version 3.0 of the PHP license
12 * that is available through the world-wide-web at the following URI:
13 * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
14 * the PHP License and are unable to obtain it through the web, please
15 * send a note to license@php.net so we can mail you a copy immediately.
16 *
17 * @category  Image
18 * @package   Image_Barcode2
19 * @author    Ryan McLaughlin <ryanmclaughlin@gmail.com>
20 * @copyright 2012 The PHP Group
21 * @license   http://www.php.net/license/3_0.txt  PHP License 3.0
22 * @link      http://pear.php.net/package/Image_Barcode2
23 */
24
25require_once 'Image/Barcode2/Driver.php';
26require_once 'Image/Barcode2/Common.php';
27require_once 'Image/Barcode2/Exception.php';
28
29/**
30 * UPC-E
31 *
32 * Package which provides a method to create UPC-A barcode using GD library.
33 *
34 * Slightly Modified Upca.php to get Upce.php I needed a way to print
35 * UPC-E bar codes on a PHP page.  The Image_Barcode2 class seemed like
36 * the best way to do it, so I modified UPC-A to print in the UPC-E format.
37 * Checked the bar code tables against some documentation below (no errors)
38 * and validated the changes with my phone app "Barcode Scanner"
39 *
40 * @category  Image
41 * @package   Image_Barcode2
42 * @author    Ryan McLaughlin <ryanmclaughlin@gmail.com>
43 * @copyright 2012 The PHP Group
44 * @license   http://www.php.net/license/3_0.txt  PHP License 3.0
45 * @version   Release: @package_version@
46 * @link      http://pear.php.net/package/Image_Barcode2
47 */
48class Image_Barcode2_Driver_Upce extends Image_Barcode2_Common implements Image_Barcode2_Driver
49{
50    /**
51     * Coding map
52     * @var array
53     */
54    private $_paritypattern = array(
55        '0' => array(1,1,1,0,0,0),
56        '1' => array(1,1,0,1,0,0),
57        '2' => array(1,1,0,0,1,0),
58        '3' => array(1,1,0,0,0,1),
59        '4' => array(1,0,1,1,0,0),
60        '5' => array(1,0,0,1,1,0),
61        '6' => array(1,0,0,0,1,1),
62        '7' => array(1,0,1,0,1,0),
63        '8' => array(1,0,1,0,0,1),
64        '9' => array(1,0,0,1,0,1)
65    );
66
67    private $_codingmap = array(
68        '0' => array(
69            'O' => array(0,0,0,1,1,0,1),
70            'E' => array(0,1,0,0,1,1,1)
71        ),
72        '1' => array(
73            'O' => array(0,0,1,1,0,0,1),
74            'E' => array(0,1,1,0,0,1,1)
75        ),
76        '2' => array(
77            'O' => array(0,0,1,0,0,1,1),
78            'E' => array(0,0,1,1,0,1,1)
79        ),
80        '3' => array(
81            'O' => array(0,1,1,1,1,0,1),
82            'E' => array(0,1,0,0,0,0,1)
83        ),
84        '4' => array(
85            'O' => array(0,1,0,0,0,1,1),
86            'E' => array(0,0,1,1,1,0,1)
87        ),
88        '5' => array(
89            'O' => array(0,1,1,0,0,0,1),
90            'E' => array(0,1,1,1,0,0,1)
91        ),
92        '6' => array(
93            'O' => array(0,1,0,1,1,1,1),
94            'E' => array(0,0,0,0,1,0,1)
95        ),
96        '7' => array(
97            'O' => array(0,1,1,1,0,1,1),
98            'E' => array(0,0,1,0,0,0,1)
99        ),
100        '8' => array(
101            'O' => array(0,1,1,0,1,1,1),
102            'E' => array(0,0,0,1,0,0,1)
103        ),
104        '9' => array(
105            'O' => array(0,0,0,1,0,1,1),
106            'E' => array(0,0,1,0,1,1,1)
107        )
108    );
109
110    /**
111     * Class constructor
112     *
113     * @param Image_Barcode2_Writer $writer Library to use.
114     */
115    public function __construct(Image_Barcode2_Writer $writer)
116    {
117        parent::__construct($writer);
118        $this->setBarcodeHeight(50);
119        $this->setBarcodeWidth(1);
120    }
121
122
123    /**
124     * Validate barcode
125     *
126     * @return void
127     * @throws Image_Barcode2_Exception
128     */
129    public function validate()
130    {
131        // Check barcode for invalid characters
132        if (!preg_match('/^[0-9]{8}$/', $this->getBarcode())) {
133            throw new Image_Barcode2_Exception('Invalid barcode');
134        }
135    }
136
137
138    /**
139     * Draws a UPC-E image barcode
140     *
141     * @return resource            The corresponding UPC-E image barcode
142     *
143     * @author  Ryan McLaughlin <ryanmclaughlin@gmail.com>
144     */
145    public function draw()
146    {
147        $text     = $this->getBarcode();
148        $writer   = $this->getWriter();
149        $fontsize = $this->getFontSize();
150
151        // Calculate the barcode width
152        $barcodewidth = (strlen($text)) * (7 * $this->getBarcodeWidth())
153            + $writer->imagefontwidth($fontsize)
154            + $writer->imagefontwidth($fontsize) // check digit padding
155            ;
156
157
158        $barcodelongheight = (int)($writer->imagefontheight($fontsize) / 2)
159            + $this->getBarcodeHeight();
160
161        // Create the image
162        $img = $writer->imagecreate(
163            $barcodewidth,
164            $barcodelongheight + $writer->imagefontheight($fontsize) + 1
165        );
166
167        // Alocate the black and white colors
168        $black = $writer->imagecolorallocate($img, 0, 0, 0);
169        $white = $writer->imagecolorallocate($img, 255, 255, 255);
170
171        // Fill image with white color
172        $writer->imagefill($img, 0, 0, $white);
173
174        // get the first digit which is the key for creating the first 6 bars
175        $key = substr($text, 0, 1);
176
177        // Initiate x position
178        $xpos = 0;
179
180        // print first digit
181        if ($this->showText) {
182            $writer->imagestring(
183                $img,
184                $fontsize,
185                $xpos,
186                $this->getBarcodeHeight(),
187                $key,
188                $black
189            );
190        }
191        $xpos = $writer->imagefontwidth($fontsize) + 1;
192
193
194        // Draws the left guard pattern (bar-space-bar)
195        // bar
196        $writer->imagefilledrectangle(
197            $img,
198            $xpos,
199            0,
200            $xpos + $this->getBarcodeWidth() - 1,
201            $barcodelongheight,
202            $black
203        );
204
205        $xpos += $this->getBarcodeWidth();
206        // space
207        $xpos += $this->getBarcodeWidth();
208        // bar
209        $writer->imagefilledrectangle(
210            $img,
211            $xpos,
212            0,
213            $xpos + $this->getBarcodeWidth() - 1,
214            $barcodelongheight,
215            $black
216        );
217
218        $xpos += $this->getBarcodeWidth();
219
220
221        // Draw middle $text contents
222        $checkdigit = substr($text, 7, 1);
223        for ($idx = 1; $idx < 7; $idx ++) {
224            $value = substr($text, $idx, 1);
225
226            if ($this->showText) {
227                $writer->imagestring(
228                    $img,
229                    $fontsize,
230                    $xpos + 1,
231                    $this->getBarcodeHeight(),
232                    $value,
233                    $black
234                );
235            }
236
237            if ($this->_paritypattern[$checkdigit][$idx-1] == 1) {
238                foreach ($this->_codingmap[$value]['E'] as $bar) {
239                    if ($bar) {
240                        $writer->imagefilledrectangle(
241                            $img,
242                            $xpos,
243                            0,
244                            $xpos + $this->getBarcodeWidth() - 1,
245                            $this->getBarcodeHeight(),
246                            $black
247                        );
248                    }
249                    $xpos += $this->getBarcodeWidth();
250                }
251            } else {
252                foreach ($this->_codingmap[$value]['O'] as $bar) {
253                    if ($bar) {
254                        $writer->imagefilledrectangle(
255                            $img,
256                            $xpos,
257                            0,
258                            $xpos + $this->getBarcodeWidth() - 1,
259                            $this->getBarcodeHeight(),
260                            $black
261                        );
262                    }
263                    $xpos += $this->getBarcodeWidth();
264                }
265            }
266        }
267
268        // space
269        $xpos += $this->getBarcodeWidth();
270
271        // Draws the right guard pattern (bar-space-bar-space-bar)
272        // bar
273        $writer->imagefilledrectangle(
274            $img,
275            $xpos,
276            0,
277            $xpos + $this->getBarcodeWidth() - 1,
278            $barcodelongheight,
279            $black
280        );
281
282        $xpos += $this->getBarcodeWidth();
283        // space
284        $xpos += $this->getBarcodeWidth();
285        // bar
286        $writer->imagefilledrectangle(
287            $img,
288            $xpos,
289            0,
290            $xpos + $this->getBarcodeWidth() - 1,
291            $barcodelongheight,
292            $black
293        );
294
295        $xpos += $this->getBarcodeWidth();
296        // space
297        $xpos += $this->getBarcodeWidth();
298        // bar
299        $writer->imagefilledrectangle(
300            $img,
301            $xpos,
302            0,
303            $xpos + $this->getBarcodeWidth() - 1,
304            $barcodelongheight,
305            $black
306        );
307
308        $xpos += $this->getBarcodeWidth();
309
310
311        // Print Check Digit
312        if ($this->showText) {
313            $writer->imagestring(
314                $img,
315                $fontsize,
316                $xpos + 1,
317                $this->getBarcodeHeight(),
318                $checkdigit,
319                $black
320            );
321        }
322
323        return $img;
324    }
325
326} // class
327