您的位置:首页 > 编程语言 > C语言/C++

关于bmp格式详解

2016-05-20 09:26 399 查看
最近在做一个绘图板遇到关于构造bmp格式问题,LoadImage不能识别,但是双击是可以打开bmp这个图片,找到详细原因,是因为LoadImage对图片的格式非常严格,但是双击打开图片的时候,会忽视一部分影响因素。

下面是详解:

一:BMP文件由文件头、位图信息头、颜色信息和图形数据四部分组成。

二:

头文件结构.(14字节)

typedef struct tagBITMAPFILEHEADER
{
WORD bfType;//位图文件的类型,必须为BM(1-2字节)
DWORD bfSize;//位图文件的大小,以字节为单位(3-6字节,低位在前)
WORD bfReserved1;//位图文件保留字,必须为0(7-8字节)
WORD bfReserved2;//位图文件保留字,必须为0(9-10字节)
DWORD bfOffBits;//位图数据的起始位置,以相对于位图(11-14字节,低位在前)
//文件头的偏移量表示,以字节为单位
}BITMAPFILEHEADER;


位图信息头(40字节)

typedef struct tagBITMAPINFOHEADER{
DWORD biSize;//本结构所占用字节数(15-18字节)
LONG biWidth;//位图的宽度,以像素为单位(19-22字节)
LONG biHeight;//位图的高度,以像素为单位(23-26字节)
WORD biPlanes;//目标设备的级别,必须为1(27-28字节)
WORD biBitCount;//每个像素所需的位数,必须是1(双色),(29-30字节)
//4(16色),8(256色)16(高彩色)或24(真彩色)之一
DWORD biCompression;//位图压缩类型,必须是0(不压缩),(31-34字节)
//1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
DWORD biSizeImage;//位图的大小(其中包含了为了补齐行数是4的倍数而添加的空字节),以字节为单位(35-38字节)
LONG biXPelsPerMeter;//位图水平分辨率,每米像素数(39-42字节)
LONG biYPelsPerMeter;//位图垂直分辨率,每米像素数(43-46字节)
DWORD biClrUsed;//位图实际使用的颜色表中的颜色数(47-50字节)
DWORD biClrImportant;//位图显示过程中重要的颜色数(51-54字节)
}BITMAPINFOHEADER;


颜色表:

<

当biBitCount=1,4,8时,分别有2,16,256个表项;

当biBitCount=24时,没有颜色表项

>

typedef struct tagRGBQUAD{
BYTE rgbBlue;//蓝色的亮度(值范围为0-255)
BYTE rgbGreen;//绿色的亮度(值范围为0-255)
BYTE rgbRed;//红色的亮度(值范围为0-255)
BYTE rgbReserved;//保留,必须为0
}RGBQUAD;


位图数据:

位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:

当biBitCount=1时,8个像素占1个字节;

当biBitCount=4时,2个像素占1个字节;

当biBitCount=8时,1个像素占1个字节;

当biBitCount=24时,1个像素占3个字节,按顺序分别为B,G,R;

Windows规定一个扫描行所占的字节数必须是

4的倍数(即以long为单位),不足的以0填充,

biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8) * bi.biHeight;

以下是我位图生成代码:(后面的位图数据数组是二维码,使用的话下个博客讲解)

#include "stdafx.h"
#include <windows.h>
#include "qrencode.h"
#include "../qrlib/lib.h"

// TODO: reference any additional headers you need in STDAFX.H
// and not in this file
#define OUT_FILE                    "code.bmp"                              // Output file name
#define OUT_FILE_PIXEL_PRESCALER    8                                           // Prescaler (number of pixels in bmp file for each QRCode pixel, on each dimension)

#define PIXEL_COLOR_R               0                                           // Color of bmp pixels
#define PIXEL_COLOR_G               0
#define PIXEL_COLOR_B               0

// BMP defines

#define BI_RGB          0L

#pragma pack(push, 2)

#pragma pack(pop)
typedef struct
{
BYTE b;
BYTE g;
BYTE r;
}RGB;
int QRcodeRest(char* str)
{
char*           szSourceSring = str;
unsigned int    unWidth, x, y, l, n, unWidthAdjusted, unDataBytes;
unsigned char*  pRGBData, *pSourceData, *pDestData;
QRcode*         pQRC;
FILE*           f;
// Compute QRCode

if (pQRC = QRcode_encodeString(szSourceSring, 0, QR_ECLEVEL_H, QR_MODE_8, 1))
{
unWidth = pQRC->width;
unWidthAdjusted = unWidth * OUT_FILE_PIXEL_PRESCALER * 3;
if (unWidthAdjusted % 4)
unWidthAdjusted = (unWidthAdjusted / 4 + 1) * 4;//这里这个计算式非常重要,我是在这里出错了,导致LodeImage没有识别出来
unDataBytes = unWidthAdjusted * unWidth * OUT_FILE_PIXEL_PRESCALER;

// Allocate pixels buffer

if (!(pRGBData = (unsigned char*)malloc(unDataBytes)))
{
return 0;
}

// Preset to white

memset(pRGBData, 0xff, unDataBytes);

// Prepare bmp headers

BITMAPFILEHEADER kFileHeader;
kFileHeader.bfType = 0x4d42;  // "BM"
kFileHeader.bfSize = sizeof(BITMAPFILEHEADER)+
sizeof(BITMAPINFOHEADER)+
unDataBytes;
kFileHeader.bfReserved1 = 0;
kFileHeader.bfReserved2 = 0;
kFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER)+
sizeof(BITMAPINFOHEADER);

BITMAPINFOHEADER kInfoHeader;
kInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
kInfoHeader.biWidth = unWidth * OUT_FILE_PIXEL_PRESCALER;
kInfoHeader.biHeight = ((int)unWidth * OUT_FILE_PIXEL_PRESCALER);
kInfoHeader.biPlanes = 1;
kInfoHeader.biBitCount = 24;
kInfoHeader.biCompression = BI_RGB;
kInfoHeader.biSizeImage = (kInfoHeader.biWidth*kInfoHeader.biBitCount+31)/32*4*kInfoHeader.biHeight;
kInfoHeader.biXPelsPerMeter = 4000;
kInfoHeader.biYPelsPerMeter = 4000;
kInfoHeader.biClrUsed = 0;
kInfoHeader.biClrImportant = 0;

// Convert QrCode bits to bmp pixels

pSourceData = pQRC->data;
for (y = 0; y < unWidth; y++)
{
pDestData = pRGBData + unWidthAdjusted * y * OUT_FILE_PIXEL_PRESCALER;
for (x = 0; x < unWidth; x++)
{
if (*pSourceData & 1)
{
for (l = 0; l < OUT_FILE_PIXEL_PRESCALER; l++)
{
for (n = 0; n < OUT_FILE_PIXEL_PRESCALER; n++)
{
*(pDestData + n * 3 + unWidthAdjusted * l) = PIXEL_COLOR_B;
*(pDestData + 1 + n * 3 + unWidthAdjusted * l) = PIXEL_COLOR_G;
*(pDestData + 2 + n * 3 + unWidthAdjusted * l) = PIXEL_COLOR_R;
}
}
}
pDestData += 3 * OUT_FILE_PIXEL_PRESCALER;
pSourceData++;
}
}
// Output the bmp file

if ((!fopen_s(&f, OUT_FILE, "wb")))
{
fwrite(&kFileHeader, sizeof(BITMAPFILEHEADER), 1, f);
fwrite(&kInfoHeader, sizeof(BITMAPINFOHEADER), 1, f);
fwrite(pRGBData, sizeof(unsigned char), unDataBytes, f);

fclose(f);
}
else
{
return 0;
}

// Free data

free(pRGBData);
QRcode_free(pQRC);
}
else
{
return 0;
}

return 0;

}


只要参考好上面的结构体,依次写入,就可以生成出对应的bmp图片。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  bmp 图片 c++ windows