Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

CLI reference

Every option of the sghtmltopdf command.

sghtmltopdf [OPTIONS] <INPUT.HTML>
sghtmltopdf server [OPTIONS]

The first converts a file; the second runs the HTTP server.

For how these map to wkhtmltopdf’s options, including the full list of the ones that are not supported, see the wkhtmltopdf option mapping.

Basics

# The simplest form; the system fonts are used
sghtmltopdf invoice.html -o invoice.pdf

# Without an output path, the input name with the extension changed to .pdf
sghtmltopdf invoice.html

# Read from standard input and write to standard output
cat invoice.html | sghtmltopdf - -o - > invoice.pdf

Input and output

OptionDefaultDescription
<INPUT.HTML>(required)The input HTML; - means standard input
-o, --output <PATH>The input name with .pdfWhere to write. - means standard output. It cannot be omitted when reading from standard input
--base-url <URL|DIR>The directory of the input HTMLThe base for resolving relative references. An http(s) URL becomes the default <base href>; a <base href> in the HTML wins
--encoding <NAME>DetectedThe character encoding of the input. The order is BOM, then --encoding, then <meta charset>, then UTF-8
--streamingOffProcess in streaming mode

The output is written to a temporary file and then renamed, so a failure never leaves a broken PDF behind.

Page setup

OptionDefaultDescription
-s, --page-size <SIZE>A4A3, A4, A5, Letter, or Legal, case insensitive
--page-width <LENGTH>The paper width; takes precedence over --page-size
--page-height <LENGTH>The paper height; takes precedence over --page-size
-O, --orientation <O>PortraitLandscape swaps width and height at the end
-T, --margin-top <LENGTH>1in (96px)Top margin
-B, --margin-bottom <LENGTH>1inBottom margin
-L, --margin-left <LENGTH>1inLeft margin
-R, --margin-right <LENGTH>1inRight margin

Lengths take the units mm, cm, in, pt, and px. A bare number means mm, as in wkhtmltopdf.

How this relates to @page in CSS

These options are initial values. If the CSS in the HTML says @page { size: … } or @page { margin: … }, the CSS wins, property by property. Note that this is the opposite of wkhtmltopdf.

Fonts

OptionDescription
--font <PATH>The font to use; may be given more than once. Without it, system fonts are used
--font-index <N>The face index inside a TrueType Collection (.ttc), for the preceding --font
--gothic-font <PATH> (with --gothic-font-index)The font behind font-family: sans-serif
--serif-font <PATH> (with --serif-font-index)The font behind font-family: serif
--mono-font <PATH> (with --mono-font-index)The font behind font-family: monospace
--disable-system-fontsNever search the system fonts; typeset with only the fonts you passed

Fonts are resolved in the order --font, then @font-face, then a system search by font-family name. Only if none of those finds anything does a system sans-serif candidate become the default font.

Without --font, the output depends on the fonts of the machine it runs on. To keep output stable on a server or in CI, name the fonts with --font or @font-face. See Fonts for details.

Even when you name fonts with --font, a face that is missing from them (the italic of font-family: serif, for example) is filled in from the system, so the output still depends on the machine it runs on. --disable-system-fonts stops that search altogether, so the same HTML gives the same PDF on any machine; characters that could not be covered are reported as a warning and left undrawn.

PDF output and metadata

OptionDefaultDescription
--title <TEXT>The <title> of the HTMLThe /Title of the PDF
--author, --subject, --keywords <TEXT>The matching entries of the Info dictionary; specific to sghtmltopdf
-d, --dpi <DPI>96How many dpi a CSS px stands for. At 72, 1px equals 1pt
--zoom <FACTOR>1.0A scale factor, multiplied into the --dpi factor
-g, --grayscaleOffConvert fills and strokes to greyscale, by sRGB relative luminance
--no-pdf-compressionOffTurn off Flate compression of PDF objects; image data is unaffected

/Producer and /CreationDate are always written.

The limits of greyscale

JPEG images, which pass through as /DCTDecode, and CMYK images have no decoder here, so they stay in colour.

What gets drawn

OptionDescription
--no-imagesDo not load <img> or the CSS background-image
--no-backgroundDo not paint element backgrounds, neither colour nor image
--user-style-sheet <PATH>CSS in the user origin; may be given more than once. Stronger than the UA stylesheet, weaker than the author’s CSS
--minimum-font-size <PX>A lower bound on the computed font-size
--disable-external-linksDo not create PDF annotations for external http(s) links
--disable-internal-linksDo not create PDF annotations for internal #id links
--keep-relative-linksWrite relative external links as they are, without making them absolute
--load-media-error-handling <ignore|abort>What to do when an image, stylesheet, or font cannot be fetched; ignore by default

Headers and footers

There are two ways to do this. If both are given for the same side, --header-html wins.

1. As text

These map onto the margin boxes of @page.

sghtmltopdf report.html \
  --header-center "Quarterly report" \
  --footer-right "[page] / [topage]" \
  --header-line
OptionDescription
--header-left, --header-center, --header-right <TEXT>The three positions across the header
--footer-left, --footer-center, --footer-right <TEXT>The three positions across the footer
--header-font-name, --header-font-sizeThe header font; the footer has the same pair
--header-line, --footer-lineDraw a rule
--header-spacing, --footer-spacing <MM>The gap from the body text; the margin grows by that much
--default-headerA default header with the title and the page number
--replace <NAME=VALUE>Replace any [NAME] with a value; may be given more than once

