vendor/liip/imagine-bundle/Imagine/Filter/PostProcessor/CwebpPostProcessor.php line 96

Open in your IDE?
  1. <?php
  2. /*
  3. * This file is part of the `liip/LiipImagineBundle` project.
  4. *
  5. * (c) https://github.com/liip/LiipImagineBundle/graphs/contributors
  6. *
  7. * For the full copyright and license information, please view the LICENSE.md
  8. * file that was distributed with this source code.
  9. */
  10. namespace Liip\ImagineBundle\Imagine\Filter\PostProcessor;
  11. use Liip\ImagineBundle\Binary\BinaryInterface;
  12. use Liip\ImagineBundle\Model\Binary;
  13. use Symfony\Component\OptionsResolver\OptionsResolver;
  14. use Symfony\Component\Process\Exception\ProcessFailedException;
  15. class CwebpPostProcessor extends AbstractPostProcessor
  16. {
  17. /**
  18. * Specify the compression factor for RGB channels between **0** and **100**. The default is **75**.
  19. *
  20. * In case of lossy compression , a small factor produces a smaller file with lower quality. Best quality is
  21. * achieved by using a value of **100**.
  22. *
  23. * In case of lossless compression (specified by the **-lossless** option), a small factor enables faster
  24. * compression speed, but produces a larger file. Maximum compression is achieved by using a value of **100**.
  25. *
  26. * @var int
  27. */
  28. protected $q;
  29. /**
  30. * Specify the compression factor for alpha compression between **0** and **100**. Lossless compression of alpha is
  31. * achieved using a value of **100**, while the lower values result in a lossy compression.
  32. *
  33. * @var int
  34. */
  35. protected $alphaQ;
  36. /**
  37. * Specify the compression method to use. This parameter controls the trade off between encoding speed and the
  38. * compressed file size and quality. Possible values range from **0** to **6**. When higher values are used, the
  39. * encoder will spend more time inspecting additional encoding possibilities and decide on the quality gain. Lower
  40. * value can result in faster processing time at the expense of larger file size and lower compression quality.
  41. *
  42. * @var int
  43. */
  44. protected $m;
  45. /**
  46. * Specify the predictive filtering method for the alpha plane. One of **none**, **fast** or **best**, in
  47. * increasing complexity and slowness order. Internally, alpha filtering is performed using four possible
  48. * predictions (none, horizontal, vertical, gradient). The **best** mode will try each mode in turn and pick the
  49. * one which gives the smaller size. The **fast** mode will just try to form an a priori guess without testing all
  50. * modes.
  51. *
  52. * @var string
  53. */
  54. protected $alphaFilter;
  55. /**
  56. * Specify the algorithm used for alpha compression: **0** or **1**. Algorithm **0** denotes no compression, **1**
  57. * uses WebP lossless format for compression.
  58. *
  59. * @var int
  60. */
  61. protected $alphaMethod;
  62. /**
  63. * Preserve RGB values in transparent area. The default is off, to help compressibility.
  64. *
  65. * @var bool
  66. */
  67. protected $exact;
  68. /**
  69. * An array of metadata to copy from the input to the output if present. Valid values: **all**, **none**, **exif**,
  70. * **icc**, **xmp**.
  71. *
  72. * Note that each input format may not support all combinations.
  73. *
  74. * @var string[]
  75. */
  76. protected $metadata;
  77. /**
  78. * @var OptionsResolver
  79. */
  80. private $resolver;
  81. /**
  82. * @param string[] $metadata
  83. */
  84. public function __construct(
  85. string $executablePath = '/usr/bin/cwebp',
  86. string $temporaryRootPath = null,
  87. int $q = null,
  88. int $alphaQ = null,
  89. int $m = null,
  90. string $alphaFilter = null,
  91. int $alphaMethod = null,
  92. bool $exact = null,
  93. array $metadata = []
  94. ) {
  95. parent::__construct($executablePath, $temporaryRootPath);
  96. $this->q = $q;
  97. $this->alphaQ = $alphaQ;
  98. $this->m = $m;
  99. $this->alphaFilter = $alphaFilter;
  100. $this->alphaMethod = $alphaMethod;
  101. $this->exact = $exact;
  102. $this->metadata = $metadata;
  103. $this->resolver = new OptionsResolver();
  104. $this->configureOptions($this->resolver);
  105. }
  106. public function process(BinaryInterface $binary, array $options = []): BinaryInterface
  107. {
  108. if (!$this->isBinaryTypeWebpImage($binary)) {
  109. return $binary;
  110. }
  111. $file = $this->writeTemporaryFile($binary, $options, 'imagine-post-processor-cwebp');
  112. $arguments = $this->getProcessArguments($options);
  113. $arguments[] = $file;
  114. $arguments[] = '-o';
  115. $arguments[] = '-';
  116. $process = $this->createProcess($arguments, $options);
  117. $process->run();
  118. if (!$this->isSuccessfulProcess($process)) {
  119. unlink($file);
  120. throw new ProcessFailedException($process);
  121. }
  122. $result = new Binary($process->getOutput(), $binary->getMimeType(), $binary->getFormat());
  123. unlink($file);
  124. return $result;
  125. }
  126. protected function isBinaryTypeWebpImage(BinaryInterface $binary): bool
  127. {
  128. return $this->isBinaryTypeMatch($binary, ['image/webp']);
  129. }
  130. protected function configureOptions(OptionsResolver $resolver): void
  131. {
  132. $resolver
  133. ->setDefault('q', $this->q)
  134. ->setAllowedTypes('q', ['null', 'int'])
  135. ->setAllowedValues('q', static function ($value) {
  136. if (null === $value) {
  137. return true;
  138. }
  139. return $value >= 0 && $value <= 100;
  140. });
  141. $resolver
  142. ->setDefault('alphaQ', $this->alphaQ)
  143. ->setAllowedTypes('alphaQ', ['null', 'int'])
  144. ->setAllowedValues('alphaQ', static function ($value) {
  145. if (null === $value) {
  146. return true;
  147. }
  148. return $value >= 0 && $value <= 100;
  149. });
  150. $resolver
  151. ->setDefault('m', $this->m)
  152. ->setAllowedTypes('m', ['null', 'int'])
  153. ->setAllowedValues('m', static function ($value) {
  154. if (null === $value) {
  155. return true;
  156. }
  157. return $value >= 0 && $value <= 6;
  158. });
  159. $resolver
  160. ->setDefault('alphaFilter', $this->alphaFilter)
  161. ->setAllowedTypes('alphaFilter', ['null', 'string'])
  162. ->setAllowedValues('alphaFilter', [null, 'none', 'fast', 'best']);
  163. $resolver
  164. ->setDefault('alphaMethod', $this->alphaMethod)
  165. ->setAllowedTypes('alphaMethod', ['null', 'int'])
  166. ->setAllowedValues('alphaMethod', [null, 0, 1]);
  167. $resolver
  168. ->setDefault('exact', $this->exact)
  169. ->setAllowedTypes('exact', ['null', 'bool']);
  170. $resolver
  171. ->setDefault('metadata', $this->metadata)
  172. ->setAllowedTypes('metadata', ['null', 'array'])
  173. ->setAllowedValues('metadata', static function ($value) {
  174. if (null === $value) {
  175. return true;
  176. }
  177. foreach ($value as $metadata) {
  178. if (!\in_array($metadata, ['all', 'none', 'exif', 'icc', 'xmp'], true)) {
  179. return false;
  180. }
  181. }
  182. return true;
  183. });
  184. }
  185. /**
  186. * @param array<mixed> $options
  187. *
  188. * @return string[]
  189. */
  190. protected function getProcessArguments(array $options = []): array
  191. {
  192. $options = $this->resolver->resolve($options);
  193. $arguments = [$this->executablePath];
  194. if ($q = $options['q']) {
  195. $arguments[] = '-q';
  196. $arguments[] = $q;
  197. }
  198. if ($alphaQ = $options['alphaQ']) {
  199. $arguments[] = '-alpha_q';
  200. $arguments[] = $alphaQ;
  201. }
  202. if ($m = $options['m']) {
  203. $arguments[] = '-m';
  204. $arguments[] = $m;
  205. }
  206. if ($alphaFilter = $options['alphaFilter']) {
  207. $arguments[] = '-alpha_filter';
  208. $arguments[] = $alphaFilter;
  209. }
  210. $alphaMethod = $options['alphaMethod'];
  211. if (null !== $alphaMethod) {
  212. $arguments[] = '-alpha_method';
  213. $arguments[] = $alphaMethod;
  214. }
  215. if ($options['exact']) {
  216. $arguments[] = '-exact';
  217. }
  218. if ($metadata = $options['metadata']) {
  219. $arguments[] = '-metadata';
  220. $arguments[] = implode(',', $metadata);
  221. }
  222. return $arguments;
  223. }
  224. }