1<?php
2/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
3
4/**
5 * Image_Barcode2_Driver_Code39 class
6 *
7 * Image_Barcode2_Code39 creates Code 3 of 9 ( Code39 ) barcode images.
8 * It's implementation borrows heavily for the perl module GD::Barcode::Code39
9 *
10 * PHP versions 5
11 *
12 * LICENSE: This source file is subject to version 3.0 of the PHP license
13 * that is available through the world-wide-web at the following URI:
14 * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
15 * the PHP License and are unable to obtain it through the web, please
16 * send a note to license@php.net so we can mail you a copy immediately.
17 *
18 * @category  Image
19 * @package   Image_Barcode2
20 * @author    Ryan Briones <ryanbriones@webxdesign.org>
21 * @copyright 2005 The PHP Group
22 * @license   http://www.php.net/license/3_0.txt  PHP License 3.0
23 * @link      http://pear.php.net/package/Image_Barcode2
24 */
25
26require_once 'Image/Barcode2/Driver.php';
27require_once 'Image/Barcode2/Common.php';
28require_once 'Image/Barcode2/DualWidth.php';
29require_once 'Image/Barcode2/Exception.php';
30
31/**
32 * Code 3 of 9
33 *
34 * Package which provides a method to create Code 3 of 9 using GD library.
35 *
36 * @category  Image
37 * @package   Image_Barcode2
38 * @author    Ryan Briones <ryanbriones@webxdesign.org>
39 * @copyright 2005 The PHP Group
40 * @license   http://www.php.net/license/3_0.txt  PHP License 3.0
41 * @version   Release: @package_version@
42 * @link      http://pear.php.net/package/Image_Barcode2
43 * @since     Image_Barcode2 0.5
44 */
45class Image_Barcode2_Driver_Code39 extends Image_Barcode2_Common implements Image_Barcode2_Driver, Image_Barcode2_DualWidth
46{
47    /**
48     * Coding map
49     * @var array
50     */
51    private $_codingmap = array(
52        '0' => '000110100',
53        '1' => '100100001',
54        '2' => '001100001',
55        '3' => '101100000',
56        '4' => '000110001',
57        '5' => '100110000',
58        '6' => '001110000',
59        '7' => '000100101',
60        '8' => '100100100',
61        '9' => '001100100',
62        'A' => '100001001',
63        'B' => '001001001',
64        'C' => '101001000',
65        'D' => '000011001',
66        'E' => '100011000',
67        'F' => '001011000',
68        'G' => '000001101',
69        'H' => '100001100',
70        'I' => '001001100',
71        'J' => '000011100',
72        'K' => '100000011',
73        'L' => '001000011',
74        'M' => '101000010',
75        'N' => '000010011',
76        'O' => '100010010',
77        'P' => '001010010',
78        'Q' => '000000111',
79        'R' => '100000110',
80        'S' => '001000110',
81        'T' => '000010110',
82        'U' => '110000001',
83        'V' => '011000001',
84        'W' => '111000000',
85        'X' => '010010001',
86        'Y' => '110010000',
87        'Z' => '011010000',
88        '-' => '010000101',
89        '*' => '010010100',
90        '+' => '010001010',
91        '$' => '010101000',
92        '%' => '000101010',
93        '/' => '010100010',
94        '.' => '110000100',
95        ' ' => '011000100'
96    );
97
98    /**
99     * Class constructor
100     *
101     * @param Image_Barcode2_Writer $writer Library to use.
102     */
103    public function __construct(Image_Barcode2_Writer $writer)
104    {
105        parent::__construct($writer);
106        $this->setBarcodeHeight(50);
107        $this->setBarcodeWidthThin(1);
108        $this->setBarcodeWidthThick(3);
109    }
110
111
112    /**
113     * Validate barcode
114     *
115     * @return void
116     * @throws Image_Barcode2_Exception
117     */
118    public function validate()
119    {
120        // Check barcode for invalid characters
121        if (preg_match("/[^0-9A-Z\-*+\$%\/. ]/", $this->getBarcode())) {
122            throw new Image_Barcode2_Exception('Invalid barcode');
123        }
124    }
125
126
127    /**
128     * Make an image resource using the GD image library
129     *
130     * @return resource           The Barcode Image (TM)
131     *
132     * @author Ryan Briones <ryanbriones@webxdesign.org>
133     */
134    public function draw()
135    {
136        $text     = $this->getBarcode();
137        $writer   = $this->getWriter();
138        $fontsize = $this->getFontSize();
139
140        // add start and stop * characters
141        $final_text = '*' . $text . '*';
142
143        $barcode = '';
144        foreach (str_split($final_text) as $character) {
145            $barcode .= $this->_dumpCode($this->_codingmap[$character] . '0');
146        }
147
148        $barcode_len = strlen($barcode);
149
150        // Create GD image object
151        $img = $writer->imagecreate($barcode_len, $this->getBarcodeHeight());
152
153        // Allocate black and white colors to the image
154        $black = $writer->imagecolorallocate($img, 0, 0, 0);
155        $white = $writer->imagecolorallocate($img, 255, 255, 255);
156        $font_height = $writer->imagefontheight($fontsize);
157        $font_width = $writer->imagefontwidth($fontsize);
158
159        // fill background with white color
160        $writer->imagefill($img, 0, 0, $white);
161
162        // Initialize X position
163        $xpos = 0;
164
165        // draw barcode bars to image
166        foreach (str_split($barcode) as $character_code) {
167            if ($character_code == 0) {
168                $writer->imageline(
169                    $img,
170                    $xpos,
171                    0,
172                    $xpos,
173                    $this->getBarcodeHeight() - $font_height - 1,
174                    $white
175                );
176            } else {
177                $writer->imageline(
178                    $img,
179                    $xpos,
180                    0,
181                    $xpos,
182                    $this->getBarcodeHeight() - $font_height - 1,
183                    $black
184                );
185            }
186
187            $xpos++;
188        }
189
190        // draw text under barcode
191        if ($this->showText) {
192            $writer->imagestring(
193                $img,
194                $fontsize,
195                ($barcode_len - $font_width * strlen($text)) / 2,
196                $this->getBarcodeHeight() - $font_height,
197                $text,
198                $black
199            );
200        }
201
202
203        return $img;
204    }
205
206
207    /**
208     * _dumpCode is a PHP implementation of dumpCode from the Perl module
209     * GD::Barcode::Code39. I royally screwed up when trying to do the thing
210     * my own way the first time. This way works.
211     *
212     * @param string $code Code39 barcode code
213     *
214     * @return string $result      barcode line code
215     * @access private
216     * @author Ryan Briones <ryanbriones@webxdesign.org>
217     */
218    private function _dumpCode($code)
219    {
220        $result = '';
221        $color = 1; // 1: Black, 0: White
222
223        // if $bit is 1, line is wide; if $bit is 0 line is thin
224        foreach (str_split($code) as $bit) {
225            if ($bit == 1) {
226                $result .= str_repeat($color, $this->getBarcodeWidthThick());
227            } else {
228                $result .= str_repeat($color, $this->getBarcodeWidthThin());
229            }
230
231            $color = ($color == 0) ? 1 : 0;
232        }
233
234        return $result;
235    }
236}
237