65

I've seen multiple questions that are very similar to this one, so I was hesitant at first to post it. But nothing suggested resolved my issue and I can't seem to figure out what's wrong myself.

For a project I made for one client they wanted to ability to convert quotes for their customers (generated using an online form) to PDFs. Simple enough. As the entire project was in PHP, I used the following simple process:

  1. Save the quote as a temporary HTML file
  2. Use WkHTMLtoPDF to convert the HTML file to a PDF
  3. Output this PDF file
  4. Clean up (delete temporary files)

This worked until they changed servers. The new server has a firewall.

At first the PDF conversion step was returning a firewall page saying that the server couldn't make outbound connections. To resolve this I fed the HTML file directly instead of linking to it (/var/www/mysite/temp/18382.html instead of www.example.com/temp/18382.html). This converted the HTML, but the firewall prevented the loading of CSS and images

I can overcome the CSS by simply embedding it directly in the site instead of linking to it (using the <style> tags), but this doesn't work for images

I tried using relative links first. I changed <img src="http://www.example.com/temp/image.jpg" /> to <img src="./image.jpg" />. This didn't work.

Next I tried <img src="file:///var/www/mysite/temp/image.jpg" /> but this didn't work, either

I read around and look through the WkHTMLtoPDF manual and I tried several different command line arguments like --enable-local-file-access, --enable /var/www/mysite/temp/, and --images but nothing seems to fix it

sanmai
  • 29,083
  • 12
  • 64
  • 76
