I am trying to work with MemoryStream in C#.
So, I do converting Image to byte array and byte array to Image.
Like this
var bytes = File.ReadAllBytes("1.jpg");
var ms = new MemoryStream(bytes, true);
var image = Image.FromStream(ms);
pictureBox1.Image = image;
It works fine (displaying image in picture box). But when i try to change byte array
bytes[0] = 254
It throws exception invalid parameter.
So, how I can change byte array or write bytes to stream? ms.WriteByte not works. Thanks
JPEG (JPG) file is compressed representation of an image. It has complex structure, it is not byte matrix. Modification of first byte in it will most likely render it invalid. You better apply your modifications to image. And then save image as JPEG.
Related
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 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.
I'm trying to convert several byte arrays (stored in SQL Server 2008 R2 as varbinary(8000)) into images so I can attach them to a PDF file (an example of the data is below). I keep getting "Parameter is not valid." when creating the Image from the MemoryStream. Any help on this?
MemoryStream memoryStream = new MemoryStream(byteArray);
Image image = Image.FromStream(memoryStream);
Bitmap bitmap = new Bitmap(image);
0x0A020101000000005E006500FA00FA0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010C00010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C1C0C7000FC2FFC1FE80C70007C2FFC1FE1FC7FFC1F03FC1FFC1FE3FC7FFC1F807C1FFC1FE3FC8FFC1F3C1FFC1FE3FC8FFC1FEC1FFC1FE3FC8FFC1FE7FC1FE3FC9FFBFC1FE3FC9FFC1DFC1FE3FC9FFC1CFC1FE3FC9FFC1F3C1FE3FC9FFC1FBC1FE3FC9FFC1F9C1FE3FC9FFC1F9C1FE3FC9FFC1FCC1FE3FC9FFC1FE7E3FC9FFC1FE7E3FCAFF7E3FC2FFC1FCC20007C4FF3E3FC2FFC1F8C300C4FF3E3FC2FFC1F1C2FFC1FC7FC3FF3E3FC2FFC1F1C2FFC1FC3FC3FF3E3FC2FFC1F1C3FF9FC3FF3E3FC2FFC1F1C3FFC1CFC3FF3E3FC2FFC1F1C3FFC1E7C3FF3E3FC2FFC1F1C3FFC1F3C3FF3E3FC2FFC1F1C3FFC1F3C3FF3E3FC2FFC1F1C3FFC1F3C3FF3E3FC2FFC1F1C3FFC1F3C3FF3E3FC2FFC1F1C3FFC1F3C3FF3E3FC2FFC1F1C3FFC1F3C3FF3E3FC2FFC1F1C3FFC1F3C2FFC1FE7E3FC2FFC1F1C3FFC1E7C2FFC1FE7E3FC2FFC1F1C3FFC1C7C2FFC1FCC1FE3FC2FFC1F1C3FFC1C7C2FFC1F9C1FE3FC2FFC1F1C3FFC1DFC2FFC1F9C1FE3FC2FFC1F1C3FFBFC2FFC1F9C1FE3FC2FFC1F1C2FFC1FC3FC2FFC1F3C1FE3FC2FFC1F0C2FFC1F8C3FFC1E7C1FE3FC2FFC1FEC2000FC3FFC1CFC1FE3FC3FFC2000FC3FF9FC1FE3FC9FF3FC1FE3FC8FFC1FE7FC1FE3FC8FFC1F0C1FFC1FE3FC8FFC1E7C1FFC1FE3FC8FFC1CFC1FFC1FE3FC8FF8FC1FFC1FE3FC8FFC1E0C1FFC1FE3FC8FFC1F8C1FFC1FE3FC8FFC1FC1FC1FE3FC9FF8FC1FE3FC9FFC1E7C1FE3FC9FFC1F0C1FE3FC9FFC1FE7E3FCAFF7E3FC2FFC1FCC300C4FF3E3FC2FFC1F8C3001FC3FF3E3FC2FFC1F1C3FF8FC3FF9E3FC2FFC1F1C3FF87C3FFC1CE3FC2FFC1F1C3FFC1F3C3FFC1CE3FC2FFC1F1C3FFC1F9C3FFC1EE3FC2FFC1F1C3FFC1FCC3FFC1E43FC2FFC1F1C3FFC1FE7FC2FFC1E43FC2FFC1F1C4FF3FC2FFC1E43FC2FFC1F1C4FF1FC2FFC1F03FC2FFC1F1C4FF1FC2FFC1F83FC2FFC1F1C4FF1FC2FFC1F83FC2FFC1F1C4FF1FC2FFC1F83FC2FFC1F1C4FF1FC2FFC1F83FC2FFC1F1C4FF1FC2FFC1F83FC2FFC1F1C4FF1FC2FFC1F83FC2FFC1F1C4FF1FC2FFC1F83FC2FFC1F1C3FFC1FE7FC2FFC1F83FC2FFC1F1C3FFC1FEC3FFC1F83FC2FFC1F1C3FFC1F9C3FFC1F83FC2FFC1F1C3FFC1F3C3FFC1F83FC2FFC1F1C3FFC1F7C3FFC1F83FC2FFC1F1C2FFC1FE0FC3FFC1F83FC2FFC1F0C3003FC3FFC1F83FC2FFC1F8C20001C4FFC1F83FC2FFC1FCC20003C4FFC1FC3FCAFFC1E43FCAFFC1E43FCAFFC1E43FCAFFC1EE3FCAFFC1EE3FCAFFC1CE3FCAFF3E3FCAFF7E3FC9FFC1FE7E3FC9FFC1FE7E3FC9FFC1FCC1FE3FC9FFC1F1C1FE3FC9FFC1C3C1FE3FC9FFC1DFC1FE3FC9FF9FC1FE3FC8FFC1E07FC1FE3FC8FFC1C1C1FFC1FE1FC7FF001FC1FFC1FEC9003FC1FFC1FE80C700C3FFC1FEC1C0C700C3FFC1FE
It's a
% file output
output: PCX ver. 2.8 image data, with palette
under linux I just transformed your hex stream from plain text to a binary file called output
echo
"0A020101000000005E006500FA00FA0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010C00010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C1C0C7000FC2FFC1FE80C70007C2FFC1FE1FC7FFC1F03FC1FFC1FE3FC7FFC1F807C1FFC1FE3FC8FFC1F3C1FFC1FE3FC8FFC1FEC1FFC1FE3FC8FFC1FE7FC1FE3FC9FFBFC1FE3FC9FFC1DFC1FE3FC9FFC1CFC1FE3FC9FFC1F3C1FE3FC9FFC1FBC1FE3FC9FFC1F9C1FE3FC9FFC1F9C1FE3FC9FFC1FCC1FE3FC9FFC1FE7E3FC9FFC1FE7E3FCAFF7E3FC2FFC1FCC20007C4FF3E3FC2FFC1F8C300C4FF3E3FC2FFC1F1C2FFC1FC7FC3FF3E3FC2FFC1F1C2FFC1FC3FC3FF3E3FC2FFC1F1C3FF9FC3FF3E3FC2FFC1F1C3FFC1CFC3FF3E3FC2FFC1F1C3FFC1E7C3FF3E3FC2FFC1F1C3FFC1F3C3FF3E3FC2FFC1F1C3FFC1F3C3FF3E3FC2FFC1F1C3FFC1F3C3FF3E3FC2FFC1F1C3FFC1F3C3FF3E3FC2FFC1F1C3FFC1F3C3FF3E3FC2FFC1F1C3FFC1F3C3FF3E3FC2FFC1F1C3FFC1F3C2FFC1FE7E3FC2FFC1F1C3FFC1E7C2FFC1FE7E3FC2FFC1F1C3FFC1C7C2FFC1FCC1FE3FC2FFC1F1C3FFC1C7C2FFC1F9C1FE3FC2FFC1F1C3FFC1DFC2FFC1F9C1FE3FC2FFC1F1C3FFBFC2FFC1F9C1FE3FC2FFC1F1C2FFC1FC3FC2FFC1F3C1FE3FC2FFC1F0C2FFC1F8C3FFC1E7C1FE3FC2FFC1FEC2000FC3FFC1CFC1FE3FC3FFC2000FC3FF9FC1FE3FC9FF3FC1FE3FC8FFC1FE7FC1FE3FC8FFC1F0C1FFC1FE3FC8FFC1E7C1FFC1FE3FC8FFC1CFC1FFC1FE3FC8FF8FC1FFC1FE3FC8FFC1E0C1FFC1FE3FC8FFC1F8C1FFC1FE3FC8FFC1FC1FC1FE3FC9FF8FC1FE3FC9FFC1E7C1FE3FC9FFC1F0C1FE3FC9FFC1FE7E3FCAFF7E3FC2FFC1FCC300C4FF3E3FC2FFC1F8C3001FC3FF3E3FC2FFC1F1C3FF8FC3FF9E3FC2FFC1F1C3FF87C3FFC1CE3FC2FFC1F1C3FFC1F3C3FFC1CE3FC2FFC1F1C3FFC1F9C3FFC1EE3FC2FFC1F1C3FFC1FCC3FFC1E43FC2FFC1F1C3FFC1FE7FC2FFC1E43FC2FFC1F1C4FF3FC2FFC1E43FC2FFC1F1C4FF1FC2FFC1F03FC2FFC1F1C4FF1FC2FFC1F83FC2FFC1F1C4FF1FC2FFC1F83FC2FFC1F1C4FF1FC2FFC1F83FC2FFC1F1C4FF1FC2FFC1F83FC2FFC1F1C4FF1FC2FFC1F83FC2FFC1F1C4FF1FC2FFC1F83FC2FFC1F1C4FF1FC2FFC1F83FC2FFC1F1C3FFC1FE7FC2FFC1F83FC2FFC1F1C3FFC1FEC3FFC1F83FC2FFC1F1C3FFC1F9C3FFC1F83FC2FFC1F1C3FFC1F3C3FFC1F83FC2FFC1F1C3FFC1F7C3FFC1F83FC2FFC1F1C2FFC1FE0FC3FFC1F83FC2FFC1F0C3003FC3FFC1F83FC2FFC1F8C20001C4FFC1F83FC2FFC1FCC20003C4FFC1FC3FCAFFC1E43FCAFFC1E43FCAFFC1E43FCAFFC1EE3FCAFFC1EE3FCAFFC1CE3FCAFF3E3FCAFF7E3FC9FFC1FE7E3FC9FFC1FE7E3FC9FFC1FCC1FE3FC9FFC1F1C1FE3FC9FFC1C3C1FE3FC9FFC1DFC1FE3FC9FF9FC1FE3FC8FFC1E07FC1FE3FC8FFC1C1C1FFC1FE1FC7FF001FC1FFC1FEC9003FC1FFC1FE80C700C3FFC1FEC1C0C700C3FFC1FE"
| xxd -p -r >output
and then the easy part with file output to get the name of the file format from the utility file.
First, make sure you know the encoding, as the Image.FromStream method knows only a limited number of formats.
Make sure that the Position of your MemoryStream is set properly to 0, and not to the end - otherwise, any reads will begin at the end appear to be empty, instead of starting at the beginning.
Also, note that
This constructor does not expose the underlying stream. GetBuffer throws UnauthorizedAccessException.1
Thus, this could be caused by some of the way Bitmap is handling the underlying stream. IF need be, try making an empty memorystream, copying the byte into it, and then resetting the position
MemoryStream memoryStream = new MemoryStream();
foreach(var b in byteArray) memoryStream.WriteByte(b);
memoryStream.Position = 0;
Image image = Image.FromStream(memoryStream);
The byte array you gave is 1117 bytes long. That's not evenly divisible by 4 or 3, so I'm pretty certain that the image is not raw bytes and is actually encoded in an image format of some sort.
The Image.FromStream() method can't decode an encoded image without knowing the format, and the byte array you gave doesn't specify what that format is. Therefore the parameter you gave is invalid. If you know the format of the image you could attempt to insert a header into the byte array before the rest of the image, and see if that helps. It's curious you have the image but not its header, although it doesn't appear to be a base-64 string either.
Without knowing the image format it could be difficult to convert these byte arrays into images. Is there any way you could find out what they are? How is the image data retrieved to be stored?
I'm trying to convert a JPG image to a (double) 2d array. Using:
Image image = Image.FromFile("image.jpg");
I get a 500 x 500 image (according to image.Size.Height(Width)). But when I try to convert this to a byte array using
byte[] arr;
using (MemoryStream ms = new MemoryStream())
{
image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
arr = ms.ToArray();
}
I get arr.GetLength(0)=35640, which is smaller than 500*500=250000. I'll convert the 1d array arr to a 2d array after that. Am I missing something?
You are not saving a pixel representation.. you are saving the bytes of a JPEG file. If you want actual pixels you need to loop over the pixels.
Also be aware that each pixel has a minimum of 3 components: Red, Green, Blue.
If you save the image in JPEG format, the pixels written to the stream will be compressed.
If you're wanting to manipulate the pixels of the image, you should probably load the image into a Bitmap and then call Bitmap.LockBits to get at the raw pixels in memory.
I'm working on a class that will help me read a game file, and part of the file is an image. Is there an image object that I can create from a byte array, or should I just store the image as a byte array? If I were to put that image into a picture displayer in winforms, can I do that with a byte array?
What's the best way to store the data from the file?
like this:
byte[] data = getYourImageData();
MemoryStream ms = new MemoryStream(data);
pictureBox1.Image = Image.FromStream(ms);
to answer the other part of your question, it is fine to store it as a byte array - maybe provide a helper method that returns a memory stream as seen above, or alternatively store it in a System.Drawing.Bitmap and return that:
return new Bitmap(ms);
The Bitmap class in System.Drawing supports a constructor that takes a stream as a parameter. This stream can be supplied by a MemoryStream that is created from a byte array.
Once you have the bitmap, a PictureBox can be used to display it.
References:
http://msdn.microsoft.com/en-us/library/z7ha67kw.aspx (for the bitmap)
http://msdn.microsoft.com/en-us/library/system.io.memorystream.aspx (for the stream)
http://msdn.microsoft.com/en-us/library/system.windows.forms.picturebox.aspx (PictureBox)