BMP格式

BMP是英文Bitmap(位圖)的簡寫,這種格式沒有對圖像數(shù)據(jù)進行壓縮,文件里保存了各個像素實際的RGB值,理解起來比較直觀,對學習圖像文件格式的入門很有幫助。

下面列出文件的結構

bmp_3.png
bmp_6.png
bmp_7.png

示例代碼bmp.h

#ifndef __BMP_H__
#define __BMP_H__


typedef unsigned char BYTE;   
typedef unsigned short WORD;   
typedef unsigned int DWORD;   
typedef long LONG;   


// bmp文件頭(bmp file header)
// 提供文件的格式、大小等信息
typedef struct
{
WORD bfType;       // 文件類型,BMP文件用0x4d42表示,即字符串"BM"。
DWORD bfSize;      // 文件大小,單位為字節(jié)
WORD bfReserved1;  // 保留,目前必須設置為0
WORD bfReserved2;  // 保留,目前必須設置為0
DWORD bfOffBits;   // 從文件開頭到圖像數(shù)據(jù)的偏移量
}BITMAPFILEHEADER;


// 位圖信息頭(bitmap information)
// 提供圖像數(shù)據(jù)的尺寸、位平面數(shù)、壓縮方式、顏色索引等信息
typedef struct
{
DWORD biSize;          // 位圖信息頭的長度,40字節(jié)
LONG biWidth;          // 位圖的寬度
LONG biHeight;         // 位圖的高度
WORD biPlanes;         // 目標設備級別,必須為1
WORD biBitCount;       // 每個像素所占位數(shù)(bit),二值圖像為1,灰度圖像為8,真彩色圖像為24
DWORD biCompression;   // 位圖壓縮類型
DWORD biSizeImage;     // 實際的位圖數(shù)據(jù)占用的字節(jié)數(shù)
LONG biXPelsPerMeter;  // 指定目標設備的水平分辨率
LONG biYPelsPerMeter;  // 指定目標設備的垂直分辨率
DWORD biClrUsed;       // 位圖實際用到的顏色數(shù)
DWORD biClrImportant;  // 位圖顯示過程中重要的顏色數(shù)
}BITMAPINFOHEADER;


// 調色板(color palette)
// 可選,如使用索引來表示圖像,調色板就是索引與其對應的顏色的映射表
// 24位的真彩色不需要這部分
typedef struct
{
BYTE rgbBlue;     // 藍色分量
BYTE rgbGreen;    // 綠色分量
BYTE rgbRed;      // 紅色分量
BYTE rgbReserved; // 保留字節(jié),暫時不用
}RGBQUAD;

bool SaveRgb888ToBmpSaveRgb888ToBmp(char * fileName,unsigned char *imgBuffer, int imWidth, int imHeight);

#endif

示例代碼bmp.cpp

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include"bmp.h"


int SaveRgb888ToBmp(char * fileName, unsigned char *imgBuffer, int imgWidth, int imgHeight)
{
    if (!imgBuffer)
    {
        return -1;
    }
    
    int biBitCount = 8;// RGB888格式,每個顏色通道8bit
    int colorTableSize = 0;// RGB888 不需要灰度圖像顏色表
    // windows規(guī)定一個掃描行所占的字節(jié)數(shù)必須是4的倍數(shù),不足4的倍數(shù)則要對其進行擴充。
    int lineByte = (imgWidth * biBitCount / 8 + 3) / 4 * 4;

    FILE *fp = fopen(fileName, "wb");
    if (!fp)
    {
        return -1;
    }

    // 填充文件頭
    BITMAPFILEHEADER fileHead;
    fileHead.bfType = 0x4D42;
    fileHead.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 
        colorTableSize + (lineByte * imHeight);
    fileHead.bfReserved1 = 0;
    fileHead.bfReserved2 = 0;
    fileHead.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + colorTableSize;

    // 寫文件頭
    fwrite(&fileHead , sizeof(LBITMAPfileHeadER), 1, fp);

    // 填充文件信息頭
    BITMAPINFOHEADER infoHead;
    infoHead.biSize = sizeof(BITMAPINFOHEADER); //40;
    infoHead.biWidth = imgWidth;
    infoHead.biHeight = 0 - imgHeight; // 正數(shù)表示RGB圖像數(shù)據(jù)行的順序倒置,負數(shù)表示RGB圖像數(shù)據(jù)行的順序正常
    infoHead.biBitCount = biBitCount;    
    infoHead.biPlanes = 1;
    infoHead.biCompression = 0;
    infoHead.biSizeImage = lineByte * imgHeight;
    infoHead.biXPelsPerMeter = 0;
    infoHead.biYPelsPerMeter = 0;
    infoHead.biClrUsed = 0;
    infoHead.biClrImportant = 0;
    
    //寫文件信息頭
    fwrite(&infoHead, sizeof(BITMAPINFOHEADER), 1, fp);

    // RGB888不需要顏色表
    /*
    RGBQUAD *pColorTable = new RGBQUAD[256];

    for (int i = 0 ; i < 256 ; i++)
    {
        pColorTable[i].rgbBlue = i;
        pColorTable[i].rgbGreen = i;
        pColorTable[i].rgbRed = i;
        //pColorTable[i].rgbReserved = 0;
    }

    fwrite(pColorTable, sizeof(RGBQUAD), 256, fp);
    */

    // RGB to BGR, 這里需要把R和B的順序兌換一下,具體原因還不知道
    unsigned char tmp;
    long imgSize = imgWidth * imgHeight * 3;
    for(unsigned long i=0; i<=imgSize-3; i+=3)
    {
        tmp = imgBuffer[i];
        imgBuffer[i] = imgBuffer[i+2];
        imgBuffer[i+2] = tmp;
    }
    
    // 寫真正的圖像數(shù)據(jù)
    fwrite(imgBuffer, imgHeight*lineByte, 1, fp);
    fclose(fp);

    return 0;
}

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容