vendor/imagine/imagine/src/Gd/Imagine.php line 58

Open in your IDE?
  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\Driver\InfoProvider;
  12. use Imagine\Exception\InvalidArgumentException;
  13. use Imagine\Exception\RuntimeException;
  14. use Imagine\Factory\ClassFactoryInterface;
  15. use Imagine\File\LoaderInterface;
  16. use Imagine\Image\AbstractImagine;
  17. use Imagine\Image\BoxInterface;
  18. use Imagine\Image\Metadata\MetadataBag;
  19. use Imagine\Image\Palette\Color\ColorInterface;
  20. use Imagine\Image\Palette\PaletteInterface;
  21. use Imagine\Image\Palette\RGB;
  22. use Imagine\Utils\ErrorHandling;
  23. /**
  24. * Imagine implementation using the GD library.
  25. *
  26. * @final
  27. */
  28. class Imagine extends AbstractImagine implements InfoProvider
  29. {
  30. /**
  31. * Initialize the class.
  32. */
  33. public function __construct()
  34. {
  35. static::getDriverInfo()->checkVersionIsSupported();
  36. }
  37. /**
  38. * {@inheritdoc}
  39. *
  40. * @see \Imagine\Driver\InfoProvider::getDriverInfo()
  41. * @since 1.3.0
  42. */
  43. public static function getDriverInfo($required = true)
  44. {
  45. return DriverInfo::get($required);
  46. }
  47. /**
  48. * {@inheritdoc}
  49. *
  50. * @see \Imagine\Image\ImagineInterface::create()
  51. */
  52. public function create(BoxInterface $size, ColorInterface $color = null)
  53. {
  54. $width = $size->getWidth();
  55. $height = $size->getHeight();
  56. $resource = imagecreatetruecolor($width, $height);
  57. if ($resource === false) {
  58. throw new RuntimeException('Create operation failed');
  59. }
  60. if ($color === null) {
  61. $palette = new RGB();
  62. $color = $palette->color('fff');
  63. } else {
  64. $palette = $color->getPalette();
  65. static::getDriverInfo()->requirePaletteSupport($palette);
  66. }
  67. $index = imagecolorallocatealpha($resource, $color->getRed(), $color->getGreen(), $color->getBlue(), round(127 * (100 - $color->getAlpha()) / 100));
  68. if ($index === false) {
  69. throw new RuntimeException('Unable to allocate color');
  70. }
  71. if (imagefill($resource, 0, 0, $index) === false) {
  72. throw new RuntimeException('Could not set background color fill');
  73. }
  74. if ($color->getAlpha() <= 5) {
  75. imagecolortransparent($resource, $index);
  76. }
  77. return $this->wrap($resource, $palette, new MetadataBag());
  78. }
  79. /**
  80. * {@inheritdoc}
  81. *
  82. * @see \Imagine\Image\ImagineInterface::open()
  83. */
  84. public function open($path)
  85. {
  86. $loader = $path instanceof LoaderInterface ? $path : $this->getClassFactory()->createFileLoader($path);
  87. $path = $loader->getPath();
  88. $data = $loader->getData();
  89. $resource = $this->createImageFromString($data);
  90. if (!($resource instanceof \GdImage) && !\is_resource($resource)) {
  91. throw new RuntimeException(sprintf('Unable to open image %s', $path));
  92. }
  93. return $this->wrap($resource, new RGB(), $this->getMetadataReader()->readFile($loader));
  94. }
  95. /**
  96. * {@inheritdoc}
  97. *
  98. * @see \Imagine\Image\ImagineInterface::load()
  99. */
  100. public function load($string)
  101. {
  102. return $this->doLoad($string, $this->getMetadataReader()->readData($string));
  103. }
  104. /**
  105. * {@inheritdoc}
  106. *
  107. * @see \Imagine\Image\ImagineInterface::read()
  108. */
  109. public function read($resource)
  110. {
  111. if (!\is_resource($resource)) {
  112. throw new InvalidArgumentException('Variable does not contain a stream resource');
  113. }
  114. $content = stream_get_contents($resource);
  115. if ($content === false) {
  116. throw new InvalidArgumentException('Cannot read resource content');
  117. }
  118. return $this->doLoad($content, $this->getMetadataReader()->readData($content, $resource));
  119. }
  120. /**
  121. * {@inheritdoc}
  122. *
  123. * @see \Imagine\Image\ImagineInterface::font()
  124. */
  125. public function font($file, $size, ColorInterface $color)
  126. {
  127. return $this->getClassFactory()->createFont(ClassFactoryInterface::HANDLE_GD, $file, $size, $color);
  128. }
  129. /**
  130. * @param resource|\GdImage $resource
  131. * @param \Imagine\Image\Palette\PaletteInterface $palette
  132. * @param \Imagine\Image\Metadata\MetadataBag $metadata
  133. *
  134. * @throws \Imagine\Exception\RuntimeException
  135. *
  136. * @return \Imagine\Image\ImageInterface
  137. */
  138. private function wrap($resource, PaletteInterface $palette, MetadataBag $metadata)
  139. {
  140. if (!imageistruecolor($resource)) {
  141. if (\function_exists('imagepalettetotruecolor')) {
  142. if (imagepalettetotruecolor($resource) === false) {
  143. throw new RuntimeException('Could not convert a palette based image to true color');
  144. }
  145. } else {
  146. list($width, $height) = array(imagesx($resource), imagesy($resource));
  147. // create transparent truecolor canvas
  148. $truecolor = imagecreatetruecolor($width, $height);
  149. $transparent = imagecolorallocatealpha($truecolor, 255, 255, 255, 127);
  150. imagealphablending($truecolor, false);
  151. imagefilledrectangle($truecolor, 0, 0, $width, $height, $transparent);
  152. imagealphablending($truecolor, false);
  153. imagecopy($truecolor, $resource, 0, 0, 0, 0, $width, $height);
  154. imagedestroy($resource);
  155. $resource = $truecolor;
  156. }
  157. }
  158. if (imagealphablending($resource, false) === false || imagesavealpha($resource, true) === false) {
  159. throw new RuntimeException('Could not set alphablending, savealpha and antialias values');
  160. }
  161. if (\function_exists('imageantialias')) {
  162. imageantialias($resource, true);
  163. }
  164. return $this->getClassFactory()->createImage(ClassFactoryInterface::HANDLE_GD, $resource, $palette, $metadata);
  165. }
  166. /**
  167. * @param string $string
  168. * @param \Imagine\Image\Metadata\MetadataBag $metadata
  169. *
  170. * @throws \Imagine\Exception\RuntimeException
  171. *
  172. * @return \Imagine\Image\ImageInterface
  173. */
  174. private function doLoad($string, MetadataBag $metadata)
  175. {
  176. $resource = $this->createImageFromString($string);
  177. if (!$resource instanceof \GdImage && !\is_resource($resource)) {
  178. throw new RuntimeException('An image could not be created from the given input');
  179. }
  180. return $this->wrap($resource, new RGB(), $metadata);
  181. }
  182. /**
  183. * Check if the raw image data represents an image in WebP format.
  184. *
  185. * @param string $data
  186. *
  187. * @return bool
  188. */
  189. private function isWebP(&$data)
  190. {
  191. return substr($data, 8, 7) === 'WEBPVP8';
  192. }
  193. /**
  194. * Create an image resource starting from its raw daa.
  195. *
  196. * @param string $string
  197. *
  198. * @return resource|\GdImage|false
  199. */
  200. private function createImageFromString(&$string)
  201. {
  202. return ErrorHandling::ignoring(-1, function () use (&$string) {
  203. // imagecreatefromstring() does not support webp images before PHP 7.3.0
  204. if (PHP_VERSION_ID < 70300 && function_exists('imagecreatefromwebp') && $this->isWebP($string)) {
  205. return imagecreatefromwebp('data:image/webp;base64,' . base64_encode($string));
  206. }
  207. return imagecreatefromstring($string);
  208. });
  209. }
  210. }