Skip to content

Commit

Permalink
Merge pull request #519 from kostiklv/binary-post-processor
Browse files Browse the repository at this point in the history
Post-processors - handlers to be applied on filtered image binary
  • Loading branch information
makasim committed Oct 29, 2014
2 parents fe51d50 + 69b3921 commit 4530ca6
Show file tree
Hide file tree
Showing 12 changed files with 499 additions and 9 deletions.
31 changes: 31 additions & 0 deletions DependencyInjection/Compiler/PostProcessorsCompilerPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace Liip\ImagineBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

/**
* Compiler pass to register post_processors tagged with liip_imagine.filter.post_processor
*
* @author Konstantin Tjuterev <[email protected]>
*/
class PostProcessorsCompilerPass implements CompilerPassInterface
{
/**
* {@inheritDoc}
*/
public function process(ContainerBuilder $container)
{
$tags = $container->findTaggedServiceIds('liip_imagine.filter.post_processor');

if (count($tags) > 0 && $container->hasDefinition('liip_imagine.filter.manager')) {
$manager = $container->getDefinition('liip_imagine.filter.manager');

foreach ($tags as $id => $tag) {
$manager->addMethodCall('addPostProcessor', array($tag[0]['post_processor'], new Reference($id)));
}
}
}
}
7 changes: 7 additions & 0 deletions DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,13 @@ public function getConfigTreeBuilder()
->prototype('variable')->end()
->end()
->end()
->arrayNode('post_processors')
->defaultValue(array())
->useAttributeAsKey('name')
->prototype('array')
->useAttributeAsKey('name')
->prototype('variable')->end()
->end()
->end()
->end()
->end()
Expand Down
1 change: 0 additions & 1 deletion DependencyInjection/LiipImagineExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ public function load(array $configs, ContainerBuilder $container)
$container->setParameter('liip_imagine.default_image', $config['default_image']);

$container->setParameter('liip_imagine.filter_sets', $config['filter_sets']);

$container->setParameter('liip_imagine.binary.loader.default', $config['data_loader']);

$container->setParameter('liip_imagine.controller.filter_action', $config['controller']['filter_action']);
Expand Down
43 changes: 42 additions & 1 deletion Imagine/Filter/FilterManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Imagine\Image\ImagineInterface;
use Liip\ImagineBundle\Binary\BinaryInterface;
use Liip\ImagineBundle\Binary\MimeTypeGuesserInterface;
use Liip\ImagineBundle\Imagine\Filter\PostProcessor\PostProcessorInterface;
use Liip\ImagineBundle\Imagine\Filter\Loader\LoaderInterface;
use Liip\ImagineBundle\Model\Binary;

Expand All @@ -30,6 +31,11 @@ class FilterManager
*/
protected $loaders = array();

/**
* @var PostProcessorInterface[]
*/
protected $postProcessors = array();

/**
* @param FilterConfiguration $filterConfig
* @param ImagineInterface $imagine
Expand Down Expand Up @@ -58,6 +64,19 @@ public function addLoader($filter, LoaderInterface $loader)
$this->loaders[$filter] = $loader;
}

/**
* Adds a post-processor to handle binaries
*
* @param string $name
* @param PostProcessorInterface $postProcessor
*
* @return void
*/
public function addPostProcessor($name, PostProcessorInterface $postProcessor)
{
$this->postProcessors[$name] = $postProcessor;
}

/**
* @return FilterConfiguration
*/
Expand Down Expand Up @@ -109,7 +128,29 @@ public function apply(BinaryInterface $binary, array $config)
$filteredContent = $image->get($filteredFormat, $options);
$filteredMimeType = $filteredFormat === $binary->getFormat() ? $binary->getMimeType() : $this->mimeTypeGuesser->guess($filteredContent);

return new Binary($filteredContent, $filteredMimeType, $filteredFormat);
return $this->applyPostProcessors(new Binary($filteredContent, $filteredMimeType, $filteredFormat), $config);
}

/**
* @param BinaryInterface $binary
* @param array $config
*
* @throws \InvalidArgumentException
*
* @return BinaryInterface
*/
public function applyPostProcessors(BinaryInterface $binary, $config)
{
foreach ($config['post_processors'] as $postProcessorName => $postProcessorOptions) {
if (!isset($this->postProcessors[$postProcessorName])) {
throw new \InvalidArgumentException(sprintf(
'Could not find post processor "%s"', $postProcessorName
));
}
$binary = $this->postProcessors[$postProcessorName]->process($binary);
}

return $binary;
}

/**
Expand Down
131 changes: 131 additions & 0 deletions Imagine/Filter/PostProcessor/JpegOptimPostProcessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<?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;

class JpegOptimPostProcessor implements PostProcessorInterface
{
/** @var string Path to jpegoptim binary */
protected $jpegoptimBin;

/**
* If set --strip-all will be passed to jpegoptim
*
* @var bool
*/
protected $stripAll = true;

/**
* If set, --max=$value will be passed to jpegoptim
*
* @var int
*/
protected $max;

/**
* If set to true --all-progressive will be passed to jpegoptim, otherwise --all-normal will be passed
*
* @var bool
*/
protected $progressive = true;

/**
* Constructor.
*
* @param string $jpegoptimBin Path to the jpegoptim binary
*/
public function __construct($jpegoptimBin = '/usr/bin/jpegoptim')
{
$this->jpegoptimBin = $jpegoptimBin;
}

