Meme Generation API
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Kynareth/src/Managers/ImageManager.Generation.cs

117 lines
3.7 KiB

using Exsersewo.Common.Utilities;
using ImageMagick;
using Kynareth.Models;
namespace Kynareth.Managers;
public static partial class ImageManager
{
private static List<ImageGenerationEndpoint> GenerationEndpoints;
private static string GenerationTemplateBaseFolder;
static void ConfigureGeneration(IConfiguration configuration, IWebHostEnvironment _appEnvironment)
{
GenerationTemplateBaseFolder = Path.Combine(_appEnvironment.WebRootPath, configuration.GetValue<string>("ShitpostBot:Folder"));
GenerationEndpoints = configuration.GetSection("ShitpostBot:Templates").Get<List<ImageGenerationEndpoint>>();
}
public static async Task<object> 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<string> 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<ImageGenerationEndpointRead> GetGenerationEndpoints()
{
return GenerationEndpoints.Select(e => new ImageGenerationEndpointRead
{
Name = e.Name,
SourcesRequired = e.SourcesRequired
});
}
}