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.
117 lines
3.7 KiB
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
|
|
});
|
|
}
|
|
} |