/lib/Imagine/Imagick/Drawer.php

https://github.com/stephaneerard/Imagine · PHP · 347 lines · 243 code · 61 blank · 43 comment · 10 complexity · 5222fa8655dee7d6a7c95f41bac563db 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\Imagick;
  11. use Imagine\Color;
  12. use Imagine\Point;
  13. use Imagine\PointInterface;
  14. use Imagine\BoxInterface;
  15. use Imagine\Draw\DrawerInterface;
  16. use Imagine\Exception\InvalidArgumentException;
  17. use Imagine\Exception\RuntimeException;
  18. final class Drawer implements DrawerInterface
  19. {
  20. private $imagick;
  21. public function __construct(\Imagick $imagick)
  22. {
  23. $this->imagick = $imagick;
  24. }
  25. /**
  26. * (non-PHPdoc)
  27. * @see Imagine\Draw.DrawerInterface::arc()
  28. */
  29. public function arc(PointInterface $center, BoxInterface $size, $start, $end, Color $color)
  30. {
  31. $x = $center->getX();
  32. $y = $center->getY();
  33. $width = $size->getWidth();
  34. $height = $size->getHeight();
  35. try {
  36. $pixel = $this->getColor($color);
  37. $arc = new \ImagickDraw();
  38. $arc->setStrokeColor($pixel);
  39. $arc->setStrokeWidth(1);
  40. $arc->setFillColor('transparent');
  41. $arc->arc($x - $width / 2, $y - $height / 2, $x + $width / 2, $y + $height / 2, $start, $end);
  42. $this->imagick->drawImage($arc);
  43. $pixel->clear();
  44. $pixel->destroy();
  45. $arc->clear();
  46. $arc->destroy();
  47. } catch (\ImagickException $e) {
  48. throw new RuntimeException(
  49. 'Draw arc operation failed', $e->getCode(), $e
  50. );
  51. }
  52. return $this;
  53. }
  54. /**
  55. * (non-PHPdoc)
  56. * @see Imagine\Draw.DrawerInterface::chord()
  57. */
  58. public function chord(PointInterface $center, BoxInterface $size, $start, $end, Color $color, $fill = false)
  59. {
  60. $x = $center->getX();
  61. $y = $center->getY();
  62. $width = $size->getWidth();
  63. $height = $size->getHeight();
  64. try {
  65. $pixel = $this->getColor($color);
  66. $chord = new \ImagickDraw();
  67. $chord->setStrokeColor($pixel);
  68. $chord->setStrokeWidth(1);
  69. if ($fill) {
  70. $chord->setFillColor($pixel);
  71. } else {
  72. $this->line(
  73. new Point(
  74. round($x + $width / 2 * cos(deg2rad($start))),
  75. round($y + $height / 2 * sin(deg2rad($start)))
  76. ),
  77. new Point(
  78. round($x + $width / 2 * cos(deg2rad($end))),
  79. round($y + $height / 2 * sin(deg2rad($end)))
  80. ),
  81. $color
  82. );
  83. $chord->setFillColor('transparent');
  84. }
  85. $chord->arc(
  86. $x - $width / 2,
  87. $y - $height / 2,
  88. $x + $width / 2,
  89. $y + $height / 2,
  90. $start,
  91. $end
  92. );
  93. $this->imagick->drawImage($chord);
  94. $pixel->clear();
  95. $pixel->destroy();
  96. $chord->clear();
  97. $chord->destroy();
  98. } catch (\ImagickException $e) {
  99. throw new RuntimeException(
  100. 'Draw chord operation failed', $e->getCode(), $e
  101. );
  102. }
  103. return $this;
  104. }
  105. /**
  106. * (non-PHPdoc)
  107. * @see Imagine\Draw.DrawerInterface::ellipse()
  108. */
  109. public function ellipse(PointInterface $center, BoxInterface $size, Color $color, $fill = false)
  110. {
  111. $width = $size->getWidth();
  112. $height = $size->getHeight();
  113. try {
  114. $pixel = $this->getColor($color);
  115. $ellipse = new \ImagickDraw();
  116. $ellipse->setStrokeColor($pixel);
  117. $ellipse->setStrokeWidth(1);
  118. if ($fill) {
  119. $ellipse->setFillColor($pixel);
  120. } else {
  121. $ellipse->setFillColor('transparent');
  122. }
  123. $ellipse->ellipse(
  124. $center->getX(),
  125. $center->getY(),
  126. $width / 2,
  127. $height / 2,
  128. 0, 360
  129. );
  130. if (false === $this->imagick->drawImage($ellipse)) {
  131. throw new RuntimeException('Ellipse operation failed');
  132. }
  133. $pixel->clear();
  134. $pixel->destroy();
  135. $ellipse->clear();
  136. $ellipse->destroy();
  137. } catch (\ImagickException $e) {
  138. throw new RuntimeException(
  139. 'Draw ellipse operation failed', $e->getCode(), $e
  140. );
  141. }
  142. return $this;
  143. }
  144. /**
  145. * (non-PHPdoc)
  146. * @see Imagine\Draw.DrawerInterface::line()
  147. */
  148. public function line(PointInterface $start, PointInterface $end, Color $color)
  149. {
  150. try {
  151. $pixel = $this->getColor($color);
  152. $line = new \ImagickDraw();
  153. $line->setStrokeColor($pixel);
  154. $line->setStrokeWidth(1);
  155. $line->line(
  156. $start->getX(),
  157. $start->getY(),
  158. $end->getX(),
  159. $end->getY()
  160. );
  161. $this->imagick->drawImage($line);
  162. $pixel->clear();
  163. $pixel->destroy();
  164. $line->clear();
  165. $line->destroy();
  166. } catch (\ImagickException $e) {
  167. throw new RuntimeException(
  168. 'Draw line operation failed', $e->getCode(), $e
  169. );
  170. }
  171. return $this;
  172. }
  173. /**
  174. * (non-PHPdoc)
  175. * @see Imagine\Draw.DrawerInterface::pieSlice()
  176. */
  177. public function pieSlice(PointInterface $center, BoxInterface $size, $start, $end, Color $color, $fill = false)
  178. {
  179. $width = $size->getWidth();
  180. $height = $size->getHeight();
  181. $x1 = round($center->getX() + $width / 2 * cos(deg2rad($start)));
  182. $y1 = round($center->getY() + $height / 2 * sin(deg2rad($start)));
  183. $x2 = round($center->getX() + $width / 2 * cos(deg2rad($end)));
  184. $y2 = round($center->getY() + $height / 2 * sin(deg2rad($end)));
  185. if ($fill) {
  186. $this->chord($center, $size, $start, $end, $color, true);
  187. $this->polygon(
  188. array(
  189. $center,
  190. new Point($x1, $y1),
  191. new Point($x2, $y2),
  192. ),
  193. $color,
  194. true
  195. );
  196. } else {
  197. $this->arc($center, $width, $height, $start, $end, $color);
  198. $this->line($center, new Point($x1, $y1), $color);
  199. $this->line($center, new Point($x2, $y2), $color);
  200. }
  201. return $this;
  202. }
  203. /**
  204. * (non-PHPdoc)
  205. * @see Imagine\Draw.DrawerInterface::dot()
  206. */
  207. public function dot(PointInterface $position, Color $color)
  208. {
  209. $x = $position->getX();
  210. $y = $position->getY();
  211. try {
  212. $pixel = $this->getColor($color);
  213. $point = new \ImagickDraw();
  214. $point->setFillColor($pixel);
  215. $point->point($x, $y);
  216. $this->imagick->drawimage($point);
  217. $pixel->clear();
  218. $pixel->destroy();
  219. $point->clear();
  220. $point->destroy();
  221. } catch (\ImagickException $e) {
  222. throw new RuntimeException(
  223. 'Draw point operation failed', $e->getCode(), $e
  224. );
  225. }
  226. return $this;
  227. }
  228. /**
  229. * (non-PHPdoc)
  230. * @see Imagine\Draw.DrawerInterface::polygon()
  231. */
  232. public function polygon(array $coordinates, Color $color, $fill = false)
  233. {
  234. if (count($coordinates) < 3) {
  235. throw new InvalidArgumentException(sprintf(
  236. 'Polygon must consist of at least 3 coordinates, %d given',
  237. count($coordinates)
  238. ));
  239. }
  240. $points = array_map(
  241. function(PointInterface $p)
  242. {
  243. return array('x' => $p->getX(), 'y' => $p->getY());
  244. },
  245. $coordinates
  246. );
  247. try {
  248. $pixel = $this->getColor($color);
  249. $polygon = new \ImagickDraw();
  250. $polygon->setStrokeColor($pixel);
  251. $polygon->setStrokeWidth(1);
  252. if ($fill) {
  253. $polygon->setFillColor($pixel);
  254. } else {
  255. $polygon->setFillColor('transparent');
  256. }
  257. $polygon->polygon($points);
  258. $this->imagick->drawImage($polygon);
  259. $pixel->clear();
  260. $pixel->destroy();
  261. $polygon->clear();
  262. $polygon->destroy();
  263. } catch (\ImagickException $e) {
  264. throw new RuntimeException(
  265. 'Draw polygon operation failed', $e->getCode(), $e
  266. );
  267. }
  268. return $this;
  269. }
  270. /**
  271. * Gets specifically formatted color string from Color instance
  272. *
  273. * @param Color $color
  274. *
  275. * @return string
  276. */
  277. private function getColor(Color $color)
  278. {
  279. $pixel = new \ImagickPixel((string) $color);
  280. $pixel->setColorValue(
  281. \Imagick::COLOR_OPACITY,
  282. number_format(abs(round($color->getAlpha() / 100, 1)), 1)
  283. );
  284. return $pixel;
  285. }
  286. }