diff --git a/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj b/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj
index 867f66761..bdc224593 100644
--- a/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj
+++ b/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj
@@ -32,4 +32,9 @@
+
+
+
+
+
diff --git a/ErsatzTV.Core.Tests/Images/ChannelLogoGeneratorTests.cs b/ErsatzTV.Core.Tests/Images/ChannelLogoGeneratorTests.cs
new file mode 100644
index 000000000..09b6238be
--- /dev/null
+++ b/ErsatzTV.Core.Tests/Images/ChannelLogoGeneratorTests.cs
@@ -0,0 +1,41 @@
+using ErsatzTV.Core.Images;
+using Microsoft.Extensions.Logging.Abstractions;
+using NUnit.Framework;
+using Shouldly;
+using SkiaSharp;
+
+namespace ErsatzTV.Core.Tests.Images;
+
+[TestFixture]
+public class ChannelLogoGeneratorTests
+{
+ [TestCase("News", 100, 200)]
+ [TestCase("A Very Long Channel Name That Should Force Font Shrinking", 100, 200)]
+ [TestCase("Tall Logo", 180, 120)]
+ public void GenerateChannelLogo_WithInjectedAssets_ReturnsValidPngWithRequestedDimensions(
+ string text,
+ int logoHeight,
+ int logoWidth)
+ {
+ var generator = new ChannelLogoGenerator(
+ NullLogger.Instance,
+ TestAssetPath("Resources", "Images", "ersatztv-500.png"),
+ TestAssetPath("Resources", "Fonts", "Sen.ttf"));
+
+ byte[] bytes = generator.GenerateChannelLogo(text, logoHeight, logoWidth, CancellationToken.None)
+ .Match(
+ Left: error => throw new AssertionException(error.Value),
+ Right: identity);
+
+ using var stream = new MemoryStream(bytes);
+ using var codec = SKCodec.Create(stream);
+
+ codec.ShouldNotBeNull();
+ codec.EncodedFormat.ShouldBe(SKEncodedImageFormat.Png);
+ codec.Info.Width.ShouldBe(logoWidth);
+ codec.Info.Height.ShouldBe(logoHeight);
+ }
+
+ private static string TestAssetPath(params string[] segments) =>
+ Path.Combine([TestContext.CurrentContext.TestDirectory, .. segments]);
+}
diff --git a/ErsatzTV.Core/Images/ChannelLogoGenerator.cs b/ErsatzTV.Core/Images/ChannelLogoGenerator.cs
index 4f6504a90..fae401afa 100644
--- a/ErsatzTV.Core/Images/ChannelLogoGenerator.cs
+++ b/ErsatzTV.Core/Images/ChannelLogoGenerator.cs
@@ -10,11 +10,25 @@ public class ChannelLogoGenerator : IChannelLogoGenerator
public const string GetRoute = "/iptv/logos/gen";
public const string GetRouteQueryParamName = "text";
+ private readonly string _fontPath;
private readonly ILogger _logger;
+ private readonly string _overlayImagePath;
public ChannelLogoGenerator(
- ILogger logger) =>
+ ILogger logger)
+ : this(logger, DefaultOverlayImagePath(), DefaultFontPath())
+ {
+ }
+
+ public ChannelLogoGenerator(
+ ILogger logger,
+ string overlayImagePath,
+ string fontPath)
+ {
_logger = logger;
+ _overlayImagePath = overlayImagePath;
+ _fontPath = fontPath;
+ }
public Either GenerateChannelLogo(
string text,
@@ -29,13 +43,11 @@ public class ChannelLogoGenerator : IChannelLogoGenerator
canvas.Clear(SKColors.Black);
//etv logo
- string overlayImagePath = Path.Combine("wwwroot", "images", "ersatztv-500.png");
- using var overlayImage = SKBitmap.Decode(overlayImagePath);
+ using var overlayImage = SKBitmap.Decode(_overlayImagePath);
canvas.DrawBitmap(overlayImage, new SKRect(155, 60, 205, 110));
//Custom Font
- string fontPath = Path.Combine(FileSystemLayout.ResourcesCacheFolder, "Sen.ttf");
- using var fontTypeface = SKTypeface.FromFile(fontPath);
+ using var fontTypeface = SKTypeface.FromFile(_fontPath);
var fontSize = 30;
var font = new SKFont
{
@@ -80,4 +92,10 @@ public class ChannelLogoGenerator : IChannelLogoGenerator
public static string GenerateChannelLogoUrl(Channel channel) =>
$"http://localhost:{Settings.StreamingPort}{GetRoute}?{GetRouteQueryParamName}={channel.WebEncodedName}";
+
+ private static string DefaultFontPath() =>
+ Path.Combine(FileSystemLayout.ResourcesCacheFolder, "Sen.ttf");
+
+ private static string DefaultOverlayImagePath() =>
+ Path.Combine("wwwroot", "images", "ersatztv-500.png");
}