前兩天,在使用位圖當紋理時候,遇到了問題.就是關于8-bit位圖不能派上用場時候,于是就萌生了想法,希望能將它完善下整理出來.于是查了一些關于bitmap的文件結構.關于位圖結構等,我就不在此詳細敘述了.因為網上已經相當的多 而且很多人也實現了很多讀取的方法.可參考此篇博文:位圖綜述
其實呢.我原先并不知道原來已經有了很強大的一個開源工具..FreeImage ..是個已經支持目前所有格式的圖像文件..所以我的基本算是白寫了.關于1 4 16 32 的完全可參考其源代碼 完善下我以下這個類:
現在僅將我寫了一個下午的源代碼獻上:詳細情況不在綜述,全部在類里表明了注釋:

BmpLoader.h
//======================================================================

/**//**
* @file BmpLoader.h
*
* 文件描述: 載入位圖類
* 適用平臺: Windows98/2000/NT/XP
*
* 作者: acmiyou
* 電子郵件: acmiyou@qq.com
*
*/
//======================================================================
#include <windows.h>
#include <stdio.h>
#ifndef _BMPLOADER_H_
#define _BMPLOADER_H_

#define BITMAP_ID 0x4D42 /**< 位圖文件的標志 */

#define BLUE 0
#define GREEN 1
#define RED 2

#define swapcolor(a,b){ \
(a) ^= (b); \
(b) ^= (a); \
(a) ^= (b); \
}

class BmpLoader


{
public:
BmpLoader();
~BmpLoader();


void Free(); /**//** 釋放內存*/


BITMAPINFOHEADER* bitInfo; /**//** 記錄位圖的頭信息*/

BYTE* image; /**//** 圖像數據*/


bool loadBitmap(const char* filename); /**//** 載入位圖文件*/

private:


void computePaletteSize(); /**//** 計算位圖中顏色表項數*/

int getImageLine(int width,int bitCount); /**//** 計算每行的字節數,結果為4的倍數*/


BYTE* getScanLine(BYTE* data ,int pitch,int scanline); /**//** 獲得像素數據每行的起始地址*/

bool covertTo24bits(BYTE* data); /**//** 強制轉換所有類型至24-bit*/

void covertLine8bTo24b(BYTE* dst,BYTE* src); /**//** 轉換8-bit行為24-bit行 */


RGBQUAD* p_ColorTable; /**//** 顏色表*/
};

#endif

BmpLoader.cpp
//======================================================================

/**//**
* @file BmpLoader.cpp
*
* 文件描述: 載入位圖類
* 適用平臺: Windows98/2000/NT/XP
*
* 作者: acmiyou
* 電子郵件: acmiyou@qq.com
*
*/
//======================================================================

#include "BmpLoader.h"

BmpLoader::BmpLoader()


{
bitInfo= 0;
image = 0;
p_ColorTable = 0;
}

BmpLoader::~BmpLoader()


{
Free();
}

/**//**
** 釋放占用內存
*/
void BmpLoader::Free()


{
if(image!=NULL)

{
delete[] image;
image = 0;
}
if(bitInfo!=NULL)

{
delete[] bitInfo;
bitInfo = 0;
}
if(p_ColorTable !=NULL)

{
delete[] p_ColorTable;
p_ColorTable = 0;
}
}

/**//*
** 載入位圖文件
** @param:
** filename 文件名
*/
bool BmpLoader::loadBitmap(const char *filename)


{
/** 如果已經存在數據 則釋放內存*/
Free(); /** 釋放內存*/
FILE* fp= fopen(filename,"rb");


if(fp==NULL) return false; /**//** 打開文件失敗*/

BITMAPFILEHEADER header;


fread(&header,sizeof(BITMAPFILEHEADER),1,fp); /**//** 讀入bitmap文件頭*/


if(header.bfType !=BITMAP_ID) /**//** 若不是 位圖類型 直接返回*/

{
Free();
fclose(fp);
return false;
}

bitInfo=(BITMAPINFOHEADER*)new BYTE[sizeof(BITMAPINFOHEADER)];

fread(bitInfo,sizeof(BITMAPINFOHEADER),1,fp); /**//** 位圖信息頭*/

if(bitInfo->biSize !=40)

{
Free();

return false; /**//** 不是RGB格式 而是壓縮的 該類不支持 返回讀取失敗 */
}


computePaletteSize(); /**//** 計算顏色表值*/

if(bitInfo->biClrUsed !=0)

{
p_ColorTable=(RGBQUAD*)new BYTE[sizeof(RGBQUAD)*bitInfo->biClrUsed];
fread(p_ColorTable,sizeof(RGBQUAD) * bitInfo->biClrUsed,1,fp);
}


/**//** 位圖像素數據大小 */
bitInfo->biSizeImage=getImageLine(bitInfo->biWidth,bitInfo->biBitCount) * bitInfo->biHeight;
BYTE* imagedata = new BYTE[bitInfo->biSizeImage];

fseek(fp,header.bfOffBits,SEEK_SET);


/**//** 讀取像素信息*/
fread(imagedata,bitInfo->biSizeImage,1,fp);
fclose(fp);


/**//** 強制轉換成24-bit*/

if(!covertTo24bits(imagedata)) /**//** 不支持 1 4 16 32位格式 則返回*/

{
Free();
return false;
}
delete[] imagedata;


/**//** 轉換bgr --> rgb*/
for(int inx= 0;inx < bitInfo->biSizeImage;inx+=3)
swapcolor(image[inx],image[inx+2]);
return true;
}


/**//*
** 計算位圖中顏色表項數
** @param: 無
*/
void BmpLoader::computePaletteSize()


{

/**//** 僅 1 4 8 存在顏色表*/
if(bitInfo->biClrUsed==0)

{
switch(bitInfo->biBitCount)

{
case 1:
bitInfo->biClrUsed=2;break;
case 4:
bitInfo->biClrUsed=16;break;
case 8:
bitInfo->biClrUsed=256;break;
case 16:
case 24:
case 32:
bitInfo->biClrUsed=0;break;
default:
break;
}
}
}


/**//*
** 計算每行的字節數
** @param:
** width 寬度
** bitCount 每個像素的位數
** @return: 行字節數
*/
int BmpLoader::getImageLine(int width,int bitCount)


{
return ((width * bitCount) + 7) / 8 + 3 & ~3;
}



/**//** 獲得像素數據每行的起始地址
** @param:
** data 像素數據
** pitch 像素行字節數
** scanline 第幾行
** @return: 行起始地址
*/
BYTE* BmpLoader::getScanLine(BYTE* data ,int pitch, int scanline)


{
return data + pitch * scanline;
}


/**//*
** 強制轉換所有類型至24-bit
** @param:
** data 像素數據
*/
bool BmpLoader::covertTo24bits(BYTE *data)


{
if(bitInfo==NULL || data == NULL) return false;

int lineImage = getImageLine(bitInfo->biWidth,24);
int lineData = getImageLine(bitInfo->biWidth,bitInfo->biBitCount);

bitInfo->biSizeImage =lineImage * bitInfo->biHeight ;

image = new BYTE[bitInfo->biSizeImage];
memset(image,0,bitInfo->biSizeImage);
switch(bitInfo->biBitCount)

{
case 1:return false;
case 4:return false;
case 8:
for(int row = 0; row < bitInfo->biHeight; row++)
covertLine8bTo24b(getScanLine(image,lineImage,row),getScanLine(data,lineData,row));
break;
case 16:
return false;
case 24:
memcpy(image,data,bitInfo->biSizeImage);
break;
case 32:
return false;
}
return true;
}

/**//*
** 轉換8-bit行為24-bit行
** @param:
** dst 目標地址
** src 源地址
*/
void BmpLoader::covertLine8bTo24b(BYTE *dst,BYTE *src)


{
for(int col = 0; col < bitInfo->biWidth ; col++)

{

/**//** 將索引值轉換成顏色表中的顏色*/
dst[BLUE] = p_ColorTable[src[col]].rgbBlue;
dst[GREEN] =p_ColorTable[src[col]].rgbGreen;
dst[RED] =p_ColorTable[src[col]].rgbRed;
dst+=3;
}
}
posted on 2009-07-31 15:30
米游 閱讀(2638)
評論(2) 編輯 收藏 引用 所屬分類:
OpenGL/OSG