The placeholders are [page] for the current page, [topage] for the total page count, [frompage], [title] and [doctitle], [date], [time], and any name you define with --replace.

[section], [subsection], [webpage], [sitepage], and [sitepages] are not supported.

2. As HTML

An HTML string can be passed directly with header_html_content: / footer_html_content: (CLI: --header-html-content / --footer-html-content), with no temporary file. header_html: / footer_html: still take a file path. Giving both a path and a string for the same side is an error. Placeholders, images and margins behave the same as with a file. The HTTP server accepts them too, but the HTML then travels in the query string, so mind URL length limits and access logs.

sghtmltopdf report.html --header-html header.html --footer-html footer.html

A separate HTML file is rendered into the margin area of every page. Placeholders are substituted in the HTML as text; JavaScript is not executed.

  • Anything that does not fit in the margin is clipped; the margin does not grow to accommodate it
  • Images embedded as data: URLs work in <img> and background-image (PNG, JPEG, WebP, SVG; SVG needs the svg feature). --no-images applies here too
  • No external resources are fetched. Images from local files or remote URLs, and external CSS, are not supported
  • @font-face inside the header or footer HTML is not loaded. Name any font used only there with --font

Cover page and table of contents

sghtmltopdf report.html --cover cover.html --toc --footer-center "[page]"

They are written in the order cover, table of contents, body.

OptionDefaultDescription
--cover <PATH>The HTML to use as the cover. It is not counted in the page numbers and gets no header or footer
--tocOffInsert a table of contents before the body; not available in streaming mode
--toc-header-text <TEXT>Table of ContentsThe <h1> of the table of contents
--toc-level-indentation <WIDTH>1emThe indent added per level
--toc-text-size-shrink <REAL>0.8The text size ratio applied per level
--disable-dotted-lines(drawn)Do not draw the dotted leader under each entry
--disable-toc-links(linked)Do not link the entries to their headings
--enable-toc-back-links(not linked)Link each heading back to the table of contents
--page-offset <N>0Shift where the page numbering starts

The HTML structure and default styling of the table of contents follow what wkhtmltopdf’s default TOC XSL produces: nested <ul> for the levels, and <div><a>heading</a><span>page number</span></div> for each entry. To change how it looks, apply CSS with --user-style-sheet; XSLT is not supported.

Headings are collected from h1 through h6. A heading without an id is given a generated destination name.

Access control

OptionCLI defaultServer default
--enable-local-file-access, --disable-local-file-accessAllowedDenied
--allow-path <PATH>No restrictionNo restriction
--allow-remote-assetsDeniedDenied

Given one or more --allow-path directories, local references are confined to those directories. This applies to <img src>, external CSS, and @font-face alike.

Ranges

References outside the base directory

Local references stay inside the base directory (--base-url, defaulting to the directory the input HTML lives in) by default. A ../ that would escape it is an error. This keeps untrusted HTML from reading arbitrary files through a reference such as <img src="../../../../etc/passwd">.

A ../ that resolves within the base directory, such as assets/../images/logo.png, keeps working as before.

Name the range explicitly with --allow-path when you mean to reference a file outside it. Once --allow-path is given, the boundary is the allowed directories rather than the base directory.

$ sghtmltopdf pages/index.html -o out.pdf
error: ../images/logo.png: the reference points outside the base directory (pages).
  To read files outside it, name the directory with --allow-path

$ sghtmltopdf pages/index.html --allow-path . -o out.pdf

The check is lexical, so symlinks under the base directory are followed. Use --allow-path when you want the boundary to hold across symlinks as well (that check resolves real paths).

A reference starting with /

A reference starting with /, such as /assets/logo.png, is first resolved relative to the site root, that is, to the base directory (<base directory>/assets/logo.png). That is the shape the Rails asset pipeline emits, so pointing the base directory at a precompiled public/ resolves it as it is.

Only when there is no file there is the same string read again as a filesystem path. It is the fallback for a document written as <img src="/var/www/app/public/logo.png">. What may be read is then decided by the same rules as for any other reference: an absolute path inside the base directory is read as it is, one outside it needs --allow-path.

When neither reading finds a file, the error names both paths.

Limits on input size

HTML with more than roughly 500,000 nodes is rejected. Computed styles, the box tree and the layout result all grow in proportion to the node count; measured at 472 B to 1210 B per node.

Even a document of several thousand pages stays in the hundreds of thousands of nodes, so real documents practically never hit this. If you do hit it, split the document or use streaming mode. Streaming releases each processed part as it goes, so it can convert documents whose total exceeds the limit.

Memory that scales with the amount of text is not covered by this limit (three elements holding 10 MiB of text still use about 1.7 GiB). In HTTP server mode --max-body-size plays that role.

Logging and exit codes

--log-level <none|error|warn|info>, info by default, and -q or --quiet, which is the same as --log-level none.

CodeMeaning
0Success
1Usage error: an unknown option, a malformed value, or an option that is not supported
2Input or resource error: a missing file, a font that cannot be read, or a failed fetch under abort
3Rendering error, such as breaking one of the streaming mode restrictions
4Time limit exceeded (HTTP server mode’s --timeout only; the CLI has no time limit, so this never appears)