Creating and uploading thumbnails for each blog post can be time-consuming, but fear not! With Laravel, a powerful PHP framework, you can automate the process of generating thumbnails for your blog posts. In this blog post, we’ll explore how to leverage Laravel to generate thumbnails effortlessly using wkhtmltoimage and laravel-snappy.
Preview
Here’s the example preview of the generated thumbnail image shared on social media:

How will it work?
The flow of the image generation process would be:
- Using Laravel’s blade view to build the HTML output.
- Then we use that HTML and pass it to
wkhtmltoimagelibrary throughlaravel-snappythe package. Which can return the binary data of a rendered image. - We then use that data to store it as an image on desired file storage.
Installing Laravel Snappy
Laravel Snappy is an open-source package developed by Barry vd. Heuvel. This package is built as a wrapper for Laravel on package Snappy. Snappy uses wkhtmltopdf and wkhtmltoimage libraries for the generation of PDFs and Images.
Install the Laravel Snappy package by running the following command.
composer require barryvdh/laravel-snappy
Then publish the snappy config file using the following command:
php artisan vendor:publish --provider="BarryvdhSnappyServiceProvider"
This will publish the snappy config file at config/snappy.php. Update the file as per below:
<?php
return [
'pdf' => [
'enabled' => false,
'binary' => env('WKHTML_PDF_BINARY', '/usr/bin/wkhtmltopdf'),
'timeout' => false,
'options' => [],
'env' => [],
],
'image' => [
'enabled' => true,
'binary' => env('WKHTML_IMG_BINARY', '/usr/bin/wkhtmltoimage'),
'timeout' => false,
'options' => [],
'env' => [],
],
];
Notice we are updating the binary paths to be configurable by .env file.
Configuring wkhtmltoimage for local and production use
For this post, we are interested in the wkhtmltoimage library. This library comes bundled with wkhtmltopdf. Whether you are running the application locally or in production. You’ll need to install the wkhtmltopdf library. You can download the wkhtmltopdf library from wkhtmltopdf.org.
During the installation keep a note of the library’s installation location.
Windows
Download the suitable installer for your system and follow the installer steps to install the library. You can download the Windows install from here: Download Windows Install
Mac
You can install the library using HomeBrew. Run the following command:
brew install wkhtmltopdf
Linux
On Ubuntu systems, you can install the library by running:
sudo apt-get install -y wkhtmltopdf
Docker and Laravel Sail
If you are running the application in docker make sure to add the install statement in the docker build file. Also, if you are using Laravel Sail then you will need to customize the docker files. To do so run the following commands.
sail artisan sail:publish
This will publish the docker build file in your project root. Then you can update the specific Dockerfile and add the following line under:
RUN apt-get update && apt-get install -y wkhtmltopdf
After the installation, the usual library locations are:
/usr/bin/wkhtmltopdfand/usr/bin/wkhtmltoimage./usr/local/bin/wkhtmltopdfand/usr/local/bin/wkhtmltoimage.
After the installation update the .env with binary path variables:
WKHTML_PDF_BINARY=/usr/local/bin/wkhtmltopdf
WKHTML_IMG_BINARY=/usr/local/bin/wkhtmltoimage
The var WKHTML_PDF_BINARY is not required for the scope of this post but can add it for later use.
Prepare Image/HTML template
Now the libraries are configured. We can work on the template from which HTML will be rendered as an Image.
Create a view file at resources/views/templates/simple.blade.php. Then add the following code.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Featured Image</title>
<style>
html body {
box-sizing: border-box;
font-size: 16px;
}
*,
*:before,
*:after {
box-sizing: inherit;
margin: 0;
padding: 0;
font-weight: normal;
line-height: normal;
}
.featured-container {
width: 1200px;
height: 628px;
display: flex;
align-items: center;
position: relative;
}
.background {
background-image: url('https://cdn.priyashpatil.com/polka-pattern.jpg');
background-repeat: repeat-x;
background-size: auto 100%;
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: -1;
fill-opacity: 0.8;
}
.content-padding {
padding: 80px;
}
.head {
font-size: 60px;
font-weight: bold;
}
</style>
</head>
<body>
<div class="featured-container content-padding">
<h1 class="head">{{ $title }}</h1>
<div class="background"></div>
</div>
</body>
</html>
You have to keep the templates simple and less dependent on external resources to avoid any rendering issues. Also do note that some CSS properties do not work well with wkhtmltopdf so, you have to try and test the template to suit your needs.
Generating and Storing the image
For this post let’s assume you have a blog post Model with a title property and you want to generate and update the post instance. Let’s say we have and post endpoint /admin/blog/{blogPost}/generate-thumbnail which you can trigger using a simple form in the admin dashboard. For example:
routes/web.php
<?php
use AppHttpControllersPostFeaturedImageGenerateController;
Route::post('/admin/blog/{blogPost}/generate-thumbnail', PostThumbnailGenerateController::class)->name('admin.posts.generate-thumbnail');
Then create an invokable controller as appHttpControllersPostThumbnailGenerateController.php:
<?php
namespace AppHttpControllers;
use AppModelsPost;
use BarryvdhSnappyFacadesSnappyImage;
use IlluminateHttpRequest;
use IlluminateSupportFacadesStorage;
use IlluminateSupportStr;
class PostThumbnailGenerateController extends Controller
{
/**
* Handle incoming request.
*/
public function __invoke(Request $request,Post $blogPost)
{
// Prep new image
$fileName = strtolower((string) Str::ulid());
$snappyImage = SnappyImage::loadView('templates/simple', ['title' => $blogPost->title]);
// Save generated image
$filePath = "thumbnails/{$fileName}.jpeg";
Storage::disk('public')->put($filePath, $snappyImage->output());
// Update blog post
$blogPost->thumbnail = Storage::disk('public')->url($filePath);
$blogPost->save();
return redirect()->back();
}
}
Then in your admin panel, you can add the form like so:
<form action="{{ route('admin.posts.generate-thumbnail', $post->id) }}" method="POST">
@csrf
<button type="submit" class="btn btn-sm btn-secondary">Generate Featured Image</button>
</form>
Adding thumbnail meta
Add the meta tags in your root layout add follows:
<!doctype html>
<head>
{{-- ... --}}
<meta property="og:image" content="{{ $post->thumbnail }}">
<meta property="twitter:image" content="{{ $post->thumbnail }}">
</head>
Rendering images directly during template development
During the development of the template, you may want to directly render the image into the browser instead of storing it in the filesystem. Snappy offers a couple of methods for it.
You can return images in browsers using the following methods:
$snappyImage = SnappyImage::loadView('templates/simple', ['title' => $blogPost->title]);
return $snappyImage->inline();
or
$snappyImage = SnappyImage::loadView('templates/simple', ['title' => $blogPost->title]);
return $snappyImage->stream();
Conclusion
Congratulations on successfully generating thumbnails based on the blog title! This post demonstrates an efficient method using the snappy package to generate captivating thumbnail images. By incorporating the Lottery Helper class, you can expand your options by including additional templates and adding a touch of randomness to the selection process.
Furthermore, you have the flexibility to automate the thumbnail generation process upon saving or updating your blog. Feel free to unleash your creativity and explore endless possibilities for creating visually appealing thumbnails that perfectly complement your content. Let your imagination soar and continue to innovate!
Keep the Conversation Going
I hope you found this post helpful! If you have any questions or feedback, feel free to reach out. You can also find me on X (Twitter) @priyashpatil for additional insights and updates on my latest content.