File indexing completed on 2024-12-22 05:36:29

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Barcode
0017  * @subpackage Object
0018  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0019  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0020  * @version    $Id$
0021  */
0022 
0023 /**
0024  * Class for generate Barcode
0025  *
0026  * @category   Zend
0027  * @package    Zend_Barcode
0028  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0029  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0030  */
0031 abstract class Zend_Barcode_Object_ObjectAbstract
0032 {
0033     /**
0034      * Namespace of the barcode for autoloading
0035      *
0036      * @var string
0037      */
0038     protected $_barcodeNamespace = 'Zend_Barcode_Object';
0039 
0040     /**
0041      * Set of drawing instructions
0042      *
0043      * @var array
0044      */
0045     protected $_instructions = array();
0046 
0047     /**
0048      * Barcode type
0049      *
0050      * @var string
0051      */
0052     protected $_type = null;
0053 
0054     /**
0055      * Height of the object
0056      *
0057      * @var integer
0058      */
0059     protected $_height = null;
0060 
0061     /**
0062      * Width of the object
0063      *
0064      * @var integer
0065      */
0066     protected $_width = null;
0067 
0068     /**
0069      * Height of the bar
0070      *
0071      * @var integer
0072      */
0073     protected $_barHeight = 50;
0074 
0075     /**
0076      * Width of a thin bar
0077      *
0078      * @var integer
0079      */
0080     protected $_barThinWidth = 1;
0081 
0082     /**
0083      * Width of a thick bar
0084      *
0085      * @var integer
0086      */
0087     protected $_barThickWidth = 3;
0088 
0089     /**
0090      * Factor to multiply bar and font measure
0091      * (barHeight, barThinWidth, barThickWidth & fontSize)
0092      *
0093      * @var integer
0094      */
0095     protected $_factor = 1;
0096 
0097     /**
0098      * Font and bars color of the object
0099      *
0100      * @var integer
0101      */
0102     protected $_foreColor = 0x000000;
0103 
0104     /**
0105      * Background color of the object
0106      *
0107      * @var integer
0108      */
0109     protected $_backgroundColor = 0xFFFFFF;
0110 
0111     /**
0112      * Activate/deactivate border of the object
0113      *
0114      * @var boolean
0115      */
0116     protected $_withBorder = false;
0117 
0118     /**
0119      * Activate/deactivate drawing of quiet zones
0120      *
0121      * @var boolean
0122      */
0123     protected $_withQuietZones = true;
0124 
0125     /**
0126      * Force quiet zones even if
0127      *
0128      * @var boolean
0129      */
0130     protected $_mandatoryQuietZones = false;
0131 
0132     /**
0133      * Orientation of the barcode in degrees
0134      *
0135      * @var float
0136      */
0137     protected $_orientation = 0;
0138 
0139     /**
0140      * Offset from the top the object
0141      * (calculated from the orientation)
0142      *
0143      * @var integer
0144      */
0145     protected $_offsetTop = null;
0146 
0147     /**
0148      * Offset from the left the object
0149      * (calculated from the orientation)
0150      *
0151      * @var integer
0152      */
0153     protected $_offsetLeft = null;
0154 
0155     /**
0156      * Text to display
0157      *
0158      * @var string
0159      */
0160     protected $_text = null;
0161 
0162     /**
0163      * Display (or not) human readable text
0164      *
0165      * @var boolean
0166      */
0167     protected $_drawText = true;
0168 
0169     /**
0170      * Adjust (or not) position of human readable characters with barcode
0171      *
0172      * @var boolean
0173      */
0174     protected $_stretchText = false;
0175 
0176     /**
0177      * Font resource
0178      *  - integer (1 to 5): corresponds to GD included fonts
0179      *  - string: corresponds to path of a TTF font
0180      *
0181      * @var integer|string
0182      */
0183     protected $_font = null;
0184 
0185     /**
0186      * Font size
0187      *
0188      * @var float
0189      */
0190     protected $_fontSize = 10;
0191 
0192     /**
0193      * Drawing of checksum
0194      *
0195      * @var boolean
0196      */
0197     protected $_withChecksum = false;
0198 
0199     /**
0200      * Drawing of checksum inside text
0201      *
0202      * @var boolean
0203      */
0204     protected $_withChecksumInText = false;
0205 
0206     /**
0207      * Fix barcode length (numeric or string like 'even')
0208      *
0209      * @var $_barcodeLength integer | string
0210      */
0211     protected $_barcodeLength = null;
0212 
0213     /**
0214      * Activate automatic addition of leading zeros
0215      * if barcode length is fixed
0216      *
0217      * @var $_addLeadingZeros boolean
0218      */
0219     protected $_addLeadingZeros = true;
0220 
0221     /**
0222      * Activation of mandatory checksum
0223      * to deactivate unauthorized modification
0224      *
0225      * @var $_mandatoryChecksum boolean
0226      */
0227     protected $_mandatoryChecksum = false;
0228 
0229     /**
0230      * Character used to substitute checksum character for validation
0231      *
0232      * @var $_substituteChecksumCharacter mixed
0233      */
0234     protected $_substituteChecksumCharacter = 0;
0235 
0236     /**
0237      * TTF font name: can be set before instanciation of the object
0238      *
0239      * @var string
0240      */
0241     protected static $_staticFont = null;
0242 
0243     /**
0244      * Constructor
0245      *
0246      * @param array|Zend_Config $options
0247      */
0248     public function __construct($options = null)
0249     {
0250         $this->_getDefaultOptions();
0251         if (self::$_staticFont !== null) {
0252             $this->_font = self::$_staticFont;
0253         }
0254         if ($options instanceof Zend_Config) {
0255             $options = $options->toArray();
0256         }
0257         if (is_array($options)) {
0258             $this->setOptions($options);
0259         }
0260         $this->_type = strtolower(
0261             substr(get_class($this), strlen($this->_barcodeNamespace) + 1)
0262         );
0263         if ($this->_mandatoryChecksum) {
0264             $this->_withChecksum = true;
0265             $this->_withChecksumInText = true;
0266         }
0267     }
0268 
0269     /**
0270      * Set default options for particular object
0271      */
0272     protected function _getDefaultOptions()
0273     {
0274     }
0275 
0276     /**
0277      * Set barcode state from options array
0278      *
0279      * @param  array $options
0280      * @return $this
0281      */
0282     public function setOptions($options)
0283     {
0284         foreach ($options as $key => $value) {
0285             $method = 'set' . $key;
0286             if (method_exists($this, $method)) {
0287                 $this->$method($value);
0288             }
0289         }
0290         return $this;
0291     }
0292 
0293     /**
0294      * Set barcode state from config object
0295      *
0296      * @param Zend_Config $config
0297      * @return $this
0298      */
0299     public function setConfig(Zend_Config $config)
0300     {
0301         return $this->setOptions($config->toArray());
0302     }
0303 
0304     /**
0305      * Set barcode namespace for autoloading
0306      *
0307      * @param string $namespace
0308      * @return $this
0309      */
0310     public function setBarcodeNamespace($namespace)
0311     {
0312         $this->_barcodeNamespace = $namespace;
0313         return $this;
0314     }
0315 
0316     /**
0317      * Retrieve barcode namespace
0318      *
0319      * @return string
0320      */
0321     public function getBarcodeNamespace()
0322     {
0323         return $this->_barcodeNamespace;
0324     }
0325 
0326     /**
0327      * Retrieve type of barcode
0328      *
0329      * @return string
0330      */
0331     public function getType()
0332     {
0333         return $this->_type;
0334     }
0335 
0336     /**
0337      * Set height of the barcode bar
0338      *
0339      * @param integer $value
0340      * @return $this
0341      * @throws Zend_Barcode_Object_Exception
0342      */
0343     public function setBarHeight($value)
0344     {
0345         if (intval($value) <= 0) {
0346             // require_once 'Zend/Barcode/Object/Exception.php';
0347             throw new Zend_Barcode_Object_Exception(
0348                 'Bar height must be greater than 0'
0349             );
0350         }
0351         $this->_barHeight = intval($value);
0352         return $this;
0353     }
0354 
0355     /**
0356      * Get height of the barcode bar
0357      *
0358      * @return integer
0359      */
0360     public function getBarHeight()
0361     {
0362         return $this->_barHeight;
0363     }
0364 
0365     /**
0366      * Set thickness of thin bar
0367      *
0368      * @param integer $value
0369      * @return $this
0370      * @throws Zend_Barcode_Object_Exception
0371      */
0372     public function setBarThinWidth($value)
0373     {
0374         if (intval($value) <= 0) {
0375             // require_once 'Zend/Barcode/Object/Exception.php';
0376             throw new Zend_Barcode_Object_Exception(
0377                 'Bar width must be greater than 0'
0378             );
0379         }
0380         $this->_barThinWidth = intval($value);
0381         return $this;
0382     }
0383 
0384     /**
0385      * Get thickness of thin bar
0386      *
0387      * @return integer
0388      */
0389     public function getBarThinWidth()
0390     {
0391         return $this->_barThinWidth;
0392     }
0393 
0394     /**
0395      * Set thickness of thick bar
0396      *
0397      * @param integer $value
0398      * @return $this
0399      * @throws Zend_Barcode_Object_Exception
0400      */
0401     public function setBarThickWidth($value)
0402     {
0403         if (intval($value) <= 0) {
0404             // require_once 'Zend/Barcode/Object/Exception.php';
0405             throw new Zend_Barcode_Object_Exception(
0406                 'Bar width must be greater than 0'
0407             );
0408         }
0409         $this->_barThickWidth = intval($value);
0410         return $this;
0411     }
0412 
0413     /**
0414      * Get thickness of thick bar
0415      *
0416      * @return integer
0417      */
0418     public function getBarThickWidth()
0419     {
0420         return $this->_barThickWidth;
0421     }
0422 
0423     /**
0424      * Set factor applying to
0425      * thinBarWidth - thickBarWidth - barHeight - fontSize
0426      *
0427      * @param int|float|string|bool $value
0428      * @return $this
0429      * @throws Zend_Barcode_Object_Exception
0430      */
0431     public function setFactor($value)
0432     {
0433         if (floatval($value) <= 0) {
0434             // require_once 'Zend/Barcode/Object/Exception.php';
0435             throw new Zend_Barcode_Object_Exception(
0436                 'Factor must be greater than 0'
0437             );
0438         }
0439         $this->_factor = floatval($value);
0440         return $this;
0441     }
0442 
0443     /**
0444      * Get factor applying to
0445      * thinBarWidth - thickBarWidth - barHeight - fontSize
0446      *
0447      * @return integer
0448      */
0449     public function getFactor()
0450     {
0451         return $this->_factor;
0452     }
0453 
0454     /**
0455      * Set color of the barcode and text
0456      *
0457      * @param string $value
0458      * @return $this
0459      * @throws Zend_Barcode_Object_Exception
0460      */
0461     public function setForeColor($value)
0462     {
0463         if (preg_match('`\#[0-9A-F]{6}`', $value)) {
0464             $this->_foreColor = hexdec($value);
0465         } elseif (is_numeric($value) && $value >= 0 && $value <= 16777125) {
0466             $this->_foreColor = intval($value);
0467         } else {
0468             // require_once 'Zend/Barcode/Object/Exception.php';
0469             throw new Zend_Barcode_Object_Exception(
0470                 'Text color must be set as #[0-9A-F]{6}'
0471             );
0472         }
0473         return $this;
0474     }
0475 
0476     /**
0477      * Retrieve color of the barcode and text
0478      *
0479      * @return unknown
0480      */
0481     public function getForeColor()
0482     {
0483         return $this->_foreColor;
0484     }
0485 
0486     /**
0487      * Set the color of the background
0488      *
0489      * @param integer $value
0490      * @return $this
0491      * @throws Zend_Barcode_Object_Exception
0492      */
0493     public function setBackgroundColor($value)
0494     {
0495         if (preg_match('`\#[0-9A-F]{6}`', $value)) {
0496             $this->_backgroundColor = hexdec($value);
0497         } elseif (is_numeric($value) && $value >= 0 && $value <= 16777125) {
0498             $this->_backgroundColor = intval($value);
0499         } else {
0500             // require_once 'Zend/Barcode/Object/Exception.php';
0501             throw new Zend_Barcode_Object_Exception(
0502                 'Background color must be set as #[0-9A-F]{6}'
0503             );
0504         }
0505         return $this;
0506     }
0507 
0508     /**
0509      * Retrieve background color of the image
0510      *
0511      * @return integer
0512      */
0513     public function getBackgroundColor()
0514     {
0515         return $this->_backgroundColor;
0516     }
0517 
0518     /**
0519      * Activate/deactivate drawing of the bar
0520      *
0521      * @param boolean $value
0522      * @return $this
0523      */
0524     public function setWithBorder($value)
0525     {
0526         $this->_withBorder = (bool) $value;
0527         return $this;
0528     }
0529 
0530     /**
0531      * Retrieve if border are draw or not
0532      *
0533      * @return boolean
0534      */
0535     public function getWithBorder()
0536     {
0537         return $this->_withBorder;
0538     }
0539 
0540     /**
0541      * Activate/deactivate drawing of the quiet zones
0542      *
0543      * @param boolean $value
0544      * @return $this
0545      */
0546     public function setWithQuietZones($value)
0547     {
0548         $this->_withQuietZones = (bool) $value;
0549         return $this;
0550     }
0551 
0552     /**
0553      * Retrieve if quiet zones are draw or not
0554      *
0555      * @return boolean
0556      */
0557     public function getWithQuietZones()
0558     {
0559         return $this->_withQuietZones;
0560     }
0561 
0562     /**
0563      * Allow fast inversion of font/bars color and background color
0564      *
0565      * @return $this
0566      */
0567     public function setReverseColor()
0568     {
0569         $tmp                    = $this->_foreColor;
0570         $this->_foreColor       = $this->_backgroundColor;
0571         $this->_backgroundColor = $tmp;
0572 
0573         return $this;
0574     }
0575 
0576     /**
0577      * Set orientation of barcode and text
0578      *
0579      * @param int|float|string|bool $value
0580      * @return $this
0581      * @throws Zend_Barcode_Object_Exception
0582      */
0583     public function setOrientation($value)
0584     {
0585         $value              = floatval($value);
0586         $this->_orientation = $value - floor($value / 360) * 360;
0587         return $this;
0588     }
0589 
0590     /**
0591      * Retrieve orientation of barcode and text
0592      *
0593      * @return float
0594      */
0595     public function getOrientation()
0596     {
0597         return $this->_orientation;
0598     }
0599 
0600     /**
0601      * Set text to encode
0602      *
0603      * @param string $value
0604      * @return $this
0605      */
0606     public function setText($value)
0607     {
0608         $this->_text = trim($value);
0609         return $this;
0610     }
0611 
0612     /**
0613      * Retrieve text to encode
0614      *
0615      * @return string
0616      */
0617     public function getText()
0618     {
0619         $text = $this->_text;
0620         if ($this->_withChecksum) {
0621             $text .= $this->getChecksum($this->_text);
0622         }
0623         return $this->_addLeadingZeros($text);
0624     }
0625 
0626     /**
0627      * Automatically add leading zeros if barcode length is fixed
0628      *
0629      * @param string  $text
0630      * @param boolean $withoutChecksum
0631      * @return string
0632      */
0633     protected function _addLeadingZeros($text, $withoutChecksum = false)
0634     {
0635         if ($this->_barcodeLength && $this->_addLeadingZeros) {
0636             $omitChecksum = (int) ($this->_withChecksum && $withoutChecksum);
0637             if (is_int($this->_barcodeLength)) {
0638                 $length = $this->_barcodeLength - $omitChecksum;
0639                 if (strlen($text) < $length) {
0640                     $text = str_repeat('0', $length - strlen($text)) . $text;
0641                 }
0642             } else {
0643                 if ($this->_barcodeLength == 'even') {
0644                     $text = ((strlen($text) - $omitChecksum) % 2 ? '0' . $text : $text);
0645                 }
0646             }
0647         }
0648         return $text;
0649     }
0650 
0651     /**
0652      * Retrieve text to encode
0653      *
0654      * @return string
0655      */
0656     public function getRawText()
0657     {
0658         return $this->_text;
0659     }
0660 
0661     /**
0662      * Retrieve text to display
0663      *
0664      * @return string
0665      */
0666     public function getTextToDisplay()
0667     {
0668         if ($this->_withChecksumInText) {
0669             return $this->getText();
0670         } else {
0671             return $this->_addLeadingZeros($this->_text, true);
0672         }
0673     }
0674 
0675     /**
0676      * Activate/deactivate drawing of text to encode
0677      *
0678      * @param boolean $value
0679      * @return $this
0680      */
0681     public function setDrawText($value)
0682     {
0683         $this->_drawText = (bool) $value;
0684         return $this;
0685     }
0686 
0687     /**
0688      * Retrieve if drawing of text to encode is enabled
0689      *
0690      * @return boolean
0691      */
0692     public function getDrawText()
0693     {
0694         return $this->_drawText;
0695     }
0696 
0697     /**
0698      * Activate/deactivate the adjustment of the position
0699      * of the characters to the position of the bars
0700      *
0701      * @param boolean $value
0702      * @return $this
0703      * @throws Zend_Barcode_Object_Exception
0704      */
0705     public function setStretchText($value)
0706     {
0707         $this->_stretchText = (bool) $value;
0708         return $this;
0709     }
0710 
0711     /**
0712      * Retrieve if the adjustment of the position of the characters
0713      * to the position of the bars is enabled
0714      *
0715      * @return boolean
0716      */
0717     public function getStretchText()
0718     {
0719         return $this->_stretchText;
0720     }
0721 
0722     /**
0723      * Activate/deactivate the automatic generation
0724      * of the checksum character
0725      * added to the barcode text
0726      *
0727      * @param boolean $value
0728      * @return $this
0729      */
0730     public function setWithChecksum($value)
0731     {
0732         if (!$this->_mandatoryChecksum) {
0733             $this->_withChecksum = (bool) $value;
0734         }
0735         return $this;
0736     }
0737 
0738     /**
0739      * Retrieve if the checksum character is automatically
0740      * added to the barcode text
0741      *
0742      * @return boolean
0743      */
0744     public function getWithChecksum()
0745     {
0746         return $this->_withChecksum;
0747     }
0748 
0749     /**
0750      * Activate/deactivate the automatic generation
0751      * of the checksum character
0752      * added to the barcode text
0753      *
0754      * @param boolean $value
0755      * @return $this
0756      * @throws Zend_Barcode_Object_Exception
0757      */
0758     public function setWithChecksumInText($value)
0759     {
0760         if (!$this->_mandatoryChecksum) {
0761             $this->_withChecksumInText = (bool) $value;
0762         }
0763 
0764         return $this;
0765     }
0766 
0767     /**
0768      * Retrieve if the checksum character is automatically
0769      * added to the barcode text
0770      *
0771      * @return boolean
0772      */
0773     public function getWithChecksumInText()
0774     {
0775         return $this->_withChecksumInText;
0776     }
0777 
0778     /**
0779      * Set the font for all instances of barcode
0780      *
0781      * @param string $font
0782      */
0783     public static function setBarcodeFont($font)
0784     {
0785         if (is_string($font) || (is_int($font) && $font >= 1 && $font <= 5)) {
0786             self::$_staticFont = $font;
0787         }
0788     }
0789 
0790     /**
0791      * Set the font:
0792      *  - if integer between 1 and 5, use gd built-in fonts
0793      *  - if string, $value is assumed to be the path to a TTF font
0794      *
0795      * @param integer|string $value
0796      * @return $this
0797      * @throws Zend_Barcode_Object_Exception
0798      */
0799     public function setFont($value)
0800     {
0801         if (is_int($value) && $value >= 1 && $value <= 5) {
0802             if (!extension_loaded('gd')) {
0803                 // require_once 'Zend/Barcode/Object/Exception.php';
0804                 throw new Zend_Barcode_Object_Exception(
0805                     'GD extension is required to use numeric font'
0806                 );
0807             }
0808 
0809             // Case of numeric font with GD
0810             $this->_font = $value;
0811 
0812             // In this case font size is given by:
0813             $this->_fontSize = imagefontheight($value);
0814         } elseif (is_string($value)) {
0815             $this->_font = $value;
0816         } else {
0817             // require_once 'Zend/Barcode/Object/Exception.php';
0818             throw new Zend_Barcode_Object_Exception(
0819                 sprintf(
0820                     'Invalid font "%s" provided to setFont()',
0821                     $value
0822                 )
0823             );
0824         }
0825         return $this;
0826     }
0827 
0828     /**
0829      * Retrieve the font
0830      *
0831      * @return integer|string
0832      */
0833     public function getFont()
0834     {
0835         return $this->_font;
0836     }
0837 
0838     /**
0839      * Set the size of the font in case of TTF
0840      *
0841      * @param float $value
0842      * @return $this
0843      * @throws Zend_Barcode_Object_Exception
0844      */
0845     public function setFontSize($value)
0846     {
0847         if (is_numeric($this->_font)) {
0848             // Case of numeric font with GD
0849             return $this;
0850         }
0851 
0852         if (!is_numeric($value)) {
0853             // require_once 'Zend/Barcode/Object/Exception.php';
0854             throw new Zend_Barcode_Object_Exception(
0855                 'Font size must be a numeric value'
0856             );
0857         }
0858 
0859         $this->_fontSize = $value;
0860         return $this;
0861     }
0862 
0863     /**
0864      * Retrieve the size of the font in case of TTF
0865      *
0866      * @return float
0867      */
0868     public function getFontSize()
0869     {
0870         return $this->_fontSize;
0871     }
0872 
0873     /**
0874      * Quiet zone before first bar
0875      * and after the last bar
0876      *
0877      * @return integer
0878      */
0879     public function getQuietZone()
0880     {
0881         if ($this->_withQuietZones || $this->_mandatoryQuietZones) {
0882             return 10 * $this->_barThinWidth * $this->_factor;
0883         } else {
0884             return 0;
0885         }
0886     }
0887 
0888     /**
0889      * Add an instruction in the array of instructions
0890      *
0891      * @param array $instruction
0892      */
0893     protected function _addInstruction(array $instruction)
0894     {
0895         $this->_instructions[] = $instruction;
0896     }
0897 
0898     /**
0899      * Retrieve the set of drawing instructions
0900      *
0901      * @return array
0902      */
0903     public function getInstructions()
0904     {
0905         return $this->_instructions;
0906     }
0907 
0908     /**
0909      * Add a polygon drawing instruction in the set of instructions
0910      *
0911      * @param array   $points
0912      * @param integer $color
0913      * @param boolean $filled
0914      */
0915     protected function _addPolygon(array $points, $color = null, $filled = true)
0916     {
0917         if ($color === null) {
0918             $color = $this->_foreColor;
0919         }
0920         $this->_addInstruction(
0921             array(
0922                 'type'   => 'polygon',
0923                 'points' => $points,
0924                 'color'  => $color,
0925                 'filled' => $filled,
0926             )
0927         );
0928     }
0929 
0930     /**
0931      * Add a text drawing instruction in the set of instructions
0932      *
0933      * @param string    $text
0934      * @param float     $size
0935      * @param array     $position
0936      * @param string    $font
0937      * @param integer   $color
0938      * @param string    $alignment
0939      * @param float|int $orientation
0940      */
0941     protected function _addText(
0942         $text,
0943         $size,
0944         $position,
0945         $font,
0946         $color,
0947         $alignment = 'center',
0948         $orientation = 0
0949     ) {
0950         if ($color === null) {
0951             $color = $this->_foreColor;
0952         }
0953         $this->_addInstruction(
0954             array(
0955                 'type'        => 'text',
0956                 'text'        => $text,
0957                 'size'        => $size,
0958                 'position'    => $position,
0959                 'font'        => $font,
0960                 'color'       => $color,
0961                 'alignment'   => $alignment,
0962                 'orientation' => $orientation,
0963             )
0964         );
0965     }
0966 
0967     /**
0968      * Checking of parameters after all settings
0969      *
0970      * @return bool
0971      */
0972     public function checkParams()
0973     {
0974         $this->_checkText();
0975         $this->_checkFontAndOrientation();
0976         $this->_checkParams();
0977         return true;
0978     }
0979 
0980     /**
0981      * Check if a text is really provided to barcode
0982      *
0983      * @param string|null $value
0984      * @throws Zend_Barcode_Object_Exception
0985      */
0986     protected function _checkText($value = null)
0987     {
0988         if ($value === null) {
0989             $value = $this->_text;
0990         }
0991         if (!strlen($value)) {
0992             // require_once 'Zend/Barcode/Object/Exception.php';
0993             throw new Zend_Barcode_Object_Exception(
0994                 'A text must be provide to Barcode before drawing'
0995             );
0996         }
0997         $this->validateText($value);
0998     }
0999 
1000     /**
1001      * Check the ratio between the thick and the thin bar
1002      *
1003      * @param int $min
1004      * @param int $max
1005      * @throws Zend_Barcode_Object_Exception
1006      */
1007     protected function _checkRatio($min = 2, $max = 3)
1008     {
1009         $ratio = $this->_barThickWidth / $this->_barThinWidth;
1010         if (!($ratio >= $min && $ratio <= $max)) {
1011             // require_once 'Zend/Barcode/Object/Exception.php';
1012             throw new Zend_Barcode_Object_Exception(
1013                 sprintf(
1014                     'Ratio thick/thin bar must be between %0.1f and %0.1f (actual %0.3f)',
1015                     $min,
1016                     $max,
1017                     $ratio
1018                 )
1019             );
1020         }
1021     }
1022 
1023     /**
1024      * Drawing with an angle is just allow TTF font
1025      *
1026      * @throws Zend_Barcode_Object_Exception
1027      */
1028     protected function _checkFontAndOrientation()
1029     {
1030         if (is_numeric($this->_font) && $this->_orientation != 0) {
1031             // require_once 'Zend/Barcode/Object/Exception.php';
1032             throw new Zend_Barcode_Object_Exception(
1033                 'Only drawing with TTF font allow orientation of the barcode.'
1034             );
1035         }
1036     }
1037 
1038     /**
1039      * Width of the result image (before any rotation)
1040      *
1041      * @return integer
1042      */
1043     protected function _calculateWidth()
1044     {
1045         return (int) $this->_withBorder
1046             + $this->_calculateBarcodeWidth()
1047             + (int) $this->_withBorder;
1048     }
1049 
1050     /**
1051      * Calculate the width of the barcode
1052      *
1053      * @return integer
1054      */
1055     abstract protected function _calculateBarcodeWidth();
1056 
1057     /**
1058      * Height of the result object
1059      *
1060      * @return int
1061      */
1062     protected function _calculateHeight()
1063     {
1064         return (int) $this->_withBorder * 2
1065             + $this->_calculateBarcodeHeight()
1066             + (int) $this->_withBorder * 2;
1067     }
1068 
1069     /**
1070      * Height of the barcode
1071      *
1072      * @return int
1073      */
1074     protected function _calculateBarcodeHeight()
1075     {
1076         $textHeight = 0;
1077         $extraHeight = 0;
1078         if ($this->_drawText) {
1079             $textHeight += $this->_fontSize;
1080             $extraHeight = 2;
1081         }
1082 
1083         return ($this->_barHeight + $textHeight) * $this->_factor
1084         + $extraHeight;
1085     }
1086 
1087     /**
1088      * Get height of the result object
1089      *
1090      * @param bool $recalculate
1091      * @return int
1092      */
1093     public function getHeight($recalculate = false)
1094     {
1095         if ($this->_height === null || $recalculate) {
1096             $this->_height =
1097                 abs(
1098                     $this->_calculateHeight() * cos(
1099                         $this->_orientation / 180 * pi()
1100                     )
1101                 )
1102                 + abs(
1103                     $this->_calculateWidth() * sin(
1104                         $this->_orientation / 180 * pi()
1105                     )
1106                 );
1107         }
1108         return $this->_height;
1109     }
1110 
1111     /**
1112      * Get width of the result object
1113      *
1114      * @param bool $recalculate
1115      * @return int
1116      */
1117     public function getWidth($recalculate = false)
1118     {
1119         if ($this->_width === null || $recalculate) {
1120             $this->_width =
1121                 abs(
1122                     $this->_calculateWidth() * cos(
1123                         $this->_orientation / 180 * pi()
1124                     )
1125                 )
1126                 + abs(
1127                     $this->_calculateHeight() * sin(
1128                         $this->_orientation / 180 * pi()
1129                     )
1130                 );
1131         }
1132         return $this->_width;
1133     }
1134 
1135     /**
1136      * Calculate the offset from the left of the object
1137      * if an orientation is activated
1138      *
1139      * @param bool $recalculate
1140      * @return float
1141      */
1142     public function getOffsetLeft($recalculate = false)
1143     {
1144         if ($this->_offsetLeft === null || $recalculate) {
1145             $this->_offsetLeft = - min(array(
1146                 0 * cos(
1147                         $this->_orientation / 180 * pi()) - 0 * sin(
1148                         $this->_orientation / 180 * pi()),
1149                 0 * cos(
1150                         $this->_orientation / 180 * pi()) - $this->_calculateBarcodeHeight() * sin(
1151                         $this->_orientation / 180 * pi()),
1152                 $this->_calculateBarcodeWidth() * cos(
1153                         $this->_orientation / 180 * pi()) - $this->_calculateBarcodeHeight() * sin(
1154                         $this->_orientation / 180 * pi()),
1155                 $this->_calculateBarcodeWidth() * cos(
1156                         $this->_orientation / 180 * pi()) - 0 * sin(
1157                         $this->_orientation / 180 * pi()),
1158             ));
1159         }
1160         return $this->_offsetLeft;
1161     }
1162 
1163     /**
1164      * Calculate the offset from the top of the object
1165      * if an orientation is activated
1166      *
1167      * @param bool $recalculate
1168      * @return float
1169      */
1170     public function getOffsetTop($recalculate = false)
1171     {
1172         if ($this->_offsetTop === null || $recalculate) {
1173             $this->_offsetTop = - min(array(
1174                 0 * cos(
1175                         $this->_orientation / 180 * pi()) + 0 * sin(
1176                         $this->_orientation / 180 * pi()),
1177                 $this->_calculateBarcodeHeight() * cos(
1178                         $this->_orientation / 180 * pi()) + 0 * sin(
1179                         $this->_orientation / 180 * pi()),
1180                 $this->_calculateBarcodeHeight() * cos(
1181                         $this->_orientation / 180 * pi()) + $this->_calculateBarcodeWidth() * sin(
1182                         $this->_orientation / 180 * pi()),
1183                 0 * cos(
1184                         $this->_orientation / 180 * pi()) + $this->_calculateBarcodeWidth() * sin(
1185                         $this->_orientation / 180 * pi()),
1186             ));
1187         }
1188         return $this->_offsetTop;
1189     }
1190 
1191     /**
1192      * Apply rotation on a point in X/Y dimensions
1193      *
1194      * @param  float $x1 x-position before rotation
1195      * @param  float $y1 y-position before rotation
1196      * @return array Array of two elements corresponding to the new XY point
1197      */
1198     protected function _rotate($x1, $y1)
1199     {
1200         $x2 = $x1 * cos($this->_orientation / 180 * pi())
1201             - $y1 * sin($this->_orientation / 180 * pi())
1202             + $this->getOffsetLeft();
1203         $y2 = $y1 * cos($this->_orientation / 180 * pi())
1204             + $x1 * sin($this->_orientation / 180 * pi())
1205             + $this->getOffsetTop();
1206 
1207         return array(
1208             intval($x2),
1209             intval($y2)
1210         );
1211     }
1212 
1213     /**
1214      * Complete drawing of the barcode
1215      *
1216      * @return array Table of instructions
1217      */
1218     public function draw()
1219     {
1220         $this->checkParams();
1221         $this->_drawBarcode();
1222         $this->_drawBorder();
1223         $this->_drawText();
1224         return $this->getInstructions();
1225     }
1226 
1227     /**
1228      * Draw the barcode
1229      */
1230     protected function _drawBarcode()
1231     {
1232         $barcodeTable = $this->_prepareBarcode();
1233 
1234         $this->_preDrawBarcode();
1235 
1236         $xpos = (int) $this->_withBorder;
1237         $ypos = (int) $this->_withBorder;
1238 
1239         $point1 = $this->_rotate(0, 0);
1240         $point2 = $this->_rotate(0, $this->_calculateHeight() - 1);
1241         $point3 = $this->_rotate(
1242             $this->_calculateWidth() - 1,
1243             $this->_calculateHeight() - 1
1244         );
1245         $point4 = $this->_rotate($this->_calculateWidth() - 1, 0);
1246 
1247         $this->_addPolygon(
1248             array(
1249                 $point1,
1250                 $point2,
1251                 $point3,
1252                 $point4
1253             ), $this->_backgroundColor
1254         );
1255 
1256         $xpos     += $this->getQuietZone();
1257         $barLength = $this->_barHeight * $this->_factor;
1258 
1259         foreach ($barcodeTable as $bar) {
1260             $width = $bar[1] * $this->_factor;
1261             if ($bar[0]) {
1262                 $point1 = $this->_rotate($xpos, $ypos + $bar[2] * $barLength);
1263                 $point2 = $this->_rotate($xpos, $ypos + $bar[3] * $barLength);
1264                 $point3 = $this->_rotate(
1265                     $xpos + $width - 1,
1266                     $ypos + $bar[3] * $barLength
1267                 );
1268                 $point4 = $this->_rotate(
1269                     $xpos + $width - 1,
1270                     $ypos + $bar[2] * $barLength
1271                 );
1272                 $this->_addPolygon(
1273                     array(
1274                         $point1,
1275                         $point2,
1276                         $point3,
1277                         $point4,
1278                     )
1279                 );
1280             }
1281             $xpos += $width;
1282         }
1283 
1284         $this->_postDrawBarcode();
1285     }
1286 
1287     /**
1288      * Partial function to draw border
1289      */
1290     protected function _drawBorder()
1291     {
1292         if ($this->_withBorder) {
1293             $point1 = $this->_rotate(0, 0);
1294             $point2 = $this->_rotate($this->_calculateWidth() - 1, 0);
1295             $point3 = $this->_rotate(
1296                 $this->_calculateWidth() - 1,
1297                 $this->_calculateHeight() - 1
1298             );
1299             $point4 = $this->_rotate(0, $this->_calculateHeight() - 1);
1300             $this->_addPolygon(
1301                 array(
1302                     $point1,
1303                     $point2,
1304                     $point3,
1305                     $point4,
1306                     $point1,
1307                 ), $this->_foreColor, false
1308             );
1309         }
1310     }
1311 
1312     /**
1313      * Partial function to draw text
1314      */
1315     protected function _drawText()
1316     {
1317         if ($this->_drawText) {
1318             $text = $this->getTextToDisplay();
1319             if ($this->_stretchText) {
1320                 $textLength = strlen($text);
1321                 $space      = ($this->_calculateWidth() - 2 * $this->getQuietZone()) / $textLength;
1322                 for ($i = 0; $i < $textLength; $i ++) {
1323                     $leftPosition = $this->getQuietZone() + $space * ($i + 0.5);
1324                     $this->_addText(
1325                         $text{$i},
1326                         $this->_fontSize * $this->_factor,
1327                         $this->_rotate(
1328                             $leftPosition,
1329                             (int) $this->_withBorder * 2
1330                                 + $this->_factor * ($this->_barHeight + $this->_fontSize) + 1
1331                         ),
1332                         $this->_font,
1333                         $this->_foreColor,
1334                         'center',
1335                         - $this->_orientation
1336                     );
1337                 }
1338             } else {
1339                 $this->_addText(
1340                     $text,
1341                     $this->_fontSize * $this->_factor,
1342                     $this->_rotate(
1343                         $this->_calculateWidth() / 2,
1344                         (int) $this->_withBorder * 2
1345                             + $this->_factor * ($this->_barHeight + $this->_fontSize) + 1
1346                     ),
1347                     $this->_font,
1348                     $this->_foreColor,
1349                     'center',
1350                     - $this->_orientation
1351                 );
1352             }
1353         }
1354     }
1355 
1356     /**
1357      * Check for invalid characters
1358      *
1359      * @param string $value Text to be ckecked
1360      */
1361     public function validateText($value)
1362     {
1363         $this->_validateText($value);
1364     }
1365 
1366     /**
1367      * Standard validation for most of barcode objects
1368      *
1369      * @param string $value
1370      * @param array  $options
1371      * @throws Zend_Barcode_Object_Exception
1372      */
1373     protected function _validateText($value, $options = array())
1374     {
1375         $validatorName = (isset($options['validator'])) ? $options['validator'] : $this->getType();
1376 
1377         $validator = new Zend_Validate_Barcode(
1378             array(
1379                 'adapter'  => $validatorName,
1380                 'checksum' => false,
1381             )
1382         );
1383 
1384         $checksumCharacter = '';
1385         $withChecksum = false;
1386         if ($this->_mandatoryChecksum) {
1387             $checksumCharacter = $this->_substituteChecksumCharacter;
1388             $withChecksum = true;
1389         }
1390 
1391         $value = $this->_addLeadingZeros($value, $withChecksum)
1392                . $checksumCharacter;
1393 
1394         if (!$validator->isValid($value)) {
1395             $message = implode("\n", $validator->getMessages());
1396 
1397             /**
1398              * @see Zend_Barcode_Object_Exception
1399              */
1400             // require_once 'Zend/Barcode/Object/Exception.php';
1401             throw new Zend_Barcode_Object_Exception($message);
1402         }
1403     }
1404 
1405     /**
1406      * Each child must prepare the barcode and return
1407      * a table like array(
1408      *     0 => array(
1409      *         0 => int (visible(black) or not(white))
1410      *         1 => int (width of the bar)
1411      *         2 => float (0->1 position from the top of the beginning of the bar in %)
1412      *         3 => float (0->1 position from the top of the end of the bar in %)
1413      *     ),
1414      *     1 => ...
1415      * )
1416      *
1417      * @return array
1418      */
1419     abstract protected function _prepareBarcode();
1420 
1421     /**
1422      * Checking of parameters after all settings
1423      */
1424     abstract protected function _checkParams();
1425 
1426     /**
1427      * Allow each child to draw something else
1428      */
1429     protected function _preDrawBarcode()
1430     {
1431     }
1432 
1433     /**
1434      * Allow each child to draw something else
1435      * (ex: bearer bars in interleaved 2 of 5 code)
1436      */
1437     protected function _postDrawBarcode()
1438     {
1439     }
1440 }