Skip to content

Commit

Permalink
Merge 82b6ed9 into 1a04fac
Browse files Browse the repository at this point in the history
  • Loading branch information
DjLeChuck committed May 19, 2022
2 parents 1a04fac + 82b6ed9 commit a724098
Show file tree
Hide file tree
Showing 3 changed files with 424 additions and 0 deletions.
230 changes: 230 additions & 0 deletions Imagine/Filter/PostProcessor/CwebpPostProcessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
<?php

namespace Liip\ImagineBundle\Imagine\Filter\PostProcessor;

use Liip\ImagineBundle\Binary\BinaryInterface;
use Liip\ImagineBundle\Exception\Imagine\Filter\PostProcessor\InvalidOptionException;
use Liip\ImagineBundle\Model\Binary;
use Symfony\Component\Process\Exception\ProcessFailedException;

class CwebpPostProcessor extends AbstractPostProcessor
{
/**
* Specify the level of near-lossless image preprocessing. This option adjusts pixel values to help
* compressibility, but has minimal impact on the visual quality. It triggers lossless compression mode
* automatically. The range is **0** (maximum preprocessing) to **100** (no preprocessing). The typical value is
* around **60**. Note that lossy with **-q 100** can at times yield better results.
*
* @var int
*/
protected $nearLossless;

/**
* Specify the compression factor for RGB channels between **0** and **100**. The default is **75**.
*
* In case of lossy compression , a small factor produces a smaller file with lower quality. Best quality is
* achieved by using a value of **100**.
*
* In case of lossless compression (specified by the **-lossless** option), a small factor enables faster
* compression speed, but produces a larger file. Maximum compression is achieved by using a value of **100**.
*
*
* @var int
*/
protected $q;

/**
* Specify the compression factor for alpha compression between **0** and **100**. Lossless compression of alpha is
* achieved using a value of **100**, while the lower values result in a lossy compression.
*
* @var int
*/
protected $alphaQ;

/**
* Specify the compression method to use. This parameter controls the trade off between encoding speed and the
* compressed file size and quality. Possible values range from **0** to **6**. When higher values are used, the
* encoder will spend more time inspecting additional encoding possibilities and decide on the quality gain. Lower
* value can result in faster processing time at the expense of larger file size and lower compression quality.
*
* @var int
*/
protected $m;

/**
* Specify the predictive filtering method for the alpha plane. One of **none**, **fast** or **best**, in
* increasing complexity and slowness order. Internally, alpha filtering is performed using four possible
* predictions (none, horizontal, vertical, gradient). The **best** mode will try each mode in turn and pick the
* one which gives the smaller size. The **fast** mode will just try to form an a priori guess without testing all
* modes.
*
* @var string
*/
protected $alphaFilter;

/**
* Specify the algorithm used for alpha compression: **0** or **1**. Algorithm **0** denotes no compression, **1**
* uses WebP lossless format for compression.
*
* @var int
*/
protected $alphaMethod;

/**
* Preserve RGB values in transparent area. The default is off, to help compressibility.
*
* @var bool
*/
protected $exact;

/**
* A comma separated list of metadata to copy from the input to the output if present. Valid values: **all**,
* **none**, **exif**, **icc**, **xmp**.
*
* Note that each input format may not support all combinations.
*
* @var string
*/
protected $metadata;

public function __construct(
string $executablePath = '/usr/bin/cwebp',
string $temporaryRootPath = null,
int $nearLossless = null,
int $q = null,
int $alphaQ = null,
int $m = null,
string $alphaFilter = null,
int $alphaMethod = null,
bool $exact = null,
string $metadata = null
) {
parent::__construct($executablePath, $temporaryRootPath);

$this->nearLossless = $nearLossless;
$this->q = $q;
$this->alphaQ = $alphaQ;
$this->m = $m;
$this->alphaFilter = $alphaFilter;
$this->alphaMethod = $alphaMethod;
$this->exact = $exact;
$this->metadata = $metadata;
}

public function process(BinaryInterface $binary, array $options = []): BinaryInterface
{
if (!$this->isBinaryTypeWebpImage($binary)) {
return $binary;
}

$file = $this->writeTemporaryFile($binary, $options, 'imagine-post-processor-cwebp');
$arguments = $this->getProcessArguments($options);
$arguments[] = $file;
$arguments[] = '-o';
$arguments[] = '-';
$process = $this->createProcess($arguments, $options);

$process->run();

if (!$this->isSuccessfulProcess($process)) {
unlink($file);

throw new ProcessFailedException($process);
}

$result = new Binary($process->getOutput(), $binary->getMimeType(), $binary->getFormat());

unlink($file);

return $result;
}

protected function isBinaryTypeWebpImage(BinaryInterface $binary): bool
{
return $this->isBinaryTypeMatch($binary, ['image/webp']);
}

/**
* @param int|string[] $options
*
* @return string[]
*/
private function getProcessArguments(array $options = []): array
{
$arguments = [$this->executablePath];

if ($nearLossless = $options['nearLossless'] ?? $this->nearLossless) {
if (!\in_array($nearLossless, range(0, 100), true)) {
throw new InvalidOptionException('The "nearLossless" option must be an int between 0 and 100', $options);
}

$arguments[] = '-near_lossless';
$arguments[] = $nearLossless;
}

if ($q = $options['q'] ?? $this->q) {
if (!\in_array($q, range(0, 100), true)) {
throw new InvalidOptionException('The "q" option must be an int between 0 and 100', $options);
}

$arguments[] = '-q';
$arguments[] = $q;
}

if ($alphaQ = $options['alphaQ'] ?? $this->alphaQ) {
if (!\in_array($alphaQ, range(0, 100), true)) {
throw new InvalidOptionException('The "alphaQ" option must be an int between 0 and 100', $options);
}

$arguments[] = '-alpha_q';
$arguments[] = $alphaQ;
}

if ($m = $options['m'] ?? $this->m) {
if (!\in_array($m, range(0, 6), true)) {
throw new InvalidOptionException('The "m" option must be an int between 0 and 6', $options);
}

$arguments[] = '-m';
$arguments[] = $m;
}

if ($alphaFilter = $options['alphaFilter'] ?? $this->alphaFilter) {
if (!\in_array($alphaFilter, ['none', 'fast', 'best'], true)) {
throw new InvalidOptionException('The "alphaFilter" option must be a string (none, fast or best)', $options);
}

$arguments[] = '-alpha_filter';
$arguments[] = $alphaFilter;
}

$alphaMethod = $options['alphaMethod'] ?? $this->alphaMethod;
if (null !== $alphaMethod) {
if (!\in_array($alphaMethod, range(0, 1), true)) {
throw new InvalidOptionException('The "alphaMethod" option must be an int between 0 and 1', $options);
}

$arguments[] = '-alpha_method';
$arguments[] = $alphaMethod;
}

if ($options['exact'] ?? $this->exact) {
$arguments[] = '-exact';
}

if ($metadata = $options['metadata'] ?? $this->metadata) {
$metadataValues = explode(',', $metadata);

foreach ($metadataValues as $metadataValue) {
if (!\in_array($metadataValue, ['all', 'none', 'exif', 'icc', 'xmp'], true)) {
throw new InvalidOptionException('The "metadata" option must be a list of string (all, none, exif, icc, xmp)', $options);
}
}

$arguments[] = '-metadata';
$arguments[] = $metadata;
}

return $arguments;
}
}
17 changes: 17 additions & 0 deletions Resources/config/imagine.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,18 @@

