public static void TestColorChange() { // Check a color with all the components to 0 DDS.ColorR5G6B5 black = Image.Color.Black; if (!Image.Color.Black.Equals((Image.Color)black)) { Console.WriteLine("Black pixel convertion failed!"); } // Check a color without color loss var gray = new Image.Color(248, 252, 248); DDS.ColorR5G6B5 convertedGray = gray; if (!gray.Equals((Image.Color)convertedGray)) { Console.WriteLine("Gray pixel convertion failed!"); } // Check the loss of the white information DDS.ColorR5G6B5 convertedWhite = Image.Color.White; if (!gray.Equals((Image.Color)convertedWhite)) { Console.WriteLine("White pixel convertion failed!"); } }
public static void TestReadBmp() { using (var fileStream = new FileStream("test.bmp", FileMode.Open)) { var bmp = BMP.BMP.read(fileStream); if (bmp.width != 16) { Console.WriteLine("Wrong BMP size"); } if (bmp.height != 16) { Console.WriteLine("Wrong BMP size"); } Image image = bmp; Image.Color firstColor = image[0, 0]; Image.Color lastColor = image[15, 15]; if (!firstColor.Equals(Image.Color.Red)) { Console.WriteLine("First pixel should be red"); } if (!lastColor.Equals(Image.Color.Black)) { Console.WriteLine("Last pixel should be black"); } fileStream.Close(); } }
public static void TestDDS() { Image gradient = gradientImage(); DDS.DDS dds = gradient; if (dds.width != (uint)(Math.Ceiling(gradient.width / 4f) * 4)) { Console.WriteLine("DDS file has an incorrent width!"); } if (dds.height != (uint)(Math.Ceiling(gradient.height / 4f) * 4)) { Console.WriteLine("DDS file has an incorrent height!"); } Image image2 = dds; Image.Color color0 = image2[5, 4]; Image.Color color1 = gradient[5, 4]; if (!color0.Equals(color1)) { Console.WriteLine("Image -> DDS -> Image fails pixel data!"); } }
public static Image gradientImage() { var image = new Image(23, 17); uint index = 0; for(uint i = 0; i < image.height; i++) { for(uint j = 0; j < image.width; j++, index++) { image[index] = new Image.Color(i * 10u, j * 10u, 0); } } return image; }
public static Image gradientImage() { var image = new Image(23, 17); uint index = 0; for (uint i = 0; i < image.height; i++) { for (uint j = 0; j < image.width; j++, index++) { image[index] = new Image.Color(i * 10u, j * 10u, 0); } } return(image); }
public void decode(ColorR5G6B5 colorOrig0, ColorR5G6B5 colorOrig1, UInt32 indices) { var color0 = colors[0] = colorOrig0; var color1 = colors[1] = colorOrig1; // Select color2 and color3 following the COMPRESSED_RGB_S3TC_DXT1_EXT spec // // https://www.opengl.org/registry/specs/EXT/texture_compression_s3tc.txt // if (colorOrig0.value >= colorOrig1.value) { colors[2] = new Image.Color( (2f * color0.r + color1.r) / 3f, (2f * color0.g + color1.g) / 3f, (2f * color0.b + color1.b) / 3f); colors[3] = new Image.Color( (color0.r + 2f * color1.r) / 3f, (color0.g + 2f * color1.g) / 3f, (color0.b + 2f * color1.b) / 3f); } else { colors[2] = new Image.Color( (color0.r + color1.r) / 2f, (color0.g + color1.g) / 2f, (color0.b + color1.b) / 2f); colors[3] = Image.Color.Black; } // Decode from bitarray for(int i = 0; i < 16; i++) { var index = (byte)(indices & 0x3); pixels[i] = colors[index]; indices = indices >> 2; } }
public static void TestDDSBlock() { // R5G6B5 lossless color var color = new Image.Color(248, 252, 248); // Image with a single block Image image = new Image(4, 4, color); // Image -> DDS DDS.DDS dds = image; if (dds.horizontalBlocks != 1 || dds.verticalBlocks != 1) { Console.WriteLine("DDS file has an incorrent number of blocks!"); } if (!dds[0][0].Equals(color) || !dds[0][0].Equals(color)) { Console.WriteLine("DDS block has an incorrent color!"); } // Get serialized block struct DDS_DXT1Block structBlock = dds[0]; Image.Color color2 = structBlock.color0; if (!color2.Equals(color) || (structBlock.indices & 0x3) != 0) { Console.WriteLine("StructBlock contains incorrect colors!"); } // Set some colors to black and get the block again image[7] = Image.Color.Black; image[15] = Image.Color.Black; // image -> dds -> block -> struct block -> block dds = image; structBlock = dds[0]; DXT1Block block = structBlock; var color3 = block[0]; var color4 = block[7]; var color5 = block[15]; if (!color3.Equals(color) || !color4.Equals(Image.Color.Black) || !color5.Equals(Image.Color.Black)) { Console.WriteLine("DDS failed saving/restoring 2 colors!"); } // Let's save the file and see what happens File.Delete("block.dds"); using (var fileStream = new FileStream("block.dds", FileMode.OpenOrCreate)) { dds.write(fileStream); fileStream.Close(); } DDS.DDS dds2; using (var fileStream = new FileStream("block.dds", FileMode.OpenOrCreate)) { dds2 = DDS.DDS.read(fileStream); fileStream.Close(); } block = dds2[0]; color3 = block[0]; color4 = block[7]; color5 = block[15]; if (!color3.Equals(color) || !color4.Equals(Image.Color.Black) || !color5.Equals(Image.Color.Black)) { Console.WriteLine("DDS failed saving/restoring 2 colors!"); } }
public static void TestWriteBmp() { BMP.BMP bmp; Image gradient = gradientImage(); // Load the example test.bmp using (var fileStream = new FileStream("test.bmp", FileMode.Open)) { bmp = BMP.BMP.read(fileStream); fileStream.Close(); } // Check replicating the test file test.bmp File.Delete("test2.bmp"); using (var fileStream2 = new FileStream("test2.bmp", FileMode.OpenOrCreate)) { // Convert to image and back to bmp Image image = bmp; bmp = image; bmp.write(fileStream2); fileStream2.Close(); } // Check the padding and content generating a gradient File.Delete("gradient.bmp"); using (var fileStream = new FileStream("gradient.bmp", FileMode.OpenOrCreate)) { // Convert to BMP bmp = gradient; // Write it to the disk bmp.write(fileStream); fileStream.Close(); } // Check the saved grandient using (var fileStream = new FileStream("gradient.bmp", FileMode.Open)) { bmp = BMP.BMP.read(fileStream); if (bmp.width != gradient.width) { Console.WriteLine("Saved and read gradient image contain different width!"); } if (bmp.uheight != gradient.height) { Console.WriteLine("Saved and read gradient image contain different height!"); } Image.Color color0 = gradient[5, 4]; Image.Color color1 = bmp[5, 4]; if (!color0.Equals(color1)) { Console.WriteLine("Saved and read gradient image contain different pixels!"); } fileStream.Close(); } }
public void encode() { // The idea is to get the most distant complementary colors in a simple way // A simple algorithm with an O(n) function cost var nearRed = pixels[0]; var nearGreen = pixels[0]; var nearBlue = pixels[0]; var nearYellow = pixels[0]; var nearCyan = pixels[0]; var nearMarge = pixels[0]; var nearWhite = pixels[0]; var nearBlack = pixels[0]; var distRed = startDistance; var distGreen = startDistance; var distBlue = startDistance; var distYellow = startDistance; var distCyan = startDistance; var distMarge = startDistance; var distWhite = startDistance; var distBlack = startDistance; var newDistance = startDistance; // First we will check the closest color to each axis foreach (var color in pixels) { newDistance = Image.Color.Red.distance(color); if (newDistance < distRed) { nearRed = color; distRed = newDistance; } newDistance = Image.Color.Green.distance(color); if (newDistance < distGreen) { nearGreen = color; distGreen = newDistance; } newDistance = Image.Color.Blue.distance(color); if (newDistance < distBlue) { nearBlue = color; distBlue = newDistance; } newDistance = Image.Color.Yellow.distance(color); if (newDistance < distYellow) { nearYellow = color; distYellow = newDistance; } newDistance = Image.Color.Cyan.distance(color); if (newDistance < distCyan) { nearCyan = color; distCyan = newDistance;; } newDistance = Image.Color.Margenta.distance(color); if (newDistance < distMarge) { nearMarge = color; distMarge = newDistance; } newDistance = Image.Color.White.distance(color); if (newDistance < distWhite) { nearWhite = color; distWhite = newDistance; } newDistance = Image.Color.Black.distance(color); if (newDistance < distBlack) { nearBlack = color; distBlack = newDistance; } } // Get the most distant complementary colors var lastDistance = nearRed.distance(nearCyan); colors[0] = nearRed; colors[1] = nearCyan; newDistance = nearBlue.distance(nearYellow); if (lastDistance < newDistance) { colors[0] = nearBlue; colors[1] = nearYellow; lastDistance = newDistance; } newDistance = nearGreen.distance(nearMarge); if (lastDistance < newDistance) { colors[0] = nearGreen; colors[1] = nearMarge; } newDistance = nearWhite.distance(nearBlack); if (lastDistance < newDistance) { colors[0] = nearWhite; colors[1] = nearBlack; } // By default make color0 bigger than color1, so we get // more interpolation values ColorR5G6B5 color_0_R5G6B5 = colors[0]; ColorR5G6B5 color_1_R5G6B5 = colors[1]; // Compare the R5G6B5 colors if (color_0_R5G6B5.value < color_1_R5G6B5.value) { colors[1] = color_1_R5G6B5; colors[0] = color_0_R5G6B5; } else { colors[0] = color_0_R5G6B5; colors[1] = color_1_R5G6B5; } // Calculate the colors after the selection colors[2] = new Image.Color( (2f * colors[0].r + colors[1].r) / 3f, (2f * colors[0].g + colors[1].g) / 3f, (2f * colors[0].b + colors[1].b) / 3f); colors[3] = new Image.Color( (colors[0].r + 2f * colors[1].r) / 3f, (colors[0].g + 2f * colors[1].g) / 3f, (colors[0].b + 2f * colors[1].b) / 3f); // For each pixel in the texel block for(int i = 0; i < 16; i++) { // Select the closer color from the 4 colors var currentColor = pixels[i]; lastDistance = currentColor.distance(colors[0]); uint candidateColor = 0; for(uint j = 1; j < 4; j++) { newDistance = currentColor.distance(colors[j]); if (newDistance < lastDistance) { lastDistance = newDistance; candidateColor = j; } } // Save it in the index array indices |= ((candidateColor & 0x3) << (i * 2)); } }