P→MPDFMDSystem documentation
Format referenceOpen converter ↗

Reference · Provisional normative

Compact PDFMD 1.0

This page states the public format contract implemented by the project parser, validator, serializer, and Markdown renderer. Formal proposal review and golden-example acceptance remain outstanding.

Conformance boundary. Recognition decides what was observed. PDFMD preserves, validates, and renders that decision. A conforming file is not proof that recognition matches the source.

Meaning, provenance, and uncertainty remain distinct

  1. Canonical text is readable extended Markdown, not a duplicated JSON graph.
  2. Each fact is written once; formatting ranges and views are derived.
  3. Logical reading structure and physical page provenance remain separate.
  4. Unknown, failed, and extension content survives parsing and round trips.
  5. Generated human Markdown is disposable and must not replace PDFMD.
  6. Source text, observed appearance, inference, and user correction remain distinguishable.

Encoding and asset rules

The canonical file uses .pdfmd, UTF-8 without a byte-order mark, Unicode NFC, LF line endings, and exactly one final line feed. A package may use document.pdfmd with content-addressed files below assets/.

assets/sha256-<64 lowercase hexadecimal digits>.<safe extension>

The digest must equal the bytes. Absolute paths, backslashes, .., symlinks, non-regular files, and paths escaping the package root are invalid.

Restricted frontmatter

Required document preface
---
pdfmd: "1.0"
id: example-document
source:
  sha256: <64 lowercase hexadecimal digits>
  pages: 4
coordinates:
  unit: pt
  origin: top-left
  bbox: left,top,right,bottom
required_features: []
---

Allowed values are strings, finite numbers, booleans, null, lists, and string-keyed maps. Duplicate keys, implicit dates, aliases, anchors, merge keys, and custom tags are invalid. Unknown entries are preserved. Unsupported required features stop rendering.

CommonMark plus four bounded constructs

document          = frontmatter block*
block             = commonmark-block | attributed-block | directive | page-break
attributed-block  = attribute-line commonmark-block
attribute-line    = "{" attribute (space attribute)* "}"
directive         = ":::" type space attribute-line newline body? newline ":::"
page-break        = "{{page:" positive-integer "-" positive-integer "}}"
attribute         = "#" id | "." class | key "=" value
value             = bare-token | JSON-quoted-string

Base text follows CommonMark with GFM tables and strikethrough, allowlisted inline HTML, attributes, directives, and page-transition tokens. Directives do not nest in 1.0. A reserved line becomes literal when escaped with one backslash.

IDs are case-sensitive, unique, and required when referenced. Optional extensions use namespaced x-… constructs. Unknown optional extensions are retained with a warning; unknown core constructs are retained with an error rather than guessed.

Common fields

AttributeMeaning
#idStable, unique element address.
p=3 / pages="1-4"One source page or an identical occurrence range.
bbox / polygonRectangular or non-rectangular source geometry.
role / layer / parentSemantic role, physical layer, and relationship.
assetContent-addressed binary evidence.
statecandidate, inferred, confirmed, rejected, unknown, or failed.
confidenceA value from zero to one for the immediately stated fact, not the whole element.

Coordinates default to PDF points with top-left origin, x increasing rightward and y downward. Bounding boxes have non-decreasing edges and fit a declared page size.

Use ordinary Markdown where it is sufficient

MeaningCanonical syntax
Bold / italic / both**text** · *text* · ***text***
Strikethrough / underline~~text~~ · <u>text</u>
Subscript / superscript<sub> · <sup>
Small caps<span style="font-variant: small-caps;">
Text color / highlightdata-text-color · data-background-color

Text highlighting, cell shading, watermark paint, colored handwriting, and decorative fills are separate facts. The HTML allowlist is limited to passive text and table elements with documented attributes. Active HTML, handlers, remote embeds, forms, and unsafe URL schemes are invalid.

Semantics and physical facts Markdown cannot carry

paragraph  page-header  page-footer  page-number  table  footnote  caption  annex
image  figure  diagram  chart  signature  stamp  seal  handwriting  line  unknown
page  page-layout  source-map  entity  relation  evidence  note

A page header is page furniture, never a logical Markdown heading. figure is the generic graphic class; more specific classes are used only when supported. A failed region remains explicit:

:::unknown {#u1 p=6 bbox="210,340,390,410" asset="assets/sha256-…png" state=failed issue=text-recognition-failed}
:::

Physical transitions do not break logical objects

{{page:3-4}} records adjacent, one-based physical source indexes. It never represents printed, annex, Bates, or global page labels. A paragraph, list item, table, or note may contain the token without being split.

Page objects carry size, rotation, and blank-page facts. Headers, footers, and printed numbers use separate directives. Concurrent numbering systems are separate page-number elements. A source-map connects zero-based, end-exclusive Unicode text ranges to source fragments and records joins such as space, line-break, or hyphen-removed.

References in for, from, to, parent, scope, and supersedes resolve to unique IDs. Parent relationships are acyclic. Manual correction preserves the observed value it supersedes. A valid file with explicit unknown or failed regions has partial validation status.

Parsing, serialization, rendering, and diagnostics

Parsing checks, in order: resource limits; restricted frontmatter; attributes, directives, and page markers; Markdown and allowlisted HTML; IDs and references; semantic invariants; assets.

parse(serialize(parse(document))) == parse(document)

Serialization uses normalized Unicode, LF endings, one final LF, and stable top-level spacing. Unknown constructs and malformed source remain in the syntax tree with diagnostics rather than disappearing.

The human renderer consumes the parsed syntax tree and a render profile. Page breaks, headers, footers, numbers, and diagnostics are independent settings. A diagnostic has stable code, severity, message, source location, element ID, and suggestion fields.

Every input form is untrusted

Implementations apply byte, line, block, directive-body, asset, file-count, archive, and expansion limits. They do not fetch external assets, execute PDF actions, scripts, macros, or active HTML, follow package symlinks, or interpret source text as instructions.

The reference limits default to 5 MiB of PDFMD, 200,000 lines, 100,000 blocks, and 2 MiB per directive body. pdfmd uses major.minor: major changes may alter grammar or meaning; minor changes are additive. Optional extensions are namespaced and required extensions are listed in frontmatter.