<?php
// +-------------------------------------------------+
// | 2002-2011 PMB Services / www.sigb.net pmb@sigb.net et contributeurs (voir www.sigb.net)
// +-------------------------------------------------+
// $Id: c39object.php,v 1.6 2025/03/27 13:37:59 dbellamy Exp $

/*
 * Barcode Render Class for PHP using the GD graphics library
 * Copyright (C) 2001 Karim Mribti
 *
 * Version 0.0.7a 2001-04-01
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 * Copy of GNU Lesser General Public License at: http://www.gnu.org/copyleft/lesser.txt
 *
 * Source code home page: http://www.mribti.com/barcode/
 * Contact author at: barcode@mribti.com
 */

/*
 * Render for Code 39
 * Code 39 is an alphanumeric bar code that can encode decimal number, case alphabet and some special symbols.
 */
class C39Object extends BarcodeObject
{

    public $mCharSet, $mChars, $mValue;

    public function __construct($Width, $Height, $Style, $Value)
    {
        parent::__construct($Width, $Height, $Style);
        $this->mValue = $Value;
        $this->mChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%";
        $this->mCharSet = array
        (
            /* 0  */ "000110100",
            /* 1  */ "100100001",
            /* 2  */ "001100001",
            /* 3  */ "101100000",
            /* 4  */ "000110001",
            /* 5  */ "100110000",
            /* 6  */ "001110000",
            /* 7  */ "000100101",
            /* 8  */ "100100100",
            /* 9  */ "001100100",
            /* A  */ "100001001",
            /* B  */ "001001001",
            /* C  */ "101001000",
            /* D  */ "000011001",
            /* E  */ "100011000",
            /* F  */ "001011000",
            /* G  */ "000001101",
            /* H  */ "100001100",
            /* I  */ "001001100",
            /* J  */ "000011100",
            /* K  */ "100000011",
            /* L  */ "001000011",
            /* M  */ "101000010",
            /* N  */ "000010011",
            /* O  */ "100010010",
            /* P  */ "001010010",
            /* Q  */ "000000111",
            /* R  */ "100000110",
            /* S  */ "001000110",
            /* T  */ "000010110",
            /* U  */ "110000001",
            /* V  */ "011000001",
            /* W  */ "111000000",
            /* X  */ "010010001",
            /* Y  */ "110010000",
            /* Z  */ "011010000",
            /* -  */ "010000101",
            /* .  */ "110000100",
            /* SP */ "011000100",
            /* *  */ "010010100",
            /* $  */ "010101000",
            /* /  */ "010100010",
            /* +  */ "010001010",
            /* %  */ "000101010"
        );
    }

    public function GetCharIndex($char)
    {
        for ($i = 0; $i < 44; $i ++) {
            if (substr($this->mChars, $i, 1) == $char)
                return $i;
        }
        return - 1;
    }

    public function GetSize($xres)
    {
        $len = strlen($this->mValue);

        if ($len == 0) {
            $this->mError = "Null value";
            return false;
        }

        for ($i = 0; $i < $len; $i ++) {
            if ($this->GetCharIndex($this->mValue[$i]) == - 1 || $this->mValue[$i] == '*') {
                /* The asterisk is only used as a start and stop code */
                $this->mError = "C39 not include the char '" . $this->mValue[$i] . "'";
                return false;
            }
        }

        /* Start, Stop is 010010100 == '*' */
        $StartSize = BCD_C39_NARROW_BAR * $xres * 6 + BCD_C39_WIDE_BAR * $xres * 3;
        $StopSize = BCD_C39_NARROW_BAR * $xres * 6 + BCD_C39_WIDE_BAR * $xres * 3;
        $CharSize = BCD_C39_NARROW_BAR * $xres * 6 + BCD_C39_WIDE_BAR * $xres * 3; /* Same for all chars */

        return $CharSize * $len + $StartSize + $StopSize + /* Space between chars */ BCD_C39_NARROW_BAR * $xres * ($len + 1);
    }

    public function DrawStart($DrawPos, $yPos, $ySize, $xres)
    { /* Start code is '*' */
        $narrow = BCD_C39_NARROW_BAR * $xres;
        $wide = BCD_C39_WIDE_BAR * $xres;
        $this->DrawSingleBar($DrawPos, $yPos, $narrow, $ySize);
        $DrawPos += $narrow;
        $DrawPos += $wide;
        $this->DrawSingleBar($DrawPos, $yPos, $narrow, $ySize);
        $DrawPos += $narrow;
        $DrawPos += $narrow;
        $this->DrawSingleBar($DrawPos, $yPos, $wide, $ySize);
        $DrawPos += $wide;
        $DrawPos += $narrow;
        $this->DrawSingleBar($DrawPos, $yPos, $wide, $ySize);
        $DrawPos += $wide;
        $DrawPos += $narrow;
        $this->DrawSingleBar($DrawPos, $yPos, $narrow, $ySize);
        $DrawPos += $narrow;
        $DrawPos += $narrow; /* Space between chars */
        return $DrawPos;
    }

