using Scry.Core.Imaging; using SkiaSharp; using Xunit; namespace Scry.Tests; public class ImagePreprocessorTests { [Fact] public void Resize_ProducesCorrectDimensions() { using var bitmap = CreateTestBitmap(100, 100); using var resized = ImagePreprocessor.Resize(bitmap, 32, 32); Assert.Equal(32, resized.Width); Assert.Equal(32, resized.Height); } [Fact] public void ToGrayscale_ProducesGrayscaleImage() { using var bitmap = CreateColorBitmap(10, 10); using var grayscale = ImagePreprocessor.ToGrayscale(bitmap); Assert.Equal(10, grayscale.Width); Assert.Equal(10, grayscale.Height); } [Fact] public void ApplyClahe_PreservesDimensions() { using var bitmap = CreateTestBitmap(64, 64); using var result = ImagePreprocessor.ApplyClahe(bitmap); Assert.Equal(64, result.Width); Assert.Equal(64, result.Height); } [Fact] public void ApplyClahe_EnhancesContrast() { using var bitmap = CreateLowContrastBitmap(64, 64); using var result = ImagePreprocessor.ApplyClahe(bitmap); Assert.NotNull(result); Assert.Equal(bitmap.Width, result.Width); Assert.Equal(bitmap.Height, result.Height); } [Theory] [InlineData("varying_quality/test1.jpg")] [InlineData("low_light/glare_toploader.png")] [InlineData("foil/rainbow_foil_secret_lair.jpg")] public void ApplyClahe_RealImages_DoesNotCrash(string imagePath) { var fullPath = Path.Combine("TestImages", imagePath); if (!File.Exists(fullPath)) { return; } using var bitmap = SKBitmap.Decode(fullPath); Assert.NotNull(bitmap); using var result = ImagePreprocessor.ApplyClahe(bitmap); Assert.Equal(bitmap.Width, result.Width); Assert.Equal(bitmap.Height, result.Height); } private static SKBitmap CreateTestBitmap(int width, int height) { var bitmap = new SKBitmap(width, height, SKColorType.Rgba8888, SKAlphaType.Premul); using var canvas = new SKCanvas(bitmap); canvas.Clear(SKColors.Gray); return bitmap; } private static SKBitmap CreateColorBitmap(int width, int height) { var bitmap = new SKBitmap(width, height, SKColorType.Rgba8888, SKAlphaType.Premul); for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++) { var r = (byte)(x * 255 / width); var g = (byte)(y * 255 / height); var b = (byte)((x + y) * 127 / (width + height)); bitmap.SetPixel(x, y, new SKColor(r, g, b)); } } return bitmap; } private static SKBitmap CreateLowContrastBitmap(int width, int height) { var bitmap = new SKBitmap(width, height, SKColorType.Rgba8888, SKAlphaType.Premul); for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++) { var gray = (byte)(120 + (x + y) % 20); bitmap.SetPixel(x, y, new SKColor(gray, gray, gray)); } } return bitmap; } private static (byte Min, byte Max) GetLuminanceRange(SKBitmap bitmap) { byte min = 255; byte max = 0; for (var y = 0; y < bitmap.Height; y++) { for (var x = 0; x < bitmap.Width; x++) { var pixel = bitmap.GetPixel(x, y); var luminance = (byte)(0.299 * pixel.Red + 0.587 * pixel.Green + 0.114 * pixel.Blue); min = Math.Min(min, luminance); max = Math.Max(max, luminance); } } return (min, max); } }