Linux C++读取RGB24格式的bitmap文件(24-bit Bitmap) – yasi

参考:

http://stackoverflow.com/questions/5751749/how-can-i-read-bmp-pixel-values-into-an-array

http://msdn.microsoft.com/en-us/library/dd183374%28v=VS.85%29.aspx

http://msdn.microsoft.com/en-us/library/dd183376%28v=VS.85%29.aspx

本文代码和测试图片下载

【测试图片】

宽50像素,高100像素,每个像素的颜色:Red=30, Green=50, Blue=80,在Windows mspaint.exe中保存为 24-bit Bitmap (.bmp)文件

【代码】

bmp_header_def.h

#ifndef _BMP_HEADER_DEF_H_#define _BMP_HEADER_DEF_H_typedef int LONG;typedef unsigned short WORD;typedef unsigned int DWORD;typedef struct tagBITMAPFILEHEADER {WORD  bfType;DWORD bfSize;WORD  bfReserved1;WORD  bfReserved2;DWORD bfOffBits;} BITMAPFILEHEADER, *PBITMAPFILEHEADER;typedef struct tagBITMAPINFOHEADER {DWORD biSize;LONG  biWidth;LONG  biHeight;WORD  biPlanes;WORD  biBitCount;DWORD biCompression;DWORD biSizeImage;LONG  biXPelsPerMeter;LONG  biYPelsPerMeter;DWORD biClrUsed;DWORD biClrImportant;} BITMAPINFOHEADER, *PBITMAPINFOHEADER;#endif

bmp_reader.h

#ifndef _BMP_READER_H_#define _BMP_READER_H_#include "bmp_header_def.h"class CBmpReader {public:CBmpReader();~CBmpReader();public:int Load(const char * bmp_file);void Unload();unsigned int GetWidth() const;unsigned int GetHeight() const;PBITMAPFILEHEADER GetFileHeader() const;PBITMAPINFOHEADER GetInfoHeader() const;char * GetRawData() const;unsigned int GetRedAt(int row, int col) const;unsigned int GetGreenAt(int row, int col) const;unsigned int GetBlueAt(int row, int col) const;private:PBITMAPFILEHEADER m_pFileHeader;PBITMAPINFOHEADER m_pInfoHeader;char * m_buffer;char * m_pRawData;unsigned int m_nWidth;unsigned int m_nHeight;unsigned int m_nLineBytes;};#endif

bmp_reader.cpp

#pragma pack(1)#include "bmp_reader.h"#include <stdio.h>CBmpReader::CBmpReader() {m_pFileHeader = NULL;m_pInfoHeader = NULL;m_buffer = NULL;m_pRawData = NULL;m_nWidth = 0;m_nHeight = 0;m_nLineBytes = 0;}CBmpReader::~CBmpReader() {Unload();}#define FOUR_BYTES_ALIGN(width_in_bit)  ((((width_in_bit)+31)>>5)<<2)int CBmpReader::Load(const char * bmp_file) {FILE * pf = fopen(bmp_file, "rb");if (NULL == pf) {return 0;}fseek(pf, 0, SEEK_END);long length = ftell(pf);rewind(pf);m_buffer = new char[length];fread(m_buffer, length, 1, pf);m_pFileHeader = (PBITMAPFILEHEADER)(m_buffer);m_pInfoHeader = (PBITMAPINFOHEADER)(m_buffer + sizeof(BITMAPFILEHEADER));m_pRawData = m_buffer + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);m_nWidth = m_pInfoHeader->biWidth;m_nHeight = m_pInfoHeader->biHeight;m_nLineBytes = FOUR_BYTES_ALIGN(m_nWidth * 24);fclose(pf);return 0;}void CBmpReader::Unload() {if (m_buffer) {m_pFileHeader = NULL;m_pInfoHeader = NULL;delete [] m_buffer;m_buffer = NULL;m_pRawData = NULL;m_nWidth = 0;m_nHeight = 0;m_nLineBytes = 0;}}unsigned int CBmpReader::GetWidth() const {return m_nWidth;}unsigned int CBmpReader::GetHeight() const {return m_nHeight;}PBITMAPFILEHEADER CBmpReader::GetFileHeader() const {return m_pFileHeader;}PBITMAPINFOHEADER CBmpReader::GetInfoHeader() const {return m_pInfoHeader;}char * CBmpReader::GetRawData() const {return m_pRawData;}#define GET_COLOR_AT(row, col, offset) \if (NULL == m_pRawData) { \return 0; \} \if ((row) > m_nHeight - 1 || (col) > m_nWidth - 1) { \return 0; \} \return m_pRawData[m_nLineBytes * (row) + 3 * (col) + (offset)];unsigned int CBmpReader::GetRedAt(int row, int col) const {GET_COLOR_AT(row, col, 2);}unsigned int CBmpReader::GetGreenAt(int row, int col) const {GET_COLOR_AT(row, col, 1);}unsigned int CBmpReader::GetBlueAt(int row, int col) const {GET_COLOR_AT(row, col, 0);}

main.cpp

