1<?php
2/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
3
4/**
5 * Image_Barcode_Code39 class
6 *
7 * Image_Barcode_Code39 creates Code 3 of 9 ( Code39 ) barcode images. It's
8 * implementation borrows heavily for the perl module GD::Barcode::Code39
9 *
10 * PHP versions 4
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_Barcode
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 * @version    CVS: $Id$
24 * @link       http://pear.php.net/package/Image_Barcode
25 */
26
27
28require_once "Image/Barcode.php";
29
30
31if (!function_exists('str_split')) {
32    require_once 'PHP/Compat.php';
33    PHP_Compat::loadFunction('str_split');
34}
35
36/**
37 * Image_Barcode_Code39 class
38 *
39 * Package which provides a method to create Code39 using GD library.
40 *
41 * @category   Image
42 * @package    Image_Barcode
43 * @author     Ryan Briones <ryanbriones@webxdesign.org>
44 * @copyright  2005 The PHP Group
45 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
46 * @version    Release: @package_version@
47 * @link       http://pear.php.net/package/Image_Barcode
48 * @since      Image_Barcode 0.5
49 */
50class Image_Barcode_Code39 extends Image_Barcode
51{
52    /**
53     * Barcode type
54     * @var string
55     */
56    var $_type = 'Code39';
57
58    /**
59     * Barcode height
60     *
61     * @var integer
62     */
63    var $_barcodeheight = 50;
64
65    /**
66     * Bar thin width
67     *
68     * @var integer
69     */
70    var $_barthinwidth = 1;
71
72    /**
73     * Bar thick width
74     *
75     * @var integer
76     */
77    var $_barthickwidth = 3;
78
79    /**
80     * Font size
81     *
82     * @var integer
83     */
84    var $_font_size = 2;
85
86    /**
87     * Coding map
88     * @var array
89     */
90    var $_coding_map = array(
91        '0' => '000110100',
92        '1' => '100100001',
93        '2' => '001100001',
94        '3' => '101100000',
95        '4' => '000110001',
96        '5' => '100110000',
97        '6' => '001110000',
98        '7' => '000100101',
99        '8' => '100100100',
100        '9' => '001100100',
101        'A' => '100001001',
102        'B' => '001001001',
103        'C' => '101001000',
104        'D' => '000011001',
105        'E' => '100011000',
106        'F' => '001011000',
107        'G' => '000001101',
108        'H' => '100001100',
109        'I' => '001001100',
110        'J' => '000011100',
111        'K' => '100000011',
112        'L' => '001000011',
113        'M' => '101000010',
114        'N' => '000010011',
115        'O' => '100010010',
116        'P' => '001010010',
117        'Q' => '000000111',
118        'R' => '100000110',
119        'S' => '001000110',
120        'T' => '000010110',
121        'U' => '110000001',
122        'V' => '011000001',
123        'W' => '111000000',
124        'X' => '010010001',
125        'Y' => '110010000',
126        'Z' => '011010000',
127        '-' => '010000101',
128        '*' => '010010100',
129        '+' => '010001010',
130        '$' => '010101000',
131        '%' => '000101010',
132        '/' => '010100010',
133        '.' => '110000100',
134        ' ' => '011000100'
135    );
136
137    /**
138     * Constructor
139     *
140     * @param  string $text     A text that should be in the image barcode
141     * @param  int $wThin       Width of the thin lines on the barcode
142     * @param  int $wThick      Width of the thick lines on the barcode
143     *
144     * @author Ryan Briones <ryanbriones@webxdesign.org>
145     *
146     */
147    function Image_Barcode_Code39( $text = '', $wThin = 0, $wThick = 0 )
148    {
149        // Check $text for invalid characters
150        if ( $this->checkInvalid( $text ) ) {
151            return false;
152        }
153
154        $this->text = $text;
155        if ( $wThin > 0 ) $this->_barthinwidth = $wThin;
156        if ( $wThick > 0 ) $this->_barthickwidth = $wThick;
157
158        return true;
159    }
160
161   /**
162    * Make an image resource using the GD image library
163    *
164    * @param    bool $noText       Set to true if you'd like your barcode to be sans text
165    * @param    int $bHeight       height of the barcode image including text
166    * @return   resource           The Barcode Image (TM)
167    *
168    * @author   Ryan Briones <ryanbriones@webxdesign.org>
169    *
170    */
171    function plot($noText = false, $bHeight = 0)
172    {
173       // add start and stop * characters
174       $final_text = '*' . $this->text . '*';
175
176        if ( $bHeight > 0 ) {
177            $this->_barcodeheight = $bHeight;
178        }
179
180       $barcode = '';
181       foreach ( str_split( $final_text ) as $character ) {
182           $barcode .= $this->_dumpCode( $this->_coding_map[$character] . '0' );
183       }
184
185       $barcode_len = strlen( $barcode );
186
187       // Create GD image object
188       $img = imagecreate( $barcode_len, $this->_barcodeheight );
189
190       // Allocate black and white colors to the image
191       $black = imagecolorallocate( $img, 0, 0, 0 );
192       $white = imagecolorallocate( $img, 255, 255, 255 );
193       $font_height = ( $noText ? 0 : imagefontheight( $this->_font_size ) );
194       $font_width = imagefontwidth( $this->_font_size );
195
196       // fill background with white color
197       imagefill( $img, 0, 0, $white );
198
199       // Initialize X position
200       $xpos = 0;
201
202       // draw barcode bars to image
203        if ( $noText ) {
204            foreach (str_split($barcode) as $character_code ) {
205                if ($character_code == 0 ) {
206                        imageline($img, $xpos, 0, $xpos, $this->_barcodeheight, $white);
207                } else {
208                        imageline($img, $xpos, 0, $xpos, $this->_barcodeheight, $black);
209                }
210
211                $xpos++;
212            }
213        } else {
214            foreach (str_split($barcode) as $character_code ) {
215                if ($character_code == 0) {
216                    imageline($img, $xpos, 0, $xpos, $this->_barcodeheight - $font_height - 1, $white);
217                } else {
218                    imageline($img, $xpos, 0, $xpos, $this->_barcodeheight - $font_height - 1, $black);
219                }
220
221                $xpos++;
222            }
223
224            // draw text under barcode
225            imagestring(
226                $img,
227                $this->_font_size,
228                ( $barcode_len - $font_width * strlen( $this->text ) )/2,
229                $this->_barcodeheight - $font_height,
230                $this->text,
231                $black
232            );
233        }
234
235        return $img;
236    }
237
238    /**
239     * Send image to the browser; for Image_Barcode compaitbility
240     *
241     * @param    string $text
242     * @param    string $imgtype     Image type; accepts jpg, png, and gif, but gif only works if you've payed for licensing
243     * @param    bool $noText        Set to true if you'd like your barcode to be sans text
244     * @param    int $bHeight        height of the barcode image including text
245     * @return   gd_image            GD image object
246     *
247     * @author   Ryan Briones <ryanbriones@webxdesign.org>
248     *
249     */
250    function &draw($text, $imgtype = 'png', $noText = false, $bHeight = 0)
251    {
252        // Check $text for invalid characters
253        if ($this->checkInvalid($text)) {
254            return PEAR::raiseError('Invalid text');
255        }
256
257        $this->text = $text;
258        $img = &$this->plot($noText, $bHeight);
259
260        return $img;
261    }
262
263    /**
264     * _dumpCode is a PHP implementation of dumpCode from the Perl module
265     * GD::Barcode::Code39. I royally screwed up when trying to do the thing
266     * my own way the first time. This way works.
267     *
268     * @param   string $code        Code39 barcode code
269     * @return  string $result      barcode line code
270     *
271     * @access  private
272     *
273     * @author   Ryan Briones <ryanbriones@webxdesign.org>
274     *
275     *
276     */
277    function _dumpCode($code)
278    {
279        $result = '';
280        $color = 1; // 1: Black, 0: White
281
282        // if $bit is 1, line is wide; if $bit is 0 line is thin
283        foreach ( str_split( $code ) as $bit ) {
284            $result .= ( ( $bit == 1 ) ? str_repeat( "$color", $this->_barthickwidth ) : str_repeat( "$color", $this->_barthinwidth ) );
285            $color = ( ( $color == 0 ) ? 1 : 0 );
286        }
287
288        return $result;
289    }
290
291    /**
292     * Check for invalid characters
293     *
294     * @param   string $text    text to be ckecked
295     * @return  bool            returns true when invalid characters have been found
296     *
297     * @author  Ryan Briones <ryanbriones@webxdesign.org>
298     *
299     */
300    function checkInvalid($text)
301    {
302        return preg_match( "/[^0-9A-Z\-*+\$%\/. ]/", $text );
303    }
304}
305?>