Slim 4 - Working with Images

Daniel Opitz
Daniel Opitz
07 May 2020

Table of contents

Requirements

Introduction

This tutorial explains how to create images and stream that files as download or inline image to the client (browser).

Installation

My favorite library for image manipulation is Intervention Image.

The best way to install Intervention Image is quickly and easily with Composer.

To install the most recent version, run the following command:

composer require intervention/image

Integration in Slim

Add the image manager settings to your Slim settings array, e.g in config/settings.php:

$settings['image_manager'] = [
    // configure image driver (gd by default)
    'driver' => 'gd',
];

Autowire the image manager using the ImageManager class:

<?php

use Intervention\Image\ImageManager;
use Psr\Container\ContainerInterface;

return [

    // ...
    
    ImageManager::class => function (ContainerInterface $container) {
        return new ImageManager($container->get('settings')['image_manager']);
    },
];

Creating & Sending Images

This single action controller shows how to create an image (in memory) and send it to the client:

<?php

namespace App\Action;

use Intervention\Image\ImageManager;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Psr7\Factory\StreamFactory;

final class ImageExampleAction
{
    /**
     * @var ImageManager
     */
    private $imageManager;

    public function __construct(ImageManager $imageManager)
    {
        $this->imageManager = $imageManager;
    }

    public function __invoke(
        ServerRequestInterface $request,
        ResponseInterface $response
    ): ResponseInterface {
        // Create image in memory
        $image = $this->imageManager->canvas(800, 600, '#719e40');

        // Encode image into given format (PNG) and quality (100%)
        $data = $image->encode('png', 100)->getEncoded();

        // Detect and set the correct content-type, e.g. image/png
        $mime = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $data);
        $response = $response->withHeader('Content-Type', $mime);

        // Output image as stream
        return $response->withBody((new StreamFactory())->createStream($data));
    }
}

Image formats

The possible image formats depend on the choosen driver (GD or Imagick) and your local configuration. By default Intervention Image currently supports the following major formats:

Sending Image Files

If you want to stream an existing file the just use the make($filename) method instead:

$image = $this->imageManager->make('public/foo.png');

Creating images using the GD and Image functions

If you want to use the native GD and image function from PHP, then you don’t have to install the Intervention Image component. The trick here is that we fetch the raw stream from the imagepng or imagejpeg function and put that data into the PSR-7 response object. Here is an example:

<?php

namespace App\Action;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Psr7\Factory\StreamFactory;

final class ImageCreateAction
{
    public function __invoke(
        ServerRequestInterface $request,
        ResponseInterface $response
    ): ResponseInterface {
        // Create image in memory
        $image = imagecreate(200, 80);
        imagecolorallocate($image, 255, 255, 255);
        $textColor = imagecolorallocate($image, 113, 158, 64);
        $lineColor = imagecolorallocate($image, 170, 170, 170);
        imagestring($image, 8, 35, 25, 'slim framework', $textColor);
        imagesetthickness($image, 2);
        imageline($image, 35, 45, 160, 45, $lineColor);

        // Fetch the raw image stream
        ob_start();
        imagepng($image);
        $data = ob_get_clean();
        imagedestroy($image);

        // Detect and set the correct content-type, e.g. image/png
        $mime = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $data);
        $response = $response->withHeader('Content-Type', $mime);

        // Output image as stream
        return $response->withBody((new StreamFactory())->createStream($data));
    }
}