NativeElixirPdfUtilities.HtmlToPdf (native_elixir_pdf_utilities v1.0.0)

View Source

Public facade for native HTML/CSS to PDF rendering.

Supported controls generate interactive AcroForm fields by default. Set forms: :static for static artwork. Names use HTML name or a generated TYPE_PAGENR_ELEMENT key; see the forms guide.

The renderer is intentionally structured as a small pipeline:

  • parse HTML into a document tree
  • compute styles
  • resolve every text grapheme to an available font
  • lay out the styled tree
  • paginate layout boxes
  • write PDF bytes

The supported surface is a strict, document-oriented HTML/CSS subset. Malformed structure and unsupported features return errors instead of using browser-like guessing. Unsupported text graphemes are visibly replaced by default. See the HTML-to-PDF compatibility guide for the current element, CSS, layout, image, and font support.

Summary

Types

Context supplied to a caller-provided asset resolver.

A callback that supplies bytes without giving the renderer network access.

Caller-approved bytes or a trusted local asset file.

An explicitly tagged inline stylesheet or local stylesheet file.

Functions

Renders an HTML document to a PDF binary.

Reads an HTML file, renders it to PDF, and writes the PDF to output_path.

Types

asset_request()

@type asset_request() :: %{
  reference: String.t(),
  kind: :image | :background_image | :font
}

Context supplied to a caller-provided asset resolver.

asset_resolver()

@type asset_resolver() :: (asset_request() ->
                       {:ok, binary()} | :not_found | {:error, term()})

A callback that supplies bytes without giving the renderer network access.

asset_source()

@type asset_source() :: {:bytes, binary()} | {:file, String.t()}

Caller-approved bytes or a trusted local asset file.

detailed_error_reason()

@type detailed_error_reason() :: {error_reason(), error_detail()}

error_detail()

error_reason()

@type error_reason() ::
  :invalid_document
  | :invalid_css
  | :invalid_encoding
  | :invalid_form
  | :invalid_html
  | :invalid_layout
  | :invalid_margin
  | :invalid_options
  | :invalid_outlines
  | :invalid_page_size
  | :invalid_path
  | :invalid_pdf_input
  | :not_implemented
  | :resource_limit_exceeded
  | :unsupported_form
  | :unsupported_glyph
  | :unsupported_html
  | File.posix()

outlines()

@type outlines() ::
  :headings | [NativeElixirPdfUtilities.Outlines.item_input()] | false | nil

page_furniture()

@type page_furniture() ::
  [header: page_furniture_variants(), footer: page_furniture_variants()]
  | %{
      optional(:header) => page_furniture_variants(),
      optional(:footer) => page_furniture_variants()
    }

page_furniture_template()

@type page_furniture_template() :: String.t() | false | nil

page_furniture_variants()

@type page_furniture_variants() ::
  page_furniture_template()
  | [
      default: page_furniture_template(),
      first: page_furniture_template(),
      odd: page_furniture_template(),
      even: page_furniture_template()
    ]
  | %{
      optional(:default) => page_furniture_template(),
      optional(:first) => page_furniture_template(),
      optional(:odd) => page_furniture_template(),
      optional(:even) => page_furniture_template()
    }

page_margin()

page_size()

pdf_metadata()

@type pdf_metadata() ::
  keyword()
  | %{
      optional(:title) => String.t(),
      optional(:author) => String.t(),
      optional(:subject) => String.t(),
      optional(:keywords) => String.t() | [String.t()],
      optional(:producer) => String.t(),
      optional(:creation_date) =>
        Date.t() | NaiveDateTime.t() | DateTime.t() | String.t(),
      optional(:modification_date) =>
        Date.t() | NaiveDateTime.t() | DateTime.t() | String.t()
    }

render_option()

@type render_option() ::
  {:forms, :interactive | :static}
  | {:page_size, page_size()}
  | {:margin, page_margin()}
  | {:base_url, String.t() | nil}
  | {:assets, %{optional(String.t()) => asset_source()}}
  | {:asset_resolver, asset_resolver() | nil}
  | {:stylesheets, [stylesheet_source()]}
  | {:default_font, String.t() | [String.t()]}
  | {:fonts, [map() | keyword() | {String.t(), String.t()}]}
  | {:system_font_discovery, boolean()}
  | {:metadata, pdf_metadata()}
  | {:outlines, outlines()}
  | {:page_furniture, page_furniture() | false | nil}
  | {:unsupported_glyphs, unsupported_glyphs()}
  | {:compress_streams, boolean()}
  | {:subset_fonts, boolean()}

stylesheet_source()

@type stylesheet_source() :: {:css, String.t()} | {:file, String.t()}

An explicitly tagged inline stylesheet or local stylesheet file.

unsupported_glyphs()

@type unsupported_glyphs() :: :replace | :error

Functions

render(html, opts \\ [])

@spec render(String.t(), [render_option()]) ::
  {:ok, binary()} | {:error, detailed_error_reason()}

Renders an HTML document to a PDF binary.

Returns {:ok, pdf_binary} when rendering succeeds or {:error, {reason, diagnostic}} when parsing, styling, layout, pagination, or PDF writing cannot be completed. Rendering failures include a broad reason and diagnostic detail, for example {:error, {:invalid_css, %{message: "...", line: 18, source: "..."}}}.

Supported options include :page_size, :margin, :base_url, :stylesheets, :default_font, explicit local :fonts, :system_font_discovery, PDF :metadata, opt-in :page_furniture headers and footers, PDF :outlines, :unsupported_glyphs, :compress_streams, and :subset_fonts. Stream compression and TrueType font subsetting are enabled by default to keep PDFs small. Set compress_streams: false or subset_fonts: false to opt out. Subsetting retains the original glyph IDs for PDF character mapping and keeps the full font when its license forbids subsetting. Metadata supports title, author, subject, keywords, producer, creation date, and modification date. An HTML <title> supplies the PDF title when metadata[:title] is not set.

Unsupported graphemes are replaced visibly with U+FFFD by default. Set unsupported_glyphs: :error to return an :unsupported_glyph diagnostic instead.

Page furniture accepts :header and :footer HTML templates. Each can be a string used on every page or variants named :default, :first, :odd, and :even. A variant set to false or nil is omitted. The :first variant has precedence on page one, followed by the matching odd/even variant and then :default. Templates can contain {{page}} and {{pages}} tokens. Furniture is disabled when :page_furniture is omitted, nil, or false. Enabled furniture must fit inside the page margin.

Set :outlines to :headings to turn visible h1 through h6 elements into nested PDF bookmarks using their final positions after pagination. An exact outline list accepted by NativeElixirPdfUtilities.Outlines.put/2 may also be supplied. Outlines are omitted by default.

:page_size accepts the CSS named sizes :a5, :a4, :a3, :b5, :b4, :jis_b5, :jis_b4, :letter, :legal, and :ledger, optionally paired with :portrait or :landscape, or a positive {width, height} tuple. Tuple values up to 20 x 20 are interpreted as inches for compatibility with ChromicPDF-style custom label sizes; larger tuples are interpreted as PDF points. CSS two-length strings retain their declared units.

:margin accepts a nonnegative point number, a CSS string containing one to four absolute lengths, or a map with :top, :right, :bottom, and :left values. Explicit renderer :page_size and :margin options override stylesheet @page defaults.

:stylesheets accepts a list of {:css, css} and {:file, path} tuples. The explicit tag determines whether content is parsed directly or read from the local filesystem; bare strings are rejected.

:base_url is also the authorization root for document-selected local image and @font-face paths. Relative paths and absolute paths beneath that root are accepted; traversal outside it and symlink components are rejected. Explicit :fonts and {:file, stylesheet} paths are trusted caller configuration and are not reclassified as document-selected resources.

render_file(input_path, output_path, opts \\ [])

@spec render_file(String.t(), String.t(), [render_option()]) ::
  :ok | {:error, detailed_error_reason()}

Reads an HTML file, renders it to PDF, and writes the PDF to output_path.

Returns :ok after writing the output file or {:error, {reason, diagnostic}} if reading, rendering, or writing fails. Rendering options are the same as render/2.