Images and custom fonts in API-rendered PDFs
pdfrender loads nothing from the network. Put images, fonts and CSS into the HTML as data: URIs, as shown here.
Last updated
pdfrender loads only data: URIs, so images, fonts and stylesheets go
into the HTML itself. A URL with http(s), file or ftp, or an @import,
fails the request with status 400 (external_resource_blocked). The error
lists every URL.
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==" alt="Logo">
<style>
@font-face {
font-family: "Inter";
src: url("data:font/woff2;base64,d09GMgABAAA...") format("woff2"); /* shortened */
}
body { font-family: "Inter", sans-serif; }
</style>
Relative URLs such as logo.png are dropped without an error, so check the
PDF for missing images.
Encode a file
This shell command works with the base64 of Linux and macOS:
printf 'data:image/png;base64,%s' "$(base64 < logo.png | tr -d '\n')" > logo.uri
The same in Python:
import base64
uri = "data:image/png;base64," + base64.b64encode(open("logo.png", "rb").read()).decode()
Use the MIME type of the file: image/png, image/jpeg, image/svg+xml,
font/woff2 or font/ttf.
Size budget
The 2 MB limit counts the UTF-8 bytes of the html field, including
every data: URI. Base64 makes a file about a third larger. Subset fonts to the
characters you use and scale images to print size.
Next step
FAQ
- Why does pdfrender reject external image and font URLs?
- pdfrender loads nothing from the network, so a render cannot hang on a slow server or reach internal addresses. The error lists every URL to inline.
- Do inlined assets count against the size limit?
- Yes. The 2 MB limit counts the whole html field, and base64 makes each file about a third larger.