Page templates: margins, columns, headers, footers and pagination.
A template describes the shape of a page once; render_document/4 then
flows text through as many copies of it as the content needs, numbering them
as it goes.
template =
Template.new(page_size: :a4, margins: {50, 50, 50, 50}, columns: 2)
|> Template.with_header("Quarterly Report", size: 14)
|> Template.with_footer("Page {page} of {total}")
{pdf, result} = Template.render_document(Tincture.new(), template, rich_text){page} and {total} in a header or footer are substituted per page. When
the total is not supplied it resolves to each page's own number, because the
real total is not known until pagination finishes — pass :page_total
explicitly if the document's length is known in advance.
render_document/4 stops at :max_pages (50 by default) and reports what
did not fit, so runaway content cannot generate an unbounded document.
XML templates
parse_xml/1 and render_xml_document/3 build the same thing from markup,
for cases where the layout is authored outside the code:
<document page_size="a4" margins="50,50,50,50" columns="2">
<header font="Helvetica-Bold" size="14">Quarterly Report</header>
<footer size="9">Page {page} of {total}</footer>
<body font="Times-Roman" size="11">...</body>
</document>
Summary
Types
@type document_option() :: Tincture.Layout.Box.option() | {:page_number_start, pos_integer()} | {:page_total, pos_integer()} | {:max_pages, pos_integer()}
@type option() :: {:page_size, Tincture.PDF.page_size()} | {:margins, margin_tuple()} | {:columns, pos_integer()} | {:gutter, number()} | {:header_height, number()} | {:footer_height, number()}
@type t() :: %Tincture.Layout.Template{ body_boxes: [box()], columns: pos_integer(), footer: Tincture.Layout.Template.Slot.t() | nil, footer_height: float(), gutter: float(), header: Tincture.Layout.Template.Slot.t() | nil, header_height: float(), margins: %{left: float(), right: float(), top: float(), bottom: float()}, page_size: Tincture.PDF.page_size() }
Functions
@spec parse_xml(String.t()) :: {:ok, t(), Tincture.Typography.RichText.t()} | {:error, xml_error()}
@spec render(Tincture.PDF.t(), t(), Tincture.Typography.RichText.t(), [ Tincture.Layout.Box.option() ]) :: {Tincture.PDF.t(), Tincture.Layout.Template.RenderResult.t()}
@spec render_document(Tincture.PDF.t(), t(), Tincture.Typography.RichText.t(), [ document_option() ]) :: {Tincture.PDF.t(), Tincture.Layout.Template.DocumentResult.t()}
@spec render_xml_document(Tincture.PDF.t(), String.t(), [document_option()]) :: {:ok, Tincture.PDF.t(), Tincture.Layout.Template.DocumentResult.t()} | {:error, xml_error()}
@spec with_header(t(), String.t(), [slot_option()]) :: t()