创建BMP文件

时间:2011-03-26 17:58:22

标签: c++ image-processing file-io bmp

我已经在图像处理上工作了一段时间,我注意到了奇怪的事情。 我正在阅读一个BMP文件,使用简单的方法,如ReadFile和东西,并使用微软的BMP结构。 这是代码:

 ReadFile(_bmpFile,&bmpfh,sizeof(bfh),&data,NULL);
 ReadFile(_bmpFile, &bmpih, sizeof(bih), &data, NULL);
 imagesize = bih.biWidth*bih.biHeight;
 image = new RGBQUAD[imagesize];
 ReadFile(_bmpFile,image, imagesize*sizeof(RGBQUAD),&written,NULL);

这就是我读取文件然后使用简单的for循环将其转换为灰度的方法。

  for (int i = 0; i < imagesize; i++)
  {
       RED = image[i].rgbRed;
       GREEN = image[i].rgbGreen;
       BLUE = image[i].rgbBlue;
       avg = (RED + GREEN + BLUE ) / 3;
       image[i].rgbRed = avg;
       image[i].rgbGreen = avg;
       image[i].rgbBlue = avg;
  }

现在,当我使用以下代码编写文件时:

#pragma pack(push, 1)
WriteFile(_bmpFile, &bmpfh, sizeof(bfh), &data, NULL);
WriteFile(_bmpFile, &bmpih, sizeof(bih), &data, NULL);
WriteFile(_bmpFile, image, imagesize*sizeof(RGBQUAD), &written, NULL);
#pragma pack(pop)

文件越来越大(30MB - > 40MB)。

它发生的原因是因为我使用的是RGBQUAD而不是RGBTRIPLE,但是如果我使用的是RGBTRIPLE,我将小图片转换为 灰度 - 创建后无法打开图片(说它不在正确的结构中)。

文件大小缺少一个字节(1174kb和1173kb之后)

之前是否有人见过这种情况(只会出现小图片)?

3 个答案:

答案 0 :(得分:3)

在BMP文件中,必须填充每条扫描线,以便下一条扫描线在32位边界上开始。如果每个像素执行32位,则会自动执行此操作,但如果每个像素使用24位,则需要添加代码才能显式执行此操作。

答案 1 :(得分:2)

你忽略了步幅(Jerry的评论)和位图的像素格式。从文件大小增加来看,这是24bpp,你写的就好像是32bpp。您的灰度转换错误,人眼对红色,绿色和蓝色不敏感。

考虑使用GDI +,您在代码中使用#include <gdiplus.h>来使用Bitmap类。它的LockBits()方法使您可以访问位图位。 ColorMatrixEffect类允许您在单个操作中应用颜色转换。检查this answer以获取获得灰度图像所需的颜色矩阵。 MSDN文档start here

答案 2 :(得分:0)

  

BMP中的每个水平行必须是4个字节长的倍数。

     

如果像素数据不占用4个字节的倍数,则在行的末尾添加0x00个字节。对于24-bpp图像,每行的字节数是(imageWidth * 3 + 3)&amp; 〜3。填充字节数为((imageWidth * 3 + 3)&amp; ~3) - (imageWidth * 3)。

这是由immibis回答的。

我想补充说,数组的大小是((imageWidth * 3 + 3)&amp; ~3)* imageHeight。 我希望这有帮助