Skip to content

Preserve unparseable TTML/SRT color values instead of dropping them - #148

Open
jason-valenzuela wants to merge 2 commits into
asticode:masterfrom
jason-valenzuela:fix/ttml-color-fidelity
Open

Preserve unparseable TTML/SRT color values instead of dropping them#148
jason-valenzuela wants to merge 2 commits into
asticode:masterfrom
jason-valenzuela:fix/ttml-color-fidelity

Conversation

@jason-valenzuela

@jason-valenzuela jason-valenzuela commented Aug 20, 2026

Copy link
Copy Markdown

Problem

newColorFromHTMLString decoded only 6-digit #RRGGBB and 8 named colors. For any other value it returned an error, and both callers — the TTML reader (ttml.go) and the SRT reader (srt.go) — gate on err == nil, so the color was silently discarded on read and omitted on write.

That dropped values which are valid per the specs:

  • #RRGGBBAA (8-digit, with alpha) — valid per TTML1 §8.3.2 and the form IMSC1 mandates for tts:color.
  • Named colors outside the 8 recognized (e.g. silver, gray, maroon, transparent) — part of the TTML1 §8.3.2 <namedColor> set.
  • rgb() / rgba() functional notation.

A TTML in → TTML out (or SRT) round-trip therefore lost styling the source explicitly set.

Fix

  • Add an unexported Color.raw field holding the original expression when it can't be decoded into an RGBA triple; HTMLString() returns it verbatim. So #RRGGBBAA, rgb()/rgba(), transparent, and unrecognized names now round-trip losslessly instead of being dropped.
  • Decode the rest of the TTML1 named-color set (silver, gray, maroon, purple, fuchsia, lime, olive, navy, teal, aqua) into RGBA, reusing the existing Color* vars, alongside the 8 already handled.
  • newColorFromHTMLString can no longer fail, so its now-dead error return is removed and the three call sites simplified to a direct assignment. An empty/blank expression yields a nil color (attribute stays omitted) rather than being flattened to #000000.

Decoded colors still normalize to hex on write (e.g. white#ffffff, silver#c0c0c0), which was already the case for the original 8 and is valid output.

Test

TestColorHTMLRoundTrip covers #RRGGBB and named-color decoding, verbatim round-trip of #RRGGBBAA / transparent / an unrecognized name / rgb(), and empty/blank → nil. gofmt, go build ./..., and go test ./... all pass.

Notes

Scope is intentionally minimal: #RRGGBBAA, rgb()/rgba(), and transparent are preserved verbatim rather than decoded into RGBA. Decoding #RRGGBBAA specifically would need Color to distinguish "alpha absent" from "alpha == 0x00" (the struct's Alpha uint8 defaults to 0), which ripples into SSAString/WebVTTString; that's a larger change best left as a follow-up.

@jason-valenzuela
jason-valenzuela marked this pull request as draft August 20, 2026 18:53
@jason-valenzuela
jason-valenzuela marked this pull request as ready for review August 20, 2026 20:28
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