Browse Source

Clean up/clarify test helper method

pull/3137/head
Erik White 1 month ago
parent
commit
fb207199f5
  1. 38
      tests/ImageSharp.Tests/Formats/Png/PngCgbiProcessorTests.cs

38
tests/ImageSharp.Tests/Formats/Png/PngCgbiProcessorTests.cs

@ -120,34 +120,42 @@ public class PngCgbiProcessorTests
Assert.True(vectorTail.SequenceEqual(inputTail)); Assert.True(vectorTail.SequenceEqual(inputTail));
} }
/// <summary>
/// Builds synthetic input for tests. Produces inputs that exercise all three alpha cases.
/// </summary>
/// <returns>Channel values laid out as a defiltered CgBI scanline in premultiplied BGRA order</returns>
private static byte[] CreateBgraScanline(int pixelCount) private static byte[] CreateBgraScanline(int pixelCount)
{ {
// Deterministic mix of edge cases (a=0, a=255, partial alpha) and varied channels. // The distinct strides keep the channels from being equal to each other or constant across pixels
// So a bug that e.g. swaps two channels or reuses one channel's value doesn't accidentally pass
const int alphaCaseCount = 7;
const int redStride = 13;
const int greenStride = 29;
const int blueStride = 53;
byte[] bytes = new byte[pixelCount * 4]; byte[] bytes = new byte[pixelCount * 4];
for (int p = 0; p < pixelCount; p++) for (int p = 0; p < pixelCount; p++)
{ {
byte a = (p % 7) switch // Cycling alpha through [0..255], and an odd partial value every pixel rotation
// ensures all three branches get covered within any scanline of 3 or more pixels
byte a = (p % alphaCaseCount) switch
{ {
0 => byte.MinValue, 0 => byte.MinValue,
1 => byte.MaxValue, 1 => byte.MaxValue,
_ => (byte)((((p * 37) + 23) & 0xFF) | 1) // never zero _ => (byte)(((p * 37) + 23) | 1) // Produce a spread of alpha values and make sure to never get 0
}; };
// CgBI premultiplied BGRA: c' = c * a / 255 int offset = p * 4;
byte r = (byte)((p * 13) & 0xFF); bytes[offset + 0] = Premultiply((byte)(p * blueStride), a);
byte g = (byte)((p * 29) & 0xFF); bytes[offset + 1] = Premultiply((byte)(p * greenStride), a);
byte b = (byte)((p * 53) & 0xFF); bytes[offset + 2] = Premultiply((byte)(p * redStride), a);
r = (byte)((r * a) / byte.MaxValue); bytes[offset + 3] = a;
g = (byte)((g * a) / byte.MaxValue);
b = (byte)((b * a) / byte.MaxValue);
bytes[(p * 4) + 0] = b;
bytes[(p * 4) + 1] = g;
bytes[(p * 4) + 2] = r;
bytes[(p * 4) + 3] = a;
} }
return bytes; return bytes;
// CgBI stores channels premultiplied by alpha
static byte Premultiply(byte channel, byte alpha) => (byte)(channel * alpha / byte.MaxValue);
} }
private static void ApplyCgbiTransformScalarReference(Span<byte> scanline) private static void ApplyCgbiTransformScalarReference(Span<byte> scanline)

Loading…
Cancel
Save