ChromicPDF - PDF generator

You can always use some paid service to convert the html to pdf for you. Then you don’t need to worry about it.

Search for “html to pdf as a service”

But, having said that, basic docker understanding will not harm you :wink: Very useful nowadays.

You can also use the wkhtmltopdf program but then you’d likely have the same problem.

So either Docker or a small VPS which you can fully control.

Yes, there was a service I looked at earlier in this journey when I was converting from a csv download using Panpipe, but I wasn’t building .html then. But now that I am it’s good to be reminded that I should revisit that. Easy to route a call to another api …
In the meantime I’m watching a Docker tutorial :slight_smile:

@shotleybuilder Sorry for the late reply

I’d be very interested to hear if you could get ChromicPDF to work on a Windows host. It should theoretically be able to communicate with the remote debugging channel through pipes on Windows as well, but maybe the command line switches are different.

a named env variable ‘chromium’

Does you mean the binary is called chromium? Otherwise, here’s the list of executable names ChromicPDF tries to launch Chrome with. If you need it to look for chrome.exe, you could try to checkout the library locally, configure it as local dependency {:chromic_pdf, path: "..."} in your project, and add chrome.exe to this list.

With regards to deployment: Yes, docker is definitely your best option. Then, you also don’t need to get it running on Windows anymore :slight_smile:

1 Like
3 Likes

Just released version 1.0 :tada:

See the Changelog for recent additions and changes.

Thanks to everyone who took interest into this little project of mine!

5 Likes

This looks interesting.
Right now I’m building PDFs using CSS3-paged-media and https://docraptor.com. ChromicPDF with https://www.pagedjs.org/ could be an alternative.

@maltoe there is a broken link in the readme: https://hexdocs.pm/chromic_pdf/examples/phoenix

For anyone interested in generating high quality PDFs I highly recommend https://print-css.rocks/

@Sebb thanks for letting me know, fixed the link.

@maltoe Thanks for this great package - makes pdf generation a lot easier!

Is there a way to link a stylesheet in the footer template?

Currently I’m

  • rendering a footer template
  • converting it to a string with HTML.safe_to_string()
  • adding it as a footer with ChromicPDF.Template.source_and_options()
  • and generating a temporary file with ChromicPDF.print_to_pdf(), that is being downloaded in the :output callback

I’m linking a stylesheet in the footer via an absolute path like this:
<link rel="stylesheet" href="<%= AppWeb.Endpoint.static_url() %><%= Routes.static_path(@conn, "/assets/app.css") %>"/>
This works well for the PDF content but when I link the stylesheet in the footer I get the following error:

** (exit) an exception was raised:
    ** (RuntimeError) Timeout in Channel.run_protocol/3!

The underlying GenServer.call/3 exited with a timeout. This happens when the browser was
not able to complete the current operation (= PDF print job) within the configured
5000 milliseconds.

If you are printing large PDFs and expect long processing times, please consult the
documentation for the `timeout` option of the session pool.

If you are *not* printing large PDFs but your print jobs still time out, this is likely a
bug in ChromicPDF. Please open an issue on the issue tracker.

Any suggestions?

Hey @timkonieczny

to be honest I’ve never tried loading an external stylesheet in the header or footer templates. We usually have some kind of PDFView helper module (like Phoenix.View but with added PDF-related functionality) which has functions to render the stylesheets inline into the markup. See the examples/phoenix directory for an example of how something like this can be done (though it can also be done totally differently :slight_smile: )

I reproduced the behaviour you’ve seen and took a look into the protocol messages: it turns out the inspector is crashing when you give it external URLs in the footer/header templates (at least on Chrome 96) - so I guess the answer to your question is: “No, it doesn’t work.”

%{"method" => "Inspector.targetCrashed", "params" => %{}, "sessionId" => "8041679B6EF313C3F4346A7C239D4F91"}

I’ll add a note about this to the docs, and perhaps extend the error message of this exception a bit to include the last message received or so. Thanks for letting me know.

Best,
malte

1 Like

img tags don’t crash, by the way, but simply remain unloaded. So my best guess is that the header/footer renderers don’t have network connectivity at all, plus for some reason the link tag makes the inspect explode. :man_shrugging: Chrome is weird.

