Created
June 4, 2025 15:20
-
-
Save JoeStead/f7e2ebdb12c9b5cd54b937e1fc19396e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| namespace Dig.Api.ImageGeneration; | |
| using SkiaSharp; | |
| using Storage; | |
| public class SkiaImageRenderer : IImageRenderer | |
| { | |
| private readonly HttpClient httpClient; | |
| public SkiaImageRenderer(HttpClient httpClient) | |
| { | |
| this.httpClient = httpClient; | |
| } | |
| public async Task<byte[]> RenderImage(Template template, Dictionary<string, string> parameters) | |
| { | |
| parameters.TryGetValue("name", out var name); | |
| using var bitmap = new SKBitmap(template.Width, template.Height); | |
| var canvas = new SKCanvas(bitmap); | |
| canvas.Clear(SKColor.Parse(template.BackgroundColour)); | |
| using var paint = new SKPaint(); | |
| paint.IsAntialias = true; | |
| await this.DrawContainers(canvas, paint, template.Containers, parameters); | |
| using var image = SKImage.FromBitmap(bitmap); | |
| using var data = image.Encode(SKEncodedImageFormat.Jpeg, 100); | |
| return data.ToArray(); | |
| } | |
| private async Task DrawContainers(SKCanvas canvas, SKPaint paint, Container[] templateContainers, Dictionary<string, string> parameters) | |
| { | |
| var orderedContainers = templateContainers.OrderBy(c => c.Order).ToList(); | |
| foreach (var orderedContainer in orderedContainers) | |
| { | |
| await orderedContainer.Render(canvas, paint, parameters, this.httpClient); | |
| } | |
| } | |
| } | |
| public static class SkiaImageExtensions | |
| { | |
| public static async Task Render(this Container container, SKCanvas canvas, SKPaint paint, Dictionary<string, string> parameters, HttpClient httpClient, Container? parent = null) | |
| { | |
| switch (container) | |
| { | |
| case TextContainer textContainer: | |
| await textContainer.Render(canvas, paint, parameters, httpClient, parent); | |
| break; | |
| case ImageContainer imageContainer: | |
| await imageContainer.Render(canvas, paint, parameters, httpClient, parent); | |
| break; | |
| default: | |
| throw new ArgumentException("Could not determine type of container to render", nameof(container)); | |
| } | |
| } | |
| private static async Task Render(this TextContainer container, SKCanvas canvas, SKPaint paint, Dictionary<string, string> parameters, HttpClient httpClient, Container? parent = null) | |
| { | |
| var parentX = parent?.X ?? 0; | |
| var parentY = parent?.Y ?? 0; | |
| using var typeface = await LoadTypefaceFromUrl(container.FontUrl, httpClient); | |
| using var font = new SKFont(); | |
| font.Typeface = typeface; | |
| font.Size = container.FontSize; | |
| paint.Color = SKColor.Parse(container.Colour); | |
| canvas.DrawText(container.DefaultText, parentX + container.X, parentY + container.Y, font, paint); | |
| } | |
| private static async Task Render(this ImageContainer container, SKCanvas canvas, SKPaint paint, Dictionary<string, string> parameters, HttpClient httpClient, Container? parent = null) | |
| { | |
| var parentX = parent?.X ?? 0; | |
| var parentY = parent?.Y ?? 0; | |
| using var image = await LoadImageFromUrl(container.ImageUrl, httpClient); | |
| //TODO: Use image stretch options | |
| canvas.DrawImage(image, new SKRect(parentX + container.X, | |
| parentY + container.Y, | |
| parentX + container.X + container.Width, | |
| parentY + container.Y + container.Height), | |
| paint); | |
| await Task.WhenAll(container.Containers.Select(c => c.Render(canvas, paint, parameters, httpClient, container))); | |
| } | |
| private static async Task<SKTypeface> LoadTypefaceFromUrl(string fontUrl, HttpClient httpClient) | |
| { | |
| var fontData = await httpClient.GetByteArrayAsync(fontUrl); | |
| using var skData = SKData.CreateCopy(fontData); | |
| return SKTypeface.FromData(skData); | |
| } | |
| public static async Task<SKImage> LoadImageFromUrl(string imageUrl, HttpClient httpClient) | |
| { | |
| var imageData = await httpClient.GetByteArrayAsync(imageUrl); | |
| return SKImage.FromEncodedData(imageData); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment