ChromicPDF is a HTML-to-PDF renderer for Elixir, based on headless Chrome.
Features
- Node-free: In contrast to many other packages, it does not use puppeteer, and hence does not require Node.js. It communicates directly with Chrome's DevTools API over pipes, offering the same performance as puppeteer, if not better.
- Header/Footer: Using the DevTools API allows to apply the full set of options of the
printToPDF
function. Most notably, it supports header and footer HTML templates. - PDF/A: It can convert printed files to PDF/A using Ghostscript, inspired by the
pdf2archive
script originally created by @matteosecli and later enhanced by @JaimeChavarriaga. Created PDF/A-2b and PDF/A-3b files pass the verapdf compliance checks.
Requirements
- Chromium or Chrome
- Ghostscript (for PDF/A support)
Installation
ChromicPDF is a supervision tree (rather than an application). You will need to inject it into the supervision tree of your application. First, add ChromicPDF to your runtime dependencies:
def deps do
[
{:chromic_pdf, "~> 0.4.0"}
]
end
Next, start ChromicPDF as part of your application:
# lib/my_app/application.ex
def MyApp.Application do
def start(_type, _args) do
children = [
# other apps...
ChromicPDF
]
Supervisor.start_link(children, strategy: :one_for_one, name: MyApp.Supervisor)
end
end
Usage
Main API
ChromicPDF.print_to_pdfa(
# URL to of local file to print
{:url, "file:///example.html"},
# Parameters to the PDF renderer, specifically for Chromium's printToPDF function,
# see https://chromedevtools.github.io/devtools-protocol/tot/Page#method-printToPDF
print_to_pdf: %{
# Margins are in given inches
marginTop: 0.393701,
marginLeft: 0.787402,
marginRight: 0.787402,
marginBottom: 1.1811,
# Print header and footer (on each page).
# This will print the default templates if none are given.
displayHeaderFooter: true,
# Even on empty string.
# To disable header or footer, pass an empty element.
headerTemplate: "<span></span>",
# Example footer template.
# They are completely unstyled by default and have a font-size of zero,
# so don't despair if they don't show up at first.
# There's a lot of documentation online about how to style them properly,
# this is just a basic example. The <span> classes shown below are
# interpolated by Chrome, see the printToPDF documentation.
footerTemplate: """
<style>
p {
color: #333;
font-size: 10pt;
text-align: right;
margin: 0 0.787402in;
width: 100%;
z-index: 1000;
}
</style>
<p>
Page <span class="pageNumber"></span> of <span class="totalPages"></span>
</p>
"""
},
# Parameters for the PDF/A converter
info: %{
title: "Example",
author: "Jane Doe",
creator: "ChromicPDF"
},
pdfa_version: "3",
# Output path.
output: "test.pdf"
)
Sample boilerplate for a template
This more sophisticated example shows how to use Phoenix.View
to move HTML markup into template
files.
defmodule MyApp.InvoiceView do
use Phoenix.View,
root: "lib/my_app/path/to/pdf_templates",
namespace: MyApp
def print_to_pdf(assigns) do
[content: content(assigns)]
|> ChromicPDF.Template.source_and_options()
|> ChromicPDF.print_to_pdf()
end
@style File.read!("../path/to/assets/css/invoice.css")
defp content(assigns) do
[
@style,
Phoenix.HTML.safe_to_string(render("content.html", assigns))
]
end
end
Development
For running the full suite of integration tests, please install and have in your $PATH
:
verapdf
- For
pdfinfo
andpdftotext
, you needpoppler-utils
(most Linux distributions) or Xpdf (OSX) - For the odd ZUGFeRD test in
pdfa_generation_test.exs
, you need to download ZUV and set the$ZUV_JAR
environment variable.