File indexing completed on 2025-01-26 05:29:14

0001 <?php
0002 
0003 namespace Intervention\Image\Gd;
0004 
0005 use Intervention\Image\Image;
0006 
0007 class Font extends \Intervention\Image\AbstractFont
0008 {
0009     /**
0010      * Get font size in points
0011      *
0012      * @return int
0013      */
0014     protected function getPointSize()
0015     {
0016         return intval(ceil($this->size * 0.75));
0017     }
0018 
0019     /**
0020      * Filter function to access internal integer font values
0021      *
0022      * @return int
0023      */
0024     private function getInternalFont()
0025     {
0026         $internalfont = is_null($this->file) ? 1 : $this->file;
0027         $internalfont = is_numeric($internalfont) ? $internalfont : false;
0028 
0029         if ( ! in_array($internalfont, [1, 2, 3, 4, 5])) {
0030             throw new \Intervention\Image\Exception\NotSupportedException(
0031                 sprintf('Internal GD font (%s) not available. Use only 1-5.', $internalfont)
0032             );
0033         }
0034 
0035         return intval($internalfont);
0036     }
0037 
0038     /**
0039      * Get width of an internal font character
0040      *
0041      * @return int
0042      */
0043     private function getInternalFontWidth()
0044     {
0045         return $this->getInternalFont() + 4;
0046     }
0047 
0048     /**
0049      * Get height of an internal font character
0050      *
0051      * @return int
0052      */
0053     private function getInternalFontHeight()
0054     {
0055         switch ($this->getInternalFont()) {
0056             case 1:
0057                 return 8;
0058 
0059             case 2:
0060                 return 14;
0061 
0062             case 3:
0063                 return 14;
0064 
0065             case 4:
0066                 return 16;
0067 
0068             case 5:
0069                 return 16;
0070         }
0071     }
0072 
0073     /**
0074      * Calculates bounding box of current font setting
0075      *
0076      * @return Array
0077      */
0078     public function getBoxSize()
0079     {
0080         $box = [];
0081 
0082         if ($this->hasApplicableFontFile()) {
0083 
0084             // get bounding box with angle 0
0085             $box = imagettfbbox($this->getPointSize(), 0, $this->file, $this->text);
0086 
0087             // rotate points manually
0088             if ($this->angle != 0) {
0089 
0090                 $angle = pi() * 2 - $this->angle * pi() * 2 / 360;
0091 
0092                 for ($i=0; $i<4; $i++) {
0093                     $x = $box[$i * 2];
0094                     $y = $box[$i * 2 + 1];
0095                     $box[$i * 2] = cos($angle) * $x - sin($angle) * $y;
0096                     $box[$i * 2 + 1] = sin($angle) * $x + cos($angle) * $y;
0097                 }
0098             }
0099 
0100             $box['width'] = intval(abs($box[4] - $box[0]));
0101             $box['height'] = intval(abs($box[5] - $box[1]));
0102 
0103         } else {
0104 
0105             // get current internal font size
0106             $width = $this->getInternalFontWidth();
0107             $height = $this->getInternalFontHeight();
0108 
0109             if (strlen($this->text) == 0) {
0110                 // no text -> no boxsize
0111                 $box['width'] = 0;
0112                 $box['height'] = 0;
0113             } else {
0114                 // calculate boxsize
0115                 $box['width'] = strlen($this->text) * $width;
0116                 $box['height'] = $height;
0117             }
0118         }
0119 
0120         return $box;
0121     }
0122 
0123     /**
0124      * Draws font to given image at given position
0125      *
0126      * @param  Image   $image
0127      * @param  int     $posx
0128      * @param  int     $posy
0129      * @return void
0130      */
0131     public function applyToImage(Image $image, $posx = 0, $posy = 0)
0132     {
0133         // parse text color
0134         $color = new Color($this->color);
0135 
0136         if ($this->hasApplicableFontFile()) {
0137 
0138             if ($this->angle != 0 || is_string($this->align) || is_string($this->valign)) {
0139 
0140                 $box = $this->getBoxSize();
0141 
0142                 $align = is_null($this->align) ? 'left' : strtolower($this->align);
0143                 $valign = is_null($this->valign) ? 'bottom' : strtolower($this->valign);
0144 
0145                 // correction on position depending on v/h alignment
0146                 switch ($align.'-'.$valign) {
0147 
0148                     case 'center-top':
0149                         $posx = $posx - round(($box[6]+$box[4])/2);
0150                         $posy = $posy - round(($box[7]+$box[5])/2);
0151                         break;
0152 
0153                     case 'right-top':
0154                         $posx = $posx - $box[4];
0155                         $posy = $posy - $box[5];
0156                         break;
0157 
0158                     case 'left-top':
0159                         $posx = $posx - $box[6];
0160                         $posy = $posy - $box[7];
0161                         break;
0162 
0163                     case 'center-center':
0164                     case 'center-middle':
0165                         $posx = $posx - round(($box[0]+$box[4])/2);
0166                         $posy = $posy - round(($box[1]+$box[5])/2);
0167                         break;
0168 
0169                     case 'right-center':
0170                     case 'right-middle':
0171                         $posx = $posx - round(($box[2]+$box[4])/2);
0172                         $posy = $posy - round(($box[3]+$box[5])/2);
0173                         break;
0174 
0175                     case 'left-center':
0176                     case 'left-middle':
0177                         $posx = $posx - round(($box[0]+$box[6])/2);
0178                         $posy = $posy - round(($box[1]+$box[7])/2);
0179                         break;
0180 
0181                     case 'center-bottom':
0182                         $posx = $posx - round(($box[0]+$box[2])/2);
0183                         $posy = $posy - round(($box[1]+$box[3])/2);
0184                         break;
0185 
0186                     case 'right-bottom':
0187                         $posx = $posx - $box[2];
0188                         $posy = $posy - $box[3];
0189                         break;
0190 
0191                     case 'left-bottom':
0192                         $posx = $posx - $box[0];
0193                         $posy = $posy - $box[1];
0194                         break;
0195                 }
0196             }
0197 
0198             // enable alphablending for imagettftext
0199             imagealphablending($image->getCore(), true);
0200 
0201             // draw ttf text
0202             imagettftext($image->getCore(), $this->getPointSize(), $this->angle, $posx, $posy, $color->getInt(), $this->file, $this->text);
0203 
0204         } else {
0205 
0206             // get box size
0207             $box = $this->getBoxSize();
0208             $width = $box['width'];
0209             $height = $box['height'];
0210 
0211             // internal font specific position corrections
0212             if ($this->getInternalFont() == 1) {
0213                 $top_correction = 1;
0214                 $bottom_correction = 2;
0215             } elseif ($this->getInternalFont() == 3) {
0216                 $top_correction = 2;
0217                 $bottom_correction = 4;
0218             } else {
0219                 $top_correction = 3;
0220                 $bottom_correction = 4;
0221             }
0222 
0223             // x-position corrections for horizontal alignment
0224             switch (strtolower($this->align)) {
0225                 case 'center':
0226                     $posx = ceil($posx - ($width / 2));
0227                     break;
0228 
0229                 case 'right':
0230                     $posx = ceil($posx - $width) + 1;
0231                     break;
0232             }
0233 
0234             // y-position corrections for vertical alignment
0235             switch (strtolower($this->valign)) {
0236                 case 'center':
0237                 case 'middle':
0238                     $posy = ceil($posy - ($height / 2));
0239                     break;
0240 
0241                 case 'top':
0242                     $posy = ceil($posy - $top_correction);
0243                     break;
0244 
0245                 default:
0246                 case 'bottom':
0247                     $posy = round($posy - $height + $bottom_correction);
0248                     break;
0249             }
0250 
0251             // draw text
0252             imagestring($image->getCore(), $this->getInternalFont(), $posx, $posy, $this->text, $color->getInt());
0253         }
0254     }
0255 }