Skip to main content

Module pdf

Module pdf 

Source
Expand description

The sheet’s PDF output contract — a minimal PDF 1.4 writer, no crate (1.7 when it carries a 3D model; see the last section).

The same SheetDrawing the SVG writer serialises, written as pages of stroked paths and text: ONE FILE for a list of sheets, one page per sheet in the order given, each page’s MediaBox its own paper size in points (the paper is millimetres, a point is 1/72 inch), each drawing in a single uncompressed content stream, and text set in the standard Helvetica base font with WinAnsi encoding. No compression, no embedded font, no transparency, no xobject — a file a text editor can read, whose xref table points at real byte offsets. Every byte is ASCII: a character outside printable ASCII is written as an octal escape inside its string literal, so the file has no binary section and needs no binary marker.

§The object graph

1  Catalog   /Pages 2 0 R
2  Pages     /Count n  /Kids [5 0 R 7 0 R … (5 + 2(n−1)) 0 R]
3  Font      Helvetica, WinAnsiEncoding — shared by every page
4  Info      /Title (the document) /Producer (BREP) /HiddenLine (…)
5  Page 1    /Parent 2 0 R  /MediaBox [0 0 w₁ h₁]  /Contents 6 0 R
6  stream    page 1's marks
7  Page 2    /Parent 2 0 R  /MediaBox [0 0 w₂ h₂]  /Contents 8 0 R
8  stream    page 2's marks
…

The page tree is FLAT: one Pages node whose kids are every page. A balanced tree only matters to a reader seeking into thousands of pages, and a drawing set is not that; flat is what the specification’s own minimal example is. A single sheet is the one-page case of the same writer (to_pdf), not a second one.

§The frame

PDF’s origin is the page’s BOTTOM-left with y running UP; a sheet is measured from the TOP-left with y running down. Every coordinate therefore goes through [point], which flips y about the page height — and a text run’s rotation flips with it, which is why the text matrix turns by the NEGATIVE of the drawing’s angle ([text_matrix]).

§What the PDF cannot carry that the SVG does

Two things, both about what a file says ABOUT itself rather than what it draws:

  • The grouping and the ids. An SVG placement is a <g id="SV2" data-view="VIEW1" data-scale="4"> a reader can select, script or style, and a placement that could not project carries its reason in a <desc>. This writer draws the marks only: the geometry is identical, the labelling is not there. A refused placement is therefore INVISIBLE in the PDF where the SVG says why it is blank — the panel and sheet_state are where that answer lives for both.
  • Characters outside WinAnsi. The SVG hands any Unicode string to whatever renders it; a Helvetica base font is a 256-glyph encoding. What is drawn is what encode_winansi can map: Latin-1 plus the CP1252 punctuation, with ⌀ written as Ø (the substitution every drawing standard already treats as the diameter sign) and − U+2212 as a hyphen. Anything else — the fourteen GD&T characteristic symbols an FCF cell draws, CJK in a note — becomes ?. Everything the dimension formatter itself emits (digits, ., ±, °, ⌀, parentheses, /) IS carried.

§Which pass drew the lines

The Info dictionary’s /HiddenLine says it for the whole file: (analytic) when every placement that projected was drawn by the exact pass, and (mesh: Sheet 1 SV2, …) naming each one the mesh approximation drew — a placement whose B-rep had not reached the scene when the file was written (ViewDrawing::hidden_line). An export from a background runner can write a sheet no one has shown yet, and this is how that file says so.

Everything else the SVG has is here: the same millimetres, the same visible edge runs, the same annotation lines and text, the same border and title block, the same stroke widths, and the same real text (selectable and searchable, not stroked outlines).

§The one exception: a live 3D model

write_pdf_3d can carry the model in 3D (super::pdf3d) — over a placement marked threeD, and on a last page given over to it. That file is PDF 1.7, its pages carry /Annots (the 3D annotations and the view buttons), and each 3D annotation has a form xobject as its (empty) appearance. It is still all ASCII: the U3D stream is ASCII85-encoded. A file that asks for no 3D is not touched by any of this — write_pdf is the no-3D case of the same writer, and its bytes are what they were.

Constants§

PT_PER_MM
PDF user-space units per millimetre — a point is 1/72 of an inch.

Functions§

encode_winansi
text in WinAnsi (CP1252) bytes. A character the encoding has no glyph for becomes ? — see this module’s header for what that costs.
string_literal
text as a PDF string literal’s CONTENTS (no parentheses): WinAnsi bytes, with (, ) and \ escaped and everything outside printable ASCII written as a three-digit octal escape, so a content stream stays readable ASCII.
text_strings
Every text string a PDF this module wrote shows, in page order: each (…) Tj literal read back from the file’s own bytes — escapes undone and WinAnsi decoded, so a ⌀ the writer substituted reads Ø and a U+2212 a hyphen, which is what the file says. What the export door reports ABOUT the file, so a script can assert the drawing’s text without a PDF reader.
text_width
A string’s advance in ems, from Helvetica’s own metrics.
to_pdf
Serialise one sheet as a one-page PDF titled with the sheet’s name — the one-page case of write_pdf.
write_pdf
Serialise pages as one PDF titled title, one page per sheet, in order, each at its own paper size.
write_pdf_3d
write_pdf, carrying a live 3D model (super::pdf3d) when three_d is given: a 3D annotation over each placement it names, and — when it asks for one — a last page given over to the model with a button per saved view.