using System.IO.Compression; namespace LudosData.Api.Tests; /// /// Builds a real PNG in memory, so upload tests exercise the actual decode path /// rather than a fixture file that could drift or go missing. /// public static class TestImages { public static byte[] Png(int width, int height) { // One filter byte per scanline, then RGB triples. var raw = new byte[height * (1 + width * 3)]; var offset = 0; for (var y = 0; y < height; y++) { raw[offset++] = 0; // filter: none for (var x = 0; x < width; x++) { raw[offset++] = (byte)(x * 8 % 256); raw[offset++] = (byte)(y * 8 % 256); raw[offset++] = 128; } } using var output = new MemoryStream(); output.Write([0x89, (byte)'P', (byte)'N', (byte)'G', 0x0D, 0x0A, 0x1A, 0x0A]); var header = new byte[13]; WriteBigEndian(header, 0, width); WriteBigEndian(header, 4, height); header[8] = 8; // bit depth header[9] = 2; // colour type: truecolour WriteChunk(output, "IHDR", header); WriteChunk(output, "IDAT", ZlibCompress(raw)); WriteChunk(output, "IEND", []); return output.ToArray(); } private static void WriteBigEndian(byte[] buffer, int index, int value) { buffer[index] = (byte)(value >> 24); buffer[index + 1] = (byte)(value >> 16); buffer[index + 2] = (byte)(value >> 8); buffer[index + 3] = (byte)value; } private static void WriteChunk(Stream stream, string type, byte[] data) { var length = new byte[4]; WriteBigEndian(length, 0, data.Length); stream.Write(length); var typeBytes = System.Text.Encoding.ASCII.GetBytes(type); stream.Write(typeBytes); stream.Write(data); var crc = Crc32([.. typeBytes, .. data]); var crcBytes = new byte[4]; WriteBigEndian(crcBytes, 0, unchecked((int)crc)); stream.Write(crcBytes); } private static byte[] ZlibCompress(byte[] data) { using var output = new MemoryStream(); using (var deflate = new ZLibStream(output, CompressionLevel.Fastest, leaveOpen: true)) { deflate.Write(data); } return output.ToArray(); } private static uint Crc32(byte[] data) { var crc = 0xFFFFFFFFu; foreach (var b in data) { crc ^= b; for (var i = 0; i < 8; i++) { crc = (crc & 1) != 0 ? (crc >> 1) ^ 0xEDB88320u : crc >> 1; } } return crc ^ 0xFFFFFFFFu; } }