Skip to content

Fix missing thin outlines in BDN XML / Blu-ray SUP export#12372

Merged
niksedk merged 1 commit into
mainfrom
feature/fix-image-export-outline
Jul 11, 2026
Merged

Fix missing thin outlines in BDN XML / Blu-ray SUP export#12372
niksedk merged 1 commit into
mainfrom
feature/fix-image-export-outline

Conversation

@niksedk

@niksedk niksedk commented Jul 11, 2026

Copy link
Copy Markdown
Member

Fixes #12206

At small outline widths (1–2) the outline vanished on horizontal glyph edges (top of T, E, H, …) in image-based exports, varying with font and font size — e.g. Franklin Gothic/Arial at size 44 lost top outlines while other sizes lost horizontal or vertical ones. v4.0.16 rendered the same settings correctly.

Root cause

Two compounding problems in ImageRenderer.RenderTextToCanvas:

  1. The outline stroke was centered on the glyph edge, so only outlineWidth / 2 extended outside the glyph — and the fill drawn on top covered the inner half. At width 1, only half a pixel of outline could ever be visible.
  2. Stroking through the glyph rasterizer applies font hinting, which snaps horizontal edges to the pixel grid. The surviving half-pixel rim landed in the same pixel row as the fill's antialiased edge, and the opaque fill blended over it — leaving ~50% alpha light-gray pixels (rgba(169,169,169,130)) instead of a black outline. Whether anything survives depends on where the cap-height edge lands on the pixel grid, which explains the font/size dependence reported in the issue.

Fix

  • Build the shaped text outline as an SKPath (via SKShaper glyph positions, preserving HarfBuzz shaping) and stroke the path directly, bypassing the hinted glyph rasterizer.
  • Stroke with 2× the requested width — the fill covers the inner half, so the visible outline matches the requested width (same semantics as ASSA/libass and v4's GDI+ path rendering).
  • Disable hinting on export fonts so the fill edges stay registered with the raw path geometry (export renders at video resolution; hinting is not needed).

The same treatment is applied to the shadow outline pass. Glyphs without outline paths (e.g. color emoji) simply get no stroke; fills are unchanged.

Verification

Headless harness calling ImageRenderer.GenerateBitmap with white text / black outline width 1, "THE HEIGHT", Arial/Tahoma/Helvetica at sizes 44/45/53. Per-column check for outline pixels above the topmost fill pixel:

Columns missing top outline
Before ~98–100% in every font/size combination
After 0 in every combination

Visual inspection at 4× zoom confirms a clean, uniform 1px outline on all edges, and a styled sample (bold/italic/font color + shadow + outline) renders correctly. LibUiLogicTests (6) and SeConvTests (217) pass.

🤖 Generated with Claude Code

At small outline widths (1-2) the outline vanished on horizontal glyph
edges in BDN XML / Blu-ray SUP export, depending on font and font size.

Two causes: the stroke was centered on the glyph edge, so only half the
requested width was outside the glyph and the fill drawn on top covered
the rest; and stroking through the hinted glyph rasterizer snapped
horizontal edges to the pixel grid, letting the fill wash out what
little outline remained.

Stroke the raw shaped glyph path with doubled width instead (the fill
covers the inner half, so the visible outline matches the requested
width), and disable hinting on export fonts so fill and outline stay
registered.

Fixes #12206

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@niksedk niksedk merged commit 3e74c9a into main Jul 11, 2026
1 of 3 checks passed
@niksedk niksedk deleted the feature/fix-image-export-outline branch July 11, 2026 20:13
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.

Outline witdh incorrectly applied in BDN XML / SUP Exports

1 participant