35

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?

Community
  • 1
  • 1
  • 2
    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 Sep 12 '14 at 02:59

11 Answers11

54

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

define("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

fonini
  • 3,243
  • 5
  • 30
  • 53
David P. P.
  • 600
  • 5
  • 11
28

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.

Jon
  • 677
  • 6
  • 13
  • Worked for me on Laravel, Thanks – ynsmtkl Jul 05 '21 at 22:30
  • This worked for me with remote images. Thank you for sharing! – vanarie Aug 13 '21 at 22:13
  • `enable_remote` has synonyms, mentioned in https://github.com/dompdf/dompdf/blob/master/src/Options.php: `elseif($key === 'isRemoteEnabled' || $key === 'is_remote_enabled' || $key === 'enable_remote') {$this->setIsRemoteEnabled($value);}` – Arya Jul 30 '22 at 17:50
  • This turned out to work well. `$dompdf = new Dompdf();` `$dompdf->set_option("enable_remote", true);` – Gjermund Dahl Oct 20 '22 at 15:09
15

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

Patrice Flao
  • 491
  • 5
  • 18
  • 4
    The reason that worked is because originally you are looking for the images directory in the root. The "./" just means "look in this directory". You could actually remove the "./" and it will still work. –  Dec 03 '14 at 20:15
  • 2
    you rule. I was about to rearrange a lot of stuff!! – Chad Caldwell Jul 22 '16 at 20:02
  • After all these try I gave... this is the solution! – Marc Aug 16 '16 at 03:40
12

You can use base64 encoded image

<img src="{{'data:image/png;base64,' . base64_encode(file_get_contents(@$image))}}" alt="image" >
BlackPearl
  • 2,532
  • 3
  • 33
  • 49
  • 2
    Thanks, Mate. I was trying to get an image from S3 to display in the PDF. Worked like a charm for me – Omer Apr 18 '21 at 22:03
11

Now (May 2018) the correct way is :

$options = new Options();
$options->set('isRemoteEnabled',true);      
$dompdf = new Dompdf( $options );
André DLC
  • 261
  • 4
  • 11
7

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);
s3c
  • 1,481
  • 19
  • 28
3

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.

Nasser Hekmati
  • 145
  • 1
  • 5
  • When providing sample code, please provide it as an example to fix the problem for the asker. (IE Sample code with a full path to an image rather than a stylesheet since this question is about an image.) – Loren Jan 17 '18 at 12:37
2

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

Owen Davey
  • 1,202
  • 1
  • 12
  • 18
1

In path :

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

change settings

enable_remote' => false,

то true.

  • For newer versions the way you specify this setting has apparently changed: https://stackoverflow.com/a/45362099/405015 – thirtydot Jul 28 '17 at 13:46
1

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 '';
        }
    }
Japo Domingo
  • 613
  • 5
  • 7
0

I had this problem when loading local images and figured out that

$dompdf->getOptions()->setChroot($path_to_images);

was not enough, I additionally had to set

chdir($path_to_images);
Mesa
  • 289
  • 2
  • 10