#include <iostream>#include "bmp_reader.h"using namespace std;#define OUTPUT_TITLE(title) \cout << "[" << #title << "]" << endl;#define OUTPUT_ITEM_CONTENT(item, name) \cout << "\t" << #name << ": " << item->name << endl;void OutputBitMapFileHeader(PBITMAPFILEHEADER pFileHeader) {OUTPUT_TITLE("Bitmap File Header");if (NULL == pFileHeader) {return;}OUTPUT_ITEM_CONTENT(pFileHeader, bfType);OUTPUT_ITEM_CONTENT(pFileHeader, bfSize);OUTPUT_ITEM_CONTENT(pFileHeader, bfReserved1);OUTPUT_ITEM_CONTENT(pFileHeader, bfReserved2);OUTPUT_ITEM_CONTENT(pFileHeader, bfOffBits);}void OutputBitMapInfoHeader(PBITMAPINFOHEADER pInfoHeader) {OUTPUT_TITLE("Bitmap Info Header");if (NULL == pInfoHeader) {return;}OUTPUT_ITEM_CONTENT(pInfoHeader, biSize);OUTPUT_ITEM_CONTENT(pInfoHeader, biWidth);OUTPUT_ITEM_CONTENT(pInfoHeader, biHeight);OUTPUT_ITEM_CONTENT(pInfoHeader, biPlanes);OUTPUT_ITEM_CONTENT(pInfoHeader, biBitCount);OUTPUT_ITEM_CONTENT(pInfoHeader, biCompression);OUTPUT_ITEM_CONTENT(pInfoHeader, biSizeImage);OUTPUT_ITEM_CONTENT(pInfoHeader, biXPelsPerMeter);OUTPUT_ITEM_CONTENT(pInfoHeader, biYPelsPerMeter);OUTPUT_ITEM_CONTENT(pInfoHeader, biClrUsed);OUTPUT_ITEM_CONTENT(pInfoHeader, biClrImportant);}void OutputColorAt(const CBmpReader &reader, int row, int col) {cout << "BGR @ [" << row << ", " << col << "]: "  << reader.GetBlueAt(row, col) << ", "<< reader.GetGreenAt(row, col) << ", "<< reader.GetRedAt(row, col) << endl;}int main(int argc, char * argv[]) {CBmpReader reader;reader.Load("./data.bmp");int width = reader.GetWidth();int height = reader.GetHeight();cout << "width: " << width << " height: " << height << endl;PBITMAPFILEHEADER pFileHeader = reader.GetFileHeader();OutputBitMapFileHeader(pFileHeader);PBITMAPINFOHEADER pInfoHeader = reader.GetInfoHeader();OutputBitMapInfoHeader(pInfoHeader);OutputColorAt(reader, 0, 0);OutputColorAt(reader, 0, 1);OutputColorAt(reader, 0, 2);OutputColorAt(reader, 1, 0);OutputColorAt(reader, 1, 1);OutputColorAt(reader, 1, 2);OutputColorAt(reader, 0, width - 1);OutputColorAt(reader, height - 1, 0);OutputColorAt(reader, height - 1, width - 1);return 0;}

Makefile

all:g++ -g bmp_reader.cpp main.cpp -o tclean:rm *.o t -f

【执行结果】

width: 50 height: 100["Bitmap File Header"]        bfType: 19778        bfSize: 0        bfReserved1: 0        bfReserved2: 54        bfOffBits: 2621440["Bitmap Info Header"]        biSize: 40        biWidth: 50        biHeight: 100        biPlanes: 1        biBitCount: 24        biCompression: 0        biSizeImage: 15200        biXPelsPerMeter: 0        biYPelsPerMeter: 0        biClrUsed: 0        biClrImportant: 0BGR @ [0, 0]: 80, 50, 30BGR @ [0, 1]: 80, 50, 30BGR @ [0, 2]: 80, 50, 30BGR @ [1, 0]: 80, 50, 30BGR @ [1, 1]: 80, 50, 30BGR @ [1, 2]: 80, 50, 30BGR @ [0, 49]: 80, 50, 30BGR @ [99, 0]: 80, 50, 30BGR @ [99, 49]: 80, 50, 30

【注意】

    RGB24格式的bitmap图像文件格式大致是:bitmap file header + bitmap info header + raw data,其中raw data是每行对齐到4字节的,图像的(0,0)点位于图像的左下角,图像的每个像素占3个字节,依次是Blue, Green和Red,而不是通常大家习惯说的RGB顺序bmp_reader.cpp 开头的#pragma pack(1) 不能取掉bmp_reader.cpp 在CBmpReader::Load() 中的m_nLineBytes = FOUR_BYTES_ALIGN(m_nWidth * 24) 不能换成m_nLineBytes = m_nWidth * 24,因为要对齐到4字节,否则在main函数中获取各个像素的RGB值的时候会错乱。关于对齐到4字节,参考《图像数据每行对齐到4字节》

勇于接受自己的不完美,认清自己不足的地方,

Linux C++读取RGB24格式的bitmap文件(24-bit Bitmap) – yasi

相关文章:

你感兴趣的文章:

标签云: