DEV Community

IronSoftware
IronSoftware

Posted on

wkhtmltopdf Images Not Showing (Issue Fixed)

Images not appearing in wkhtmltopdf-generated PDFs is one of the most common issues developers encounter. Whether local images fail to load, remote images time out, base64 images render blank, or SVGs display incorrectly, the root causes trace back to wkhtmltopdf's security model, path resolution quirks, and the limitations of its abandoned rendering engine. This article documents the eight most common image rendering failures, explains their technical causes, and provides working solutions.

The Problem

wkhtmltopdf converts HTML to PDF using a headless WebKit rendering engine. When images fail to appear, the resulting PDF contains blank spaces, broken image placeholders, or nothing at all where images should be. The HTML may render correctly in a browser, but the same content produces missing images when processed by wkhtmltopdf.

This problem has plagued developers for years. A search through GitHub issues, Stack Overflow questions, and community forums reveals thousands of reports, many without satisfactory resolutions. The issue became permanent when wkhtmltopdf was archived on January 2, 2023, meaning these problems will never receive official fixes.

Error Messages and Symptoms

Depending on the specific cause, developers may see these warnings in the console output:

Warning: Blocked access to file /path/to/image.png
Failed to load file:///path/to/image.png (ignore)
QSslSocket: cannot resolve TLSv1_1_client_method
Warning: SSL error ignored
Exit with code 1 due to network error: ContentNotFoundError
Enter fullscreen mode Exit fullscreen mode

In many cases, wkhtmltopdf produces no error at all. The PDF generates successfully, but images simply do not appear. The HTML displays correctly in Chrome, Firefox, and Edge, yet wkhtmltopdf outputs blank rectangles where images should render.

Who Is Affected

This issue affects developers across multiple scenarios:

  • Local development environments: Images load in the browser but not in generated PDFs
  • Docker containers: Paths that work on host machines fail inside containers
  • Linux servers: Different path resolution and permission models than Windows
  • Cloud deployments: Network restrictions, HTTPS certificate validation, and containerized environments
  • CI/CD pipelines: Isolated build environments with restricted filesystem access
  • Applications using wkhtmltopdf wrappers: DinkToPdf, TuesPechkin, Rotativa, Snappy, wicked_pdf, and PDFKit all inherit these issues

Eight Common Causes of Missing Images

1. Local File Access Blocked (Security Restriction)

Starting with version 0.12.6 (June 2020), wkhtmltopdf disabled local file access by default. This security change addressed CVE-2020-21365, a directory traversal vulnerability that could expose sensitive files. However, it also broke countless applications that referenced local images.

Symptoms:

Warning: Blocked access to file /var/www/app/images/logo.png
Enter fullscreen mode Exit fullscreen mode

The Fix:

Add the --enable-local-file-access flag:

wkhtmltopdf --enable-local-file-access input.html output.pdf
Enter fullscreen mode Exit fullscreen mode

For PHP Snappy:

$snappy = new Pdf('/usr/local/bin/wkhtmltopdf');
$snappy->setOption('enable-local-file-access', true);
Enter fullscreen mode Exit fullscreen mode

For Ruby wicked_pdf:

WickedPdf.new.pdf_from_string(html, enable_local_file_access: true)
Enter fullscreen mode Exit fullscreen mode

Limitations:

The flag placement matters. wkhtmltopdf's argument parser requires global options like --enable-local-file-access to appear before input files:

# Correct
wkhtmltopdf --enable-local-file-access input.html output.pdf

# Incorrect (may fail silently)
wkhtmltopdf input.html --enable-local-file-access output.pdf
Enter fullscreen mode Exit fullscreen mode

Even with the flag enabled, some users report continued failures. The flag does not exist in wkhtmltopdf versions prior to 0.12.6, causing older code to error with "unrecognized option."

2. Relative Path Resolution Failures

wkhtmltopdf interprets relative paths differently than web browsers. When processing HTML from a string or stdin, wkhtmltopdf has no base URL context, causing relative paths to resolve against unexpected directories.

Symptoms:

Images work when HTML is loaded from a file but fail when passed as a string. The path /images/logo.png resolves to the filesystem root rather than the web root.

Example failure:

<!-- This path is ambiguous to wkhtmltopdf -->
<img src="/images/logo.png">
Enter fullscreen mode Exit fullscreen mode

When wkhtmltopdf processes this from stdin:

cat input.html | wkhtmltopdf --enable-local-file-access - output.pdf
Enter fullscreen mode Exit fullscreen mode

The path /images/logo.png becomes file:///images/logo.png, looking for /images/logo.png at the filesystem root.

Solutions:

Use absolute filesystem paths:

<img src="file:///var/www/myapp/public/images/logo.png">
Enter fullscreen mode Exit fullscreen mode

Or use the --allow flag to specify the base directory:

wkhtmltopdf --enable-local-file-access --allow /var/www/myapp/ input.html output.pdf
Enter fullscreen mode Exit fullscreen mode

Or use full HTTP URLs:

<img src="http://localhost:3000/images/logo.png">
Enter fullscreen mode Exit fullscreen mode

3. Docker Container Path Issues

Docker containers present unique challenges. Paths that work on the host machine may not exist inside the container. Volume mounts, user permissions, and network isolation all contribute to image loading failures.

Symptoms:

Application works locally on Windows or macOS but images disappear when deployed to a Docker container. No error messages appear, but the PDF contains blank spaces.

Common causes:

  1. Volume not mounted: The image directory exists on the host but is not accessible to the container
  2. Permission denied: Container user lacks read access to mounted directories
  3. Different filesystem paths: /Users/developer/project/images on macOS becomes /app/images in the container

Solutions:

Mount the images directory correctly in docker-compose.yml:

services:
  app:
    volumes:
      - ./images:/app/images:ro
Enter fullscreen mode Exit fullscreen mode

Ensure the wkhtmltopdf container can access the files:

FROM surnet/alpine-wkhtmltopdf:3.16.2-0.12.6-small
RUN chmod -R 755 /app/images
Enter fullscreen mode Exit fullscreen mode

Use absolute container paths in HTML:

<img src="file:///app/images/logo.png">
Enter fullscreen mode Exit fullscreen mode

Or serve images via HTTP from another container:

<img src="http://nginx/images/logo.png">
Enter fullscreen mode Exit fullscreen mode

4. HTTPS and SSL Certificate Problems

wkhtmltopdf's SSL implementation is outdated. It cannot handle modern TLS configurations, causing HTTPS images to fail silently or produce SSL warnings.

Symptoms:

Warning: SSL error ignored
Failed to load https://cdn.example.com/image.png
QSslSocket: cannot resolve TLSv1_1_client_method
Enter fullscreen mode Exit fullscreen mode

Images load from HTTP URLs but not HTTPS. The same HTTPS URL works in curl and browsers.

Root cause:

wkhtmltopdf links against an old version of Qt's SSL libraries. Many CDNs and image hosts require TLS 1.2 or 1.3, which wkhtmltopdf's Qt WebKit may not properly negotiate.

Workarounds:

Ignore SSL errors (security risk):

wkhtmltopdf --no-stop-slow-scripts --ssl-crt-path /etc/ssl/certs/ input.html output.pdf
Enter fullscreen mode Exit fullscreen mode

Switch HTTPS URLs to HTTP (only for non-sensitive content):

$html = str_replace('https://', 'http://', $html);
Enter fullscreen mode Exit fullscreen mode

Download images and embed as base64:

// Download image, convert to base64, embed inline
var imageBytes = httpClient.GetByteArrayAsync(url).Result;
var base64 = Convert.ToBase64String(imageBytes);
var dataUri = $"data:image/png;base64,{base64}";
html = html.Replace(url, dataUri);
Enter fullscreen mode Exit fullscreen mode

5. Base64 Image Rendering Failures

Base64 data URIs should bypass network and filesystem issues entirely. Yet developers frequently report base64 images not rendering in wkhtmltopdf, particularly for background images and certain formats.

Symptoms:

Images embedded as base64 render in browsers but appear blank in the PDF. No error messages in wkhtmltopdf output.

Known issues:

  1. Background images: Base64-encoded CSS background images often fail where <img> tags succeed
  2. BMP format: Base64 BMP images may not render even when PNG and JPG work
  3. Large images: Base64 strings exceeding certain lengths can cause silent failures
  4. SVG with embedded base64: SVGs containing base64 image data may render blank

Example of broken CSS background:

/* This often fails in wkhtmltopdf */
.logo {
    background-image: url(data:image/png;base64,iVBORw0KGgo...);
    width: 200px;
    height: 100px;
}
Enter fullscreen mode Exit fullscreen mode

Workarounds:

Use <img> tags instead of CSS backgrounds:

<img src="data:image/png;base64,iVBORw0KGgo..." style="width: 200px; height: 100px;">
Enter fullscreen mode Exit fullscreen mode

Convert BMP to PNG before base64 encoding.

For large images, consider external HTTP references or local file paths.

6. SVG Rendering Issues

wkhtmltopdf uses Qt's SVG renderer, which has significant limitations. SVGs that render correctly in browsers may appear blank, distorted, or missing elements in wkhtmltopdf output.

Symptoms:

  • SVG images not appearing at all
  • SVG paths missing or partially rendered
  • SVGs squashed or incorrectly sized
  • Images embedded inside SVGs not visible

Known Qt SVG limitations:

  • Complex clip-paths may not render
  • Opacity properties sometimes ignored
  • External references inside SVGs fail
  • Certain filters and effects unsupported
  • CSS conflicts with HTML attributes

Example failures:

<!-- IMG tag with SVG src may not render -->
<img src="logo.svg" width="100" height="50">

<!-- Inline SVG with clip-path may render incorrectly -->
<svg>
  <defs>
    <clipPath id="clip">
      <circle cx="50" cy="50" r="50"/>
    </clipPath>
  </defs>
  <image clip-path="url(#clip)" href="photo.jpg"/>
</svg>
Enter fullscreen mode Exit fullscreen mode

Workarounds:

Use SVG as CSS background with explicit dimensions:

<span style="display:inline-block; width:100px; height:50px; background:url(logo.svg) no-repeat;"></span>
Enter fullscreen mode Exit fullscreen mode

Convert SVGs to PNG before PDF generation:

# Using Inkscape
inkscape --export-type=png --export-filename=logo.png logo.svg
Enter fullscreen mode Exit fullscreen mode

Embed SVG inline with explicit viewBox and dimensions:

<svg viewBox="0 0 100 50" width="100" height="50">
  <!-- SVG content -->
</svg>
Enter fullscreen mode Exit fullscreen mode

7. Background Images Not Rendering

CSS background images frequently fail to appear in wkhtmltopdf output, even when foreground images render correctly. This affects gradients, patterns, and image backgrounds.

Symptoms:

Background images show in HTML preview but disappear in PDF. Background colors work, but background-image does not.

Causes:

  1. Print media mode: wkhtmltopdf renders in print mode by default, which suppresses backgrounds
  2. CSS shorthand issues: The background shorthand may not work; individual properties may be required
  3. Local file access: Background image paths subject to same security restrictions as <img> tags

Solutions:

Enable background printing:

wkhtmltopdf --print-media-type --no-background input.html output.pdf
# Or explicitly enable backgrounds
wkhtmltopdf --background input.html output.pdf
Enter fullscreen mode Exit fullscreen mode

Use individual CSS properties instead of shorthand:

/* Instead of: background: url(image.png) no-repeat center; */
background-image: url(image.png);
background-repeat: no-repeat;
background-position: center;
Enter fullscreen mode Exit fullscreen mode

Use print media query to ensure backgrounds render:

@media print {
    .header {
        background-image: url(header-bg.png) !important;
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }
}
Enter fullscreen mode Exit fullscreen mode

8. Network Timeout and Racing Conditions

When wkhtmltopdf fetches images over HTTP, network latency can cause images to be skipped. The tool may not wait long enough for slow CDNs or high-latency connections.

Symptoms:

Images load inconsistently. Sometimes they appear, sometimes they do not. The same HTML produces different results on different runs.

Root cause:

wkhtmltopdf has timeouts for network requests. If an image response is not received in time, wkhtmltopdf proceeds without it. This is non-deterministic when dealing with variable network conditions.

Solutions:

Increase JavaScript delay (also affects image loading):

wkhtmltopdf --javascript-delay 2000 input.html output.pdf
Enter fullscreen mode Exit fullscreen mode

Use the --load-media-error-handling and --load-error-handling options:

wkhtmltopdf --load-error-handling abort --load-media-error-handling abort input.html output.pdf
Enter fullscreen mode Exit fullscreen mode

Pre-fetch all images before PDF generation and embed as base64.

Evidence from the Developer Community

These issues have accumulated thousands of reports across developer platforms.

Timeline

Date Event Source
2015-03-23 "Images don't appear on the pdf" Laracasts forum
2016-03-15 "Images are not rendering properly" GitHub Issue #2834
2018-04-16 "Images randomly not loading" GitHub Issue #3879
2018-11-02 "Images not showing up using PDFKit and WkHTMLtoPDF" DEV Community
2020-06-01 Version 0.12.6 disables local file access by default Release notes
2020-09-21 "Image not render" with relative paths GitHub Issue #4832
2021-01-17 "Image not displayed - WKHTMLTOPDF" Google Groups
2023-01-02 wkhtmltopdf repository archived GitHub
2023-01-06 "Images missing in PDF" - Frappe community solution Frappe Forum

Community Reports

"I was able to get the style sheets to work using absolute URLs, but have not been able to get the images to show."
— Stack Overflow, 12 years of views

"The image gets rendered properly in the .html file, but when converting to pdf using wkhtmltopdf, the image is not shown in the pdf file (just a blank line instead). There are no errors in the cmd output."
— GitHub Issue #4723

"When PDF files are generated the images in header are not shown. Cause: Frappe framework uses a library called wkhtmltopdf to generate PDF files."
— Frappe Forum, 2023

Root Cause Analysis

wkhtmltopdf's image rendering problems stem from architectural limitations:

  1. Abandoned Qt WebKit engine: The rendering engine has not been updated since 2015. Modern image formats, network protocols, and CSS features are unsupported.

  2. Security-first breaking changes: The 0.12.6 security update broke existing applications without clear migration paths. Documentation was sparse.

  3. Inconsistent path resolution: No standardized approach to handling relative paths, leading to unpredictable behavior across environments.

  4. Outdated SSL/TLS stack: The Qt libraries linked by wkhtmltopdf cannot negotiate modern TLS connections required by most CDNs.

  5. No maintainer support: With the project archived, these issues will never receive fixes. Workarounds are the only option.

A Different Approach: IronPDF

For applications where image rendering reliability is critical, IronPDF provides an alternative based on embedded Chromium rather than Qt WebKit. This architectural difference eliminates the image rendering issues documented above.

Why IronPDF Handles Images Correctly

IronPDF uses the same rendering engine as Google Chrome. Images that display in Chrome will display in IronPDF-generated PDFs:

  • Local file access: Works without special flags; no security-related breaking changes
  • Path resolution: Consistent with browser behavior; relative paths work as expected
  • HTTPS support: Modern TLS 1.2/1.3 with proper certificate validation
  • Base64 images: Full support for data URIs in both <img> tags and CSS backgrounds
  • SVG rendering: Chromium's SVG implementation handles complex paths, clip-paths, and embedded images
  • Background images: Print media emulation with proper background rendering
  • Network handling: Chromium's robust network stack with configurable timeouts

Code Example: Reliable Image Rendering

using IronPdf;