/**
* @param int $max
*
* @return JpegOptimPostProcessor
*/
public function setMax($max)
{
$this->max = $max;

return $this;
}

/**
* @param boolean $progressive
*
* @return JpegOptimPostProcessor
*/
public function setProgressive($progressive)
{
$this->progressive = $progressive;

return $this;
}

/**
* @param boolean $stripAll
*
* @return JpegOptimPostProcessor
*/
public function setStripAll($stripAll)
{
$this->stripAll = $stripAll;

return $this;
}

/**
* @param BinaryInterface $binary
*
* @throws ProcessFailedException
*
* @return BinaryInterface
*
* @see Implementation taken from Assetic\Filter\JpegoptimFilter
*/
public function process(BinaryInterface $binary)
{
$type = strtolower($binary->getMimeType());
if (!in_array($type, array('image/jpeg', 'image/jpg'))) {
return $binary;
}

$pb = new ProcessBuilder(array($this->jpegoptimBin));

if ($this->stripAll) {
$pb->add('--strip-all');
}

if ($this->max) {
$pb->add('--max='.$this->max);
}

if ($this->progressive) {
$pb->add('--all-progressive');
} else {
$pb->add('--all-normal');
}

$pb->add($input = tempnam(sys_get_temp_dir(), 'imagine_jpegoptim'));
file_put_contents($input, $binary->getContent());

$proc = $pb->getProcess();
$proc->run();

if (false !== strpos($proc->getOutput(), 'ERROR') || 0 !== $proc->getExitCode()) {
unlink($input);
throw new ProcessFailedException($proc);
}

$result = new Binary(file_get_contents($input), $binary->getMimeType(), $binary->getFormat());

unlink($input);

return $result;
}
}
20 changes: 20 additions & 0 deletions Imagine/Filter/PostProcessor/PostProcessorInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Liip\ImagineBundle\Imagine\Filter\PostProcessor;

use Liip\ImagineBundle\Binary\BinaryInterface;

/**
* Interface for PostProcessors - handlers which can operate on binaries prepared in FilterManager
*
* @author Konstantin Tjuterev <[email protected]>
*/
interface PostProcessorInterface
{
/**
* @param BinaryInterface $binary
*
* @return BinaryInterface
*/
function process(BinaryInterface $binary);
}
2 changes: 2 additions & 0 deletions LiipImagineBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Liip\ImagineBundle\DependencyInjection\Compiler\FiltersCompilerPass;
use Liip\ImagineBundle\DependencyInjection\Compiler\LoadersCompilerPass;
use Liip\ImagineBundle\DependencyInjection\Compiler\PostProcessorsCompilerPass;
use Liip\ImagineBundle\DependencyInjection\Compiler\ResolversCompilerPass;
use Liip\ImagineBundle\DependencyInjection\Factory\Loader\FileSystemLoaderFactory;
use Liip\ImagineBundle\DependencyInjection\Factory\Loader\StreamLoaderFactory;
Expand All @@ -24,6 +25,7 @@ public function build(ContainerBuilder $container)

$container->addCompilerPass(new LoadersCompilerPass);
$container->addCompilerPass(new FiltersCompilerPass);
$container->addCompilerPass(new PostProcessorsCompilerPass);
$container->addCompilerPass(new ResolversCompilerPass);

/** @var $extension LiipImagineExtension */
Expand Down
12 changes: 12 additions & 0 deletions Resources/config/imagine.xml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@
<!-- Form types -->

<parameter key="liip_imagine.form.type.image.class">Liip\ImagineBundle\Form\Type\ImageType</parameter>

<!-- Post processors' classes -->
<parameter key="liip_imagine.filter.post_processor.jpegoptim.class">Liip\ImagineBundle\Imagine\Filter\PostProcessor\JpegOptimPostProcessor</parameter>

<parameter key="liip_imagine.jpegoptim.binary">/usr/bin/jpegoptim</parameter>

</parameters>

<services>
Expand Down Expand Up @@ -248,5 +254,11 @@
<service id="liip_imagine.cache.signer" class="%liip_imagine.cache.signer.class%">
<argument>%kernel.secret%</argument>
</service>

<!-- Post processors -->
<service id="liip_imagine.filter.post_processor.jpegoptim" class="%liip_imagine.filter.post_processor.jpegoptim.class%">
<argument>%liip_imagine.jpegoptim.binary%</argument>
<tag name="liip_imagine.filter.post_processor" post_processor="jpegoptim" />
</service>
</services>
</container>
6 changes: 6 additions & 0 deletions Resources/doc/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ liip_imagine:

# Prototype
name: []

post_processors:

# Prototype
name: []
```
There are several configuration options available:
Expand Down Expand Up @@ -71,6 +76,7 @@ Each filter set that you specify has the following options:

- `filters` - determine the type of filter to be used (refer to *Filters* section for more information)
and options that should be passed to the specific filter type
- `post_processors` - sets post-processors to be applied on filtered image (see [Post-Processors](filters.md#post-processors) for details)
- `path` - used in place of the filter name to determine the path in combination with the global `cache_prefix`
- `quality` - override the default quality of 100 for the generated images
- `cache` - override the default cache setting
Expand Down
Loading

0 comments on commit 4530ca6

Please sign in to comment.