From fb207199f5b3db589f8a2013caeb72f238e6c8e7 Mon Sep 17 00:00:00 2001
From: Erik White <26148654+Erik-White@users.noreply.github.com>
Date: Thu, 11 Jun 2026 16:38:29 +0200
Subject: [PATCH] Clean up/clarify test helper method
---
.../Formats/Png/PngCgbiProcessorTests.cs | 38 +++++++++++--------
1 file changed, 23 insertions(+), 15 deletions(-)
diff --git a/tests/ImageSharp.Tests/Formats/Png/PngCgbiProcessorTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngCgbiProcessorTests.cs
index 426afb6d42..cd03c5e488 100644
--- a/tests/ImageSharp.Tests/Formats/Png/PngCgbiProcessorTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Png/PngCgbiProcessorTests.cs
@@ -120,34 +120,42 @@ public class PngCgbiProcessorTests
Assert.True(vectorTail.SequenceEqual(inputTail));
}
+ ///
+ /// Builds synthetic input for tests. Produces inputs that exercise all three alpha cases.
+ ///
+ /// Channel values laid out as a defiltered CgBI scanline in premultiplied BGRA order
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];
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,
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
- byte r = (byte)((p * 13) & 0xFF);
- byte g = (byte)((p * 29) & 0xFF);
- byte b = (byte)((p * 53) & 0xFF);
- r = (byte)((r * a) / byte.MaxValue);
- 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;
+ int offset = p * 4;
+ bytes[offset + 0] = Premultiply((byte)(p * blueStride), a);
+ bytes[offset + 1] = Premultiply((byte)(p * greenStride), a);
+ bytes[offset + 2] = Premultiply((byte)(p * redStride), a);
+ bytes[offset + 3] = a;
}
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 scanline)