HTML to Image PHP Script

App or game developer always needs a small tool that can convert static or dynamic HTML into an image. If you are a PHP developer and want a simple HTML-to-JPEG solution, this article is for you.

I discovered this trick while I was making a Facebook game. The script needed to post a dynamic game score on the user’s wall. My client already had the result page in HTML, but we needed a JPEG snapshot of that result.

The basic idea is still simple: convert the HTML into a PDF, then turn the first PDF page into a JPEG. This method does not use an external screenshot API or the GD library, but it does require HTML2PDF, the Imagick PHP extension, ImageMagick, and PDF support on the server.

This is a practical solution for score cards, receipts, certificates, and other controlled layouts. For a modern webpage with complex CSS, a real browser screenshot is usually better.

Why I Needed This

The game result changed for every player. Rebuilding the same card with PHP image functions would mean positioning every line, color, logo, and number manually. We already had correct HTML, so converting that page was the faster option.

The same situation appears in many projects:

  • Generate a share image from a result page
  • Save an invoice or receipt as a JPEG
  • Create a certificate from an HTML template
  • Produce a preview for an email or landing page
  • Archive a simple report as an image

You should control the HTML template. Do not accept any random public URL and send it directly to the converter. That can expose internal URLs, local files, or server resources.

What This Script Uses

The conversion has two steps:

  1. HTML2PDF reads the HTML and creates a temporary PDF.
  2. Imagick opens the first PDF page and writes it as a JPEG.

This is not the same as taking a screenshot in Chrome. HTML2PDF has its own HTML and CSS support, so some layouts will look different. Simple tables, text, colors, borders, and basic blocks normally work well. Complex Grid, advanced Flexbox, animations, video, canvas, and JavaScript-rendered content may not.

Imagick also needs a working PDF delegate, commonly provided through Ghostscript. Some hosting companies disable PDF reading in ImageMagick’s policy for security. If the PHP extension exists but PDF conversion fails, check the server policy and logs instead of changing random PHP code.

You need:

  • A supported PHP version
  • Composer
  • The imagick PHP extension
  • ImageMagick with permitted PDF reading
  • A writable temporary directory
  • Enough memory for the page size and DPI

Install the Requirements

Install the PHP package with Composer:

composer require spipu/html2pdf

Imagick is a PHP extension, not a normal Composer package. Its installation command depends on your operating system and PHP setup. On shared hosting, check the PHP extensions panel or ask the host whether Imagick and PDF reading are enabled.

Before running the full script, make a small check:

<?php
require __DIR__ . '/vendor/autoload.php';

use Spipu\Html2Pdf\Html2Pdf;

if (!class_exists(Html2Pdf::class)) {
    throw new RuntimeException('HTML2PDF is not available.');
}

if (!extension_loaded('imagick')) {
    throw new RuntimeException('The Imagick PHP extension is not enabled.');
}

The output folder must be writable by the PHP process. Do not solve permission errors with chmod 777. Give the application only the access it needs, and keep generated files outside a public directory unless visitors must download them.

Convert HTML to JPEG

Here is the complete converter. I have kept the code direct and removed unnecessary comments.

<?php
require __DIR__ . '/vendor/autoload.php';

use Spipu\Html2Pdf\Html2Pdf;

function htmlToJpeg(
    string $html,
    string $imagePath,
    int $quality = 88,
    int $dpi = 144
): void {
    $tempPdf = tempnam(sys_get_temp_dir(), 'html2pdf_');

    if ($tempPdf === false) {
        throw new RuntimeException('Could not create a temporary PDF file.');
    }

    try {
        $pdf = new Html2Pdf('P', 'A4', 'en', true, 'UTF-8', [10, 10, 10, 10]);
        $pdf->writeHTML($html);
        $pdf->output($tempPdf, 'F');

        $image = new Imagick();
        $image->setResolution($dpi, $dpi);
        $image->readImage($tempPdf . '[0]');
        $image->setImageBackgroundColor('white');
        $image = $image->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN);
        $image->setImageFormat('jpeg');
        $image->setImageCompression(Imagick::COMPRESSION_JPEG);
        $image->setImageCompressionQuality($quality);
        $image->stripImage();
        $image->writeImage($imagePath);
        $image->clear();
        $image->destroy();
    } finally {
        if (is_file($tempPdf)) {
            unlink($tempPdf);
        }
    }
}

$html = file_get_contents(__DIR__ . '/result.html');

if ($html === false) {
    throw new RuntimeException('Could not read result.html.');
}

htmlToJpeg($html, __DIR__ . '/result.jpg');

The [0] after the PDF path tells Imagick to read only the first page. That keeps the output predictable for a single score card or receipt. If your document has several pages, decide whether you need separate images or one long combined image before changing the code.

Set the resolution before readImage(). Increasing DPI after the PDF is loaded will not create the same result. A value around 144 DPI is a useful starting point. Higher values improve detail but also increase memory, processing time, and file size.

JPEG quality around 85–90 is enough for most cards. Use PNG when sharp text, transparency, or flat-color graphics matter more than file size.

Load a Webpage Safely

The original script used file_get_contents() with a URL. That can work when allow_url_fopen is enabled, but accepting a user-provided URL creates a server-side request forgery risk.

For a game score or invoice, I prefer rendering a known template locally:

$data = [
    'player' => 'Rohit',
    'score' => 1250,
];

ob_start();
require __DIR__ . '/templates/score-card.php';
$html = ob_get_clean();

htmlToJpeg($html, __DIR__ . '/output/score-card.jpg');

Escape dynamic values inside the template with htmlspecialchars() unless they intentionally contain trusted HTML. Keep the template and its CSS under your control.

If your application must fetch a webpage, allow only specific HTTPS hosts, block redirects unless they are validated, set a short timeout, limit the response size, and reject private or loopback network addresses. A simple host-name check alone is not enough for a public conversion service because DNS results can change.

Also place limits on HTML size, PDF pages, image dimensions, DPI, execution time, and concurrent jobs. One oversized document can consume a surprising amount of memory.

Quality and Limitations

This two-step method is easy to understand, but you have to compromise when the HTML depends on browser features. If the result is blank or broken, check these points first:

  • Confirm Imagick can read a small local PDF.
  • Check the ImageMagick security policy and PHP error log.
  • Use absolute local paths for images and fonts.
  • Keep CSS simple and supported by HTML2PDF.
  • Verify the temporary and output directories are writable.
  • Reduce DPI when memory usage is too high.
  • Make sure the HTML is valid and encoded as UTF-8.

Do not disable ImageMagick security rules globally just to make one script work. Ask the server administrator for the narrow policy required by this application.

For a page that depends on JavaScript, web fonts, modern CSS, charts, or responsive browser layout, use a headless browser such as Chromium through Playwright or Puppeteer. The browser approach is heavier, but it renders the page much closer to what a visitor actually sees.

Which Method Should You Use?

Use HTML2PDF plus Imagick when the input is a controlled PHP template and the layout is simple. It is a good fit for the same kind of Facebook game score that made me discover this trick, along with basic receipts and certificates.

Use a headless browser screenshot when you need the exact browser layout or must wait for JavaScript. Use an external screenshot API only when you accept its cost, privacy policy, rate limits, and network dependency.

The important part is not to make the solution bigger than the problem. For a controlled HTML card, the PHP pipeline above is enough: load the template, create a temporary PDF, convert the first page, clean the temporary file, and save the final JPEG.