I am trying to read the bytes of a .png image using File.ReadAllBytes(string)
method without success.
My images are of size 2464x2056x3 (15.197.952 bytes), but this method returns an array of about 12.000.000 bytes.
I tried with a white image of the same size, and I am getting a byte array of 25.549, and checking the byte array I can see all kind of values, that obviously is not correct because is a white image.
The code I am using is:
var frame = File.ReadAllBytes("C:\\workspace\\white.png");
I've also tried to open the image first as an Image object then get the byte array with the following:
using (var ms = new MemoryStream())
{
var imageIn = Image.FromFile("C:\\workspace\\white.png");
imageIn.Save(ms, imageIn.RawFormat);
var array = ms.ToArray();
}
But the result is the same as before...
Any idea of what's happening?
How can I read the byte array?
CodePudding user response:
PNG is a compressed format.
See some info about it: Portable Network Graphics - Wikipedia.
This means that the binary representation is not the actual pixel values that you expect.
You need some kind of a PNG decoder to get the pixel values from the compressed data.
This post might steer you in the right direction: Reading a PNG image file in .Net 2.0. Note that it's quite old, maybe there are newer methods for doing it.
On a side note: even a non compressed format like BMP has a header, so you can't simply read the binary file and get the pixel values in a trivial way.
Update: One way to get the pixel values from a PNG file is demonstrated below:
using System.Drawing.Imaging;
byte[] GetPngPixels(string filename)
{
byte[] rgbValues = null;
// Load the png and convert to Bitmap. This will use a .NET PNG decoder:
using (var imageIn = Image.FromFile(filename))
using (var bmp = new Bitmap(imageIn))
{
// Lock the pixel data to gain low level access:
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat);
// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;
// Declare an array to hold the bytes of the bitmap.
int bytes = Math.Abs(bmpData.Stride) * bmp.Height;
rgbValues = new byte[bytes];
// Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
// Unlock the pixel data:
bmp.UnlockBits(bmpData);
}
// Here rgbValues is an array of the pixel values.
return rgbValues;
}
This method will return a byte array with the size that you expect.
In order to use the data with opencv (or any similar usage), I advise you to enhance my code example and return also the image metadata (width, height, stride, pixel-format). You will need this metadata to construct a cv::Mat
.