【图形】能读取所有种类的BMP并将其转换为真彩色的库
这应该被命名为libbmp。不知道各种开源的组织有没有人弄这个。我这个读取bmp文件的工具除了能读取BMP文件,还能将索引颜色或RLE压缩的BMP转换为真彩色或32位高彩色!要不然我为毛编写这个东西?其实我写的这个东西目前只能读取位图,不能保存位图。如果要弄成支持保存位图的,我需要把颜色降级、抖动算法等都完成,目前我不需要这些功能。我需要的是把一个位图加载到内存然后丢给OpenGL。这个东西足够我玩了。
用法很简单,包含我的头文件,编译我的.c文件,然后使用我头文件导出的函数:LoadBMP,ConvToTrueColor,DestroyBMP。
其中LoadBMP函数负责把BMP位图原样加载到内存,不做任何转换。然后用ConvToTrueColor可以将其转换为24位或32位的位图。之后,调用DestroyBMP销毁内存中的位图。
大家可以使用GDI的StretchDIBits来在窗口上绘制位图,也可以用glTexImage加载转换后的真彩色位图。其中为了保证可移植性,我把BITMAPFILEHEADER和BITMAPINFOHEADER等结构体用自己的方式定义了(BitmapFileHeader、BitmapInfoHeader,把WORD、DWORD、LONG等替换成了uint16_t、uint32_t、int32_t等)。
废话不多说。上源码。
bmpfile.h//=============================================================================
//作者:0xAA55
//网址:http://www.0xaa55.com
//请保留原作者信息,否则视为侵权。
//-----------------------------------------------------------------------------
#ifndef _BMPFILE_HEADER_
#define _BMPFILE_HEADER_
#include<stdint.h>
#pragma pack(push,1)
//=============================================================================
//结构:BitmapFileHeader
//描述:位图文件头,BMP文件必须以此结构开头。
//-----------------------------------------------------------------------------
typedef struct
{
uint16_t bfType; //必须为BM
uint32_t bfSize; //整个文件的尺寸
uint16_t bfReserved1;//必须为0
uint16_t bfReserved2;//必须为0
uint32_t bfOffBits; //位图数据的偏移
}BitmapFileHeader,*BitmapFileHeaderP;
#define BF_BMP 0x4D42 //bfType的值
//=============================================================================
//结构:BitmapInfoHeader
//描述:位图信息头,在BMP文件中紧接在BitmapFileHeader的后面。
//-----------------------------------------------------------------------------
typedef struct
{
uint32_t biSize; //位图信息头和调色板的总尺寸
int32_t biWidth; //位图宽度
int32_t biHeight; //位图高度
uint16_t biPlanes; //位面数(必须为1,扯蛋的)
uint16_t biBitCount; //颜色位数
uint32_t biCompression; //压缩方式
uint32_t biSizeImage; //位图部分尺寸
int32_t biXPelsPerMeter;//宽度每米像素数(扯蛋的)
int32_t biYPelsPerMeter;//高度每米像素数(扯蛋的)
uint32_t biClrUsed; //使用的颜色数(扯蛋的)
uint32_t biClrImportant; //重要的颜色数(扯蛋的)
}BitmapInfoHeader,*BitmapInfoHeaderP;
//=============================================================================
//枚举:BiCompressionType
//描述:biCompression使用的数值。
//-----------------------------------------------------------------------------
typedef enum
{
Bi_RGB =0, //无压缩
Bi_RLE8 =1, //RLE8
Bi_RLE4 =2, //RLE4
Bi_BitFields=3 //位域,也就是用“调色板”的位置来存储位域信息
}BiCompressionType,*BiCompressionTypeP;
typedef enum
{
BitF_R =0, //红色的位
BitF_G =1, //绿色的位
BitF_B =2, //蓝色的位
BitF_X =3 //透明通道的位
}BitFIndex,*BitFIndexP;
//=============================================================================
//结构:RGBQuad
//描述:四个字节描述红绿蓝的结构,通常用于描述调色板
//-----------------------------------------------------------------------------
typedef struct
{
uint8_t B;
uint8_t G;
uint8_t R;
uint8_t X;
}RGBQuad,*RGBQuadP;
//=============================================================================
//结构:RGBTriple
//描述:三个字节描述红绿蓝的结构,通常用于读取24位BMP
//-----------------------------------------------------------------------------
typedef struct
{
uint8_t B;
uint8_t G;
uint8_t R;
}RGBTriple,*RGBTripleP;
typedef enum
{
TC_AutoFit =0, //如果读取的位图文件低于24位则转换为24位,否则转换为32位
TC_24 =24,//读取的位图文件强制转换为24位
TC_32 =32 //读取的位图文件强制转换为32位
}TrueColorBits,*TrueColorBitsP;
//=============================================================================
//结构:BitmapPicture
//描述:用于读取BMP文件的结构体
//-----------------------------------------------------------------------------
typedef struct
{
BitmapFileHeader BMFH; //位图文件头
BitmapInfoHeader BMIF; //位图信息头
union
{
RGBQuad Palette; //调色板
uint32_t BitFields; //位域
}AdditionalData;//额外数据
size_t Width; //宽度
size_t Height; //高度
size_t cbPitch; //每行字节数
void *pBits; //位图数据
size_t cbBits; //位图数据大小
}BitmapPicture,*BitmapPictureP;
#pragma pack(pop)
//=============================================================================
//函数:LoadBMP
//描述:读取BMP文件,建立BitmapPicture结构体
//-----------------------------------------------------------------------------
BitmapPictureP LoadBMP(char*szFilePath);
//=============================================================================
//函数:ConvToTrueColor
//描述:将一个已读取的BMP文件转换为真彩色,返回新的位图。
//-----------------------------------------------------------------------------
BitmapPictureP ConvToTrueColor(BitmapPictureP pOrgBMP,TrueColorBits TCBits);
//=============================================================================
//函数:DestroyBMP
//描述:销毁BitmapPicture结构体,释放内存。
//-----------------------------------------------------------------------------
void DestroyBMP(BitmapPictureP pBMP);
#endif // !_BMPFILE_HEADER_bmpfile.c//=============================================================================
//作者:0xAA55
//网址:http://www.0xaa55.com
//请保留原作者信息,否则视为侵权。
//-----------------------------------------------------------------------------
#include"bmpfile.h"
#include<stdio.h>
#include<malloc.h>
#include<memory.h>
typedef int shift_t;
#define CalcPitch(w,b) ((((w)*(b)-1)/32+1)*4)
//=============================================================================
//函数:LoadBMP
//描述:读取BMP文件,建立BitmapPicture结构体
//-----------------------------------------------------------------------------
BitmapPictureP LoadBMP(char*szFilePath)
{
FILE*fp=NULL;
BitmapPictureP pBMP;
//=========================================================================
//给要返回的结构体分配内存。
pBMP=(BitmapPictureP)malloc(sizeof(BitmapPicture));
if(!pBMP)
{
//内存不足
goto ErrorHandler;
}
memset(pBMP,0,sizeof(BitmapPicture));
//=========================================================================
//打开文件
fp=fopen(szFilePath,"rb");
if(!fp)
goto ErrorHandler;
//=========================================================================
//读取文件头
if(fread(&(pBMP->BMFH),
1,sizeof(pBMP->BMFH),fp)!=sizeof(pBMP->BMFH))
{
//读取失败
goto ErrorHandler;
}
//=========================================================================
//判断文件头的结构正确性
if( pBMP->BMFH.bfType!=BF_BMP||
pBMP->BMFH.bfReserved1 ||
pBMP->BMFH.bfReserved2)
{
//文件头格式错误
goto ErrorHandler;
}
//=========================================================================
//读取信息头
if(fread(&(pBMP->BMIF),
1,sizeof(pBMP->BMIF),fp)!=sizeof(pBMP->BMIF))
{
//读取失败
goto ErrorHandler;
}
//=========================================================================
//判断信息头的结构正确性
if( pBMP->BMIF.biWidth<=0//宽度必须大于0
||
!(pBMP->BMIF.biHeight)//高度必须不为0(顶到下型时,值为负)
||
//必须只能是这么几种压缩类型。
(pBMP->BMIF.biCompression!=Bi_RGB &&
pBMP->BMIF.biCompression!=Bi_RLE8 &&
pBMP->BMIF.biCompression!=Bi_RLE4 &&
pBMP->BMIF.biCompression!=Bi_BitFields)
||
//如果是压缩位图,则必须是底到上型,并且指定大小
((pBMP->BMIF.biCompression==Bi_RLE8 ||
pBMP->BMIF.biCompression==Bi_RLE4) &&
(pBMP->BMIF.biHeight<0 ||
!pBMP->BMIF.biSizeImage))
||
//RLE8只能压缩8位BMP
(pBMP->BMIF.biCompression==Bi_RLE8 && pBMP->BMIF.biBitCount!=8)
||
//RLE4只能压缩4位BMP
(pBMP->BMIF.biCompression==Bi_RLE4 && pBMP->BMIF.biBitCount!=4))
{
//文件头格式错误
goto ErrorHandler;
}
pBMP->Width=pBMP->BMIF.biWidth;
pBMP->Height=pBMP->BMIF.biHeight>=0?
pBMP->BMIF.biHeight:-pBMP->BMIF.biHeight;
//=========================================================================
//读取调色板
if(pBMP->BMIF.biBitCount<=8 && pBMP->BMIF.biCompression!=Bi_BitFields)
{
size_t NbPal=pBMP->BMIF.biClrUsed;
if(!NbPal)
NbPal=(size_t)1<<pBMP->BMIF.biBitCount;
fread(pBMP->AdditionalData.Palette,
1,sizeof(RGBQuad)*NbPal,fp);
}
//或者读取位域
else if(pBMP->BMIF.biCompression==Bi_BitFields)
{
fread(pBMP->AdditionalData.BitFields,
1,sizeof(pBMP->AdditionalData.BitFields),fp);
}
//=========================================================================
//计算位图数据的大小
if( pBMP->BMIF.biCompression==Bi_RGB ||
pBMP->BMIF.biCompression==Bi_BitFields)
{
pBMP->cbPitch=//每行字节数4字节对齐
CalcPitch(pBMP->Width,pBMP->BMIF.biBitCount);
pBMP->cbBits=pBMP->cbPitch*pBMP->Height;
}
else
pBMP->cbBits=pBMP->BMIF.biSizeImage;
//=========================================================================
//读取位图数据
pBMP->pBits=malloc(pBMP->cbBits);
if(!pBMP->pBits)
{
//内存不足
goto ErrorHandler;
}
if(fread(pBMP->pBits,1,pBMP->cbBits,fp)!=pBMP->cbBits)
{
//读取失败
goto ErrorHandler;
}
//读取完成
fclose(fp);
return pBMP;
ErrorHandler:
if(fp)
fclose(fp);
if(pBMP)
DestroyBMP(pBMP);
return NULL;
}
//=============================================================================
//函数:GetI32Shift
//描述:取得一个32位数右边的0的数量
//-----------------------------------------------------------------------------
static
shift_t GetI32Shift(uint32_t Val)
{
shift_t NbShift=0;
if(!Val)
return 0;
while(!(Val&1))
{
NbShift++;
Val>>=1;
}
return NbShift;
}
//=============================================================================
//函数:GetI32Bits
//描述:取得一个32位数最左边的1的位置
//-----------------------------------------------------------------------------
static
shift_t GetI32Bits(uint32_t Val)
{
shift_t NbBits=0;
while(Val)
{
NbBits++;
Val>>=1;
}
return NbBits;
}
//=============================================================================
//函数:ConvToTrueColor
//描述:将一个已读取的BMP文件转换为真彩色,返回新的位图。
//-----------------------------------------------------------------------------
BitmapPictureP ConvToTrueColor(BitmapPictureP pOrgBMP,TrueColorBits TCBits)
{
BitmapPictureP pBMP;
size_t x,y;
uint8_t*pOrgBitPtr;
uint8_t*pOrgLinePtr;
uint8_t*pBitPtr;
uint8_t*pLinePtr;
if( TCBits!=TC_24 &&
TCBits!=TC_32 &&
TCBits!=TC_AutoFit)
{
//参数不正确
return NULL;
}
//=========================================================================
//给要返回的结构体分配内存。
pBMP=(BitmapPictureP)malloc(sizeof(BitmapPicture));
if(!pBMP)
{
//内存不足
goto ErrorHandler;
}
memset(pBMP,0,sizeof(BitmapPicture));
//=========================================================================
//补充BMP信息
//填写BMP文件头
pBMP->BMFH.bfType=BF_BMP;
pBMP->BMFH.bfOffBits=sizeof(BitmapFileHeader)+sizeof(BitmapInfoHeader);
//填写BMP信息头
pBMP->BMIF.biSize=sizeof(BitmapInfoHeader);
pBMP->BMIF.biWidth=pOrgBMP->BMIF.biWidth;
pBMP->BMIF.biHeight=pOrgBMP->BMIF.biHeight;
pBMP->BMIF.biPlanes=pOrgBMP->BMIF.biPlanes;
if(TCBits==TC_AutoFit)
TCBits=pOrgBMP->BMIF.biBitCount>24?TC_32:TC_24;
if(TCBits==TC_32)
pBMP->BMIF.biBitCount=32;
else if(TCBits==TC_24)
pBMP->BMIF.biBitCount=24;
pBMP->BMIF.biCompression=Bi_RGB;
pBMP->BMIF.biSizeImage=0;
pBMP->BMIF.biXPelsPerMeter=pOrgBMP->BMIF.biXPelsPerMeter;
pBMP->BMIF.biYPelsPerMeter=pOrgBMP->BMIF.biYPelsPerMeter;
pBMP->BMIF.biClrUsed=0;
pBMP->BMIF.biClrImportant=0;
//绝对值尺寸
pBMP->Width=pOrgBMP->Width;
pBMP->Height=pOrgBMP->Height;
//计算位图总尺寸
pBMP->cbPitch=CalcPitch(pBMP->BMIF.biWidth,pBMP->BMIF.biBitCount);
pBMP->cbBits=pBMP->Height*pBMP->cbPitch;
pBMP->pBits=malloc(pBMP->cbBits);
if(!pBMP->pBits)
{
//内存不足
goto ErrorHandler;
}
memset(pBMP->pBits,0,pBMP->cbBits);
pBMP->BMFH.bfSize=(uint32_t)(pBMP->BMFH.bfOffBits+pBMP->cbBits);
//=========================================================================
//开始转换过程
//判断压缩类型
if(pOrgBMP->BMIF.biCompression==Bi_RGB)//无压缩
{
pOrgLinePtr=(uint8_t*)(pOrgBMP->pBits);
pLinePtr=(uint8_t*)(pBMP->pBits);
//=====================================================================
//2、4、16色位图的处理方式一致。
if( pOrgBMP->BMIF.biBitCount==1 || //双色位图(通常为黑白)
pOrgBMP->BMIF.biBitCount==2 || //四色位图(几乎见不到)
pOrgBMP->BMIF.biBitCount==4) //16色位图
{
uint8_t LastByte;
shift_t PixelsLast=0;
size_t PalIndex=0;
shift_t PixelsPerBytes;
PixelsPerBytes=8/pOrgBMP->BMIF.biBitCount;//每字节像素数
for(y=0;y<pBMP->Height;y++)//遍历每一行
{
pOrgBitPtr=pOrgLinePtr;
pBitPtr=pLinePtr;
for(x=0;x<pBMP->Width;x++)//遍历每个字节
{
if(!PixelsLast)//如果读完这个字节
{
PixelsLast=PixelsPerBytes;
LastByte=*pOrgBitPtr++;//读取新的字节
}
PalIndex=LastByte>>(8-pOrgBMP->BMIF.biBitCount);//查颜色表
LastByte<<=pOrgBMP->BMIF.biBitCount;//上次读取的字节
PixelsLast--;//能取得的像素数
*pBitPtr++=pOrgBMP->AdditionalData.Palette.B;
*pBitPtr++=pOrgBMP->AdditionalData.Palette.G;
*pBitPtr++=pOrgBMP->AdditionalData.Palette.R;
if(TCBits==TC_32)
*pBitPtr++=pOrgBMP->AdditionalData.Palette.X;
}
pOrgLinePtr+=pOrgBMP->cbPitch;//转到下一行
pLinePtr+=pBMP->cbPitch;
PixelsLast=0;
}
}
//=====================================================================
//256色位图,一个像素一个字节
else if(pOrgBMP->BMIF.biBitCount==8)
{
for(y=0;y<pBMP->Height;y++)//遍历每一行
{
pOrgBitPtr=pOrgLinePtr;
pBitPtr=pLinePtr;
for(x=0;x<pBMP->Width;x++)//遍历每一列
{
uint8_t Pix8=*pOrgBitPtr++;
*pBitPtr++=pOrgBMP->AdditionalData.Palette.B;
*pBitPtr++=pOrgBMP->AdditionalData.Palette.G;
*pBitPtr++=pOrgBMP->AdditionalData.Palette.R;
if(TCBits==TC_32)
*pBitPtr++=pOrgBMP->AdditionalData.Palette.X;
}
pOrgLinePtr+=pOrgBMP->cbPitch;//转到下一行
pLinePtr+=pBMP->cbPitch;
}
}
//=====================================================================
//没有位域定义时,16位BMP为1:5:5:5
else if(pOrgBMP->BMIF.biBitCount==16)
{
for(y=0;y<pBMP->Height;y++)//遍历每一行
{
pOrgBitPtr=pOrgLinePtr;
pBitPtr=pLinePtr;
for(x=0;x<pBMP->Width;x++)//遍历每一列
{
uint16_t Pix16=*(uint16_t*)pOrgBitPtr;
*pBitPtr++=(uint8_t)(((Pix16&0x001F)<<3)|((Pix16&0x001F)>>2));//同时填充高位和低位
*pBitPtr++=(uint8_t)(((Pix16&0x03E0)>>2)|((Pix16&0x03E0)>>7));
*pBitPtr++=(uint8_t)(((Pix16&0x7C00)>>7)|((Pix16&0x7C00)>>12));
if(TCBits==TC_32)
*pBitPtr++=(Pix16&0x80)?0xFF:0;
pOrgBitPtr+=2;
}
pOrgLinePtr+=pOrgBMP->cbPitch;
pLinePtr+=pBMP->cbPitch;
}
}
//=====================================================================
//24位真彩色位图
else if(pOrgBMP->BMIF.biBitCount==24)
{
if(TCBits==TC_24)
memcpy(pBMP->pBits,pOrgBMP->pBits,pOrgBMP->cbBits);//无须转换
else//转成32位
{
for(y=0;y<pBMP->Height;y++)//遍历每一行
{
pOrgBitPtr=pOrgLinePtr;
pBitPtr=pLinePtr;
for(x=0;x<pBMP->Width;x++)//遍历每一列
{
*pBitPtr++=*pOrgBitPtr++;
*pBitPtr++=*pOrgBitPtr++;
*pBitPtr++=*pOrgBitPtr++;
*pBitPtr++=0;
}
pOrgLinePtr+=pOrgBMP->cbPitch;
pLinePtr+=pBMP->cbPitch;
}
}
}
//=====================================================================
//32位高彩色位图,比24位多了个透明度通道。
else if(pOrgBMP->BMIF.biBitCount==32)
{
if(TCBits==TC_24)//降级
{
for(y=0;y<pBMP->Height;y++)//遍历每一行
{
pOrgBitPtr=pOrgLinePtr;
pBitPtr=pLinePtr;
for(x=0;x<pBMP->Width;x++)//遍历每一列
{
*pBitPtr++=*pOrgBitPtr++;
*pBitPtr++=*pOrgBitPtr++;
*pBitPtr++=*pOrgBitPtr++;
pOrgBitPtr++;
}
pOrgLinePtr+=pOrgBMP->cbPitch;
pLinePtr+=pBMP->cbPitch;
}
}
else
memcpy(pBMP->pBits,pOrgBMP->pBits,pOrgBMP->cbBits);//无须转换
}
else
{
//不认识的BMP格式
goto ErrorHandler;
}
return pBMP;
}
//=========================================================================
//RLE8压缩类型,Run-Length Encode
else if(pOrgBMP->BMIF.biCompression==Bi_RLE8)
{
size_t cbPixel=(pBMP->BMIF.biBitCount-1)/8+1;//输出的每像素字节数
size_t RightBound;//右边界
//没有画过的像素都是索引0的颜色。
pLinePtr=(uint8_t*)(pBMP->pBits);
for(y=0;y<pBMP->Height;y++)//遍历每一行
{
pBitPtr=pLinePtr;
for(x=0;x<pBMP->Width;x++)//遍历每一列
{
*pBitPtr++=pOrgBMP->AdditionalData.Palette.B;
*pBitPtr++=pOrgBMP->AdditionalData.Palette.G;
*pBitPtr++=pOrgBMP->AdditionalData.Palette.R;
if(TCBits==TC_32)
*pBitPtr++=pOrgBMP->AdditionalData.Palette.X;
}
pLinePtr+=pBMP->cbPitch;
}
//然后开始准备绘图
pOrgBitPtr=(uint8_t*)(pOrgBMP->pBits);
pLinePtr=(uint8_t*)(pBMP->pBits);
RightBound=(size_t)(pOrgBMP->pBits)+pOrgBMP->cbBits;
pBitPtr=pLinePtr;
while((size_t)pOrgBitPtr<RightBound)
{
if(*pOrgBitPtr)//单个像素复制模式
{
uint8_t NbNextPix=*pOrgBitPtr++;//要复制的次数
uint8_t Pix8=*pOrgBitPtr++;//像素值
while(NbNextPix--)
{
*pBitPtr++=pOrgBMP->AdditionalData.Palette.B;
*pBitPtr++=pOrgBMP->AdditionalData.Palette.G;
*pBitPtr++=pOrgBMP->AdditionalData.Palette.R;
if(TCBits==TC_32)
*pBitPtr++=pOrgBMP->AdditionalData.Palette.X;
}
}
else//转义字节
{
pOrgBitPtr++;
if(*pOrgBitPtr==0)//转义0:行结尾
{
pOrgBitPtr++;
pLinePtr+=pBMP->cbPitch;
pBitPtr=pLinePtr;
}
else if(*pOrgBitPtr==1)//转义1:位图结尾
break;
else if(*pOrgBitPtr==2)//转义2:下一个像素的偏移
{
pBitPtr+=cbPixel**++pOrgBitPtr;//放荡不羁的代码只为好玩
pBitPtr+=*++pOrgBitPtr*pBMP->cbPitch;
pLinePtr+=*pOrgBitPtr++*pBMP->cbPitch;
}
else//转义3-0xFF:绝对模式
{
uint8_t NbCopy=*pOrgBitPtr++;//需要复制的像素数
uint8_t NbCopied=0;//已经复制的像素数
while(NbCopied++<NbCopy)
{
uint8_t Pix8=*pOrgBitPtr++;//像素值
*pBitPtr++=pOrgBMP->AdditionalData.Palette.B;
*pBitPtr++=pOrgBMP->AdditionalData.Palette.G;
*pBitPtr++=pOrgBMP->AdditionalData.Palette.R;
if(TCBits==TC_32)
*pBitPtr++=pOrgBMP->AdditionalData.Palette.X;
}
pOrgBitPtr+=NbCopy&1;//要复制的像素数据是以字对齐的
}
}
}
return pBMP;
}
//=========================================================================
//RLE8压缩类型
else if(pOrgBMP->BMIF.biCompression==Bi_RLE4)
{
size_t cbPixel=(pBMP->BMIF.biBitCount-1)/8+1;
size_t RightBound;
//没有画过的像素都是索引0的颜色。
pLinePtr=(uint8_t*)(pBMP->pBits);
for(y=0;y<pBMP->Height;y++)//遍历每一行
{
pBitPtr=pLinePtr;
for(x=0;x<pBMP->Width;x++)//遍历每一列
{
*pBitPtr++=pOrgBMP->AdditionalData.Palette.B;
*pBitPtr++=pOrgBMP->AdditionalData.Palette.G;
*pBitPtr++=pOrgBMP->AdditionalData.Palette.R;
if(TCBits==TC_32)
*pBitPtr++=pOrgBMP->AdditionalData.Palette.X;
}
pLinePtr+=pBMP->cbPitch;
}
//然后开始准备绘图
pOrgBitPtr=(uint8_t*)(pOrgBMP->pBits);
pLinePtr=(uint8_t*)(pBMP->pBits);
RightBound=(size_t)(pOrgBMP->pBits)+pOrgBMP->cbBits;
pBitPtr=pLinePtr;
while((size_t)pOrgBitPtr<RightBound)
{
if(*pOrgBitPtr)//单个像素复制模式
{
uint8_t NbNextPix=*pOrgBitPtr++;//要复制的次数
uint8_t Pix8=*pOrgBitPtr++;//像素值
while(NbNextPix--)
{
//RLE4模式下,一个字节两个像素交替出现。
*pBitPtr++=pOrgBMP->AdditionalData.Palette.B;
*pBitPtr++=pOrgBMP->AdditionalData.Palette.G;
*pBitPtr++=pOrgBMP->AdditionalData.Palette.R;
if(TCBits==TC_32)
*pBitPtr++=pOrgBMP->AdditionalData.Palette.X;
if(!NbNextPix--)
break;
*pBitPtr++=pOrgBMP->AdditionalData.Palette.B;
*pBitPtr++=pOrgBMP->AdditionalData.Palette.G;
*pBitPtr++=pOrgBMP->AdditionalData.Palette.R;
if(TCBits==TC_32)
*pBitPtr++=pOrgBMP->AdditionalData.Palette.X;
}
}
else//转义字节
{
pOrgBitPtr++;
if(*pOrgBitPtr==0)//转义0:行结尾
{
pOrgBitPtr++;
pLinePtr+=pBMP->cbPitch;
pBitPtr=pLinePtr;
}
else if(*pOrgBitPtr==1)//转义1:位图结尾
break;
else if(*pOrgBitPtr==2)//转义2:下一个像素的偏移
{
pBitPtr+=cbPixel**++pOrgBitPtr;
pBitPtr+=*++pOrgBitPtr*pBMP->cbPitch;
pLinePtr+=*pOrgBitPtr++*pBMP->cbPitch;
}
else//转义3-0xFF:绝对模式
{
uint8_t NbCopy=*pOrgBitPtr++;//需要复制的像素数
uint8_t NbCopied=0;//已经复制的像素数
while(NbCopied++<NbCopy)
{
uint8_t Pix8=*pOrgBitPtr++;//像素值
//RLE4模式下,一个字节两个像素交替出现。
*pBitPtr++=pOrgBMP->AdditionalData.Palette.B;
*pBitPtr++=pOrgBMP->AdditionalData.Palette.G;
*pBitPtr++=pOrgBMP->AdditionalData.Palette.R;
if(TCBits==TC_32)
*pBitPtr++=pOrgBMP->AdditionalData.Palette.X;
if(!(NbCopied++<NbCopy))
break;
*pBitPtr++=pOrgBMP->AdditionalData.Palette.B;
*pBitPtr++=pOrgBMP->AdditionalData.Palette.G;
*pBitPtr++=pOrgBMP->AdditionalData.Palette.R;
if(TCBits==TC_32)
*pBitPtr++=pOrgBMP->AdditionalData.Palette.X;
}
pOrgBitPtr+=(NbCopy&3)?1:0;//要复制的像素数据是以字对齐的
}
}
}
return pBMP;
}
//=========================================================================
//位域,占用调色板的位置,通常用在16位颜色上表示每个位的意义。
else if(pOrgBMP->BMIF.biCompression==Bi_BitFields)
{
size_t cbPixel=(pOrgBMP->BMIF.biBitCount-1)/8+1;//每个像素字节数
uint32_t PixVal;//像素值
//每种颜色的位域低位(S=Shift)
shift_t BS=GetI32Shift(pOrgBMP->AdditionalData.BitFields);
shift_t GS=GetI32Shift(pOrgBMP->AdditionalData.BitFields);
shift_t RS=GetI32Shift(pOrgBMP->AdditionalData.BitFields);
shift_t XS=GetI32Shift(pOrgBMP->AdditionalData.BitFields);
//每种颜色的位域位数
shift_t BBits=GetI32Bits(pOrgBMP->AdditionalData.BitFields)-BS;
shift_t GBits=GetI32Bits(pOrgBMP->AdditionalData.BitFields)-GS;
shift_t RBits=GetI32Bits(pOrgBMP->AdditionalData.BitFields)-RS;
shift_t XBits=GetI32Bits(pOrgBMP->AdditionalData.BitFields)-XS;
pOrgLinePtr=(uint8_t*)(pOrgBMP->pBits);
pLinePtr=(uint8_t*)(pBMP->pBits);
for(y=0;y<pBMP->Height;y++)//遍历每一行
{
pOrgBitPtr=pOrgLinePtr;
pBitPtr=pLinePtr;
for(x=0;x<pBMP->Width;x++)//遍历每一列
{
int Fill;
uint8_t XVal,RVal,GVal,BVal;
PixVal=*(uint32_t*)pOrgBitPtr;//取得像素值
pOrgBitPtr+=cbPixel;//转到下一个像素
//取得当前像素值每个域的颜色值
BVal=(PixVal & pOrgBMP->AdditionalData.BitFields)>>BS;
GVal=(PixVal & pOrgBMP->AdditionalData.BitFields)>>GS;
RVal=(PixVal & pOrgBMP->AdditionalData.BitFields)>>RS;
XVal=(PixVal & pOrgBMP->AdditionalData.BitFields)>>RS;
//填充蓝色值
*pBitPtr=0;Fill=8;
while(Fill>0)
{
Fill-=BBits;
*pBitPtr|=BVal<<Fill;
}
pBitPtr++;
//填充绿色值
*pBitPtr=0;Fill=8;
while(Fill>0)
{
Fill-=GBits;
*pBitPtr|=GVal<<Fill;
}
pBitPtr++;
//填充红色值
*pBitPtr=0;Fill=8;
while(Fill>0)
{
Fill-=RBits;
*pBitPtr|=RVal<<Fill;
}
pBitPtr++;
//如果要输出32位位图,填充透明色值。
if(TCBits==TC_32)
{
*pBitPtr=0;
if(XBits)
{
Fill=8;
while(Fill>0)
{
Fill-=XBits;
*pBitPtr|=XVal<<Fill;
}
}
pBitPtr++;
}
}
pOrgLinePtr+=pOrgBMP->cbPitch;//转到下一行
pLinePtr+=pBMP->cbPitch;
}
return pBMP;
}
//必须只能是这几种压缩类型,否则报错:不支持的压缩类型
ErrorHandler:
if(pBMP)
DestroyBMP(pBMP);
return NULL;
}
//=============================================================================
//函数:DestroyBMP
//描述:销毁BitmapPicture结构体,释放内存。
//-----------------------------------------------------------------------------
void DestroyBMP(BitmapPictureP pBMP)
{
if(pBMP->pBits)
free(pBMP->pBits);
free(pBMP);
}基本所有的BMP都能读取了,无论是1,2,4,8,16,24,32,还是带位域的X1R5G5B5、R5G6B5、X4R4G4B4、X8R8G8B8等都能读取。无论是RLE4还是RLE8也都能读取。脱离Windows可以使用。
BIN:
SRC: 哇,收藏了。
页:
[1]