Skip to content

Export vector PDF pages: ink as paths, text as text, images as images - #95

Merged
marcosqlbi merged 1 commit into
mainfrom
feature/export-e4-vector-pdf
Sep 3, 2026
Merged

Export vector PDF pages: ink as paths, text as text, images as images#95
marcosqlbi merged 1 commit into
mainfrom
feature/export-e4-vector-pdf

Conversation

@marcosqlbi

Copy link
Copy Markdown
Collaborator

Why

Phase E4 of docs/export.md, on top of #94 (base is the E3 branch; retarget to main once it merges). A picture page is exact but soft under zoom and dead to selection. A reader who wants to copy the DAX off a page, or print at any size, needs the text to be text and the ink to be paths.

What it does

  • Page content: Picture or Vector, a choice on the Export dialog for PDF, with Picture the default because it is exact.
  • Vector reuses the editable slide's element list, with one difference: the ink goes out as strokes in their own z-order between the containers rather than as one overlay, because a path costs nothing to layer correctly.
  • A stroke is the sweep of its nib. For each pair of points the writer fills the convex hull of the two nib polygons, which is exactly the area a convex nib sweeps along a segment, and joins every hull into one path filled once with the non-zero rule, so a translucent stroke does not darken where it overlaps itself. The nibs follow WPF: a pen is an ellipse whose diameter is thickness × 2 × pressure, a highlighter a flat rectangle with no pressure drawn at half opacity when its color is opaque, calligraphy a tall bar following pressure.
  • Text is laid out in the writer: paragraphs on line breaks, runs measured left to right, wrapped at the last space that fits, in the language's font at the board's size, clipped to the container as the board clips it. Fonts are embedded as subsets of Segoe UI and Consolas from the Windows fonts folder, with Arial and Courier New standing in.

Where the code is

  • SQLBI.Whiteboard.Export/ExportPage.cs: SlideInkElement, SlideStroke, SlidePoint.
  • PdfDocumentWriter: draws elements into the rectangle the picture would have used; the font resolver serves both families in four styles.
  • EditableSlide builds strokes in z-order when asked; ExportSettings and the dialog gain the page content choice.
  • Smoke tests write a vector page with a pen, a highlighter, a calligraphy stroke, and a dot, and check that the text's font is embedded.

The smaller calls are under E4 in docs/export-decisions.md; decision 26 is updated.

🤖 Generated with Claude Code

@marcosqlbi
marcosqlbi force-pushed the feature/export-e3-editable-deck branch from c20fe20 to 94a3ad7 Compare September 3, 2026 18:27
@marcosqlbi
marcosqlbi force-pushed the feature/export-e4-vector-pdf branch from 18fb9bb to 87cb28f Compare September 3, 2026 18:27
@marcosqlbi
marcosqlbi force-pushed the feature/export-e3-editable-deck branch from 94a3ad7 to 6b416d9 Compare September 3, 2026 21:54
@marcosqlbi
marcosqlbi force-pushed the feature/export-e4-vector-pdf branch from 87cb28f to 86bdf04 Compare September 3, 2026 21:54
Base automatically changed from feature/export-e3-editable-deck to main September 3, 2026 21:58
Phase of docs/export.md squashed onto its base after the previous phase merged; the tree is unchanged.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
@marcosqlbi
marcosqlbi force-pushed the feature/export-e4-vector-pdf branch from 86bdf04 to d738e3c Compare September 3, 2026 21:58
@marcosqlbi
marcosqlbi merged commit c208457 into main Sep 3, 2026
5 checks passed
@marcosqlbi
marcosqlbi deleted the feature/export-e4-vector-pdf branch September 3, 2026 22:03
marcosqlbi added a commit that referenced this pull request Sep 3, 2026
## Why

Phase E5 of [docs/export.md](docs/export.md), on top of #95 (base is the
E4 branch; retarget to `main` once it merges). The automatic cut serves
a board drawn without a deck in mind. Someone preparing a board for a
deck wants to say where the slides are, and on a whiteboard the way to
say it is to draw a rectangle. Decision 27 is the summary.

## What it does

- **View → Frame** (mnemonic A) adds a frame the size of the visible
board, titled "Slide n", and selects it. Drag its edge to move it, the
handle to resize it (aspect kept, so it stays slide-shaped), F2 to
rename it, Delete to remove it, Bring to front and Send to back to
reorder it, which under Drawing order is also the slide order.
- **A frame is selected by its edge or its title tab, never by its
inside**, so everything in it stays reachable to the pen and the mouse.
Moving a frame moves nothing inside it: it is a label over content, read
at export time.
- **A frame is not a container.** It links no strokes and takes no part
in the single-container test, so a frame drawn around a picture does not
stop ink from linking to the picture.
- **Frames win in the partitioner**: whatever sits inside one is that
slide, with the frame's rectangle and title; frames come first; the rest
of the board is cut as before. Frames appear in no export picture, no
overview, and no `preview.png`.
- **The archive version moves to 6 only for a board that holds a
frame.** A board without one is still written as version 5 and keeps
opening in every release since format 5.

## Where the code is

- `Core/Model`: `FrameBoardObject` with its edge-and-tab hit test;
`BoardDocument.HitTestTopContainer` takes the zoom and reaches frames by
their edge; `BoardArchive` writes and reads `frame`, choosing the
version per board.
- `Core/Export/BoardPartitioner`: frames first.
- `SQLBI.Whiteboard`: `BoardSurface` draws frames over everything when
asked and the rasterizer and preview renderer ask it not to;
`MainWindow` gains the command, the rename, and frame cases in the
gesture code; `FrameTitleWindow` is the rename dialog.
- Smoke tests: archive round trip and version choice, partition with a
frame, hit testing.

The smaller calls are under E5 in
[docs/export-decisions.md](docs/export-decisions.md).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Fable 5.1 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant