opengl 使用bmp位图纹理(8-bit 24bit)
前两天,在使用位图当纹理时候,遇到了问题.就是关于8-bit位图不能派上用场时候,于是就萌生了想法,希望能将它完善下整理出来.于是查了一些关于bitmap的文件结构.关于位图结构等,我就不在此详细叙述了.因为网上已经相当的多 而且很多人也实现了很多读取的方法.可参考此篇博文:位图综述
其实呢.我原先并不知道原来已经有了很强大的一个开源工具..FreeImage ..是个已经支持目前所有格式的图像文件..所以我的基本算是白写了.关于1 4 16 32 的完全可参考其源代码 完善下我以下这个类:
现在仅将我写了一个下午的源代码献上:详细情况不在综述,全部在类里表明了注释:
BmpLoader.h
//======================================================================
/**//**
* @file BmpLoader.h
*
* 文件描述: 载入位图类
* 适用平台: Windows98/2000/NT/XP
*
* 作者: acmiyou
* 电子邮件: [email protected]
*
*/
//======================================================================
#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
//======================================================================
/**//**
* @file BmpLoader.h
*
* 文件描述: 载入位图类
* 适用平台: Windows98/2000/NT/XP
*
* 作者: acmiyou
* 电子邮件: [email protected]
*
*/
//======================================================================
#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
* 电子邮件: [email protected]
*
*/
//======================================================================
#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;
}
}
//======================================================================
/**//**
* @file BmpLoader.cpp
*
* 文件描述: 载入位图类
* 适用平台: Windows98/2000/NT/XP
*
* 作者: acmiyou
* 电子邮件: [email protected]
*
*/
//======================================================================
#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;
}
}