ImageGD.php 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: AlexLcDee
  5. * Date: 15.02.2017
  6. * Time: 17:34
  7. */
  8. namespace yiins\components;
  9. class ImageGD
  10. {
  11. const WM_POS_LEFT_TOP = 'leftTop';
  12. const WM_POS_CENTER_TOP = 'top';
  13. const WM_POS_RIGHT_TOP = 'rightTop';
  14. const WM_POS_LEFT_CENTER = 'leftCenter';
  15. const WM_POS_CENTER_CENTER = 'center';
  16. const WM_POS_RIGHT_CENTER = 'rightCenter';
  17. const WM_POS_LEFT_BOTTOM = 'leftBottom';
  18. const WM_POS_CENTER_BOTTOM = 'bottom';
  19. const WM_POS_RIGHT_BOTTOM = 'rightBottom';
  20. protected $sourceResource;
  21. protected $destinationResource;
  22. protected $watermarkSource;
  23. protected $imageSize;
  24. protected $qualityMultiplier = 1;
  25. protected $mustCopy = false;
  26. protected $outputWidth;
  27. protected $outputHeight;
  28. protected $quality = 100;
  29. protected $offsetX = 0;
  30. protected $offsetY = 0;
  31. protected $cropWidth = 0;
  32. protected $cropHeight = 0;
  33. private function __construct($sourcePath)
  34. {
  35. $this->imageSize = getimagesize($sourcePath);
  36. $this->outputWidth = $this->cropWidth = $this->imageSize[0];
  37. $this->outputHeight = $this->cropHeight = $this->imageSize[1];
  38. $this->destinationResource = imagecreatetruecolor($this->outputWidth, $this->outputHeight);
  39. list($creationFunction, $outputFunction) = $this->functionNames();
  40. $this->sourceResource = $creationFunction($sourcePath);
  41. $this->outputFunction = $outputFunction;
  42. }
  43. /**
  44. * Set up the appropriate image handling functions based on the original image's mime type
  45. * @return array
  46. */
  47. protected function functionNames()
  48. {
  49. $size = $this->imageSize;
  50. switch ($size['mime']) {
  51. case 'image/gif':
  52. // We will be converting GIFs to PNGs to avoid transparency issues when resizing GIFs
  53. // This is maybe not the ideal solution, but IE6 can suck it
  54. $creationFunction = 'ImageCreateFromGif';
  55. $outputFunction = 'ImagePng';
  56. break;
  57. case 'image/x-png':
  58. case 'image/png':
  59. $creationFunction = 'ImageCreateFromPng';
  60. $outputFunction = 'ImagePng';
  61. $this->qualityMultiplier = 0.01;
  62. break;
  63. default:
  64. $creationFunction = 'ImageCreateFromJpeg';
  65. $outputFunction = 'ImageJpeg';
  66. break;
  67. }
  68. return [
  69. $creationFunction,
  70. $outputFunction,
  71. ];
  72. }
  73. public static function resize($sourcePath, $width, $height, $offsetX, $offsetY, $cropWidth, $cropHeight)
  74. {
  75. $instance = new static($sourcePath);
  76. $instance->outputWidth($width);
  77. $instance->outputHeight($height);
  78. $instance->offsetX($offsetX);
  79. $instance->offsetY($offsetY);
  80. $instance->cropWidth($cropWidth);
  81. $instance->cropHeight($cropHeight);
  82. $instance->copyResampled($instance->sourceResource, $instance->destinationResource);
  83. return $instance;
  84. }
  85. public function outputWidth($width, $reset = true)
  86. {
  87. $this->outputWidth = $width;
  88. if ($reset) {
  89. $this->setDestination();
  90. }
  91. return $this;
  92. }
  93. protected function setDestination()
  94. {
  95. $this->destinationResource = imageCreateTruecolor($this->outputWidth, $this->outputHeight);
  96. $this->preserveAlfa();
  97. if ($this->mustCopy) {
  98. call_user_func_array([$this, $this->mustCopy], [$this->sourceResource, $this->destinationResource]);
  99. }
  100. }
  101. private function preserveAlfa()
  102. {
  103. if (in_array($this->imageSize['mime'], array('image/gif', 'image/png'))) {
  104. // If this is a GIF or a PNG, we need to set up transparency
  105. imageAlphaBlending($this->destinationResource, false);
  106. imageSaveAlpha($this->destinationResource, true);
  107. }
  108. }
  109. public function outputHeight($height, $reset = true)
  110. {
  111. $this->outputHeight = $height;
  112. if ($reset) {
  113. $this->setDestination();
  114. }
  115. return $this;
  116. }
  117. public function offsetX($value)
  118. {
  119. $this->offsetX = $value;
  120. if ($this->mustCopy) {
  121. call_user_func_array([$this, $this->mustCopy], [$this->sourceResource, $this->destinationResource]);
  122. }
  123. return $this;
  124. }
  125. public function offsetY($value)
  126. {
  127. $this->offsetY = $value;
  128. if ($this->mustCopy) {
  129. call_user_func_array([$this, $this->mustCopy], [$this->sourceResource, $this->destinationResource]);
  130. }
  131. return $this;
  132. }
  133. public function cropWidth($width)
  134. {
  135. $this->cropWidth = $width;
  136. if ($this->mustCopy) {
  137. call_user_func_array([$this, $this->mustCopy], [$this->sourceResource, $this->destinationResource]);
  138. }
  139. return $this;
  140. }
  141. public function cropHeight($height)
  142. {
  143. $this->cropHeight = $height;
  144. if ($this->mustCopy) {
  145. call_user_func_array([$this, $this->mustCopy], [$this->sourceResource, $this->destinationResource]);
  146. }
  147. return $this;
  148. }
  149. public function copyResampled($source, $destination)
  150. {
  151. $this->mustCopy = 'copyResampled';
  152. imageCopyResampled(
  153. $destination,
  154. $source,
  155. 0, 0,
  156. $this->offsetX,
  157. $this->offsetY,
  158. $this->outputWidth,
  159. $this->outputHeight,
  160. $this->cropWidth,
  161. $this->cropHeight);
  162. return $this;
  163. }
  164. public static function watermark($sourcePath, $watermarkPath, $position = false)
  165. {
  166. if (!$position) {
  167. $position = static::WM_POS_CENTER_CENTER;
  168. }
  169. $instance = new static($sourcePath);
  170. $instance->setWatermark($watermarkPath);
  171. $watermarkSizes = getimagesize($watermarkPath);
  172. $instance->copy($instance->sourceResource, $instance->destinationResource);
  173. $offsets = $instance->calculatePosition($position,
  174. ['width' => $watermarkSizes[0], 'height' => $watermarkSizes[1]]);
  175. $instance->mustCopy = false;
  176. $instance->offsetX($offsets['x']);
  177. $instance->offsetY($offsets['y']);
  178. $instance->outputWidth($watermarkSizes[0], false);
  179. $instance->outputHeight($watermarkSizes[1], false);
  180. $instance->copy($instance->watermarkSource, $instance->destinationResource);
  181. return $instance;
  182. }
  183. protected function setWatermark($watermarkPath)
  184. {
  185. $this->watermarkSource = imagecreatefrompng($watermarkPath);
  186. return $this;
  187. }
  188. public function copy($source, $destination)
  189. {
  190. $this->mustCopy = 'copy';
  191. imagecopy(
  192. $destination,
  193. $source,
  194. $this->offsetX, $this->offsetY,
  195. 0,
  196. 0,
  197. $this->outputWidth,
  198. $this->outputHeight
  199. );
  200. return $this;
  201. }
  202. protected function calculatePosition($position, $wmSizes = ['width' => 0, 'height' => 0])
  203. {
  204. return call_user_func_array([$this, 'pos' . ucfirst($position)], $wmSizes);
  205. }
  206. public function quality($quality)
  207. {
  208. $this->quality = $quality;
  209. return $this;
  210. }
  211. public function output($destination = null)
  212. {
  213. $outputFunction = $this->outputFunction;
  214. $path = dirname($destination);
  215. if (!file_exists($path)) {
  216. mkdir($path, 0777, true);
  217. }
  218. $outputFunction($this->destinationResource, $destination, $this->quality * $this->qualityMultiplier);
  219. }
  220. protected function posLeftTop($width, $height)
  221. {
  222. return [
  223. 'x' => 10,
  224. 'y' => 10,
  225. ];
  226. }
  227. protected function posTop($width, $height)
  228. {
  229. return [
  230. 'x' => $this->outputWidth / 2 - $width / 2,
  231. 'y' => 10,
  232. ];
  233. }
  234. protected function posRightTop($width, $height)
  235. {
  236. return [
  237. 'x' => $this->outputWidth - $width - 10,
  238. 'y' => 10,
  239. ];
  240. }
  241. protected function posLeftCenter($width, $height)
  242. {
  243. return [
  244. 'x' => 10,
  245. 'y' => $this->outputHeight / 2 - $height / 2,
  246. ];
  247. }
  248. protected function posCenter($width, $height)
  249. {
  250. return [
  251. 'x' => $this->outputWidth / 2 - $width / 2,
  252. 'y' => $this->outputHeight / 2 - $height / 2,
  253. ];
  254. }
  255. protected function posRightCenter($width, $height)
  256. {
  257. return [
  258. 'x' => $this->outputWidth - $width - 10,
  259. 'y' => $this->outputHeight / 2 - $height / 2,
  260. ];
  261. }
  262. protected function posLeftBottom($width, $height)
  263. {
  264. return [
  265. 'x' => 10,
  266. 'y' => $this->outputHeight - $height - 10,
  267. ];
  268. }
  269. protected function posBottom($width, $height)
  270. {
  271. return [
  272. 'x' => $this->outputWidth / 2 - $width / 2,
  273. 'y' => $this->outputHeight - $height - 10,
  274. ];
  275. }
  276. protected function posRightBottom($width, $height)
  277. {
  278. return [
  279. 'x' => $this->outputWidth - $width - 10,
  280. 'y' => $this->outputHeight - $height - 10,
  281. ];
  282. }
  283. }