关于bmp格式详解
2016-05-20 09:26
399 查看
最近在做一个绘图板遇到关于构造bmp格式问题,LoadImage不能识别,但是双击是可以打开bmp这个图片,找到详细原因,是因为LoadImage对图片的格式非常严格,但是双击打开图片的时候,会忽视一部分影响因素。
下面是详解:
一:BMP文件由文件头、位图信息头、颜色信息和图形数据四部分组成。
二:
头文件结构.(14字节)
位图信息头(40字节)
颜色表:
<
当biBitCount=1,4,8时,分别有2,16,256个表项;
当biBitCount=24时,没有颜色表项
>
位图数据:
位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:
当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;
以下是我位图生成代码:(后面的位图数据数组是二维码,使用的话下个博客讲解)
只要参考好上面的结构体,依次写入,就可以生成出对应的bmp图片。
下面是详解:
一: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图片。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 如何重装TCP/IP协议
- 关于指针的一些事情
- Windows 8 官方高清壁纸欣赏与下载
- 谁是桌面王者?Win PK Linux三大镇山之宝
- 对《大家都在点赞 Windows Terminal,我决定给你泼一盆冷水》一文的商榷
- Windows Clang开发环境备忘
- 从Windows系统下访问Linux分区相关软件
- 对《大家都在点赞 Windows Terminal,我决定给你泼一盆冷水》一文的商榷
- Windows下搭建本地SVN服务器
- 使用Windows原生命令一键清空剪贴板
- c++ primer 第五版 笔记前言
- 利用开源软件打造自己的全功能远程工具
- Windows 8虚拟机不能全屏的解决方法
- Visual Studio 2012 示例代码浏览器 - 数以千计的开发示例近在手边,唾手可得
- Visual Studio 2012 示例代码浏览器 - 数以千计的开发示例近在手边,唾手可得
- share_ptr的几个注意点
- 微软镜像下载