diff --git a/Jellyfin.Plugin.SRFPlay/Utilities/PlaceholderImageGenerator.cs b/Jellyfin.Plugin.SRFPlay/Utilities/PlaceholderImageGenerator.cs index 3d05157..1c82cb6 100644 --- a/Jellyfin.Plugin.SRFPlay/Utilities/PlaceholderImageGenerator.cs +++ b/Jellyfin.Plugin.SRFPlay/Utilities/PlaceholderImageGenerator.cs @@ -41,26 +41,25 @@ public static class PlaceholderImageGenerator Typeface = SKTypeface.FromFamilyName("Arial", SKFontStyle.Bold) }; - // Calculate font size to fit text (max 48, min 24) + // Calculate font size and wrap text if needed float fontSize = 48; textPaint.TextSize = fontSize; - var textWidth = textPaint.MeasureText(text); var maxWidth = Width * 0.85f; + var maxHeight = Height * 0.8f; - if (textWidth > maxWidth) + var lines = WrapText(text, textPaint, maxWidth, maxHeight, ref fontSize); + + // Draw each line centered + var lineHeight = fontSize * 1.2f; + var totalHeight = lines.Count * lineHeight; + var startY = ((Height - totalHeight) / 2) + fontSize; + + foreach (var line in lines) { - fontSize = fontSize * maxWidth / textWidth; - fontSize = fontSize < 24 ? 24 : fontSize; - textPaint.TextSize = fontSize; + canvas.DrawText(line, Width / 2, startY, textPaint); + startY += lineHeight; } - // 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); @@ -70,4 +69,73 @@ public static class PlaceholderImageGenerator stream.Position = 0; return stream; } + + /// + /// Wraps text to fit within the specified width and height constraints. + /// + /// The text to wrap. + /// The paint to use for measuring. + /// Maximum width for each line. + /// Maximum total height. + /// Font size (will be adjusted if needed). + /// List of text lines. + private static System.Collections.Generic.List WrapText( + string text, + SKPaint paint, + float maxWidth, + float maxHeight, + ref float fontSize) + { + const float minFontSize = 20; + var words = text.Split(' '); + var lines = new System.Collections.Generic.List(); + + while (fontSize >= minFontSize) + { + paint.TextSize = fontSize; + lines.Clear(); + + var currentLine = string.Empty; + foreach (var word in words) + { + var testLine = string.IsNullOrEmpty(currentLine) ? word : $"{currentLine} {word}"; + var testWidth = paint.MeasureText(testLine); + + if (testWidth > maxWidth && !string.IsNullOrEmpty(currentLine)) + { + lines.Add(currentLine); + currentLine = word; + } + else + { + currentLine = testLine; + } + } + + if (!string.IsNullOrEmpty(currentLine)) + { + lines.Add(currentLine); + } + + // Check if total height fits + var lineHeight = fontSize * 1.2f; + var totalHeight = lines.Count * lineHeight; + + if (totalHeight <= maxHeight) + { + break; + } + + // Reduce font size and try again + fontSize -= 2; + } + + // If still doesn't fit, just return what we have + if (lines.Count == 0) + { + lines.Add(text); + } + + return lines; + } }