Skip to content

Export image: honor <font face> and <font size> per segment - #14477

Merged
niksedk merged 1 commit into
mainfrom
claude/subtitleedit-discussion-14476-0f8977
Sep 3, 2026
Merged

niksedk merged 1 commit into
mainfrom
claude/subtitleedit-discussion-14476-0f8977

Conversation

@niksedk

@niksedk niksedk commented Sep 3, 2026

Copy link
Copy Markdown
Member

Fixes the report in discussion #14476: when exporting to Blu-ray sup (and every other image-based export), an inline <font face="..."> was ignored and every line rendered with the global Font name from the dialog, while the color attribute of the very same tag was honored per line.

Cause

ImageRenderer read only the color attribute of a <font> tag. The segment model carried italic/bold/colour but no face or size, and the four fonts (regular, bold, italic, bold-italic) were created once per image from the dialog font. SE4's exporter honored both face= and size=, so this was a regression.

Change

  • <font face="..."> and <font size="..."> are parsed (quoted, single-quoted or bare values, any attribute order) and carried on the text segment; the dialog font is only the default for text outside such a tag, matching how color already worked.
  • Fonts are made on demand and cached per render (FontSet) keyed by face/size/bold/italic. Unknown faces fall back exactly as an unknown dialog font does.
  • Each line's box comes from the tallest tagged font on it, so a <font size> makes only its own line taller. Untagged text keeps the dialog font's line box exactly - bold/italic variants do not count - so plain/italic/bold subtitles render pixel-identically to before and the PGS/VobSub export: subtitle images change vertical position depending on text content #13202 baseline stability holds. A tag can grow a line, never shrink it below the dialog font's box.
  • <font size> nested inside <font color> now keeps the colour (the old parser reset it to the default).
  • size is in the same unit as the dialog font size (what SE4 did, and what libass does for an SRT <font size>). ASSA {\fs..} is in script resolution, so ApplyStyleOverrideTags now sets ImageParameter.TagFontSizeScale to ScreenHeight / PlayResY, the same way it scales \bord / \shad. The export dialog, batch convert and seconv all already call it.
  • Box-per-line and the advanced text effects paths (both the layered and the glyph-geometry variant) use the same per-line baselines.

Tests

tests/libuilogic/Export/ImageRendererFontTagTests.cs (15 tests): face tag renders with that font and per line; size tag matches the dialog at that size, grows only its own line, never shrinks the line box; colour + face in one tag; nested colour/size; bare attributes; unknown face and bad size values; box-per-line; both text-effect paths; ASSA \fs scaling; no-tag rendering unchanged. Full LibUiLogicTests (774) and the UI ImageRenderer*/ExportImage* tests pass.

🤖 Generated with Claude Code

The image renderer read only the color attribute of a <font> tag, so a
line tagged face="Papyrus" was drawn with the global dialog font while
its color from the same tag was applied - SE4 honored both face and size
(discussion #14476).

Segments now carry their own face/size. Fonts are made on demand and
cached per render (FontSet) instead of a fixed regular/bold/italic/
bold-italic set, and each line's box comes from the tallest tagged font
on it, so a <font size> makes only its own line taller. Untagged text
keeps the dialog font's line box exactly, so plain/italic/bold subtitles
render as before (issue #13202 baseline stability).

A <font size> inside a <font color> now keeps the colour (the old parser
reset it). ASSA "{\fs..}" is in script resolution, so
ApplyStyleOverrideTags sets ImageParameter.TagFontSizeScale like it
scales \bord/\shad.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@niksedk
niksedk merged commit 3a1dbed into main Sep 3, 2026
1 check passed
@niksedk
niksedk deleted the claude/subtitleedit-discussion-14476-0f8977 branch September 3, 2026 10:03
@niksedk niksedk mentioned this pull request Sep 4, 2026
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