Font.php 7.4 KB

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