How to create a bmp file from byte[] in C#

41,646

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;
    }
Share:
41,646
P. Duw
Author by

P. Duw

Updated on June 28, 2020

Comments

  • P. Duw
    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
    Oliver Friedrich about 15 years
    The 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
    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
    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
    P. Duw about 15 years
    I 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
    Samuel about 15 years
    WriteBitmapFile("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
    P. Duw about 15 years
    "new Bitmap(width, height, stride" What is stride? I misunderstood.
  • Guffa
    Guffa about 15 years
    The 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
    P. Duw about 15 years
    Note - it should be something like this -> img26.imageshack.us/img26/4329/6e5647.png ,but its not :(
  • Samuel
    Samuel about 15 years
    It seems that he might not know the stride, so he may be screwed unless it's the default.
  • Guffa
    Guffa about 15 years
    The 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
    P. Duw about 15 years
    Its 32 bit,but its reversed :( stackoverflow.com/questions/743037/…
  • dovla110010101
    dovla110010101 over 8 years
    Hi 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.