0xAA55 发表于 2015-2-4 07:10:53

【图形】能读取所有种类的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:

Ink_Hin_fifteen 发表于 2019-5-10 20:47:03

哇,收藏了。
页: [1]
查看完整版本: 【图形】能读取所有种类的BMP并将其转换为真彩色的库