Browse Source

add text element text_fit options (#2441)

pull/2442/head
Jason Dove 4 months ago committed by GitHub
parent
commit
c8679144c5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 7
      CHANGELOG.md
  2. 18
      ErsatzTV.Core/Graphics/TextGraphicsElement.cs
  3. 75
      ErsatzTV.Infrastructure/Streaming/Graphics/Text/TextElement.cs

7
CHANGELOG.md

@ -37,8 +37,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -37,8 +37,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- `loop` - loop forever
- `hold` - hold last frame forever, or `hold_seconds`
- Draw order (`z_index`)
- Add search fields to filter collections, schedules, playouts tables
- Add search fields to filter collections, schedules and playouts tables
- Add selected row background color to schedules and playouts tables
- Graphics engine text element: add `width_percent` and `text_fit` to support wrapping and scaling text
- `text_fit: none` or unspecified will keep existing behavior (render text exactly as configured)
- `text_fit: wrap` will wrap text to the given `width_percent`
- `text_fit: scale` will scale text *smaller* to fit the given `width_percent`
- Text that already fits with the configured style will not be adjusted
### Fixed
- Fix green output when libplacebo tonemapping is used with NVIDIA acceleration and 10-bit output in FFmpeg Profile

18
ErsatzTV.Core/Graphics/TextGraphicsElement.cs

@ -19,14 +19,11 @@ public class TextGraphicsElement @@ -19,14 +19,11 @@ public class TextGraphicsElement
[YamlMember(Alias = "vertical_margin_percent", ApplyNamingConventions = false)]
public double? VerticalMarginPercent { get; set; }
[YamlMember(Alias = "horizontal_alignment", ApplyNamingConventions = false)]
public string HorizontalAlignment { get; set; }
[YamlMember(Alias = "width_percent", ApplyNamingConventions = false)]
public double? WidthPercent { get; set; }
[YamlMember(Alias = "location_x", ApplyNamingConventions = false)]
public double? LocationX { get; set; }
[YamlMember(Alias = "location_y", ApplyNamingConventions = false)]
public double? LocationY { get; set; }
[YamlMember(Alias = "text_fit", ApplyNamingConventions = false)]
public TextFit Fit { get; set; } = TextFit.None;
[YamlMember(Alias = "z_index", ApplyNamingConventions = false)]
public int? ZIndex { get; set; }
@ -45,6 +42,13 @@ public class TextGraphicsElement @@ -45,6 +42,13 @@ public class TextGraphicsElement
public string Text { get; set; }
}
public enum TextFit
{
None,
Wrap,
Scale
}
public class StyleDefinition
{
public string Name { get; set; }

75
ErsatzTV.Infrastructure/Streaming/Graphics/Text/TextElement.cs

@ -62,6 +62,21 @@ public partial class TextElement( @@ -62,6 +62,21 @@ public partial class TextElement(
RichTextKit.TextBlock textBlock = BuildTextBlock(textElement.Text);
if (textElement.WidthPercent.HasValue)
{
var maxWidth = (float)Math.Round(textElement.WidthPercent.Value / 100.0 * context.FrameSize.Width);
switch (textElement.Fit)
{
case TextFit.Wrap:
textBlock.MaxWidth = maxWidth;
break;
case TextFit.Scale:
FitTextBlock(textBlock, maxWidth);
break;
}
}
_image = new SKBitmap(
(int)Math.Ceiling(textBlock.MeasuredWidth),
(int)Math.Ceiling(textBlock.MeasuredHeight));
@ -216,6 +231,66 @@ public partial class TextElement( @@ -216,6 +231,66 @@ public partial class TextElement(
}
}
private static void FitTextBlock(RichTextKit.TextBlock block, float maxWidth)
{
if (block.MeasuredWidth <= maxWidth)
{
return;
}
var originalContent = block.StyleRuns
.Select(run => (run.ToString(), run.Style))
.ToList();
float scale = maxWidth / block.MeasuredWidth;
const float MIN_FONT_SIZE = 5.0f;
while (true)
{
block.Clear();
var isAtMinSize = false;
foreach ((string text, RichTextKit.IStyle style) in originalContent)
{
var newStyle = new RichTextKit.Style
{
FontFamily = style.FontFamily,
FontItalic = style.FontItalic,
FontSize = style.FontSize,
FontWidth = style.FontWidth,
FontWeight = style.FontWeight,
LetterSpacing = style.LetterSpacing,
TextColor = style.TextColor
};
float newSize = newStyle.FontSize * scale;
if (newSize < MIN_FONT_SIZE)
{
newSize = MIN_FONT_SIZE;
isAtMinSize = true;
}
newStyle.FontSize = newSize;
block.AddText(text, newStyle);
}
if (block.MeasuredWidth <= maxWidth)
{
break;
}
if (isAtMinSize)
{
break;
}
scale -= 0.01f;
}
}
[GeneratedRegex(@"\[(\w+)\](.*?)\[/\1\]")]
private static partial Regex StyleRegex();
}

Loading…
Cancel
Save