Ignore token if dev, pass through request cancellation token, tweak word wrapping
This commit is contained in:
@@ -20,7 +20,7 @@ public class RequireTokenAttribute : ActionFilterAttribute
|
|||||||
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
|
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
|
||||||
|
|
||||||
var invalidRequest = EventResult.FromFailure("Unauthorized request");
|
var invalidRequest = EventResult.FromFailure("Unauthorized request");
|
||||||
await context.HttpContext.Response.WriteAsync(invalidRequest.ToJson());
|
await context.HttpContext.Response.WriteAsync(invalidRequest.ToJson(), context.HttpContext.RequestAborted);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -34,7 +34,7 @@ public class ImageGenerationController : BaseController<ImageGenerationControlle
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await ImageManager.GenerateImageAsync(template, variant, sources);
|
var result = await ImageManager.GenerateImageAsync(template, variant, sources, Request.HttpContext.RequestAborted);
|
||||||
|
|
||||||
if (result is byte[] data)
|
if (result is byte[] data)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public class ImageManipulationController : BaseController<ImageManipulationContr
|
|||||||
{
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(image))
|
if (!string.IsNullOrWhiteSpace(image))
|
||||||
{
|
{
|
||||||
var (data, contentType) = await ImageManager.GetLiquidRescaledImageAsync(image);
|
var (data, contentType) = await ImageManager.GetLiquidRescaledImageAsync(image, HttpContext.RequestAborted);
|
||||||
|
|
||||||
return HttpContext.SendStream(data, contentType);
|
return HttpContext.SendStream(data, contentType);
|
||||||
}
|
}
|
||||||
@@ -68,7 +68,7 @@ public class ImageManipulationController : BaseController<ImageManipulationContr
|
|||||||
{
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(template))
|
if (!string.IsNullOrWhiteSpace(template))
|
||||||
{
|
{
|
||||||
var result = await ImageManager.GenerateMemeImageAsync(template, text);
|
var result = await ImageManager.GenerateMemeImageAsync(template, text, HttpContext.RequestAborted);
|
||||||
|
|
||||||
if (result is byte[] data)
|
if (result is byte[] data)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,6 +6,13 @@ namespace Kynareth.Helpers;
|
|||||||
|
|
||||||
public static class RequestHelper
|
public static class RequestHelper
|
||||||
{
|
{
|
||||||
|
private static WebApplication _webApplication;
|
||||||
|
|
||||||
|
public static void Configure(WebApplication webApp)
|
||||||
|
{
|
||||||
|
_webApplication = webApp;
|
||||||
|
}
|
||||||
|
|
||||||
public static string GetUrlHostname(this HttpContext context)
|
public static string GetUrlHostname(this HttpContext context)
|
||||||
{
|
{
|
||||||
var origin = context.Request.Headers["X-Original-Host"];
|
var origin = context.Request.Headers["X-Original-Host"];
|
||||||
@@ -15,17 +22,27 @@ public static class RequestHelper
|
|||||||
|
|
||||||
public static async Task<bool> IsRequestAuthenticatedAsync(this HttpRequest request)
|
public static async Task<bool> IsRequestAuthenticatedAsync(this HttpRequest request)
|
||||||
{
|
{
|
||||||
string key = request.GetToken();
|
if (_webApplication.Environment.IsDevelopment()) return true;
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(key)) return false;
|
while (true)
|
||||||
|
{
|
||||||
|
if(request.HttpContext.RequestAborted.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string key = request.GetToken();
|
||||||
|
|
||||||
await using var database = request.HttpContext.RequestServices.GetRequiredService<KynarethDbContext>();
|
if (string.IsNullOrWhiteSpace(key)) return false;
|
||||||
|
|
||||||
var tokenEntry = database.Tokens.FirstOrDefault(token => token.Token.Equals(key));
|
await using var database = request.HttpContext.RequestServices.GetRequiredService<KynarethDbContext>();
|
||||||
|
|
||||||
if (tokenEntry is not { IsValid: true }) return false;
|
var tokenEntry = database.Tokens.FirstOrDefault(token => token.Token.Equals(key));
|
||||||
|
|
||||||
return true;
|
if (tokenEntry is not { IsValid: true }) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetToken(this HttpRequest request)
|
public static string GetToken(this HttpRequest request)
|
||||||
|
|||||||
@@ -24,24 +24,31 @@ public class StreamResult : ActionResult, IStatusCodeActionResult, IActionResult
|
|||||||
throw new ArgumentNullException(nameof(context));
|
throw new ArgumentNullException(nameof(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
var response = context.HttpContext.Response;
|
try
|
||||||
|
{
|
||||||
|
var response = context.HttpContext.Response;
|
||||||
|
|
||||||
response.StatusCode = StatusCode ?? 200;
|
response.StatusCode = StatusCode ?? 200;
|
||||||
|
|
||||||
response.ContentType = !string.IsNullOrEmpty(ContentType)
|
response.ContentType = !string.IsNullOrEmpty(ContentType)
|
||||||
? ContentType
|
? ContentType
|
||||||
: "image/png";
|
: "image/png";
|
||||||
|
|
||||||
Value.Position = 0;
|
Value.Position = 0;
|
||||||
|
|
||||||
await Value.CopyToAsync(response.Body);
|
await Value.CopyToAsync(response.Body, context.HttpContext.RequestAborted);
|
||||||
|
|
||||||
await Value.FlushAsync();
|
await Value.FlushAsync(context.HttpContext.RequestAborted);
|
||||||
|
|
||||||
await Value.DisposeAsync();
|
await Value.DisposeAsync();
|
||||||
|
|
||||||
context.HttpContext.Response.RegisterForDisposeAsync(Value);
|
context.HttpContext.Response.RegisterForDisposeAsync(Value);
|
||||||
|
|
||||||
GC.Collect();
|
GC.Collect();
|
||||||
|
}
|
||||||
|
catch (TaskCanceledException)
|
||||||
|
{
|
||||||
|
//assume that request was cancelled if this is invoked
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Exsersewo.Common" Version="2023.1.14" />
|
<PackageReference Include="Exsersewo.Common" Version="2023.1.14" />
|
||||||
|
<PackageReference Include="ICU4N" Version="60.1.0-alpha.356" />
|
||||||
<PackageReference Include="JwtSharp" Version="1.1.0" />
|
<PackageReference Include="JwtSharp" Version="1.1.0" />
|
||||||
<PackageReference Include="Magick.NET-Q8-AnyCPU" Version="12.2.2" />
|
<PackageReference Include="Magick.NET-Q8-AnyCPU" Version="12.2.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.2" />
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.2" />
|
||||||
|
|||||||
@@ -16,93 +16,111 @@ public static partial class ImageManager
|
|||||||
GenerationEndpoints = configuration.GetSection("ShitpostBot:Templates").Get<List<ImageGenerationEndpoint>>();
|
GenerationEndpoints = configuration.GetSection("ShitpostBot:Templates").Get<List<ImageGenerationEndpoint>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<object> GenerateImageAsync(string template, string variant, string[] sources)
|
public static async Task<object> GenerateImageAsync(string template, string variant, string[] sources, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
ImageGenerationImage imageTemplate = null;
|
while (true)
|
||||||
|
|
||||||
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));
|
if(cancellationToken.IsCancellationRequested)
|
||||||
|
|
||||||
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(
|
return null;
|
||||||
$"Invalid variant given \"{variant}\" for endpoint \"{template}\"",
|
}
|
||||||
nameof(variant)
|
|
||||||
);
|
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));
|
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);
|
if (!string.IsNullOrWhiteSpace(variant))
|
||||||
|
|
||||||
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);
|
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 background = !string.IsNullOrWhiteSpace(position.Background) ? $"#{position.Background}" : MagickColors.Transparent.ToHexString();
|
string image = Path.Combine(GenerationTemplateBaseFolder, !string.IsNullOrWhiteSpace(endpoint.Folder) ? endpoint.Folder : "", imageTemplate.Image);
|
||||||
|
|
||||||
var tmp = new MagickImage($"xc:{background}", position.Width, position.Height);
|
using MagickImage templateImage = new(System.IO.File.ReadAllBytes(image));
|
||||||
|
using MagickImage baseImage = new(MagickColors.Transparent, templateImage.Width, templateImage.Height);
|
||||||
|
|
||||||
tmp.Composite(srcImg, Gravity.Center, 0, 0, CompositeOperator.Over);
|
baseImage.Format = MagickFormat.Png;
|
||||||
|
|
||||||
image.Composite(tmp, Gravity.Northwest, position.X, position.Y, CompositeOperator.Over);
|
if (imageTemplate.PlaceUnder)
|
||||||
|
{
|
||||||
img++;
|
await AddSourcesToImage(baseImage, imageTemplate, sources, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
baseImage.Composite(templateImage, Gravity.Northwest, CompositeOperator.Over);
|
||||||
|
|
||||||
|
if (!imageTemplate.PlaceUnder)
|
||||||
|
{
|
||||||
|
await AddSourcesToImage(baseImage, imageTemplate, sources, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseImage.ToByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async Task AddSourcesToImage(MagickImage image, ImageGenerationImage template, IEnumerable<string> sources, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if(cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,27 +9,35 @@ public static partial class ImageManager
|
|||||||
readonly static Encoding s_defaultEncoding = Encoding.Unicode;
|
readonly static Encoding s_defaultEncoding = Encoding.Unicode;
|
||||||
const double c_defaultFontSize = 20;
|
const double c_defaultFontSize = 20;
|
||||||
|
|
||||||
public static async Task<(MemoryStream data, string contentType)> GetLiquidRescaledImageAsync(string image)
|
public static async Task<(MemoryStream data, string contentType)> GetLiquidRescaledImageAsync(string image, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var imageStream = await HttpWebClient.GetStreamAsync(new Uri(image)).ConfigureAwait(false);
|
while (true)
|
||||||
|
{
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
return (null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
var imageStream = await HttpWebClient.GetStreamAsync(new Uri(image)).ConfigureAwait(false);
|
||||||
|
|
||||||
using var magikImage = new MagickImageCollection(imageStream);
|
using var magikImage = new MagickImageCollection(imageStream);
|
||||||
|
|
||||||
Parallel.ForEach(magikImage, LiquidResizeFrame);
|
Parallel.ForEach(magikImage, LiquidResizeFrame);
|
||||||
|
|
||||||
MemoryStream stream = new();
|
MemoryStream stream = new();
|
||||||
|
|
||||||
magikImage.Write(stream);
|
magikImage.Write(stream);
|
||||||
|
|
||||||
stream.Position = 0;
|
stream.Position = 0;
|
||||||
|
|
||||||
magikImage.Dispose();
|
magikImage.Dispose();
|
||||||
|
|
||||||
string cType = "image/png";
|
string cType = "image/png";
|
||||||
|
|
||||||
if (magikImage.Count > 1) cType = "image/gif";
|
if (magikImage.Count > 1) cType = "image/gif";
|
||||||
|
|
||||||
return (stream, cType);
|
return (stream, cType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LiquidResizeFrame(IMagickImage<byte> frame)
|
static void LiquidResizeFrame(IMagickImage<byte> frame)
|
||||||
|
|||||||
@@ -26,40 +26,48 @@ public static partial class ImageManager
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<object> GenerateMemeImageAsync(string template, string[] texts)
|
public static async Task<object> GenerateMemeImageAsync(string template, string[] texts, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
ImageManipulationImage imageTemplate = ManipulationEndpoints.FirstOrDefault(e => e.Name.ToLowerInvariant().Equals(template.ToLowerInvariant()));
|
while (true)
|
||||||
|
|
||||||
if (imageTemplate is null)
|
|
||||||
{
|
{
|
||||||
var ex = new ArgumentException($"Couldn't find endpoint named \"{template}\"", nameof(template));
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
return GetResult(StatusCodes.Status404NotFound, EventResult.FromFailureException(ex.Message, ex));
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (imageTemplate.TextPositions.Count > texts.Length)
|
|
||||||
{
|
|
||||||
var ex = new ArgumentException("Not enough texts provided", nameof(texts));
|
|
||||||
|
|
||||||
return GetResult(StatusCodes.Status400BadRequest, EventResult.FromFailureException(ex.Message, ex));
|
|
||||||
}
|
|
||||||
|
|
||||||
string image = Path.Combine(ManipulationTemplateBaseFolder, imageTemplate.Image);
|
|
||||||
|
|
||||||
using MagickImage templateImage = new(File.ReadAllBytes(image));
|
ImageManipulationImage imageTemplate = ManipulationEndpoints.FirstOrDefault(e => e.Name.ToLowerInvariant().Equals(template.ToLowerInvariant()));
|
||||||
using MagickImage baseImage = new(MagickColors.Transparent, templateImage.Width, templateImage.Height);
|
|
||||||
|
if (imageTemplate is null)
|
||||||
|
{
|
||||||
|
var ex = new ArgumentException($"Couldn't find endpoint named \"{template}\"", nameof(template));
|
||||||
|
|
||||||
baseImage.Format = MagickFormat.Png;
|
return GetResult(StatusCodes.Status404NotFound, EventResult.FromFailureException(ex.Message, ex));
|
||||||
|
}
|
||||||
|
|
||||||
baseImage.Composite(templateImage, CompositeOperator.Over);
|
if (imageTemplate.TextPositions.Count > texts.Length)
|
||||||
|
{
|
||||||
|
var ex = new ArgumentException("Not enough texts provided", nameof(texts));
|
||||||
|
|
||||||
int textPoint = 0;
|
return GetResult(StatusCodes.Status400BadRequest, EventResult.FromFailureException(ex.Message, ex));
|
||||||
foreach (var textArea in imageTemplate.TextPositions)
|
}
|
||||||
{
|
|
||||||
baseImage.WriteText(texts[textPoint], textArea, MagickColors.White, Encoding.Unicode);
|
string image = Path.Combine(ManipulationTemplateBaseFolder, imageTemplate.Image);
|
||||||
textPoint++;
|
|
||||||
|
using MagickImage templateImage = new(File.ReadAllBytes(image));
|
||||||
|
using MagickImage baseImage = new(MagickColors.Transparent, templateImage.Width, templateImage.Height);
|
||||||
|
|
||||||
|
baseImage.Format = MagickFormat.Png;
|
||||||
|
|
||||||
|
baseImage.Composite(templateImage, CompositeOperator.Over);
|
||||||
|
|
||||||
|
int textPoint = 0;
|
||||||
|
foreach (var textArea in imageTemplate.TextPositions)
|
||||||
|
{
|
||||||
|
baseImage.WriteText(texts[textPoint], textArea, MagickColors.White, Encoding.Unicode);
|
||||||
|
textPoint++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseImage.ToByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
return baseImage.ToByteArray();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
|
using System.Globalization;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using ICU4N.Text;
|
||||||
using ImageMagick;
|
using ImageMagick;
|
||||||
using Kynareth.Models;
|
using Kynareth.Models;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
@@ -14,38 +16,63 @@ public static partial class ImageManager
|
|||||||
ConfigureManipulation(configuration, appEnvironment);
|
ConfigureManipulation(configuration, appEnvironment);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ObjectResult GetResult(int statusCode, object data)
|
static BreakIterator lineBreakIterator = BreakIterator.GetLineInstance(CultureInfo.InvariantCulture);
|
||||||
=> new(data) { StatusCode = statusCode };
|
|
||||||
|
|
||||||
public static MagickImage WriteText(this MagickImage image, string text, PositionRect rect, MagickColor fontColor, Encoding encoding, string font = "Impact", int strokeWidth = 2, MagickColor? strokeColor = null)
|
private static ObjectResult GetResult(int statusCode, object data) => new(data) { StatusCode = statusCode };
|
||||||
|
|
||||||
|
private static string GetText(string text)
|
||||||
{
|
{
|
||||||
using var label = new MagickImage($"label:{text}", new MagickReadSettings()
|
StringBuilder newText = new();
|
||||||
|
|
||||||
|
// set the text to be broken
|
||||||
|
lineBreakIterator.SetText(text);
|
||||||
|
|
||||||
|
// get the first boundary
|
||||||
|
int start = lineBreakIterator.First();
|
||||||
|
|
||||||
|
// iterate over all boundaries
|
||||||
|
for (int end = lineBreakIterator.Next(); end != BreakIterator.Done; start = end, end = lineBreakIterator.Next())
|
||||||
|
{
|
||||||
|
// get the current line
|
||||||
|
string line = text.Substring(start, end - start);
|
||||||
|
|
||||||
|
// do something with the line
|
||||||
|
newText.AppendLine(line);
|
||||||
|
Console.WriteLine(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newText.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MagickImage WriteText(this MagickImage image, string text, PositionRect rect, MagickColor fontColor, Encoding encoding, string font = "Impact", int strokeWidth = 2, MagickColor? strokeColor = null, bool wrapText = true, Gravity textGravity = Gravity.Northwest)
|
||||||
|
{
|
||||||
|
using var label = new MagickImage($"{(wrapText ? "caption" : "label")}:{text}", new MagickReadSettings()
|
||||||
{
|
{
|
||||||
Width = rect.Width,
|
Width = rect.Width,
|
||||||
Height = rect.Height,
|
Height = rect.Height,
|
||||||
BackgroundColor = MagickColors.Transparent,
|
BackgroundColor = MagickColors.Transparent,
|
||||||
FillColor = fontColor,
|
FillColor = fontColor,
|
||||||
TextGravity = Gravity.Center,
|
TextGravity = textGravity,
|
||||||
Font = font,
|
Font = font,
|
||||||
TextEncoding = encoding,
|
TextEncoding = encoding,
|
||||||
StrokeColor = new MagickColor(strokeColor ?? MagickColors.Black),
|
StrokeColor = new MagickColor(strokeColor ?? MagickColors.Black),
|
||||||
StrokeWidth = strokeWidth
|
StrokeWidth = strokeWidth,
|
||||||
});
|
});
|
||||||
|
|
||||||
image.Composite(label, rect.X, rect.Y, CompositeOperator.Over);
|
image.Composite(label, rect.X, rect.Y, CompositeOperator.Over);
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MagickImage WriteText(this MagickImage image, string text, PositionRect rect, MagickColor fontColor, Encoding encoding, double fontSize, string font = "Impact", int strokeWidth = 2, MagickColor? strokeColor = null)
|
public static MagickImage WriteText(this MagickImage image, string text, PositionRect rect, MagickColor fontColor, Encoding encoding, double fontSize, string font = "Impact", int strokeWidth = 2, MagickColor? strokeColor = null, bool wrapText = true, Gravity textGravity = Gravity.Northwest)
|
||||||
{
|
{
|
||||||
using var label = new MagickImage($"caption:{text}", new MagickReadSettings()
|
using var label = new MagickImage($"{(wrapText ? "caption" : "label")}:{text}", new MagickReadSettings()
|
||||||
{
|
{
|
||||||
Width = rect.Width,
|
Width = rect.Width,
|
||||||
Height = rect.Height,
|
Height = rect.Height,
|
||||||
BackgroundColor = MagickColors.Transparent,
|
BackgroundColor = MagickColors.Transparent,
|
||||||
FillColor = fontColor,
|
FillColor = fontColor,
|
||||||
TextGravity = Gravity.Center,
|
TextGravity = textGravity,
|
||||||
FontPointsize = fontSize,
|
FontPointsize = fontSize,
|
||||||
Font = font,
|
Font = font,
|
||||||
TextEncoding = encoding,
|
TextEncoding = encoding,
|
||||||
@@ -58,15 +85,15 @@ public static partial class ImageManager
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MagickImage WriteText(this MagickImage image, string text, Vector2 position, MagickColor fontColor, Encoding encoding, string font = "Impact", int strokeWidth = 2, MagickColor? strokeColor = null)
|
public static MagickImage WriteText(this MagickImage image, string text, Vector2 position, MagickColor fontColor, Encoding encoding, string font = "Impact", int strokeWidth = 2, MagickColor? strokeColor = null, bool wrapText = true, Gravity textGravity = Gravity.Northwest)
|
||||||
{
|
{
|
||||||
using var label = new MagickImage($"caption:{text}", new MagickReadSettings()
|
using var label = new MagickImage($"{(wrapText ? "caption" : "label")}:{text}", new MagickReadSettings()
|
||||||
{
|
{
|
||||||
Width = image.Width,
|
Width = image.Width,
|
||||||
Height = image.Height,
|
Height = image.Height,
|
||||||
BackgroundColor = MagickColors.Transparent,
|
BackgroundColor = MagickColors.Transparent,
|
||||||
FillColor = fontColor,
|
FillColor = fontColor,
|
||||||
TextGravity = Gravity.Center,
|
TextGravity = textGravity,
|
||||||
Font = font,
|
Font = font,
|
||||||
TextEncoding = encoding,
|
TextEncoding = encoding,
|
||||||
StrokeColor = new MagickColor(strokeColor ?? MagickColors.Black),
|
StrokeColor = new MagickColor(strokeColor ?? MagickColors.Black),
|
||||||
@@ -78,15 +105,15 @@ public static partial class ImageManager
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MagickImage WriteText(this MagickImage image, string text, Vector2 position, MagickColor fontColor, Encoding encoding, double fontSize, string font = "Impact", int strokeWidth = 2, MagickColor? strokeColor = null)
|
public static MagickImage WriteText(this MagickImage image, string text, Vector2 position, MagickColor fontColor, Encoding encoding, double fontSize, string font = "Impact", int strokeWidth = 2, MagickColor? strokeColor = null, bool wrapText = true, Gravity textGravity = Gravity.Northwest)
|
||||||
{
|
{
|
||||||
using var label = new MagickImage($"caption:{text}", new MagickReadSettings()
|
using var label = new MagickImage($"{(wrapText ? "caption" : "label")}:{text}", new MagickReadSettings()
|
||||||
{
|
{
|
||||||
Width = image.Width,
|
Width = image.Width,
|
||||||
Height = image.Height,
|
Height = image.Height,
|
||||||
BackgroundColor = MagickColors.Transparent,
|
BackgroundColor = MagickColors.Transparent,
|
||||||
FillColor = fontColor,
|
FillColor = fontColor,
|
||||||
TextGravity = Gravity.Center,
|
TextGravity = textGravity,
|
||||||
FontPointsize = fontSize,
|
FontPointsize = fontSize,
|
||||||
Font = font,
|
Font = font,
|
||||||
TextEncoding = encoding,
|
TextEncoding = encoding,
|
||||||
@@ -99,15 +126,15 @@ public static partial class ImageManager
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MagickImage WriteText(this MagickImage image, string text, PointD position, MagickColor fontColor, Encoding encoding, string font = "Impact", int strokeWidth = 2, MagickColor? strokeColor = null)
|
public static MagickImage WriteText(this MagickImage image, string text, PointD position, MagickColor fontColor, Encoding encoding, string font = "Impact", int strokeWidth = 2, MagickColor? strokeColor = null, bool wrapText = true, Gravity textGravity = Gravity.Northwest)
|
||||||
{
|
{
|
||||||
using var label = new MagickImage($"caption:{text}", new MagickReadSettings()
|
using var label = new MagickImage($"{(wrapText ? "caption" : "label")}:{text}", new MagickReadSettings()
|
||||||
{
|
{
|
||||||
Width = image.Width,
|
Width = image.Width,
|
||||||
Height = image.Height,
|
Height = image.Height,
|
||||||
BackgroundColor = MagickColors.Transparent,
|
BackgroundColor = MagickColors.Transparent,
|
||||||
FillColor = fontColor,
|
FillColor = fontColor,
|
||||||
TextGravity = Gravity.Center,
|
TextGravity = textGravity,
|
||||||
Font = font,
|
Font = font,
|
||||||
TextEncoding = encoding,
|
TextEncoding = encoding,
|
||||||
StrokeColor = new MagickColor(strokeColor ?? MagickColors.Black),
|
StrokeColor = new MagickColor(strokeColor ?? MagickColors.Black),
|
||||||
@@ -119,15 +146,15 @@ public static partial class ImageManager
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MagickImage WriteText(this MagickImage image, string text, PointD position, MagickColor fontColor, Encoding encoding, double fontSize, string font = "Impact", int strokeWidth = 2, MagickColor? strokeColor = null)
|
public static MagickImage WriteText(this MagickImage image, string text, PointD position, MagickColor fontColor, Encoding encoding, double fontSize, string font = "Impact", int strokeWidth = 2, MagickColor? strokeColor = null, bool wrapText = true, Gravity textGravity = Gravity.Northwest)
|
||||||
{
|
{
|
||||||
using var label = new MagickImage($"caption:{text}", new MagickReadSettings()
|
using var label = new MagickImage($"{(wrapText ? "caption" : "label")}:{text}", new MagickReadSettings()
|
||||||
{
|
{
|
||||||
Width = image.Width,
|
Width = image.Width,
|
||||||
Height = image.Height,
|
Height = image.Height,
|
||||||
BackgroundColor = MagickColors.Transparent,
|
BackgroundColor = MagickColors.Transparent,
|
||||||
FillColor = fontColor,
|
FillColor = fontColor,
|
||||||
TextGravity = Gravity.Center,
|
TextGravity = textGravity,
|
||||||
FontPointsize = fontSize,
|
FontPointsize = fontSize,
|
||||||
Font = font,
|
Font = font,
|
||||||
TextEncoding = encoding,
|
TextEncoding = encoding,
|
||||||
@@ -140,15 +167,15 @@ public static partial class ImageManager
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MagickImage WriteText(this MagickImage image, string text, int x, int y, MagickColor fontColor, Encoding encoding, string font = "Impact", int strokeWidth = 2, MagickColor? strokeColor = null)
|
public static MagickImage WriteText(this MagickImage image, string text, int x, int y, MagickColor fontColor, Encoding encoding, string font = "Impact", int strokeWidth = 2, MagickColor? strokeColor = null, bool wrapText = true, Gravity textGravity = Gravity.Northwest)
|
||||||
{
|
{
|
||||||
using var label = new MagickImage($"caption:{text}", new MagickReadSettings()
|
using var label = new MagickImage($"{(wrapText ? "caption" : "label")}:{text}", new MagickReadSettings()
|
||||||
{
|
{
|
||||||
Width = image.Width,
|
Width = image.Width,
|
||||||
Height = image.Height,
|
Height = image.Height,
|
||||||
BackgroundColor = MagickColors.Transparent,
|
BackgroundColor = MagickColors.Transparent,
|
||||||
FillColor = fontColor,
|
FillColor = fontColor,
|
||||||
TextGravity = Gravity.Center,
|
TextGravity = textGravity,
|
||||||
Font = font,
|
Font = font,
|
||||||
TextEncoding = encoding,
|
TextEncoding = encoding,
|
||||||
StrokeColor = new MagickColor(strokeColor ?? MagickColors.Black),
|
StrokeColor = new MagickColor(strokeColor ?? MagickColors.Black),
|
||||||
@@ -160,15 +187,15 @@ public static partial class ImageManager
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MagickImage WriteText(this MagickImage image, string text, int x, int y, MagickColor fontColor, Encoding encoding, double fontSize, string font = "Impact", int strokeWidth = 2, MagickColor? strokeColor = null)
|
public static MagickImage WriteText(this MagickImage image, string text, int x, int y, MagickColor fontColor, Encoding encoding, double fontSize, string font = "Impact", int strokeWidth = 2, MagickColor? strokeColor = null, bool wrapText = true, Gravity textGravity = Gravity.Northwest)
|
||||||
{
|
{
|
||||||
using var label = new MagickImage($"caption:{text}", new MagickReadSettings()
|
using var label = new MagickImage($"{(wrapText ? "caption" : "label")}:{text}", new MagickReadSettings()
|
||||||
{
|
{
|
||||||
Width = image.Width,
|
Width = image.Width,
|
||||||
Height = image.Height,
|
Height = image.Height,
|
||||||
BackgroundColor = MagickColors.Transparent,
|
BackgroundColor = MagickColors.Transparent,
|
||||||
FillColor = fontColor,
|
FillColor = fontColor,
|
||||||
TextGravity = Gravity.Center,
|
TextGravity = textGravity,
|
||||||
FontPointsize = fontSize,
|
FontPointsize = fontSize,
|
||||||
Font = font,
|
Font = font,
|
||||||
TextEncoding = encoding,
|
TextEncoding = encoding,
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ builder.Services.AddDbContext<KynarethDbContext>(options =>
|
|||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
|
RequestHelper.Configure(app);
|
||||||
ImageManager.Configure(app.Configuration, app.Environment);
|
ImageManager.Configure(app.Configuration, app.Environment);
|
||||||
AmogusHelper.Configure(app.Environment);
|
AmogusHelper.Configure(app.Environment);
|
||||||
|
|
||||||
|
|||||||
@@ -1702,7 +1702,7 @@
|
|||||||
"x": 593,
|
"x": 593,
|
||||||
"y": 411,
|
"y": 411,
|
||||||
"w": 169,
|
"w": 169,
|
||||||
"h": 75
|
"h": 300
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user