Sonata – MediaBundle Image Resizer

Sonata MediaBundle comes with two type of resizer: sonata.media.resizer.simple and sonata.media.resizer.square.
To make a custom resizer which will always keeps the same defined width and height, you need to create your own custom resizer.

Step 1: create a service

First you have to create a resizer service in order to call it:

# app/config/services.yml

services:
    sonata.media.resizer.fixedresizer:
        class: Application\Sonata\MediaBundle\Resizer\FixedDimensionsResizer
        arguments: [@sonata.media.adapter.image.gd, 'outbound', @sonata.media.metadata.proxy]

Step 2:

Then you have to create your own resizing method. In Application/Sonata/MediaBundle/Resizer/, create the FixedDimensionsResizer.php file and add:

# Application/Sonata/MediaBundle/Resizer/

namespace Application\Sonata\MediaBundle\Resizer;

use Imagine\Image\ImagineInterface;
use Imagine\Image\Box;
use Gaufrette\File;
use Sonata\MediaBundle\Model\MediaInterface;
use Imagine\Image\ImageInterface;
use Imagine\Exception\InvalidArgumentException;
use Sonata\MediaBundle\Metadata\MetadataBuilderInterface;
use Sonata\MediaBundle\Resizer\ResizerInterface;

class FixedDimensionsResizer implements ResizerInterface
{
    protected $adapter;

    protected $mode;

    protected $metadata;

    /**
     * @param ImagineInterface $adapter
     * @param string           $mode
     */
    public function __construct(ImagineInterface $adapter, $mode, MetadataBuilderInterface $metadata)
    {
        $this->adapter  = $adapter;
        $this->mode     = $mode;
        $this->metadata = $metadata;
    }

    /**
     * {@inheritdoc}
     */
    public function resize(MediaInterface $media, File $in, File $out, $format, array $settings)
    {
        if (!isset($settings['width'])) {
            throw new \RuntimeException(sprintf('Width parameter is missing in context "%s" for provider "%s"', $media->getContext(), $media->getProviderName()));
        }

        $image = $this->adapter->load($in->getContent());

        $content = $image
            ->thumbnail($this->getBox($media, $settings), $this->mode)
            ->get($format, array('quality' => $settings['quality']));

        $out->setContent($content, $this->metadata->get($media, $out->getName()));
    }

    /**
     * {@inheritdoc}
     */
    public function getBox(MediaInterface $media, array $settings)
    {
        $size = $media->getBox();

        if ($settings['width'] == null && $settings['height'] == null) {
            throw new \RuntimeException(sprintf('Width/Height parameter is missing in context "%s" for provider "%s". Please add at least one parameter.', $media->getContext(), $media->getProviderName()));
        }

        if($settings['constraint'] === false){
            return new Box($settings['width'], $settings['height']);
        }

        if ($settings['height'] == null) {
            $settings['height'] = (int) ($settings['width'] * $size->getHeight() / $size->getWidth());
        }

        if ($settings['width'] == null) {
            $settings['width'] = (int) ($settings['height'] * $size->getWidth() / $size->getHeight());
        }

        return $this->computeBox($media, $settings);
    }

    /**
     * @throws InvalidArgumentException
     *
     * @param MediaInterface $media
     * @param array          $settings
     *
     * @return Box
     */
    private function computeBox(MediaInterface $media, array $settings)
    {
        if ($this->mode !== ImageInterface::THUMBNAIL_INSET && $this->mode !== ImageInterface::THUMBNAIL_OUTBOUND) {
            throw new InvalidArgumentException('Invalid mode specified');
        }

        $size = $media->getBox();

        $ratios = array(
            $settings['width'] / $size->getWidth(),
            $settings['height'] / $size->getHeight()
        );

        if ($this->mode === ImageInterface::THUMBNAIL_INSET) {
            $ratio = min($ratios);
        } else {
            $ratio = max($ratios);
        }

        return $size->scale($ratio);
    }
}

Step 3:

Finaly, define the service in the config file. Use constraint option to set or unset the resizer option.

# app/config/config.yml

sonata_media:
    // ...
    contexts:
        default:
            // ...
            formats:
                small: { width: 150, height: 150, quality: 70, constraint: true}
                big:   { width: 320, height: 240, quality: 70, constraint: false}
    // ...
    providers:
        image:
            resizer: sonata.media.resizer.fixedresizer

Raphaël has written 45 articles

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>