30
votes

For some reason, DomPDF won't render an image included in the html that is being parsed:

PDF Image missing

However, the image is rendered on the page when it is returned as html:

HTML Image exists

I've looked at these issues and have make sure that DOMPDF_ENABLE_REMOTE is set to true and verified file permissions:
dompdf image not real image not readable or empty
Image error in DOMPDF for ZF2

Are there any other things that I should be checking for?

10
Is the PHP setting allow_url_fopen set to true? If you're using 0.6.x you can load dompdf/www/setup.php to see if there are any red marks in your install. - BrianS

10 Answers

50
votes

Following helped me like charm, at least localy, and even with

def("DOMPDF_ENABLE_REMOTE", false);

The solution is to change the image SRC to the absolute path on the server, like this:

<img src="/var/www/domain/images/myimage.jpg" />

All of the following worked for me:

<img src="<?php echo $_SERVER["DOCUMENT_ROOT"].'/placeholder.jpg';?>"/>
<img src="<?php echo $_SERVER["DOCUMENT_ROOT"].'\placeholder.jpg';?>"/>
<img src="<?php echo $_SERVER["DOCUMENT_ROOT"].'./placeholder.jpg';?>"/>

$_SERVER["DOCUMENT_ROOT"] is C:/wamp/www/ZendSkeletonApplication/public

Thanks to this: lost in code

16
votes

As there was another answer that suggests enabling the remote option in module.config.php and I can't yet add comments, I thought it would be best to answer that this file does not exist in newer versions of DomPDF.

If you need to include remotely stored images in a newer version you have to pass it as an option to the constructor:

$dompdf = new Dompdf(array('enable_remote' => true));

This fixed the issue I had.

14
votes

Ok I had the same problem with image using :

<img id="logo" src="/images/flags/fr.png" width="50" alt="Logo">

But if I add a . before /images, without changing anything in dompdf_config.custom.inc, it works

<img id="logo" src="./images/flags/fr.png" width="50" alt="Logo">

Hope it helps

10
votes

Now (May 2018) the correct way is :

$options = new Options();
$options->set('isRemoteEnabled',true);      
$dompdf = new Dompdf( $options );
7
votes

You can use base64 encoded image

<img src="{{'data:image/png;base64,' . base64_encode(file_get_contents(@$image))}}" alt="image" >
3
votes

I solve this problem by using external CSS's full path. This one worked on my linux ubuntu server :

<link href="{{ public_path('css/style.css') }}" />

<img src="{{ public_path('images/image.jpg') }}" />

and work on image.

2
votes

None of the solutions here worked for me. Instead I just base64 encoded the image and then it worked. You can use this tool.

2
votes

You don't really need isRemoteEnabled turned on, if all your images and what not are on the same server that executes the script.

Why it doesn't load your image

DomPdf protects you from being attacked through it. As per documentation the following won't work:

$dompdf = new Dompdf();
$dompdf->getOptions()->getChroot(); // something like 'C:\\laragon\\www\\your-local-website\\vendor\\dompdf\\dompdf'

$html = <<<HTML
<!DOCTYPE html>
<html lang="en">
    <body>
        <img src="C:\\laragon\\www\\your-local-website\\public\\img\\logo.png">
    </body>
</html>
HTML;

$dompdf->loadHtml($html);

You should change CHROOT to your desired absolute path with

$dompdf->getOptions()->setChroot("C:\\laragon\\www\\your-local-website\\public");

and then you can insert any <img> with src from within (can be nested) that /public folder into HTML.

Security note

It seems like an easy win to just set Chroot to your app root folder, but don't. It opens up a nasty gate, one you want to keep shut. Supposedly there are no critical scripts in /public, only images, public documents, routing etc.

Usage note

Note that I used a different directory separator than the one being used in documentation. I believe the best practice would be to do something in lines of:

define('DS', DIRECTORY_SEPARATOR);

