Files
LightlessServer/LightlessSyncServer/LightlessSyncServer/Services/ImageCheckService.cs

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.");
}
}
}
}