I have two c# functions that convert byte[] to images and back. I thought that the two functions would be exactly reversible:
public static byte[] ImageToByte(System.Drawing.Image image, System.Drawing.Imaging.ImageFormat format)
{
using (MemoryStream ms = new MemoryStream())
{
// Convert Image to byte[]
image.Save(ms, format);
byte[] imageBytes = ms.ToArray();
return imageBytes;
}
}
public static Image ByteToImage(byte[] imageBytes)
{
using (MemoryStream ms = new MemoryStream())
{
ms.Write(imageBytes, 0, imageBytes.Length);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
}
However, if i look at the original byte array and then converted/reconverted array they are different (different lengths). I am not clear why? I would like to be able to tell if the image has been modified in my app so need to be able to compare the image array before and after.
Thanks
There is no reason to expect that both functions are reversible to get identical byte data, unless you choose an image format that does not use compression schemes controlled by variable parameters (like PNG or JPG, for example) and does not feature metadata fields that can change without altering the pixel data (like bytes 6...9 in a BMP format header, for example), or are not maintained by the infrastructure underlying System.Drawing.Image.
Instead of trying to compare the raw byte data (which can be variable depending on the image file format being used), compare the actual pixel data. In other words, load both your "before" image and "after" image into System.Drawing.Image instances, and then compare the pixel data of both images. Make sure both image instances use the same pixel format before you compare the pixel data. (Use the widest pixel format available like 64bppArgb to avoid potential reduction of the color space of the images loaded, which otherwise could spoil your efforts.) Also make sure that you don't use a "lossy" format like JPEG for your "before" and "after" pictures, otherwise the simple act of uncompressing/decoding and re-compressing/encoding of the image might change the actual pixel data.
I'm working on a C# form that reads graphics from a binary file and allows me to create maps with it. I'm having trouble trying to display an image on the form based on the bytes in the binary file. This binary file stores a bunch of 8x8 pixel images and each row of this image is stored in two different bytes, which I have to do some processing on. After reading all the bytes, I need to get palette data based on these bytes and then I can finally get my image colored properly.
I won't get into details of how the image processing works, since I think I can do that by myself (unless someone is curious, then I can explain in more detail - I'm basically reading a CHR file that contains patterns for a NES game and displaying a tile using the NES palette). By the end of all this processing, I have the RGB values for each pixel of the image stored as a byte array. My problem is that I don't know how to convert this byte array into a 8x8 image.
So for example, suppose I have a 8x8 tile that is just a red tile. By the end of the processing, this tile would be represented by an array like this (each pixel uses 3 bytes: byte 1 = R, byte 2 = G, byte 3 = B):
byte[] tilecolors = {255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0, }
So, binary file has a bunch of these images stored in it as bytes and I want to do is transform those bytes into 8x8 images that will be displayed in an app (probably inside a picturebox, since I want the app user to use these tiles to create maps and stuff).
I tried using a function I saw on another website that reads loads an image from bytes using MemoryStream, but I get a "Parameter is not valid" error. This is the function I tried:
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
EDIT:
I got it to work by following #ckuri 's suggestion. After I calculate the RGB colors from reading the binary file, I can use the Bitmap class's SetPixel method to draw the image.
I have a .png file and I did the following two things
Read the file as a byte array
byte[] arr = File.ReadAllBytes(Filename)
Read it using Emgu, read the file into Image and then converted the Bitmap to a byte array using the following.
Image<Gray,Byte> Img = new Image<Gray,Byte>(Filename);
byte[] arr = ImageToByte2(Img.Bitmap);
public static byte[] ImageToByte2(Image img)
{
using (MemoryStream stream = new MemoryStream())
{
img.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
return stream.ToArray();
}
}
I have a difference in length of the byte array. I don't understand why there is a difference. Please help.
The first option reads all bytes of the file including the header, while the second one just reads the byte of the plain image.
For more info on the structure and the header of a png look here: https://en.wikipedia.org/wiki/Portable_Network_Graphics
When you use EMGU to generate the PNG byte array, you can't be sure that the compression level is the same as the PNG image you had in the first place.
There is an overload for the save method, where you can specify encoder parameters as well. If you adjust the compression level, maybe you can get the same byte length.