md2star.pptx_audit module
Model-free audit of an assembled deck: what a reviewer would catch by eye.
md2star.pptx_fit decides, before assembly, whether a slide’s content
should fit a candidate layout. This module asks the complementary question
after assembly, of the saved .pptx itself: given the shapes that actually
exist, with the geometry and the font sizes they actually carry, is anything
wrong with this deck? Six checks, all arithmetic on OOXML — no model, no
render, no network:
off-slideA shape extends past the canvas. Content that nobody will ever see.
overlapTwo text shapes cover the same region, or a picture covers part of a text shape: words with a photograph laid over them (or under them) are as unreadable as words over words. A picture filling most of the canvas (
BACKDROP_SHARE) is a backdrop, the photo-hero composition, and is not counted. A one-glyph ornament (md2star.pptx_assemble.is_ornament()) does not count as one of the two — a “01” inside a title’s generous box is a designer’s composition too, and cloned pages are full of them.ghost-placeholderA placeholder the slide inherited from its layout and never filled. The assembler removes these (see
md2star.pptx_assemble.drop_empty_placeholders()); this is the invariant re-checked on the file, which is the only place it matters.illegible-typeA run below
LEGIBLE_MIN_PT. Not the 30 pt ideal — the size below which a projected slide stops being readable at all.low-contrastText a reader cannot separate from what is behind it, by the WCAG ratio (sRGB-linearised relative luminance), against the 3:1 floor large type earns and the 4.5:1 floor small type does not. The backdrop is resolved the way a renderer resolves it — shapes under the text, then the slide’s background, then the layout’s shapes and background, then the master’s — because on a real template the colour panel a heading sits on is a shape on the layout while the layout’s own background is the other half of the slide. Only runs that state their own colour are judged, and a backdrop this module cannot read (a photograph, a gradient) is left unjudged rather than guessed at.
under-min-ptOnly with
min_pt(md2star audit --min-pt 30): slide content set under that size — Kawasaki’s 30 pt, enforced instead of observed. Footer chrome is not content: date / footer / slide-number placeholders, any shape holding a field (<a:fld>, e.g. the page number), and a single line of text in the bottom 12 % of the slide are exempt. A photo credit (a shape namedmd2star-credit, seemd2star.pptx_assemble.add_credit()) is exempt from this, fromillegible-type,overrunandoverlap: it is small and over its picture by design. Its contrast is still judged.overrunThe text needs more room than its box gives it at the size it declares. Reported with the size that would fit, because PowerPoint’s auto-shrink means the consequence is quiet (smaller type), not visible (clipped text). An observation about the deck’s density, in the same spirit as
md2star.pptx_fit.KAWASAKI_MIN_PT: a finding, never an error.
Why bother, when md2star.pptx_assemble.eyeball_slides() already shows
each slide to a vision model? Because that loop needs a resolved VLM,
LibreOffice and poppler, while every failure above is measurable.
A geometry bug deserves arithmetic, not an opinion — and this way the quality
gate still runs on a laptop with no model at all, which is md2star’s whole
offline-by-default posture. The dimensions are the ones PPTEval scores a deck
on by eye (Design: “proper layout … element placement, and absence of
overlaps”, arXiv 2501.03936); this is the half of that rubric a machine can
settle on its own.
- md2star.pptx_audit.BACKDROP_SHARE = 0.8
Share of the canvas above which a picture is a backdrop (a full-bleed photo with a title on it, by design) rather than a picture placed beside words.
- md2star.pptx_audit.BLEED_TOLERANCE = 0.01
How far past the canvas edge a shape may sit before it counts as bleeding off the slide, as a fraction of the canvas. Designer templates routinely bleed a background band a hair past the edge on purpose, and rounding EMU through inches leaves sub-point residue, so an exact test would cry wolf.
- md2star.pptx_audit.CHROME_BAND = 0.12
Share of the slide’s height, from the bottom, where a single line of text is footer chrome (a course name, a page number) for
under-min-pt.
- md2star.pptx_audit.CONTRAST_LARGE_PT = 18.0
1 of it against its background instead of the 4.5:1 it asks of body copy. A slide is mostly large type by that definition, which is why the floor here is usually the lenient one — and why a run that falls under it is a real problem rather than a strict reading of a web rule.
- Type:
WCAG 2.x calls type large at 18 pt, or 14 pt when bold, and asks 3
- md2star.pptx_audit.DEFECT_KINDS = frozenset({'ghost-placeholder', 'illegible-type', 'low-contrast', 'off-slide', 'overlap', 'under-min-pt'})
The kinds that are defects rather than observations, and so decide the exit status. An overrun is left out on purpose: PowerPoint auto-shrinks the text, so a dense deck is a choice, not a breakage. –strict counts it too.
- class md2star.pptx_audit.Finding(slide, kind, detail, shape='', measured_pt=None, fits_pt=None)[source]
Bases:
objectOne thing wrong with one slide.
- Parameters:
- measured_pt, fits_pt
An
overrun’s declared size and the size that would fit.Nonefor every other kind, where the question does not arise.- Type:
float or None
- measured_pt: float | None = None
the size the text declares, and the size that would fit. Carried as numbers, not only inside detail, because the eyeball loop consumes this (see
md2star.pptx_assemble._measured_verdict()) and a loop that reads them can apply the exact correction instead of nudging toward it.- Type:
For an
overrun
- md2star.pptx_audit.KINDS: tuple[str, ...] = ('off-slide', 'overlap', 'ghost-placeholder', 'illegible-type', 'under-min-pt', 'low-contrast', 'overrun')
Every finding kind this module can report, in descending severity. Used to order a report and to keep the vocabulary closed (a typo’d kind in a caller would otherwise sort and summarise silently).
- md2star.pptx_audit.LEGIBLE_MIN_PT = 12.0
Point size below which a projected slide stops being readable from the back of a room. Deliberately far below
md2star.pptx_fit.KAWASAKI_MIN_PT(30 pt): that is the ideal this project reports against, while this is the floor under which something has gone wrong — a caption nobody can read.
- md2star.pptx_audit.OVERLAP_TOLERANCE = 0.1
Shared area, as a fraction of the smaller shape’s own area, above which two text shapes are judged to collide. A few percent is a touching corner; a tenth of a shape is a legibility problem.
- md2star.pptx_audit.audit(deck, *, canvas=None, min_pt=None)[source]
Audit a saved
.pptx, slide by slide.- Parameters:
deck (pathlib.Path) – The assembled presentation to inspect. Read-only; nothing is written.
canvas (tuple of int, optional) –
(width, height)in EMU to measure against. Defaults to the deck’s own slide size, which is what you want unless you are checking a deck against a different target canvas.min_pt (float, optional) – Also report content text under this size (
under-min-pt).
- Returns:
Sorted by slide, then by descending severity (
KINDSorder). Empty means the deck passed every check.- Return type:
Examples
>>> findings = audit(Path("deck.pptx")) >>> print(summarise(findings)) layout audit: clean (12 slides)
- md2star.pptx_audit.log_findings(findings)[source]
Send each finding to the logger at a level that matches its severity.
- md2star.pptx_audit.run(deck_path, *, as_json=False, strict=False, min_pt=None)[source]
md2star audit <deck.pptx>— measure a deck and report what is wrong.Works on any presentation, not only the ones md2star built: everything it checks is read off the OOXML, so a deck somebody made in PowerPoint is just as auditable. No model, no render, no network.
The flags arrive parsed: since 3.10.0 this package has exactly one command line, built with click in
md2star.cli, so nothing here re-parses an argv.- Parameters:
deck_path (str) – The
.pptxto inspect. Never modified.as_json (bool, optional) – Emit the findings as JSON instead of one line each plus a summary.
strict (bool, optional) – Also fail on
overrun, which is otherwise an observation.min_pt (float, optional) – Fail on content text under this size (
under-min-pt); footer chrome is exempt.
- Returns:
0when nothing but observations were found,1when a defect was (seeDEFECT_KINDS, and strict),2on a usage or read error.- Return type:
- md2star.pptx_audit.summarise(findings, *, slides=None)[source]
One line fit for stdout: what the audit found, or that it found nothing.
- Parameters:
- Returns:
A single line, never empty.
- Return type:
Examples
>>> summarise([], slides=12) 'layout audit: clean (12 slides)' >>> summarise([Finding(3, "overlap", "x")]) 'layout audit: 1 finding on 1 slide (1 overlap)'