public class ReliableImagePdf
{
    public void GeneratePdfWithImages()
    {
        var renderer = new ChromePdfRenderer();

        // Chromium handles all image types correctly
        string html = @"
        <!DOCTYPE html>
        <html>
        <head>
            <style>
                .hero {
                    background-image: url('https://example.com/hero.jpg');
                    background-size: cover;
                    height: 300px;
                }
                .logo-container {
                    background: url(data:image/svg+xml;base64,PHN2ZyB4bW...) no-repeat;
                    width: 150px;
                    height: 50px;
                }
            </style>
        </head>
        <body>
            <!-- HTTPS images load correctly -->
            <img src='https://cdn.example.com/photo.jpg' alt='Photo'>

            <!-- Local images work without special flags -->
            <img src='file:///var/www/app/images/local.png' alt='Local'>

            <!-- Base64 images render in all contexts -->
            <img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEU...' alt='Inline'>

            <!-- SVGs render completely -->
            <img src='logo.svg' alt='SVG Logo'>

            <!-- CSS backgrounds work -->
            <div class='hero'>
                <div class='logo-container'></div>
            </div>
        </body>
        </html>";

        using (var pdf = renderer.RenderHtmlAsPdf(html))
        {
            pdf.SaveAs("images-working.pdf");
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Code Example: Docker Deployment

IronPDF includes all dependencies, eliminating container configuration issues:

using IronPdf;

public class DockerPdfGenerator
{
    public byte[] GenerateInvoicePdf(string htmlContent)
    {
        // No additional flags or configuration needed
        var renderer = new ChromePdfRenderer();

        // Works identically on Windows, Linux, macOS, and Docker
        renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;

        // Images from any source render correctly
        using (var pdf = renderer.RenderHtmlAsPdf(htmlContent))
        {
            return pdf.BinaryData;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY --from=build /app/publish .
# No wkhtmltopdf installation, no libwkhtmltox.so, no permission issues
ENTRYPOINT ["dotnet", "MyApp.dll"]
Enter fullscreen mode Exit fullscreen mode

API Reference

For image handling and rendering configuration:

Migration Considerations

Licensing

IronPDF is commercial software with per-developer licensing. A free trial is available for evaluation. The cost should be weighed against developer time spent debugging wkhtmltopdf image issues that will never be fixed upstream.

API Differences

Migration from wkhtmltopdf requires code changes:

wkhtmltopdf IronPDF Equivalent
--enable-local-file-access Not needed; works by default
--allow /path/ Not needed; paths resolve correctly
--javascript-delay 2000 RenderingOptions.RenderDelay = 2000
--background Backgrounds render by default
External binary installation NuGet package includes all dependencies

What You Gain

  • Images render consistently across all environments
  • No security flag configuration required
  • Modern TLS support for HTTPS resources
  • Full SVG rendering with Chromium's engine
  • CSS background images work correctly
  • Base64 data URIs in all contexts
  • No version-specific path resolution bugs

What to Consider

  • Commercial licensing cost
  • Larger deployment size (embedded Chromium)
  • Different rendering output (Chromium vs WebKit)
  • Learning curve for new API

Conclusion

Image rendering failures in wkhtmltopdf trace back to its abandoned Qt WebKit engine, security model changes, and inconsistent path resolution. With the project archived since January 2023, these issues are permanent. Developers can apply workarounds for specific scenarios, but the underlying problems will never receive fixes. For applications where reliable image rendering matters, migrating to a maintained solution with modern browser engine support eliminates these issues entirely.


Jacob Mellor is CTO at Iron Software and has spent 25+ years developing commercial software, including IronPDF.


References

  1. Wkhtmltopdf not rendering images - Stack Overflow{:rel="nofollow"} - Original Stack Overflow discussion
  2. Image not render - Issue #4832{:rel="nofollow"} - Relative path rendering failure
  3. Images not showing up using PDFKit and WkHTMLtoPDF - DEV Community{:rel="nofollow"} - Base64 workaround solution
  4. wkhtmltopdf not loading any images - Issue #1883{:rel="nofollow"} - Early reports of image failures
  5. Images randomly not loading - Issue #3879{:rel="nofollow"} - Network timing issues
  6. --enable-local-file-access still showing blocked access - Issue #5210{:rel="nofollow"} - Security flag failures
  7. Base64-encoded Background Image Does Not Render - Issue #2552{:rel="nofollow"} - CSS background image failures
  8. SVG Image not rendering properly - Issue #1975{:rel="nofollow"} - SVG rendering limitations
  9. Loading CSS or images with HTTPS - Issue #4462{:rel="nofollow"} - SSL/TLS failures
  10. wkhtmltopdf background-image not working - Issue #2054{:rel="nofollow"} - Background image rendering
  11. Not render images and css in docker container - Issue #20{:rel="nofollow"} - Docker deployment issues
  12. Solution - Images missing in PDF - Frappe Forum{:rel="nofollow"} - Community workaround
  13. wkhtmltopdf Enable Local File Access Guide{:rel="nofollow"} - Security flag documentation
  14. wkhtmltopdf GitHub Repository - Archived{:rel="nofollow"} - Project archived January 2, 2023

For IronPDF documentation and tutorials, visit ironpdf.com.

Top comments (0)