如何在C#中从byte []创建bmp文件

Iva*_*nov 8 c# rgb byte bitmap 24-bit

我在TCP Client中收到了一个byte []数组.该数组包含一个24位RGB位图文件.如何创建具有给定宽度,高度和数据的位图文件?

在C++中我使用它

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;
}
Run Code Online (Sandbox Code Playgroud)

我怎么能在C#中做到这一点?

Guf*_*ffa 12

如果数组实际包含位图文件,那么您只需将字节保存为文件:

File.WriteAllBytes(fileName, imageData);
Run Code Online (Sandbox Code Playgroud)

如果数组仅包含原始像素数据,则可以使用以下数据创建Bitmap对象:

unsafe {
   fixed (byte* ptr = imageData) {
      using (Bitmap image = new Bitmap(width, height, stride, PixelFormat.Format24bppRgb, new IntPtr(ptr))) {
         image.Save(fileName);
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

stride值是扫描线之间的字节数.如果扫描线之间没有填充,width * 3则为24bpp格式.

此方法使用数组中的数据,而不在内存中创建整个图像的另一个副本(这就是它需要步幅值的原因).

如果位图数据在数组中颠倒存储,则该stride值应为负数,指针应为memory(ptr + stride * (height - 1))中最后一条扫描行的开头.


Sam*_*uel 10

我无法使用您将收到的流进行测试,但这应该可行.

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;
}
Run Code Online (Sandbox Code Playgroud)

  • @BeowulfOF:如果你不知道你在说什么,请不要发表评论.使用语句的开销几乎没有*并且您应该处理所有IDisposable对象,除非您需要它们才能生存.像你这样的人是我们仍然需要终结者的原因. (3认同)
  • @BeowulfOF:在MemoryStream上使用并没用.您应该始终关闭(或处置)内存流.此函数结束后,MemoryStream可用于清理,但不保证在任何特定时间处理,因此可能会长时间保持打开状态. (2认同)

Ree*_*sey 6

我建议在C#中创建一个Bitmap,并让它自己保存.

例如,请看这篇文章.(特别是,最后的回答是正确的.)