关于bmp格式详解

最近在做一个绘图板遇到关于构造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图片。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值