How to create a screenshot of a website using SnappyBundle (wkhtmltoimage) in Symfony 3

Thanks god the creation of screenshots is not a task that a developer need to execute frequently, however know how to create them can be beneficial for your development knowledge. In this case, to create a screenshot of a website in Symfony 3, we are going to use wkhtmltoimage and KnpSnappyBundle (a wrapper written in PHP for the wkhtmltoimage console commands).

wkhtmltopdf and wkhtmltoimage are open source command line tools to render HTML into PDF and various image formats using the Qt WebKit rendering engine, these run entirely "headless" and do not require a display or display service.

Requirements

You'll need wkhtmltoimage available in your system and accesible in the command prompt. wkhtmltoimage is a command line tool to render HTML into PDF and various image formats using the Qt WebKit rendering engine. These run entirely "headless" and do not require a display or display service.

  • Windows: you can download an installer for each architecture (x86 and x64) in the installation area. Although you can change the path of the wkhtmltoimage executable later in the config.yml file, is recommendable to have wkhtmltoimage accesible as an environment variable on your system (if you don't want to create an environment variable for wkhtmltopdf, then you can provide the entire path to the executable later). You can read how to create environment variables in windows in this article.
  • Debian/Ubuntu: You can install the distribution from wkhtmltopdf directly in the console using the following command :
$ sudo apt-get install wkhtmltopdf

Visit the homepage of wkhtmltopdf and wkhtmltoimage for more information here.

1) Installing and configuring SnappyBundle

Snappy by itself is a PHP (5.3+) wrapper for the wkhtmltopdf and wkhtmltoimage conversion utility. It allows you to generate either pdf or image files from html documents or websites, using the webkit engine. The KnpSnappyBundle provides a simple integration for your Symfony project.

To install SnappyBundle in your project, execute the following composer command :

composer require knplabs/knp-snappy-bundle

Or add manually adding the package name into your composer.json file and then execute composer install:

{
    "require": {
        "knplabs/knp-snappy-bundle": "~1.4"
    }
}

When the download is complete, enable the bundle adding the following line to your kernel :

$bundles = [
    //..//
    new Knp\Bundle\SnappyBundle\KnpSnappyBundle(),
];

Finally you just need to add the basic configuration in your config.yml file providing and enabling the binary path of wkhtmltoimage.

Note that as mentioned previously, SnappyBundle requires wkhtmltoimage to work, therefore we need to provide in the binary option of the config.yml the fullpath to the executable of wkhtmltoimage before using it, otherwise you'll face one of the most known errors :

Binary path in Windows

With the default installer (and default installation settings) of wkhtmltopdf, there should be a folder wkhtmltopdf/bin in the Program Files of your main partition with the executable of wkhtmltopdf (which includes wkhtmltoimage) inside, so you only need to provide the path of the following example.

However, if you used a custom installation, just change the path with the new one that contains the wkhtmltoimage executable in the binaryproperty.

# Windows configuration
knp_snappy:
    image:
        enabled:    true
        binary:     "\"C:\\Program Files\\wkhtmltopdf\\bin\\wkhtmltoimage.exe\""
        options:    []

Binary path in Linux/Unix like

If you installed wkhtmltopdf using the apt-get method, the paths probably are :

# app/config/config.yml
knp_snappy:
    image:
        enabled:    true
        binary:     /usr/local/bin/wkhtmltoimage
        options:    []

How to change screenshots generation settings

You can dinamically change settings by default in the config.yml file :

# config.yml
knp_snappy:
    image:
        enabled:    true
        binary:     "wkhtmltoimage"
        options:    
            width: 1920
            height: 1080

Or dinamically in your controller (or service etc) using PHP with the setOption method of snappy :

<?php 

$snappyImage = $this->get('knp_snappy.image');

$snappyImage->setOption('height', 1080);
$snappyImage->setOption('width', 1920);
$snappyImage->setOption('quality', 100);
$snappyImage->setOption('disable-javascript', false);
//$snappyImage->setOption('crop-x', 0);
//$snappyImage->setOption('crop-y', 0);

2) Examples

Save screenshot from website in storage

By default, snappy provide you a way to generate images easily and the image will be saved in the path providen as second parameter of the generate method:

<?php

namespace sandboxBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;

class DefaultController extends Controller
{
    public function indexAction()
    {
        // Get snappy.image service
        $imageGenerator = $this->get('knp_snappy.image');
        
        $filepath = 'imagehd.jpg';//or filename.png
        
        // Set dimensions of the output image
        $imageGenerator->setOption('width',1920);
        $imageGenerator->setOption('height',1080);
        
        // Take a screenshot of Our Code World website !
        $imageGenerator->generate('http://www.ourcodeworld.com', $filepath);
        
        return new Response("Image succesfully created in ".$filepath);
    }
}

Generate file download in a controller

To return an image as attachment, use a BinaryFileResponse with disposition as attachment:

<?php

namespace sandboxBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;

class DefaultController extends Controller
{
    public function indexAction()
    {
        // Get snappy.image service
        $imageGenerator = $this->get('knp_snappy.image');
        
        $filepath = 'imagehd.jpg';//or image.png
        
        // Set dimensions of the output image
        $imageGenerator->setOption('width',1920);
        $imageGenerator->setOption('height',1080);
        
        // Take a screenshot of Our Code World website !
        $imageGenerator->generate('http://www.ourcodeworld.com', $filepath);
        
        $response = new BinaryFileResponse($filepath);
        $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT);

        return $response;
    }
}

Return image as response in a controller

To return an image as response, use a BinaryFileResponse with disposition inline:

<?php

namespace sandboxBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;

class DefaultController extends Controller
{
    public function indexAction()
    {
        // Get snappy.image service
        $imageGenerator = $this->get('knp_snappy.image');
        
        $filepath = 'imagehd.jpg';
        
        // Set dimensions of the output image
        $imageGenerator->setOption('width',1920);
        $imageGenerator->setOption('height',1080);
        
        // Take a screenshot of Our Code World website !
        $imageGenerator->generate('http://www.ourcodeworld.com', $filepath);
        
        $response = new BinaryFileResponse($filepath);
        $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_INLINE);

        return $response;
    }
}

Have fun !

Become a more social person