    public function DrawStop($DrawPos, $yPos, $ySize, $xres)
    { /* Stop code is '*' */
        $narrow = BCD_C39_NARROW_BAR * $xres;
        $wide = BCD_C39_WIDE_BAR * $xres;
        $this->DrawSingleBar($DrawPos, $yPos, $narrow, $ySize);
        $DrawPos += $narrow;
        $DrawPos += $wide;
        $this->DrawSingleBar($DrawPos, $yPos, $narrow, $ySize);
        $DrawPos += $narrow;
        $DrawPos += $narrow;
        $this->DrawSingleBar($DrawPos, $yPos, $wide, $ySize);
        $DrawPos += $wide;
        $DrawPos += $narrow;
        $this->DrawSingleBar($DrawPos, $yPos, $wide, $ySize);
        $DrawPos += $wide;
        $DrawPos += $narrow;
        $this->DrawSingleBar($DrawPos, $yPos, $narrow, $ySize);
        $DrawPos += $narrow;
        return $DrawPos;
    }

    public function DrawObject($xres)
    {
        $len = strlen($this->mValue);

        $narrow = BCD_C39_NARROW_BAR * $xres;
        $wide = BCD_C39_WIDE_BAR * $xres;

        if (($size = $this->GetSize($xres)) == 0) {
            return false;
        }

        $cPos = 0;
        if ($this->mStyle & BCS_ALIGN_CENTER)
            $sPos = (integer) (($this->mWidth - $size) / 2);
        else if ($this->mStyle & BCS_ALIGN_RIGHT)
            $sPos = $this->mWidth - $size;
        else
            $sPos = 0;

        /* Total height of bar code -Bars only- */
        if ($this->mStyle & BCS_DRAW_TEXT)
            $ysize = $this->mHeight - BCD_DEFAULT_MAR_Y1 - BCD_DEFAULT_MAR_Y2 - $this->GetFontHeight($this->mFont);
        else
            $ysize = $this->mHeight - BCD_DEFAULT_MAR_Y1 - BCD_DEFAULT_MAR_Y2;

        /* Draw text */
        if ($this->mStyle & BCS_DRAW_TEXT) {
            if ($this->mStyle & BCS_STRETCH_TEXT) {
                for ($i = 0; $i < $len; $i ++) {
                    $this->DrawChar($this->mFont, $sPos + ($size / ($len + 2)) * ($i + 1.5) - $this->GetFontWidth($this->mFont) / 2, $ysize + BCD_DEFAULT_MAR_Y1 + BCD_DEFAULT_TEXT_OFFSET, $this->mValue[$i]);
                }
            } else { /* Center */
                $text_width = $this->GetFontWidth($this->mFont) * strlen($this->mValue);
                $this->DrawText($this->mFont, $sPos + (($size - $text_width) / 2), $ysize + BCD_DEFAULT_MAR_Y1 + BCD_DEFAULT_TEXT_OFFSET, $this->mValue);
            }
        }

        $DrawPos = $this->DrawStart($sPos, BCD_DEFAULT_MAR_Y1, $ysize, $xres);
        do {
            $c = $this->GetCharIndex($this->mValue[$cPos]);
            $cset = $this->mCharSet[$c];
            $this->DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, ($cset[0] == '0') ? $narrow : $wide, $ysize);
            $DrawPos += ($cset[0] == '0') ? $narrow : $wide;
            $DrawPos += ($cset[1] == '0') ? $narrow : $wide;
            $this->DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, ($cset[2] == '0') ? $narrow : $wide, $ysize);
            $DrawPos += ($cset[2] == '0') ? $narrow : $wide;
            $DrawPos += ($cset[3] == '0') ? $narrow : $wide;
            $this->DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, ($cset[4] == '0') ? $narrow : $wide, $ysize);
            $DrawPos += ($cset[4] == '0') ? $narrow : $wide;
            $DrawPos += ($cset[5] == '0') ? $narrow : $wide;
            $this->DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, ($cset[6] == '0') ? $narrow : $wide, $ysize);
            $DrawPos += ($cset[6] == '0') ? $narrow : $wide;
            $DrawPos += ($cset[7] == '0') ? $narrow : $wide;
            $this->DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, ($cset[8] == '0') ? $narrow : $wide, $ysize);
            $DrawPos += ($cset[8] == '0') ? $narrow : $wide;
            $DrawPos += $narrow; /* Space between chars */
            $cPos ++;
        } while ($cPos < $len);
        $DrawPos = $this->DrawStop($DrawPos, BCD_DEFAULT_MAR_Y1, $ysize, $xres);
        return true;
    }
}