<parameter key="liip_imagine.mozjpeg.binary">/opt/mozjpeg/bin/cjpeg</parameter>

<!-- cwebp parameters -->

<parameter key="liip_imagine.cwebp.binary">/usr/bin/cwebp</parameter>
<parameter key="liip_imagine.cwebp.near_lossless">100</parameter>
<parameter key="liip_imagine.cwebp.q">75</parameter>
<parameter key="liip_imagine.cwebp.alpha_q">100</parameter>
<parameter key="liip_imagine.cwebp.m">4</parameter>
<parameter key="liip_imagine.cwebp.alpha_filter">fast</parameter>
<parameter key="liip_imagine.cwebp.alpha_method">1</parameter>
<parameter key="liip_imagine.cwebp.exact">false</parameter>
<parameter key="liip_imagine.cwebp.metadata">none</parameter>

</parameters>

<services>
Expand Down Expand Up @@ -424,5 +436,10 @@
<tag name="liip_imagine.filter.post_processor" post_processor="mozjpeg" />
</service>

<service id="liip_imagine.filter.post_processor.cwebp" class="Liip\ImagineBundle\Imagine\Filter\PostProcessor\CwebpPostProcessor">
<argument>%liip_imagine.cwebp.binary%</argument>
<tag name="liip_imagine.filter.post_processor" post_processor="cwebp" />
</service>

</services>
</container>

0 comments on commit a724098

Please sign in to comment.