stevendesu
  • 15,753
  • 22
  • 105
  • 182
  • Have you had a look at the firewall logs? That might help you identify the actual issue. Local file access is not affected by a firewall. – likeitlikeit May 18 '13 at 18:00
  • @likeitlikeit I'm aware local access isn't affected by a firewall, but I suspect it's either not supported by wkhtmltopdf or I'm not implementing it correctly. I'll check the logs right now to see if it was using HTTP when I requested the file locally – stevendesu May 18 '13 at 18:10
  • @likeitlikeit Just checked, nothing. It's requesting locally but failing to load – stevendesu May 18 '13 at 18:16
  • Have a look at [this](http://stackoverflow.com/a/10503212/1553481) then. I don't know the package. I could have helped if it was actually a firewall thingy. – likeitlikeit May 18 '13 at 18:23
  • 1
    if your are on linux check the ownership of your images. For windows you will find some info on https://code.google.com/p/wkhtmltopdf/wiki/Usage. I tried: 1:
    2:
    3:
    4:
    all images are showed correct. I didn't use any command line arguments (only wkhtmltopdf /var/www/testpdf/makepdf.html makepdf.pdf)
    – Bass Jobsen May 18 '13 at 22:10
  • 1
    @BassJobsen Oh my god, that was it! WkHTMLtoPDF is running on its own user but the images are owned by the Apache user. I put `chown` just before the call to WkHTMLtoPDF and suddenly it's working. Please post this as an answer so I can accept it =) – stevendesu May 20 '13 at 13:12

17 Answers17

52

In my case - wkhtmltopdf version 0.12.2.1 (with patched qt) - adding a base tag to the head section with the absolute path made sure images and css did get loaded.

<html>
<head>
...
<base href="http://www.example.com/">
<link href="/assets/css/style.css" rel="stylesheet">
...
</head>
10us
  • 1,622
  • 18
  • 13
30

If you're on Linux, check the ownership of your images. For Windows, you will find some info on http://code.google.com/p/wkhtmltopdf/wiki/Usage.

I tried different kind of paths to the image:

  1. <img src="file:///var/www/testpdf/flowers.jpg">
  2. <img src="./flowers.jpg">
  3. <img src="flowers.jpg">
  4. <img src="/var/www/testpdf/flowers.jpg">

All images are shown correctly. I didn't use any command line arguments (only wkhtmltopdf /var/www/testpdf/makepdf.html makepdf.pdf)

Reed Dunkle
  • 3,408
  • 1
  • 18
  • 29
Bass Jobsen
  • 48,736
  • 16
  • 143
  • 224
  • 30
    hei, why this answer be voted? I haven't found any solution to your question? Now i'm facing the same problem, image can't be captured in pdf, but show well in browser. – Awakening Apr 18 '16 at 08:11
  • 1
    Solution #4 worked for me. If you use linux console just write the command "pwd" to get the current server path. – Tomkay Sep 20 '16 at 09:20
  • 1
    The only one that works for me is #1 : file:///var/www/path/to/my/project/and/assets/flowers.jpg – ArGh Apr 06 '17 at 13:07
  • It's been years since I had this issue and I couldn't say specifically why I chose this answer, but my guess is that upon inspecting the permissions I found the file ownership was wrong. – stevendesu Feb 28 '18 at 16:36
  • Using #1 also worked for me when trying to generate a PDF with a lot of images (+-150). – cristiancastrodc Jul 18 '19 at 03:05
  • 2nd and 3rd options didn't work on both linux and windows. – Deepesh Kumar Aug 08 '19 at 18:07
  • this helped me figure out how to solve my problem. had related problem with "how to load custom font in css file" and this tells you quite a bit `src: url("./proxima-bold.otf") format("opentype");` – equivalent8 Sep 28 '20 at 10:19
21

For Windows you need to use absolute file system paths in your markup. For instance:

<link href='C:\Projects\Hello\Hello.Web\Content\custom\home.css' rel='stylesheet' type='text/css' />

! not http://localhost/Hello.Web/Content/custom/home.css

Vince I
  • 570
  • 5
  • 22
vladimir
  • 13,428
  • 2
  • 44
  • 70
  • 1
    Latest version work for me with a local setup (i.e. http://localhost/Hello.Web/Content/custom/home.css) They may have fixed this. Though relative paths were still not working for me on windows. – Scott Flack Apr 18 '16 at 00:16
  • I use this lib (old version, without namespaces) in Yii2, and link worked for me too:`= Html::img(Url::to('@web/images/settlement-raports/label.png', true)); ?>`, where `to()` method returns `http://mp.local/images/settlement-raports/label.png`. – Boolean_Type Apr 27 '16 at 17:28
  • This worked for me. The images weren't rendering properly, and now they finally are. – Anonymous12332313 Sep 19 '21 at 04:41
  • 1
    This may help Razor / cshtml developers to avoid hard-coding the absolute path: `` – Markus May 13 '22 at 15:47
21

In order to have them embed, you can insert base64 encoded images like :

<img src="data:image/png;base64,someBase64content"/>
6opko
  • 1,718
  • 2
  • 20
  • 28
YemM
  • 331
  • 2
  • 5
11

When a browser renders your HTML, it uses a relative path (sometimes with a URL at the beginning of it) like this:

<img src="/static/images/some_picture.png">
<img src="http://www.example.com/static/images/some_picture.png">

But when WkHTMLtoPDF is running on your server, it's interfacing with your local files directly through the filesystem, not through a web server. So for local files, unlike a browser, WkHTMLtoPDF wants the actual filepath:

<img src="/var/www/myapplication/static/images/some_picture.png">

(This worked for me with Python Flask)

Josh
  • 2,790
  • 26
  • 30
5

on Windows use path: file:///C:/some/dir/some/file.img (notice the tripple /)

paranoiq
  • 69
  • 1
  • 4
5

It is may be too late :)

BTW, just add this config into your options in last.

options = {'enable-local-file-access': None}
pdfkit.from_string(html, 'filename.pdf', options=options)
Dhana D.
  • 1,670
  • 3
  • 9
  • 33
sumiya
  • 51
  • 1
  • 3
3

After taking in everyone's kind assistance from here and around the net, I discovered something that worked for me - coding in asp.net (c#).

I needed to access the image by url (not file path), as the original source html still needed to be accessed. Through troubleshooting, I discovered these points.

  1. These flags had to be passed in to the command line process: "-q -n --disable-smart-shrinking --images --page-size A4"

  2. URL still has to be absolute.

  3. Image must be a jpg! I was originally trying to do a gif, to no avail.

  4. I discovered adding "--enable-local-file-access" didn't help, as it requires '\' slashes in the image path instead of '/' slashes, which doesn't help if you also hope to use the source html (in some browsers). Also, if you need to access the local file system, you need to provide an absolute path, as it reads straight from the root and goes from there.

Hope this helps others.

Cheers

-y

Yves
  • 39
  • 2
3

I know this is quite old topic, but I've just faced the same issue and maybe it will help to someone.
I tried different approaches, like css background image and using string as base64 encoded data image. Sometimes it helped, sometimes not - no particular rule I could found.
It turned out that upgrading library wkhtmltopdf solved the problem. I was using version 0.12.0 and upgraded to 0.12.3

wladimirec
  • 339
  • 4
  • 6
  • What was your process for upgrading to 0.12.3? – Joel Mar 16 '16 at 12:59
  • 1
    @Joel Upgrade has been made just by replacing binaries. However I'm afraid my judgment was too quick. It doesn't solve the problem at all, but it happens less frequently I think. General problem is when I'm trying to generate PDF from multiple input html files. The only solution I found so far is to convert every input HTML one by one and finally merge them into single PDF using some other library. – wladimirec Mar 17 '16 at 10:43
  • OK, finally it turned out the problem was related to OS somehow. For me problem occurs on ubuntu 10.04, but it has never happen again after upgrade to 12.04. – wladimirec Apr 04 '16 at 13:51
3

make sure you have the latest version of wkhtmltopdf with patched qt.
you can implement a helper that flask jinja uses it to distinguish if the template is for rendering or only generating pdf, or maybe both.
let' say that tmpl_bind is the data object to bind in the template, add a new key tmpl_bind["pdf"] set it True or False.
when using wkhtmltopdf or pdfkit, add enable-local-file-access to options object.
now create a helper function called static_file

def static_file(filename, pdf=False):
    # wkhtmltopdf only read absolute path
    if pdf:
        basedir = os.path.abspath(app.root_path)
        return "".join([basedir, "/static/", filename])
    else:
        return url_for('static', filename = filename)  

as we say, wkhtmltopdf for some os only read files when you include their absolute path. Note that you may add or remove parts from the app.root_path, according to your app structure, but this will work in most of cases.

in app configuration add this line after importing static_file function if it is in another file

app.jinja_env.globals['static'] = static_file

finally, in the template import files, images by calling the static_file helper function

<link href="{{ static('css/style.css', pdf) }}" rel="stylesheet" />
<img src="{{ static('assets/images/logo.svg', pdf) }}" class="logo"> 
alim91
  • 538
  • 1
  • 8
  • 17
2

Just spent a few days on getting a Flask/ Blueprint /static file/ css to be read by wkhtmltopdf, so I thought I'd share what I learned. Win 7, Flask 0.12 on Python 3.4.4, using Pycharm pro, latest pdfkit and wkhtmltopdf.

  1. download the wkhtmltopdf here

  2. install it -mine installed on:

    C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe

  3. right after you import pdfkit into your flask routes.py script ,insert the lines:

    path_wkthmltopdf = r'C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe'

    config = pdfkit.configuration(wkhtmltopdf=path_wkthmltopdf)

(note the "r" in the first line here !! )

  1. when you use pdfkit in a route, add ",configuration = config" as an argument, eg:

    pdfkit.from_string(html_text, output_filename, configuration = config)

this tells pdfkit where to look for wkhtmltopdf. Yes, you need to do this.

  1. NOW in your flask BASE TEMPLATE add , _external = True to your css route, eg:

(this will keep wkhtmltopdf from throwing error cant find css)

  1. NOW (serious bootstrap template juju warning): go into your flask /external libraries /site-packages /flask_bootstrap /templates /base.html template and:

a. fix CSS link:

<link href="{{bootstrap_find_resource('css/bootstrap.css', cdn='bootstrap')}}" rel="stylesheet" media="screen">

add "http:" so it looks like:

<link href="http:{{bootstrap_find_resource('css/bootstrap.css', cdn='bootstrap')}}" rel="stylesheet" media="screen">

b. fix JS links:

add "http:" so the JS links look like:

<script src="http:{{bootstrap_find_resource('jquery.js', cdn='jquery')}}"></script>

<script src="http:{{bootstrap_find_resource('js/bootstrap.js', cdn='bootstrap')}}"></script>

and with all this

your flask html to pdf conversion

using pdfkit and wkhtmltopdf

should run without errors.

note: I moved to flask from PHP and if you are a flask-er, please post your solutions up here. The flask community is MUCH smaller than the PHP community so we all have to pitch in.

Regolith
  • 2,944
  • 9
  • 33
  • 50
pelon
  • 129
  • 1
  • 2
2

This is probably due to SE Linux or firewall rules that prevent you from going out on the internet and back to your own server. You can update your host file to point calls to your domain back to your machine's home address.

E W
  • 21
  • 1
2

What fixed it for me was removing the references to my CSS files. It turned out I had was setting img { max-height: 100%; } in an otherwise-empty div so that was being interpreted as max-height: 0.

So check out your CSS and there might an issue there. This worked:

<div><img src="image.png"/></div>

And running command line in the directory with image.png:

wkhtmltopdf example.html example.pdf

But this does not:

<div><img src="image.png" style = "max-height: 100%; "/></div>

Because the image gets squished to 0 height. Firefox seems to correct this so it wasn't obvious.

1

For me the problem was resolved by doing two things: 1: In your app/config/config.yml
- Under the knp_snappy
- For the option temporary_folder write ./
- i.e: temporary_folder: ./
2: Now in your html.twig pages remove the asset and write:
From:

 <link rel="stylesheet" type="text/css" href="{{ asset('css/default_template.css') }}">
To:
 <link rel="stylesheet" type="text/css" href="css/default_template.css">

And after that, it worked for me.

Hopefully i've helped somebody. Thank you !

Tiesco
  • 21
  • 5
1

To generate your pdf with your images or styles you need to provide the server path as follows:

<img src="https://upload.wikimedia.org/wikipedia/...image.png" />

<link href="http://localhost:8080/css/file.css" media="all" rel="stylesheet" type="text/css" />

Note this second link, it's the local address to your stylesheet, or could be a remote like the first link. The file path didn't work for me, only the server path to the resource.

Ps: In my situation, I am using spring boot in Intellij IDE and I needed to invalidate cache of IDE and not run in debug mode in order to work, otherwise it may be not update things.

Guilherme Alencar
  • 1,243
  • 12
  • 21
1

URL of images must be absolute not relative. Check this working example in a twig template:

<img src="{{ absolute_url(asset('images/example.png')) }}"/>
numediaweb
  • 16,362
  • 12
  • 74
  • 110
0
opt = dict()
opt["orientation"] = "landscape"
opt["enable-local-file-access"] = ""
config = pdfkit.configuration(wkhtmltopdf='/usr/bin/wkhtmltopdf')

enable local file access to access images