/vendor/imagine/imagine/lib/Imagine/Gd/Drawer.php

https://bitbucket.org/hanutimes/hanutimes · PHP · 279 lines · 182 code · 38 blank · 59 comment · 23 complexity · 3b41b9712f99d8bc36962e5a68208590 MD5 · raw file

  1. <?php
  2. /*
  3. * This file is part of the Imagine package.
  4. *
  5. * (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Imagine\Gd;
  11. use Imagine\Draw\DrawerInterface;
  12. use Imagine\Exception\InvalidArgumentException;
  13. use Imagine\Exception\RuntimeException;
  14. use Imagine\Image\AbstractFont;
  15. use Imagine\Image\BoxInterface;
  16. use Imagine\Image\Color;
  17. use Imagine\Image\PointInterface;
  18. /**
  19. * Drawer implementation using the GD library
  20. */
  21. final class Drawer implements DrawerInterface
  22. {
  23. /**
  24. * @var resource
  25. */
  26. private $resource;
  27. /**
  28. * @var array
  29. */
  30. private $info;
  31. /**
  32. * Constructs Drawer with a given gd image resource
  33. *
  34. * @param resource $resource
  35. */
  36. public function __construct($resource)
  37. {
  38. $this->loadGdInfo();
  39. $this->resource = $resource;
  40. }
  41. /**
  42. * {@inheritdoc}
  43. */
  44. public function arc(PointInterface $center, BoxInterface $size, $start, $end, Color $color, $thickness = 1)
  45. {
  46. imagesetthickness($this->resource, max(1, (int) $thickness));
  47. if (false === imagearc(
  48. $this->resource, $center->getX(), $center->getY(),
  49. $size->getWidth(), $size->getHeight(), $start, $end,
  50. $this->getColor($color)
  51. )) {
  52. throw new RuntimeException('Draw arc operation failed');
  53. }
  54. return $this;
  55. }
  56. /**
  57. * This function doesn't work properly because of a bug in GD
  58. *
  59. * {@inheritdoc}
  60. */
  61. public function chord(PointInterface $center, BoxInterface $size, $start, $end, Color $color, $fill = false, $thickness = 1)
  62. {
  63. imagesetthickness($this->resource, max(1, (int) $thickness));
  64. if ($fill) {
  65. $style = IMG_ARC_CHORD;
  66. } else {
  67. $style = IMG_ARC_CHORD | IMG_ARC_NOFILL;
  68. }
  69. if (false === imagefilledarc(
  70. $this->resource, $center->getX(), $center->getY(),
  71. $size->getWidth(), $size->getHeight(), $start, $end,
  72. $this->getColor($color), $style
  73. )) {
  74. throw new RuntimeException('Draw chord operation failed');
  75. }
  76. return $this;
  77. }
  78. /**
  79. * {@inheritdoc}
  80. */
  81. public function ellipse(PointInterface $center, BoxInterface $size, Color $color, $fill = false, $thickness = 1)
  82. {
  83. imagesetthickness($this->resource, max(1, (int) $thickness));
  84. if ($fill) {
  85. $callback = 'imagefilledellipse';
  86. } else {
  87. $callback = 'imageellipse';
  88. }
  89. if (false === $callback(
  90. $this->resource, $center->getX(), $center->getY(),
  91. $size->getWidth(), $size->getHeight(), $this->getColor($color))
  92. ) {
  93. throw new RuntimeException('Draw ellipse operation failed');
  94. }
  95. return $this;
  96. }
  97. /**
  98. * {@inheritdoc}
  99. */
  100. public function line(PointInterface $start, PointInterface $end, Color $color, $thickness = 1)
  101. {
  102. imagesetthickness($this->resource, max(1, (int) $thickness));
  103. if (false === imageline(
  104. $this->resource, $start->getX(), $start->getY(),
  105. $end->getX(), $end->getY(), $this->getColor($color)
  106. )) {
  107. throw new RuntimeException('Draw line operation failed');
  108. }
  109. return $this;
  110. }
  111. /**
  112. * {@inheritdoc}
  113. */
  114. public function pieSlice(PointInterface $center, BoxInterface $size, $start, $end, Color $color, $fill = false, $thickness = 1)
  115. {
  116. imagesetthickness($this->resource, max(1, (int) $thickness));
  117. if ($fill) {
  118. $style = IMG_ARC_EDGED;
  119. } else {
  120. $style = IMG_ARC_EDGED | IMG_ARC_NOFILL;
  121. }
  122. if (false === imagefilledarc(
  123. $this->resource, $center->getX(), $center->getY(),
  124. $size->getWidth(), $size->getHeight(), $start, $end,
  125. $this->getColor($color), $style
  126. )) {
  127. throw new RuntimeException('Draw chord operation failed');
  128. }
  129. return $this;
  130. }
  131. /**
  132. * {@inheritdoc}
  133. */
  134. public function dot(PointInterface $position, Color $color)
  135. {
  136. if (false === imagesetpixel(
  137. $this->resource, $position->getX(), $position->getY(),
  138. $this->getColor($color)
  139. )) {
  140. throw new RuntimeException('Draw point operation failed');
  141. }
  142. return $this;
  143. }
  144. /**
  145. * {@inheritdoc}
  146. */
  147. public function polygon(array $coordinates, Color $color, $fill = false, $thickness = 1)
  148. {
  149. imagesetthickness($this->resource, max(1, (int) $thickness));
  150. if (count($coordinates) < 3) {
  151. throw new InvalidArgumentException(sprintf(
  152. 'A polygon must consist of at least 3 points, %d given',
  153. count($coordinates)
  154. ));
  155. }
  156. $points = array();
  157. foreach ($coordinates as $coordinate) {
  158. if (!$coordinate instanceof PointInterface) {
  159. throw new InvalidArgumentException(sprintf(
  160. 'Each entry in coordinates array must be instance of '.
  161. 'Imagine\Image\PointInterface, %s given', var_export($coordinate)
  162. ));
  163. }
  164. $points[] = $coordinate->getX();
  165. $points[] = $coordinate->getY();
  166. }
  167. if ($fill) {
  168. $callback = 'imagefilledpolygon';
  169. } else {
  170. $callback = 'imagepolygon';
  171. }
  172. if (false === $callback(
  173. $this->resource, $points, count($coordinates),
  174. $this->getColor($color)
  175. )) {
  176. throw new RuntimeException('Draw polygon operation failed');
  177. }
  178. return $this;
  179. }
  180. /**
  181. * {@inheritdoc}
  182. */
  183. public function text($string, AbstractFont $font, PointInterface $position, $angle = 0)
  184. {
  185. if (!$this->info['FreeType Support']) {
  186. throw new RuntimeException('GD is not compiled with FreeType support');
  187. }
  188. $angle = -1 * $angle;
  189. $fontsize = $font->getSize();
  190. $fontfile = $font->getFile();
  191. $x = $position->getX();
  192. $y = $position->getY() + $fontsize;
  193. if (false === imagealphablending($this->resource, true)) {
  194. throw new RuntimeException('Font mask operation failed');
  195. }
  196. if (false === imagefttext(
  197. $this->resource, $fontsize, $angle, $x, $y,
  198. $this->getColor($font->getColor()), $fontfile, $string
  199. )) {
  200. throw new RuntimeException('Font mask operation failed');
  201. }
  202. if (false === imagealphablending($this->resource, false)) {
  203. throw new RuntimeException('Font mask operation failed');
  204. }
  205. return $this;
  206. }
  207. /**
  208. * Internal
  209. *
  210. * Generates a GD color from Color instance
  211. *
  212. * @param Imagine\Image\Color $color
  213. *
  214. * @return resource
  215. *
  216. * @throws Imagine\Exception\RuntimeException
  217. */
  218. private function getColor(Color $color)
  219. {
  220. $gdColor = imagecolorallocatealpha(
  221. $this->resource,
  222. $color->getRed(), $color->getGreen(), $color->getBlue(),
  223. round(127 * $color->getAlpha() / 100)
  224. );
  225. if (false === $gdColor) {
  226. throw new RuntimeException(sprintf(
  227. 'Unable to allocate color "RGB(%s, %s, %s)" with '.
  228. 'transparency of %d percent', $color->getRed(),
  229. $color->getGreen(), $color->getBlue(), $color->getAlpha()
  230. ));
  231. }
  232. return $gdColor;
  233. }
  234. private function loadGdInfo()
  235. {
  236. if (!function_exists('gd_info')) {
  237. throw new RuntimeException('Gd not installed');
  238. }
  239. $this->info = gd_info();
  240. }
  241. }