using Exsersewo.Common.Utilities; using ImageMagick; using Kynareth.Models; namespace Kynareth.Managers; public static partial class ImageManager { private static List GenerationEndpoints; private static string GenerationTemplateBaseFolder; static void ConfigureGeneration(IConfiguration configuration, IWebHostEnvironment _appEnvironment) { GenerationTemplateBaseFolder = Path.Combine(_appEnvironment.WebRootPath, configuration.GetValue("ShitpostBot:Folder")); GenerationEndpoints = configuration.GetSection("ShitpostBot:Templates").Get>(); } public static async Task GenerateImageAsync(string template, string variant, string[] sources) { ImageGenerationImage imageTemplate = null; var endpoint = GenerationEndpoints.FirstOrDefault(e => e.Name.ToLowerInvariant().Equals(template.ToLowerInvariant())); if (endpoint is null) { var ex = new ArgumentException($"Couldn't find endpoint named \"{template}\"", nameof(template)); return GetResult(StatusCodes.Status404NotFound, EventResult.FromFailureException(ex.Message, ex)); } if (endpoint.SourcesRequired > sources.Length) { var ex = new ArgumentException("Not enough sources provided", nameof(sources)); return GetResult(StatusCodes.Status400BadRequest, EventResult.FromFailureException(ex.Message, ex)); } if (!string.IsNullOrWhiteSpace(variant)) { imageTemplate = endpoint.Variants? .FirstOrDefault(v => v.Name.ToLowerInvariant().Equals(variant.ToLowerInvariant())); if (imageTemplate is null) { var ex = new ArgumentException( $"Invalid variant given \"{variant}\" for endpoint \"{template}\"", nameof(variant) ); return GetResult(StatusCodes.Status400BadRequest, EventResult.FromFailureException(ex.Message, ex)); } } else { imageTemplate = endpoint; } string image = Path.Combine(GenerationTemplateBaseFolder, !string.IsNullOrWhiteSpace(endpoint.Folder) ? endpoint.Folder : "", imageTemplate.Image); using MagickImage templateImage = new(System.IO.File.ReadAllBytes(image)); using MagickImage baseImage = new(MagickColors.Transparent, templateImage.Width, templateImage.Height); baseImage.Format = MagickFormat.Png; if (imageTemplate.PlaceUnder) { await AddSourcesToImage(baseImage, imageTemplate, sources); } baseImage.Composite(templateImage, Gravity.Northwest, CompositeOperator.Over); if (!imageTemplate.PlaceUnder) { await AddSourcesToImage(baseImage, imageTemplate, sources); } return baseImage.ToByteArray(); } static async Task AddSourcesToImage(MagickImage image, ImageGenerationImage template, IEnumerable sources) { int img = 0; foreach (var src in sources) { var position = template.Positions.ElementAtOrDefault(img); using MagickImage srcImg = new MagickImage(await HttpWebClient.GetStreamAsync(new Uri(src))); srcImg.Resize(position.Width, position.Height); if (position.Rotation != 0) { srcImg.Rotate(template.Rotate > 0 ? -position.Rotation : position.Rotation); } string background = !string.IsNullOrWhiteSpace(position.Background) ? $"#{position.Background}" : MagickColors.Transparent.ToHexString(); var tmp = new MagickImage($"xc:{background}", position.Width, position.Height); tmp.Composite(srcImg, Gravity.Center, 0, 0, CompositeOperator.Over); image.Composite(tmp, Gravity.Northwest, position.X, position.Y, CompositeOperator.Over); img++; } } public static IEnumerable GetGenerationEndpoints() { return GenerationEndpoints.Select(e => new ImageGenerationEndpointRead { Name = e.Name, SourcesRequired = e.SourcesRequired }); } }