using System.IO; using SkiaSharp; namespace Jellyfin.Plugin.SRFPlay.Utilities; /// /// Generates placeholder images for content without thumbnails. /// public static class PlaceholderImageGenerator { private const int Width = 640; private const int Height = 360; // 16:9 aspect ratio /// /// Generates a placeholder image with the given text centered. /// /// The text to display (typically channel/show name). /// A memory stream containing the PNG image. public static MemoryStream GeneratePlaceholder(string text) { using var surface = SKSurface.Create(new SKImageInfo(Width, Height)); var canvas = surface.Canvas; // Dark gradient background using var backgroundPaint = new SKPaint(); using var shader = SKShader.CreateLinearGradient( new SKPoint(0, 0), new SKPoint(Width, Height), new[] { new SKColor(45, 45, 48), new SKColor(28, 28, 30) }, null, SKShaderTileMode.Clamp); backgroundPaint.Shader = shader; canvas.DrawRect(0, 0, Width, Height, backgroundPaint); // Text using var textPaint = new SKPaint { Color = SKColors.White, IsAntialias = true, TextAlign = SKTextAlign.Center, Typeface = SKTypeface.FromFamilyName("Arial", SKFontStyle.Bold) }; // Calculate font size to fit text (max 48, min 24) float fontSize = 48; textPaint.TextSize = fontSize; var textWidth = textPaint.MeasureText(text); var maxWidth = Width * 0.85f; if (textWidth > maxWidth) { fontSize = fontSize * maxWidth / textWidth; fontSize = fontSize < 24 ? 24 : fontSize; textPaint.TextSize = fontSize; } // Center text vertically SKRect textBounds = default; textPaint.MeasureText(text, ref textBounds); var yPos = (Height / 2) - textBounds.MidY; canvas.DrawText(text, Width / 2, yPos, textPaint); // Encode to PNG using var image = surface.Snapshot(); using var data = image.Encode(SKEncodedImageFormat.Png, 100); var stream = new MemoryStream(); data.SaveTo(stream); stream.Position = 0; return stream; } }