Files
ersatztv/ErsatzTV.Core/Images/ChannelLogoGenerator.cs
T
timothy 8e6379a51b
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 4m13s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 5m14s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
test: make channel logo generator testable
refs #39
2026-06-30 18:14:23 +02:00

102 lines
3.3 KiB
C#

using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Images;
using Microsoft.Extensions.Logging;
using SkiaSharp;
namespace ErsatzTV.Core.Images;
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<ChannelLogoGenerator> logger)
: this(logger, DefaultOverlayImagePath(), DefaultFontPath())
{
}
public ChannelLogoGenerator(
ILogger<ChannelLogoGenerator> logger,
string overlayImagePath,
string fontPath)
{
_logger = logger;
_overlayImagePath = overlayImagePath;
_fontPath = fontPath;
}
public Either<BaseError, byte[]> GenerateChannelLogo(
string text,
int logoHeight,
int logoWidth,
CancellationToken cancellationToken)
{
try
{
using var surface = SKSurface.Create(new SKImageInfo(logoWidth, logoHeight));
SKCanvas canvas = surface.Canvas;
canvas.Clear(SKColors.Black);
//etv logo
using var overlayImage = SKBitmap.Decode(_overlayImagePath);
canvas.DrawBitmap(overlayImage, new SKRect(155, 60, 205, 110));
//Custom Font
using var fontTypeface = SKTypeface.FromFile(_fontPath);
var fontSize = 30;
var font = new SKFont
{
Typeface = fontTypeface,
Size = fontSize
};
var paint = new SKPaint
{
IsAntialias = true,
Color = SKColors.White,
Style = SKPaintStyle.Fill
};
font.MeasureText(text, out SKRect textBounds, paint);
// Ajuster la taille de la police si nécessaire
while (textBounds.Width > logoWidth - 10 && fontSize > 16)
{
fontSize -= 2;
font.Size = fontSize;
font.MeasureText(text, out textBounds, paint);
}
// Dessiner le texte
float x = logoWidth / 2f;
float y = logoHeight / 2f - textBounds.MidY;
canvas.DrawText(text, x, y, SKTextAlign.Center, font, paint);
using SKImage image = surface.Snapshot();
using var ms = new MemoryStream();
image.Encode(SKEncodedImageFormat.Png, 100).SaveTo(ms);
ms.Seek(0, SeekOrigin.Begin);
return ms.ToArray();
}
catch (Exception ex)
{
_logger.LogError("Can't generate Channel Logo ([{ErrorType}] {ErrorMessage})", ex.GetType(), ex.Message);
return BaseError.New("Can't generate Channel Logo " + ex.Message);
}
}
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");
}