printpdf XML syntax

November 7, 2024 ยท View on GitHub

To optimize for small compile size and quick PDF rendering, the XML syntax does not support all features like wkhtmltopdf does, but it's close enough to be usable in practice.

The XML syntax intentionally doesn't support everything that HTML does, however, it's easier to configure than LaTeX or other proprietary-ish XML formats.

Basic structure

The <body> node will automatically break into pages, depending on whether

<html title="Document title">
    <head>

        <header exclude-pages="1"> <!-- do not render header on page 1 -->
            <p style="color:red">This will be at the top of each page</p>
            <hr style="color:green;">
        </header>

        <footer>
            <hr style="color:blue;"> <!-- do not render footer on page 1 -->
            <p style="color:black">This will be at the bottom of each page</p>
        </footer>

        <!-- 
            CAREFUL: In difference to standard CSS, this 
            is applied AFTER the inline styling, to allow 
            for overriding the styles of preconfigured components 
        -->
        <style>
            * { color: red; }
        </style>
    </head>
    <body style="padding:10mm">

        <!-- 100% width / height corresponds to the page width / height -->
        <!-- so this will fill up exactly one page -->
        <div class="titlepage" style="width:100%;height:100%;">
            <h1>Title of my book</h1>
        </div>

        <!-- this will be rendered on the second page -->
        <div class="titlepage" style="width:100%;height:100%;">
            <h1 style="background:yellow;font-family:sans-serif;">Hello World!</h1>
            <!-- temp1.png has to be added to the XMLRenderingOptions image map-->
            <!-- 1px = 1mm in the PDF -->
            <img src="temp1.png" style="width:500px;height:500px"></img>
        </div>

        <!-- The layout system is similar to flexbox with minor differences: -->
        <!-- First, everything will be expanded to its MINIMUM size (text, images, etc.) -->
        <!-- Then, if space is still remaining and flex-grow > 0, the space will be expanded -->
        <!-- to its maximum, while respecting max-width / max-height -->

        <!-- So, this div will take up one entire page, since no max-height is set -->
        <div style="background:blue;padding:10px;display:flex;flex-grow:1;">

        </div>
    <body>
</html>

CSS features

keyexample values
displayblock, inline-block, flex (default)
floatleft, right, both
box-sizingborder-box, content-box
colorred, green, ..., #efefef, rgb(), rgba(), hsl(), hsla()
font-size10px, 5pt, 40%, 10em, 5rem
font-familysans-serif, serif, ..., "Times New Roman"
text-alignleft, center, right
letter-spacing0.0 - infinite
line-height0.0 - infinite
word-spacing0.0 - infinite
tab-width0.0 - infinite
width10px, 5%, 10rem, 5em
height10px, 5%, 10rem, 5em
min-width10px, 5%, 10rem, 5em
min-height10px, 5%, 10rem, 5em
max-width10px, 5%, 10rem, 5em
max-height10px, 5%, 10rem, 5em
positionstatic (default), relative, absolute, fixed
top10px, 5%, 10rem, 5em (+position:absolute / fixed)
right10px, 5%, 10rem, 5em (+position:absolute / fixed)
left10px, 5%, 10rem, 5em (+position:absolute / fixed)
bottom10px, 5%, 10rem, 5em (+position:absolute / fixed)
flex-wrapwrap, no-wrap
flex-directionrow, column, row-reverse, column-reverse
flex-grow0.0 - infinite
flex-shrink0.0 - infinite
justify-contentstretch, center, flex-start, flex-end, space-between, space-around
align-itemsstretch, center, flex-start, flex-end
align-contentstretch, center, flex-start, flex-end, space-between, space-around
overflowoverflow[-x, -y] auto (default), scroll, hidden, visible
padding10px, 5%, 10rem, 5em
margin10px, 5%, 10rem, 5em
backgroundred, [linear-, radial-, conic-]gradient(), image(id)
background-position10% 10%, 10px 10px, left top
background-sizeauto, cover, contain, 10% 40%, 100px 200px
background-repeatrepeat, no-repeat
border-radius10px, 5%, 10rem, 5e
border-top-left-radius10px, 5%, 10rem, 5em
border-top-right-radius10px, 5%, 10rem, 5em
border-bottom-left-radius10px, 5%, 10rem, 5em
border-bottom-right-radius10px, 5%, 10rem, 5em
border, border-[top, ...]1px solid red, 10px dotted #efefef
border-top-width10px, 10rem, 5em (NO PERCENTAGE)
border-right-width10px, 10rem, 5em (NO PERCENTAGE)
border-left-width10px, 10rem, 5em (NO PERCENTAGE)
border-bottom-width10px, 10rem, 5em (NO PERCENTAGE)
border-top-stylesolid, dashed, dotted, ...
border-right-stylesolid, dashed, dotted, ...
border-left-stylesolid, dashed, dotted, ...
border-bottom-stylesolid, dashed, dotted, ...
border-top-colorred, green, ..., #efefef, rgb(), rgba(), hsl(), hsla()
border-right-colorred, green, ..., #efefef, rgb(), rgba(), hsl(), hsla()
border-left-colorred, green, ..., #efefef, rgb(), rgba(), hsl(), hsla()
border-bottom-colorred, green, ..., #efefef, rgb(), rgba(), hsl(), hsla()
opacity0.0 - 1.0
transform matrix(), translate(), scale(), rotate(), ...
perspective-origin100px 100px, 50% 50%
transform-origin100px 100px, 50% 50%
backface-visibilityvisible (default), hidden
box-shadow0px 0px 10px black inset
background-colorred, green, #efefefaa, rgb(), rgba(), hsl(), hsla()
background-imageid("my-id")