Font.php 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. <?php
  2. namespace Intervention\Image\Gd;
  3. use Intervention\Image\Image;
  4. class Font extends \Intervention\Image\AbstractFont
  5. {
  6. /**
  7. * Get font size in points
  8. *
  9. * @return integer
  10. */
  11. protected function getPointSize()
  12. {
  13. return intval(ceil($this->size * 0.75));
  14. }
  15. /**
  16. * Filter function to access internal integer font values
  17. *
  18. * @return integer
  19. */
  20. private function getInternalFont()
  21. {
  22. $internalfont = is_null($this->file) ? 1 : $this->file;
  23. $internalfont = is_numeric($internalfont) ? $internalfont : false;
  24. if ( ! in_array($internalfont, array(1, 2, 3, 4, 5))) {
  25. throw new \Intervention\Image\Exception\NotSupportedException(
  26. sprintf('Internal GD font (%s) not available. Use only 1-5.', $internalfont)
  27. );
  28. }
  29. return intval($internalfont);
  30. }
  31. /**
  32. * Get width of an internal font character
  33. *
  34. * @return integer
  35. */
  36. private function getInternalFontWidth()
  37. {
  38. return $this->getInternalFont() + 4;
  39. }
  40. /**
  41. * Get height of an internal font character
  42. *
  43. * @return integer
  44. */
  45. private function getInternalFontHeight()
  46. {
  47. switch ($this->getInternalFont()) {
  48. case 1:
  49. return 8;
  50. case 2:
  51. return 14;
  52. case 3:
  53. return 14;
  54. case 4:
  55. return 16;
  56. case 5:
  57. return 16;
  58. }
  59. }
  60. /**
  61. * Calculates bounding box of current font setting
  62. *
  63. * @return Array
  64. */
  65. public function getBoxSize()
  66. {
  67. $box = array();
  68. if ($this->hasApplicableFontFile()) {
  69. // get bounding box with angle 0
  70. $box = imagettfbbox($this->getPointSize(), 0, $this->file, $this->text);
  71. // rotate points manually
  72. if ($this->angle != 0) {
  73. $angle = pi() * 2 - $this->angle * pi() * 2 / 360;
  74. for ($i=0; $i<4; $i++) {
  75. $x = $box[$i * 2];
  76. $y = $box[$i * 2 + 1];
  77. $box[$i * 2] = cos($angle) * $x - sin($angle) * $y;
  78. $box[$i * 2 + 1] = sin($angle) * $x + cos($angle) * $y;
  79. }
  80. }
  81. $box['width'] = intval(abs($box[4] - $box[0]));
  82. $box['height'] = intval(abs($box[5] - $box[1]));
  83. } else {
  84. // get current internal font size
  85. $width = $this->getInternalFontWidth();
  86. $height = $this->getInternalFontHeight();
  87. if (strlen($this->text) == 0) {
  88. // no text -> no boxsize
  89. $box['width'] = 0;
  90. $box['height'] = 0;
  91. } else {
  92. // calculate boxsize
  93. $box['width'] = strlen($this->text) * $width;
  94. $box['height'] = $height;
  95. }
  96. }
  97. return $box;
  98. }
  99. /**
  100. * Draws font to given image at given position
  101. *
  102. * @param Image $image
  103. * @param integer $posx
  104. * @param integer $posy
  105. * @return void
  106. */
  107. public function applyToImage(Image $image, $posx = 0, $posy = 0)
  108. {
  109. // parse text color
  110. $color = new Color($this->color);
  111. if ($this->hasApplicableFontFile()) {
  112. if ($this->angle != 0 || is_string($this->align) || is_string($this->valign)) {
  113. $box = $this->getBoxSize();
  114. $align = is_null($this->align) ? 'left' : strtolower($this->align);
  115. $valign = is_null($this->valign) ? 'bottom' : strtolower($this->valign);
  116. // correction on position depending on v/h alignment
  117. switch ($align.'-'.$valign) {
  118. case 'center-top':
  119. $posx = $posx - round(($box[6]+$box[4])/2);
  120. $posy = $posy - round(($box[7]+$box[5])/2);
  121. break;
  122. case 'right-top':
  123. $posx = $posx - $box[4];
  124. $posy = $posy - $box[5];
  125. break;
  126. case 'left-top':
  127. $posx = $posx - $box[6];
  128. $posy = $posy - $box[7];
  129. break;
  130. case 'center-center':
  131. case 'center-middle':
  132. $posx = $posx - round(($box[0]+$box[4])/2);
  133. $posy = $posy - round(($box[1]+$box[5])/2);
  134. break;
  135. case 'right-center':
  136. case 'right-middle':
  137. $posx = $posx - round(($box[2]+$box[4])/2);
  138. $posy = $posy - round(($box[3]+$box[5])/2);
  139. break;
  140. case 'left-center':
  141. case 'left-middle':
  142. $posx = $posx - round(($box[0]+$box[6])/2);
  143. $posy = $posy - round(($box[1]+$box[7])/2);
  144. break;
  145. case 'center-bottom':
  146. $posx = $posx - round(($box[0]+$box[2])/2);
  147. $posy = $posy - round(($box[1]+$box[3])/2);
  148. break;
  149. case 'right-bottom':
  150. $posx = $posx - $box[2];
  151. $posy = $posy - $box[3];
  152. break;
  153. case 'left-bottom':
  154. $posx = $posx - $box[0];
  155. $posy = $posy - $box[1];
  156. break;
  157. }
  158. }
  159. // enable alphablending for imagettftext
  160. imagealphablending($image->getCore(), true);
  161. // draw ttf text
  162. imagettftext($image->getCore(), $this->getPointSize(), $this->angle, $posx, $posy, $color->getInt(), $this->file, $this->text);
  163. } else {
  164. // get box size
  165. $box = $this->getBoxSize();
  166. $width = $box['width'];
  167. $height = $box['height'];
  168. // internal font specific position corrections
  169. if ($this->getInternalFont() == 1) {
  170. $top_correction = 1;
  171. $bottom_correction = 2;
  172. } elseif ($this->getInternalFont() == 3) {
  173. $top_correction = 2;
  174. $bottom_correction = 4;
  175. } else {
  176. $top_correction = 3;
  177. $bottom_correction = 4;
  178. }
  179. // x-position corrections for horizontal alignment
  180. switch (strtolower($this->align)) {
  181. case 'center':
  182. $posx = ceil($posx - ($width / 2));
  183. break;
  184. case 'right':
  185. $posx = ceil($posx - $width) + 1;
  186. break;
  187. }
  188. // y-position corrections for vertical alignment
  189. switch (strtolower($this->valign)) {
  190. case 'center':
  191. case 'middle':
  192. $posy = ceil($posy - ($height / 2));
  193. break;
  194. case 'top':
  195. $posy = ceil($posy - $top_correction);
  196. break;
  197. default:
  198. case 'bottom':
  199. $posy = round($posy - $height + $bottom_correction);
  200. break;
  201. }
  202. // draw text
  203. imagestring($image->getCore(), $this->getInternalFont(), $posx, $posy, $this->text, $color->getInt());
  204. }
  205. }
  206. }