How to create a bmp file from byte[] in C#
Solution 1
If the array actually contains a bitmap file, then you can just save the bytes as a file:
File.WriteAllBytes(fileName, imageData);
If the array contains only raw pixel data, you can create a Bitmap object using the data:
unsafe {
fixed (byte* ptr = imageData) {
using (Bitmap image = new Bitmap(width, height, stride, PixelFormat.Format24bppRgb, new IntPtr(ptr))) {
image.Save(fileName);
}
}
}
The stride
value is the number of bytes between the scan lines. If there is no padding between the scan lines, it's width * 3
for a 24bpp format.
This method uses the data in the array without creating another copy of the entire image in memory (which is why it needs the stride value).
If the bitmap data is stored upside down in the array, the stride
value should be negative, and the pointer should be the start of the last scan line in memory (ptr + stride * (height - 1)
).
Solution 2
I can't test it using the stream you will be receiving, but this should work.
int WriteBitmapFile(string filename, int width, int height, byte[] imageData)
{
using (var stream = new MemoryStream(imageData))
using (var bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb))
{
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0,
bmp.Width,
bmp.Height),
ImageLockMode.WriteOnly,
bmp.PixelFormat);
Marshal.Copy(imageData, 0, bmpData.Scan0, imageData.Length);
bmp.UnlockBits(bmpData);
bmp.Save(filename);
}
return 1;
}
Solution 3
I'd recommend making a Bitmap in C#, and letting it save itself.
For an example, see this post. (Particularly, the last response is correct.)
Solution 4
this is one way of doing it, here i have created a custom Event args that contains the size at which the image was stored as a byte array. You may not need to bother with this, this was code i created to retreive images from a byte array that a gige camera was storing to so for me this made sence.
public Bitmap ShowImage(byte[] sender, EventImageParams e)
{
Bitmap bitmap = new Bitmap(e.width, e.height, PixelFormat.Format24bppRgb);
BitmapData bmData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, bitmap.PixelFormat);
IntPtr pNative = bmData.Scan0;
Marshal.Copy(sender, 0, pNative, (e.width * e.height * 3));
//
bitmap.UnlockBits(bmData);
return bitmap;
}
Comments
-
P. Duw about 4 years
I have a byte[] array received in TCP Client.The array contains a 24-bit RGB Bitmap file.How to create that bitmap file with given Width ,Height and data?
In C++ I use this
int WriteBitmapFile(const char *filename, int width, int height, unsigned char *imageData) { FILE *filePtr; // file pointer BITMAPFILEHEADER bitmapFileHeader; // bitmap file header BITMAPINFOHEADER bitmapInfoHeader; // bitmap info header DWORD imageIdx; // used for swapping RGB->BGR unsigned char tempRGB; // used for swapping // open file for writing binary mode filePtr = fopen(filename, "wb"); if (!filePtr) return 0; // define the bitmap file header bitmapFileHeader.bfSize = sizeof(BITMAPFILEHEADER); bitmapFileHeader.bfType = 0x4D42; bitmapFileHeader.bfReserved1 = 0; bitmapFileHeader.bfReserved2 = 0; bitmapFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // define the bitmap information header bitmapInfoHeader.biSize = sizeof(BITMAPINFOHEADER); bitmapInfoHeader.biPlanes = 1; bitmapInfoHeader.biBitCount = 32; // 24-bit bitmapInfoHeader.biCompression = BI_RGB; // no compression bitmapInfoHeader.biSizeImage = width * abs(height) * 4; // width * height * (RGB bytes) bitmapInfoHeader.biXPelsPerMeter = 0; bitmapInfoHeader.biYPelsPerMeter = 0; bitmapInfoHeader.biClrUsed = 0; bitmapInfoHeader.biClrImportant = 0; bitmapInfoHeader.biWidth = width; // bitmap width bitmapInfoHeader.biHeight = height; // bitmap height // switch the image data from RGB to BGR for(imageIdx = 0; imageIdx < bitmapInfoHeader.biSizeImage; imageIdx+=4) { tempRGB = imageData[imageIdx]; imageData[imageIdx] = imageData[imageIdx + 2]; imageData[imageIdx + 2] = tempRGB; } // write the bitmap file header fwrite(&bitmapFileHeader, 1, sizeof(BITMAPFILEHEADER), filePtr); // write the bitmap info header fwrite(&bitmapInfoHeader, 1, sizeof(BITMAPINFOHEADER), filePtr); // write the image data fwrite(imageData, 1, bitmapInfoHeader.biSizeImage, filePtr); // close our file fclose(filePtr); // Success return 1; }
How could I do that in C#?
-
Oliver Friedrich about 15 yearsThe first using-Statement ist totally useless and just slows down the whole process, as the MemoryStream will be destroyed at the end of the function also without this using. The GarbageCollector does this for you. Using without brackets just slows down.
-
Reed Copsey about 15 years@BeowulfOF: The using on MemoryStream is not useless. You should always close (or Dispose) a memory stream. The MemoryStream will be available for cleanup after this function ends, but is not guaranteed to be disposed of at any specific time, so could stay open for a long time.
-
Samuel about 15 years@BeowulfOF: Please refrain from commenting if you have no idea what you are talking about. The overhead from using statements is almost nothing and you are supposed to dispose of all IDisposable objects unless you need them to survive. People like you are the reason why we still need finalizers.
-
P. Duw about 15 yearsI get exception on line "Marshal.Copy(imageData, 0, bmpData.Scan0, imageData.Length);" Memory is corrupt.ImgData has the length of 64 * 200 and the imageData.Length is exactly 64 * 200.Height is 64 and Width is 200.
-
Samuel about 15 yearsWriteBitmapFile("test.bmp", 64, 200, new byte[64 * 200]); works for me. It's hard to tell what's wrong without a sample stream.
-
P. Duw about 15 years"new Bitmap(width, height, stride" What is stride? I misunderstood.
-
Guffa about 15 yearsThe stride value is the number of bytes from the start address of a scan line to the start address of the next scan line. For 24 bit RGB data with no extra padding the stride value is width * 3.
-
P. Duw about 15 yearsNote - it should be something like this -> img26.imageshack.us/img26/4329/6e5647.png ,but its not :(
-
Samuel about 15 yearsIt seems that he might not know the stride, so he may be screwed unless it's the default.
-
Guffa about 15 yearsThe stride seems to be slightly off. If width * 4 is closer than 3 the data may actually be 32bppRgb. The scan lines might be padded to an even four byte boundary. Also as the image is upside down the stride should be negative and you need to point to the last scan line in memory.
-
P. Duw about 15 yearsIts 32 bit,but its reversed :( stackoverflow.com/questions/743037/…
-
dovla110010101 over 8 yearsHi Colm, since this is your custom code, can you please tell me how did you declare EventImageParams. I would like to see the code for "EventImageParams"... Can you please add this also to your answer.