// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // namespace ImageSharp.Tests { using System; using System.Collections.Generic; using System.Numerics; using ImageSharp.PixelFormats; using Xunit.Abstractions; public abstract partial class TestImageProvider where TPixel : struct, IPixel { /// /// A test image provider that produces test patterns. /// /// private class TestPatternProvider : BlankProvider { static Dictionary> testImages = new Dictionary>(); public TestPatternProvider(int width, int height) : base(width, height) { } public TestPatternProvider() : base() { } public override string SourceFileOrDescription => $"TestPattern{this.Width}x{this.Height}"; public override Image GetImage() { lock (testImages) { if (!testImages.ContainsKey(this.SourceFileOrDescription)) { Image image = new Image(this.Width, this.Height); DrawTestPattern(image); testImages.Add(this.SourceFileOrDescription, image); } } return new Image(testImages[this.SourceFileOrDescription]); } /// /// Draws the test pattern on an image by drawing 4 other patterns in the for quadrants of the image. /// /// private static void DrawTestPattern(Image image) { // first lets split the image into 4 quadrants using (PixelAccessor pixels = image.Lock()) { BlackWhiteChecker(pixels); // top left VirticalBars(pixels); // top right TransparentGradients(pixels); // bottom left Rainbow(pixels); // bottom right } } /// /// Fills the top right quadrant with alternating solid vertical bars. /// /// private static void VirticalBars(PixelAccessor pixels) { // topLeft int left = pixels.Width / 2; int right = pixels.Width; int top = 0; int bottom = pixels.Height / 2; int stride = pixels.Width / 12; TPixel[] c = { NamedColors.HotPink, NamedColors.Blue }; int p = 0; for (int y = top; y < bottom; y++) { for (int x = left; x < right; x++) { if (x % stride == 0) { p++; p = p % c.Length; } pixels[x, y] = c[p]; } } } /// /// fills the top left quadrant with a black and white checker board. /// /// private static void BlackWhiteChecker(PixelAccessor pixels) { // topLeft int left = 0; int right = pixels.Width / 2; int top = 0; int bottom = pixels.Height / 2; int stride = pixels.Width / 6; TPixel[] c = { NamedColors.Black, NamedColors.White }; int p = 0; for (int y = top; y < bottom; y++) { if (y % stride == 0) { p++; p = p % c.Length; } int pstart = p; for (int x = left; x < right; x++) { if (x % stride == 0) { p++; p = p % c.Length; } pixels[x, y] = c[p]; } p = pstart; } } /// /// Fills the bottom left quadrent with 3 horizental bars in Red, Green and Blue with a alpha gradient from left (transparent) to right (solid). /// /// private static void TransparentGradients(PixelAccessor pixels) { // topLeft int left = 0; int right = pixels.Width / 2; int top = pixels.Height / 2; int bottom = pixels.Height; int height = (int)Math.Ceiling(pixels.Height / 6f); Vector4 red = Rgba32.Red.ToVector4(); // use real color so we can see har it translates in the test pattern Vector4 green = Rgba32.Green.ToVector4(); // use real color so we can see har it translates in the test pattern Vector4 blue = Rgba32.Blue.ToVector4(); // use real color so we can see har it translates in the test pattern TPixel c = default(TPixel); for (int x = left; x < right; x++) { blue.W = red.W = green.W = (float)x / (float)right; c.PackFromVector4(red); int topBand = top; for (int y = topBand; y < top + height; y++) { pixels[x, y] = c; } topBand = topBand + height; c.PackFromVector4(green); for (int y = topBand; y < topBand + height; y++) { pixels[x, y] = c; } topBand = topBand + height; c.PackFromVector4(blue); for (int y = topBand; y < bottom; y++) { pixels[x, y] = c; } } } /// /// Fills the bottom right quadrant with all the colors producable by converting itterating over a uint and unpacking it. /// A better algorithm could be used but it works /// /// private static void Rainbow(PixelAccessor pixels) { int left = pixels.Width / 2; int right = pixels.Width; int top = pixels.Height / 2; int bottom = pixels.Height; int pixelCount = left * top; uint stepsPerPixel = (uint)(uint.MaxValue / pixelCount); TPixel c = default(TPixel); Rgba32 t = new Rgba32(0); for (int x = left; x < right; x++) for (int y = top; y < bottom; y++) { t.PackedValue += stepsPerPixel; Vector4 v = t.ToVector4(); //v.W = (x - left) / (float)left; c.PackFromVector4(v); pixels[x, y] = c; } } } } }