$public = ABSPATH . DS . 'public'; // ABSPATH is defined to be __DIR__ in root folder of your app
$image = $public . DS . 'logo' . DS . 'logo-md.png';

/* Optional */
$saveLocation = ABSPATH . DS . '..' . DS . 'private' . DS . 'invoices'; // Note that save location doesn't have to be in '/public' (or even in 'www')

$html = <<<HTML
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8">
        <style type="text/css">
            * {
                font-family: DejaVu Sans !important;
            }
            @page {
                margin: 0;
                padding: 0;
            }
            html, body {
                margin: 0;
                min-height: 100%;
                padding: 0;
            }          
        </style>
    </head>
    <body>
        <img src="{$image}">
    </body>
</html>
HTML;

$dompdf = new Dompdf();
$dompdf->getOptions()->setChroot($public);
$domPdf->loadHtml($html, 'UTF-8');
$domPdf->setPaper('A4', 'portrait');
$domPdf->render();

/* either */
$domPdf->stream($filename); // filename is optional

/* or */
$outputString = $domPdf->output();
$pdfFile = fopen($saveLocation, 'w');
fwrite($pdfFile, $outputString);
fclose($pdfFile);
1
votes

In path :

vendor/dino/dompdf-module/config/module.config.php

change settings

enable_remote' => false,

то true.

1
votes

For our use case we had to convert all the images on the page to base64 since the pdf should be usable offline. Our code lives inside a controller class but you can modify that to your needs.

Here's the code:


    /**
     * Convert images to Base64 so it's included in the PDF.
     *
     * @param $html  Full html render of the page.
     */
    public function convertReportImagesToURI($html): string
    {
        $doc = new DOMDocument();
        libxml_use_internal_errors(true);
        $doc->loadHTML($html);
        $tags = $doc->getElementsByTagName('img');
        $imgArr = array();

        // Iterate over all image tags.
        foreach ($tags as $tag) {
            // Get the src attribute.
            $imgSrc = $tag->getAttribute('src');

            // Convert to base64.
            $base64src = self::getImageDataURI($imgSrc);
            $tag->setAttribute('src', $base64src);
        }
        return $doc->saveHTML();
    }

    /**
     * This does the actual encoding.
     */
    public static function getImageDataURI($image, $mime = ''): string
    {
        // Director::absoluteURL('/') gets the base url of the site.
        // We had to remove the leading slash of the image hence the use of substr.
        // If your images have absolute urls you will need to modify this.
        $imageLocation = Director::absoluteURL('/') . substr($image, 1);
        // Get the image location. remove leading slash on image url.
        return 'data:' . self::get_image_mime_type($imageLocation) . ';base64,' . base64_encode(file_get_contents($imageLocation));
    }

    /**
     * https://stackoverflow.com/a/45054843
     * @param $image_path
     * @return string
     */
    public static function get_image_mime_type($image_path): string
    {
        $mimes  = array(
            IMAGETYPE_GIF => "image/gif",
            IMAGETYPE_JPEG => "image/jpg",
            IMAGETYPE_PNG => "image/png",
            IMAGETYPE_SWF => "image/swf",
            IMAGETYPE_PSD => "image/psd",
            IMAGETYPE_BMP => "image/bmp",
            IMAGETYPE_TIFF_II => "image/tiff",
            IMAGETYPE_TIFF_MM => "image/tiff",
            IMAGETYPE_JPC => "image/jpc",
            IMAGETYPE_JP2 => "image/jp2",
            IMAGETYPE_JPX => "image/jpx",
            IMAGETYPE_JB2 => "image/jb2",
            IMAGETYPE_SWC => "image/swc",
            IMAGETYPE_IFF => "image/iff",
            IMAGETYPE_WBMP => "image/wbmp",
            IMAGETYPE_XBM => "image/xbm",
            IMAGETYPE_ICO => "image/ico");

        if (($image_type = exif_imagetype($image_path))
            && (array_key_exists($image_type, $mimes))) {
            return $mimes[$image_type];
        } else {
            return '';
        }
    }