Instead of using the header/footer you could use CSS3 paged media and https://www.pagedjs.org/. So you get full control over the page.

1 Like

@Sebb indeed, pagedjs is great. Though it is kind of the “cool thing” about Chrome / ChromicPDF that you don’t really need it for simple use-cases. The header/footer templates work pretty nicely, also on multipage setups.

Thanks @maltoe and @Sebb for the clarification and the suggestions! Sounds like Chrome is indeed a bit odd.

Hey @maltoe
Thanks for the hard work and this nice lib
It works like a charm

Sometimes I need to print very (>>very<<) large pdf files and the memory consumption jumps too high

Would it be possible support transferMode as ReturnAsStream?

If you think is something achievable I could try to implement it. (I’m pretty newbie in Elixir though)

Hey @danferreira

The streaming mode is something I’ve always wanted to support (and basically replace the default “give-me-the-full-blob” mode with it), and yes, of course it should be generally possible to do. However, it won’t be easy, both in terms of additional parts of the protocol needed to be implemented (i.e. how to read from the returned stream) and in terms of refactoring of the library architecture.

Could you open an issue in the repository? If you want to tackle it, feel free to take a look, and we can discuss ideas there. If you think it’s too hard, I’d also give it a try at some point, but can’t make any promises about the timeline, unfortunately.

cheers & thanks for your kind words!
malte

3 Likes

Thank you for this. It’s very useful.

1 Like

Hello @maltoe Any guides to make this work on Docker with Alpine image?

Thanks

Edit: Sorry for my lack of research. I tried to use google-chrome-stable but chromium-browser works just fine

EDIT: Edited, didn’t mean to be passively aggressive :slight_smile:

2 Likes

Hello @maltoe. Just came across your lib and put it to work in the current project. Over the last number of years I always used https://wkhtmltopdf.org/ with very good results (Yes, I read your text saying that you might not be able to concur) so I’d normally do the same this time. Especially that there is a well established Elixir wrapper for it. But this project is a little different than previous ones. There I typically had a “web view” and “print view” separated, both with different markup. This way I was able to fine-tune the markup fed to wkhtmltopdf independently from the browser window view of the same document. This worked excellent for me. In this project though I want users to be able to press the key combination they usually press in order to print the webpage, and have the printed (or browser-pdf-exported) document looking the same as it looks on a generated PDF. This is where things start to be “less than optimal” for wkhtmltopdf if I don’t want to scale back the browser view to the HTML and CSS, which wkhtmltopdf can chew. Especially Flexbox stuff is problematic for it. This is an understandable result if the underlying WebKit hasn’t been updated for a long while. Therefore, all in all looks like a perfect moment to give a stab at something else then.

Theoretically I could still use the PdfGenerator as it currently supports generating PDFs through Chrome too but the first point on your features list is such a teaser that I couldn’t resist :wink: I mean the part about “Node.js” of course…

So, I’ve got the first document saved in PDF format relatively quickly, proving that your thing actually works :wink: Moreover the output looks the same in the PDF generated from ChromicPDF and the one “printed to PDF” from browser window. This is exactly what was needed and while it was to be expected it is still nice to see this be in fact the case. So far this is all great (and here comes the “but”) but…

  • whether pooled or “on_demand” it is slow. About 2 to 2.5 times slower than processing the same HTML with `wkhtmltopdf. This means that while I was usually able to deliver generated PDFs synchronously in less than a second even under some load, over two seconds with no load begs for async processing (and a job queue!)
  • the output is “bloated”. This type of documents comes out of wkhtmltopdf as about 40KiB. Maybe 50 KiB on occasions. Chrome puts out not less than five times as many bytes…

Please don’t get me wrong - this is not a complaint about things I know you have little to no influence on. It is more for others about what to expect if someone finds himself in a position similar to mine: I really don’t feel like rewriting the whole, fine-tuned markup for wkhtmpltopdf and manually (well, “eyeually”) testing – how else? – that the two generation paths deliver visually the same result. All in all I haven’t yet 100% decided but I am very much tending towards ChromicPDF. Vision of writing two sets of markup for each type of document, and especially maintaining them later in visual sync is a highly un-promising one :wink: