-
Notifications
You must be signed in to change notification settings - Fork 381
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #717 from antoligy/implement-pngquant-mozjpeg
Introduce mozjpeg and pngquant post-processors, add transform options.
- Loading branch information
Showing
7 changed files
with
324 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 25 additions & 0 deletions
25
Imagine/Filter/PostProcessor/ConfigurablePostProcessorInterface.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?php | ||
|
||
namespace Liip\ImagineBundle\Imagine\Filter\PostProcessor; | ||
|
||
use Liip\ImagineBundle\Binary\BinaryInterface; | ||
|
||
/** | ||
* Interface to make PostProcessors configurable without breaking BC. | ||
* | ||
* @see PostProcessorInterface for the original interface. | ||
* | ||
* @author Alex Wilson <[email protected]> | ||
*/ | ||
interface ConfigurablePostProcessorInterface | ||
{ | ||
/** | ||
* Allows processing a BinaryInterface, with run-time options, so PostProcessors remain stateless. | ||
* | ||
* @param BinaryInterface $binary | ||
* @param array $options Operation-specific options | ||
* | ||
* @return BinaryInterface | ||
*/ | ||
public function processWithConfiguration(BinaryInterface $binary, array $options); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
<?php | ||
|
||
namespace Liip\ImagineBundle\Imagine\Filter\PostProcessor; | ||
|
||
use Liip\ImagineBundle\Binary\BinaryInterface; | ||
use Liip\ImagineBundle\Model\Binary; | ||
use Symfony\Component\Process\Exception\ProcessFailedException; | ||
use Symfony\Component\Process\ProcessBuilder; | ||
|
||
/** | ||
* mozjpeg post-processor, for noticably better jpeg compression. | ||
* | ||
* @see http://calendar.perfplanet.com/2014/mozjpeg-3-0/ | ||
* @see https://mozjpeg.codelove.de/binaries.html | ||
* | ||
* @author Alex Wilson <[email protected]> | ||
*/ | ||
class MozJpegPostProcessor implements PostProcessorInterface, ConfigurablePostProcessorInterface | ||
{ | ||
/** @var string Path to the mozjpeg cjpeg binary */ | ||
protected $mozjpegBin; | ||
|
||
/** @var null|int Quality factor */ | ||
protected $quality; | ||
|
||
/** | ||
* Constructor. | ||
* | ||
* @param string $mozjpegBin Path to the mozjpeg cjpeg binary | ||
* @param int|null $quality Quality factor | ||
*/ | ||
public function __construct( | ||
$mozjpegBin = '/opt/mozjpeg/bin/cjpeg', | ||
$quality = null | ||
) { | ||
$this->mozjpegBin = $mozjpegBin; | ||
$this->setQuality($quality); | ||
} | ||
|
||
/** | ||
* @param int $quality | ||
* | ||
* @return MozJpegPostProcessor | ||
*/ | ||
public function setQuality($quality) | ||
{ | ||
$this->quality = $quality; | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
* @param BinaryInterface $binary | ||
* | ||
* @uses MozJpegPostProcessor::processWithConfiguration | ||
* | ||
* @throws ProcessFailedException | ||
* | ||
* @return BinaryInterface | ||
*/ | ||
public function process(BinaryInterface $binary) | ||
{ | ||
return $this->processWithConfiguration($binary, array()); | ||
} | ||
|
||
/** | ||
* @param BinaryInterface $binary | ||
* @param array $options | ||
* | ||
* @throws ProcessFailedException | ||
* | ||
* @return BinaryInterface | ||
*/ | ||
public function processWithConfiguration(BinaryInterface $binary, array $options) | ||
{ | ||
$type = strtolower($binary->getMimeType()); | ||
if (!in_array($type, array('image/jpeg', 'image/jpg'))) { | ||
return $binary; | ||
} | ||
|
||
$pb = new ProcessBuilder(array($this->mozjpegBin)); | ||
|
||
// Places emphasis on DC | ||
$pb->add('-quant-table'); | ||
$pb->add(2); | ||
|
||
$transformQuality = array_key_exists('quality', $options) ? $options['quality'] : $this->quality; | ||
if ($transformQuality !== null) { | ||
$pb->add('-quality'); | ||
$pb->add($transformQuality); | ||
} | ||
|
||
$pb->add('-optimise'); | ||
|
||
// Favor stdin/stdout so we don't waste time creating a new file. | ||
$pb->setInput($binary->getContent()); | ||
|
||
$proc = $pb->getProcess(); | ||
$proc->run(); | ||
|
||
if (false !== strpos($proc->getOutput(), 'ERROR') || 0 !== $proc->getExitCode()) { | ||
throw new ProcessFailedException($proc); | ||
} | ||
|
||
$result = new Binary($proc->getOutput(), $binary->getMimeType(), $binary->getFormat()); | ||
|
||
return $result; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
<?php | ||
|
||
namespace Liip\ImagineBundle\Imagine\Filter\PostProcessor; | ||
|
||
use Liip\ImagineBundle\Binary\BinaryInterface; | ||
use Liip\ImagineBundle\Model\Binary; | ||
use Symfony\Component\Process\Exception\ProcessFailedException; | ||
use Symfony\Component\Process\ProcessBuilder; | ||
|
||
/** | ||
* pngquant post-processor, for optimal, web-safe, lossy png compression | ||
* This requires a recent version of pngquant (so 2.3 or higher?) | ||
* See pngqaunt.org if you are unable to find a binary package for your distribution. | ||
* | ||
* @see https://pngquant.org/ | ||
* | ||
* @author Alex Wilson <[email protected]> | ||
*/ | ||
class PngquantPostProcessor implements PostProcessorInterface, ConfigurablePostProcessorInterface | ||
{ | ||
/** @var string Path to pngquant binary */ | ||
protected $pngquantBin; | ||
|
||
/** @var string Quality to pass to pngquant */ | ||
protected $quality; | ||
|
||
/** | ||
* Constructor. | ||
* | ||
* @param string $pngquantBin Path to the pngquant binary | ||
*/ | ||
public function __construct($pngquantBin = '/usr/bin/pngquant', $quality = '80-100') | ||
{ | ||
$this->pngquantBin = $pngquantBin; | ||
$this->setQuality($quality); | ||
} | ||
|
||
/** | ||
* @param string $quality | ||
* | ||
* @return PngquantPostProcessor | ||
*/ | ||
public function setQuality($quality) | ||
{ | ||
$this->quality = $quality; | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
* @param BinaryInterface $binary | ||
* | ||
* @uses PngquantPostProcessor::processWithConfiguration | ||
* | ||
* @throws ProcessFailedException | ||
* | ||
* @return BinaryInterface | ||
*/ | ||
public function process(BinaryInterface $binary) | ||
{ | ||
return $this->processWithConfiguration($binary, array()); | ||
} | ||
|
||
/** | ||
* @param BinaryInterface $binary | ||
* @param array $options | ||
* | ||
* @throws ProcessFailedException | ||
* | ||
* @return BinaryInterface | ||
*/ | ||
public function processWithConfiguration(BinaryInterface $binary, array $options) | ||
{ | ||
$type = strtolower($binary->getMimeType()); | ||
if (!in_array($type, array('image/png'))) { | ||
return $binary; | ||
} | ||
|
||
$pb = new ProcessBuilder(array($this->pngquantBin)); | ||
|
||
// Specify quality. | ||
$tranformQuality = array_key_exists('quality', $options) ? $options['quality'] : $this->quality; | ||
$pb->add('--quality'); | ||
$pb->add($tranformQuality); | ||
|
||
// Read to/from stdout to save resources. | ||
$pb->add('-'); | ||
$pb->setInput($binary->getContent()); | ||
|
||
$proc = $pb->getProcess(); | ||
$proc->run(); | ||
|
||
// 98 and 99 are "quality too low" to compress current current image which, while isn't ideal, is not a failure | ||
if (!in_array($proc->getExitCode(), array(0, 98, 99))) { | ||
throw new ProcessFailedException($proc); | ||
} | ||
|
||
$result = new Binary($proc->getOutput(), $binary->getMimeType(), $binary->getFormat()); | ||
|
||
return $result; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,8 @@ | |
/** | ||
* Interface for PostProcessors - handlers which can operate on binaries prepared in FilterManager. | ||
* | ||
* @see ConfigurablePostProcessorInterface For a means to configure these at run-time. | ||
* | ||
* @author Konstantin Tjuterev <[email protected]> | ||
*/ | ||
interface PostProcessorInterface | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters