PdfElixide.Editor.from_markdown/2, from_html/2 and from_plain_text/2 lay text out in a new PDF, and from_images/2 places images on new pages. Each returns an editor. You can edit it further, write it to a file, or return it as a binary:

"# Report\n\nAll **good**."
|> PdfElixide.Editor.from_markdown!(title: "Report")
|> PdfElixide.Editor.save!("report.pdf")
|> PdfElixide.Editor.close()

The text functions are simple typesetters, not the reverse of the document conversion functions. Lines are not wrapped, so break long lines in the source. Editors created this way have no source file and cannot be saved incrementally.

Markdown

Markdown creation recognises # to #### headings, paragraphs, - and * bullets, > quotes, fenced code blocks, pipe tables, and **bold**, *italic* and `code` spans. Block constructs must start at the beginning of an unindented line. Numbered lists, links, deeper headings and indented bullets appear as source text.

Long runs of blank lines can make a later line print over the first line of the page instead of starting a new page, especially on a short custom page. Collapse repeated blank lines in Markdown and HTML input.

HTML

HTML creation accepts fragments rather than complete web pages. It recognises lower-case, attribute-free <h1> to <h4>, <p>, <br>, <b>, <strong>, <i>, <em>, <code>, <pre>, <ul>, <ol> and <li> tags. Ordered and unordered list items both become bullets.

Pass body content with each block on its own unindented line. Source line breaks and indentation are preserved, so pretty-printed or inline block tags may appear as literal Markdown markers instead of receiving their intended formatting. Tags with attributes or upper-case names are not recognised.

Other tags are removed but their contents remain. This includes title, style and script content, so do not pass a complete HTML document. <h5> and <h6> print with literal ##### and ###### markers. Entities are not decoded. A literal < starts a tag-like region and can discard text up to the next > or the end of the input, and a lone > is removed; avoid angle brackets in running text. The remaining text is laid out as Markdown, so Markdown-looking source may be formatted.

Use <pre>x</pre> rather than <pre><code>x</code></pre>: a code tag inside pre is printed as backticks.

Characters and fonts

Markdown and HTML embed a font when the input needs characters beyond Windows-1252. It covers Latin, Greek, Cyrillic, Hebrew, Arabic and common symbols, but not Chinese, Japanese, Korean, Indic or Thai text and many emoji. Missing characters may print as an empty box and disappear from extracted text even though creation succeeds.

Hebrew and Arabic are drawn left to right without Arabic letter joining. Italic becomes upright when the embedded font is used. Code spans, code blocks and tables use Courier and show ? for characters outside Windows-1252.

Plain-text creation uses 12-point Helvetica and accepts Windows-1252 characters only; see PdfElixide.Editor.from_plain_text/2 for the error other characters return.

Images

from_images/2 takes a list of JPEG and PNG binaries and puts each on its own page, in list order:

["page1.jpg", "page2.png"]
|> Enum.map(&File.read!/1)
|> PdfElixide.Editor.from_images!(page_size: :a4)
|> PdfElixide.Editor.save!("scans.pdf")
|> PdfElixide.Editor.close()

Every page has the size given by :page_size. Each image is scaled, up or down and keeping its proportions, until it fills the area inside the four margins in one direction, and is centred in that area. With the defaults, a landscape photo therefore lies across the middle of a Letter page with an inch of white on either side and more above and below.

Pages are not sized to their images. To make a page that matches a single image, give a page size in points computed from its pixel size and the resolution you want it to have, with every margin set to zero. At 300 dots per inch, a 2480 × 3508 pixel scan is 595.2 × 841.92 points:

PdfElixide.Editor.from_images!([scan],
  page_size: {2480 * 72 / 300, 3508 * 72 / 300},
  margin_top: 0,
  margin_bottom: 0,
  margin_left: 0,
  margin_right: 0
)

Because one page size applies to the whole list, images of different shapes in one call cannot each fill their page. Build one editor per image and combine them with PdfElixide.Editor.merge_binary/2 if they must.

A JPEG is embedded without re-encoding, so it keeps its quality and size. A PNG is decoded and its pixels stored losslessly, so an 8-bit PNG keeps every pixel exactly. Transparency is kept, 16-bit channels are reduced to 8 bits, and colour profiles and gamma are ignored. GIF, WebP, TIFF, HEIC and other formats are refused, and so are damaged and very large images; PdfElixide.Editor.from_images/2 lists the errors and size limits.

An EXIF orientation tag is not applied: each image is placed the way its pixels are stored. Phones and cameras often store a photo sideways and record its rotation in that tag, so such a photo comes out sideways, upside down or mirrored, and is laid out by its stored shape. Rotate the pixels first with a tool that applies the tag, such as magick photo.jpg -auto-orient upright.jpg.

CMYK JPEGs are embedded without colour correction, so most of them, including those from Photoshop and ImageMagick, come out with inverted colours. Convert them to RGB first.

Page layout

The three text functions accept page size, top, bottom and left margins, and line spacing. Markdown and HTML also accept a body font size. See PdfElixide.Editor.create_opts/0 and PdfElixide.Editor.plain_text_create_opts/0 for defaults and validation. from_images/2 accepts page size and all four margins; see PdfElixide.Editor.image_create_opts/0.

The text functions have no right-margin option because lines are not wrapped. A custom page must leave enough vertical room for at least two lines and enough horizontal room after the left margin. Invalid layouts raise ArgumentError before the document is created.