/ManaPHP/Image/Adapter/Imagick.php

https://gitlab.com/szlongshu/manaphp · PHP · 258 lines · 141 code · 36 blank · 81 comment · 19 complexity · f4bf15e17821d222301ef19dc25d726d MD5 · raw file

  1. <?php
  2. namespace ManaPHP\Image\Adapter {
  3. use ManaPHP\Image\AdapterInterface;
  4. class Imagick implements AdapterInterface
  5. {
  6. /**
  7. * @var string
  8. */
  9. protected $_file;
  10. /**
  11. * @var string
  12. */
  13. protected $_real_path;
  14. /**
  15. * @var \Imagick
  16. */
  17. protected $_image;
  18. /**
  19. * @var int
  20. */
  21. protected $_width;
  22. /**
  23. * @var int
  24. */
  25. protected $_height;
  26. /**
  27. * @param string $file
  28. *
  29. * @throws \ManaPHP\Image\Adapter\Exception
  30. */
  31. public function __construct($file)
  32. {
  33. if (!extension_loaded('imagick')) {
  34. throw new Exception('Imagick is not installed, or the extension is not loaded');
  35. }
  36. $this->_file = $file;
  37. $this->_image = new \Imagick();
  38. $real_path = realpath($this->_file);
  39. if ($real_path) {
  40. $this->_real_path = $real_path;
  41. if (!$this->_image->readImage($this->_real_path)) {
  42. throw new Exception('Imagick::readImage ' . $this->_file . ' failed');
  43. }
  44. if ($this->_image->getNumberImages() !== 1) {
  45. throw new Exception('Not support multiple iterations: ' . $this->_file);
  46. }
  47. if (!$this->_image->getImageAlphaChannel()) {
  48. $this->_image->setImageAlphaChannel(\Imagick::ALPHACHANNEL_SET);
  49. }
  50. } else {
  51. throw new Exception('the file is not exist: ' . $file);
  52. }
  53. $this->_width = $this->_image->getImageWidth();
  54. $this->_height = $this->_image->getImageHeight();
  55. }
  56. /**
  57. * Image width
  58. *
  59. * @return int
  60. */
  61. public function getWidth()
  62. {
  63. return $this->_width;
  64. }
  65. /**
  66. * Image height
  67. *
  68. * @return int
  69. */
  70. public function getHeight()
  71. {
  72. return $this->_height;
  73. }
  74. public function getInternalHandle()
  75. {
  76. return $this->_image;
  77. }
  78. /**
  79. * @param int $width
  80. * @param int $height
  81. *
  82. * @return static
  83. */
  84. public function resize($width, $height)
  85. {
  86. $this->_image->scaleImage($width, $height);
  87. $this->_width = $this->_image->getImageWidth();
  88. $this->_height = $this->_image->getImageHeight();
  89. return $this;
  90. }
  91. /**
  92. * Rotate the image by a given degrees
  93. *
  94. * @param int $degrees
  95. * @param int $background
  96. * @param float $alpha
  97. *
  98. * @return static
  99. */
  100. public function rotate($degrees, $background = 0xffffff, $alpha = 1.0)
  101. {
  102. $backgroundColor = sprintf('rgba(%u,%u,%u,%f)', ($background >> 16) & 0xFF, ($background >> 8) & 0xFF,
  103. $background & 0xFF, $alpha);
  104. $this->_image->rotateImage(new \ImagickPixel($backgroundColor), $degrees);
  105. $this->_image->setImagePage($this->_width, $this->_height, 0, 0);
  106. $this->_width = $this->_image->getImageWidth();
  107. $this->_height = $this->_image->getImageHeight();
  108. return $this;
  109. }
  110. /**
  111. * @param int $width
  112. * @param int $height
  113. * @param int $offsetX
  114. * @param int $offsetY
  115. *
  116. * @return static
  117. */
  118. public function crop($width, $height, $offsetX = 0, $offsetY = 0)
  119. {
  120. $this->_image->cropImage($width, $height, $offsetX, $offsetY);
  121. $this->_image->setImagePage($width, $height, 0, 0);
  122. $this->_width = $this->_image->getImageWidth();
  123. $this->_height = $this->_image->getImageHeight();
  124. return $this;
  125. }
  126. /**
  127. * Execute a text
  128. *
  129. * @param string $text
  130. * @param int $offsetX
  131. * @param int $offsetY
  132. * @param float $opacity
  133. * @param int $color
  134. * @param int $size
  135. * @param string $font_file
  136. *
  137. * @return static
  138. */
  139. public function text(
  140. $text,
  141. $offsetX = 0,
  142. $offsetY = 0,
  143. $opacity = 1.0,
  144. $color = 0x000000,
  145. $size = 12,
  146. $font_file = null
  147. ) {
  148. $draw = new \ImagickDraw();
  149. $textColor = sprintf('rgb(%u,%u,%u)', ($color >> 16) & 0xFF, ($color >> 8) & 0xFF, $color & 0xFF);
  150. $draw->setFillColor(new \ImagickPixel($textColor));
  151. if ($font_file) {
  152. $draw->setFont($font_file);
  153. }
  154. $draw->setFontSize($size);
  155. $draw->setFillOpacity($opacity);
  156. $draw->setGravity(\Imagick::GRAVITY_NORTHWEST);
  157. $this->_image->annotateImage($draw, $offsetX, $offsetY, 0, $text);
  158. $draw->destroy();
  159. return $this;
  160. }
  161. /**
  162. * @param string $file
  163. * @param int $offsetX
  164. * @param int $offsetY
  165. * @param float $opacity
  166. *
  167. * @return static
  168. * @throws \ManaPHP\Image\Adapter\Exception
  169. */
  170. public function watermark($file, $offsetX = 0, $offsetY = 0, $opacity = 1.0)
  171. {
  172. $watermark = new \Imagick($file);
  173. if ($watermark->getImageAlphaChannel() === \Imagick::ALPHACHANNEL_UNDEFINED) {
  174. $watermark->setImageOpacity($opacity);
  175. }
  176. if ($watermark->getNumberImages() !== 1) {
  177. throw new Exception('Not support multiple iterations: ' . $file);
  178. }
  179. if (!$this->_image->compositeImage($watermark, \Imagick::COMPOSITE_OVER, $offsetX, $offsetY)) {
  180. throw new Exception('Imagick::compositeImage Failed');
  181. }
  182. $watermark->clear();
  183. $watermark->destroy();
  184. return $this;
  185. }
  186. /**
  187. * @param string $file
  188. * @param int $quality
  189. *
  190. * @throws \ManaPHP\Image\Adapter\Exception
  191. */
  192. public function save($file = null, $quality = 80)
  193. {
  194. $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
  195. $this->_image->setFormat($ext);
  196. if ($ext === 'gif') {
  197. $this->_image->optimizeImageLayers();
  198. } else {
  199. if ($ext === 'jpg' || $ext === 'jpeg') {
  200. $this->_image->setImageCompression(\Imagick::COMPRESSION_JPEG);
  201. $this->_image->setImageCompressionQuality($quality);
  202. }
  203. }
  204. if ($file === null) {
  205. $file = $this->_file;
  206. } else {
  207. $dir = dirname($file);
  208. if (!@mkdir($dir, 0755, true) && !is_dir($dir)) {
  209. throw new Exception('Create directory "' . $dir . '" failed: ' . error_get_last()['message']);
  210. }
  211. }
  212. if (!$this->_image->writeImage($file)) {
  213. throw new Exception('save image failed: ' . $file);
  214. }
  215. }
  216. public function __destruct()
  217. {
  218. $this->_image->clear();
  219. $this->_image->destroy();
  220. }
  221. }
  222. }