Skip to main content

Module write

Module write 

Source
Expand description

Document writer: a NEW PDF, one full-page JPEG per page, optional embedded ICC profile.

The editing half of this crate changes existing files; this module creates one from nothing, for print, slideshow and book exports that place a JPEG on every page.

use rightkit_pdf::write::Document;
let mut doc = Document::new("1.4")?;
let srgb = doc.add_icc_profile(srgb_profile_bytes, 3)?;
doc.add_jpeg_page(595.0, 842.0, jpeg_bytes, Some(srgb))?;
let pdf: Vec<u8> = doc.finish();
doc.write_to(path)?; // feature `edit`: rightkit-fs atomic replace

§What is written

  • The header is %PDF-<version> (1.0 to 1.7) plus the binary-marker comment, then a classic cross-reference table (no object or xref streams), so a PDF 1.4 reader accepts it.
  • Per page: /Page with /MediaBox [0 0 w h], a content stream q w 0 0 h 0 0 cm /Im0 Do Q, and an image XObject with /Filter /DCTDecode, /BitsPerComponent 8. The JPEG bytes are copied unchanged (no re-encoding).
  • Colour space: /DeviceRGB (3 components) or /DeviceGray (1), or, when an ICC profile is chosen, [/ICCBased n 0 R] with the profile as a stream (/N, /Alternate). A profile is written once however many pages use it.
  • Deterministic: object numbers follow insertion order, no dates, no /Info, and the trailer /ID is the SHA-256 of the body. The same calls give the same bytes.

§Limits

  • JPEG: baseline, extended-sequential or progressive Huffman (SOF0, SOF1, SOF2), 8 bits per component, 1 or 3 components. 4-component (CMYK/YCCK, whose Adobe inversion needs a /Decode array), 12-bit, lossless and arithmetic-coded files are refused, not guessed. The ICC profile’s component count must equal the JPEG’s.
  • The ICC profile is checked for the acsp signature at byte 36 and a header of at least 128 bytes, not for validity. Streams are stored uncompressed (this module has no deflate).
  • One image per page, full page, no rotation or crop: the image is stretched to the media box, so pass the JPEG’s own aspect ratio.
  • Text (feature fonts, on by default): Document::add_font takes a TrueType font (glyf/loca outlines, .ttf or a TrueType collection face; CFF/OpenType-CFF is refused by the subsetter) and Document::draw_text draws a string with it. At finish each used font is subset to exactly the glyphs drawn (font::subset_for_pdf) and embedded as Type0 / CIDFontType2 / FontFile2, /Encoding /Identity-H, /CIDToGIDMap /Identity, a /W widths array and a ToUnicode CMap, so CJK or any covered script is real, selectable text. The string is shown as 2-byte glyph codes in a hex string; there is no shaping, kerning, bidi or line breaking (one draw_text call is one run at one point), and a character the font has no glyph for is refused (WriteError::MissingGlyph), never substituted. A font whose OS/2 fsType forbids embedding or subsetting is refused. Text is painted after the page image. Subset tags and /BaseFont are derived from the font and the glyph set, so output stays deterministic.
  • The PDF is built in memory; lopdf is used by the tests to read it back.
  • Not embedded: font hinting programs beyond what the subsetter keeps, /CIDSet, glyph variations (a variable font is written at its default instance, as the subsetter does).

Structs§

Document
A PDF being built. See the module documentation.
FontId
Handle to a font added with Document::add_font.
IccId
Handle to an ICC profile added with Document::add_icc_profile.
JpegInfo
What a JPEG header says.
PageId
Handle to a page added with Document::add_page (its zero-based index).

Enums§

WriteError

Constants§

MAX_PAGE_SIDE_PT
Longest page side accepted, in points (the PDF 1.4 implementation limit, 200 inches).