106 lines
3.6 KiB
C#
106 lines
3.6 KiB
C#
using SixLabors.ImageSharp;
|
|
using SixLabors.ImageSharp.Formats;
|
|
using SixLabors.ImageSharp.PixelFormats;
|
|
using SixLabors.ImageSharp.Processing;
|
|
|
|
namespace LightlessSyncServer.Services
|
|
{
|
|
public class ImageCheckService
|
|
{
|
|
private static readonly int _imageWidthAvatar = 512;
|
|
private static readonly int _imageHeightAvatar = 512;
|
|
private static readonly int _imageWidthBanner = 840;
|
|
private static readonly int _imageHeightBanner = 260;
|
|
private static readonly int _imageSize = 2000;
|
|
|
|
public class ImageLoadResult
|
|
{
|
|
public bool Success { get; init; }
|
|
public string? Base64Image { get; init; }
|
|
public string? ErrorMessage { get; init; }
|
|
|
|
public static ImageLoadResult Fail(string message) => new()
|
|
{
|
|
Success = false,
|
|
ErrorMessage = message,
|
|
};
|
|
|
|
public static ImageLoadResult Ok(string base64) => new()
|
|
{
|
|
Success = true,
|
|
Base64Image = base64,
|
|
};
|
|
}
|
|
|
|
|
|
public static async Task<ImageLoadResult> ValidateImageAsync(string base64String, bool banner, CancellationToken token)
|
|
{
|
|
if (token.IsCancellationRequested)
|
|
return ImageLoadResult.Fail("Operation cancelled.");
|
|
|
|
byte[] imageData;
|
|
try
|
|
{
|
|
imageData = Convert.FromBase64String(base64String);
|
|
}
|
|
catch (FormatException)
|
|
{
|
|
return ImageLoadResult.Fail("The provided image is not a valid Base64 string.");
|
|
}
|
|
|
|
Image<Rgba32>? image = null;
|
|
bool imageLoaded = false;
|
|
IImageFormat? format = null;
|
|
|
|
try
|
|
{
|
|
using (var ms = new MemoryStream(imageData))
|
|
{
|
|
format = await Image.DetectFormatAsync(ms, token).ConfigureAwait(false);
|
|
}
|
|
|
|
if (format == null)
|
|
{
|
|
return ImageLoadResult.Fail("Unable to detect image format.");
|
|
}
|
|
|
|
using (image = Image.Load<Rgba32>(imageData))
|
|
{
|
|
imageLoaded = true;
|
|
|
|
int maxWidth = banner ? _imageWidthBanner : _imageWidthAvatar;
|
|
int maxHeight = banner ? _imageHeightBanner : _imageHeightAvatar;
|
|
|
|
if (image.Width > maxWidth || image.Height > maxHeight)
|
|
{
|
|
var ratio = Math.Min((double)maxWidth / image.Width, (double)maxHeight / image.Height);
|
|
int newWidth = (int)(image.Width * ratio);
|
|
int newHeight = (int)(image.Height * ratio);
|
|
|
|
image.Mutate(x => x.Resize(newWidth, newHeight));
|
|
}
|
|
|
|
using var memoryStream = new MemoryStream();
|
|
|
|
await image.SaveAsPngAsync(memoryStream, token).ConfigureAwait(false);
|
|
|
|
if (memoryStream.Length > _imageSize * 1024)
|
|
{
|
|
return ImageLoadResult.Fail("Your image exceeds 2 MiB after resizing/conversion.");
|
|
}
|
|
|
|
string base64Png = Convert.ToBase64String(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);
|
|
return ImageLoadResult.Ok(base64Png);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
if (imageLoaded)
|
|
image?.Dispose();
|
|
|
|
return ImageLoadResult.Fail("Failed to load or process the image. It may be corrupted or unsupported.");
|
|
}
|
|
}
|
|
}
|
|
}
|