找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 3950|回复: 1

【图形】能读取所有种类的BMP并将其转换为真彩色的库

[复制链接]

1109

主题

1649

回帖

7万

积分

用户组: 管理员

一只技术宅

UID
1
精华
244
威望
743 点
宅币
24180 个
贡献
46222 次
宅之契约
0 份
在线时间
2294 小时
注册时间
2014-1-26
发表于 2015-2-4 07:10:53 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
这应该被命名为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
  1. //=============================================================================
  2. //作者:0xAA55
  3. //网址:http://www.0xaa55.com
  4. //请保留原作者信息,否则视为侵权。
  5. //-----------------------------------------------------------------------------
  6. #ifndef _BMPFILE_HEADER_
  7. #define        _BMPFILE_HEADER_

  8. #include<stdint.h>

  9. #pragma pack(push,1)

  10. //=============================================================================
  11. //结构:BitmapFileHeader
  12. //描述:位图文件头,BMP文件必须以此结构开头。
  13. //-----------------------------------------------------------------------------
  14. typedef struct
  15. {
  16.         uint16_t        bfType;                //必须为BM
  17.         uint32_t        bfSize;                //整个文件的尺寸
  18.         uint16_t        bfReserved1;//必须为0
  19.         uint16_t        bfReserved2;//必须为0
  20.         uint32_t        bfOffBits;        //位图数据的偏移
  21. }BitmapFileHeader,*BitmapFileHeaderP;

  22. #define        BF_BMP        0x4D42                //bfType的值

  23. //=============================================================================
  24. //结构:BitmapInfoHeader
  25. //描述:位图信息头,在BMP文件中紧接在BitmapFileHeader的后面。
  26. //-----------------------------------------------------------------------------
  27. typedef struct
  28. {
  29.     uint32_t        biSize;                        //位图信息头和调色板的总尺寸
  30.     int32_t                biWidth;                //位图宽度
  31.     int32_t                biHeight;                //位图高度
  32.     uint16_t        biPlanes;                //位面数(必须为1,扯蛋的)
  33.     uint16_t        biBitCount;                //颜色位数
  34.     uint32_t        biCompression;        //压缩方式
  35.     uint32_t        biSizeImage;        //位图部分尺寸
  36.     int32_t                biXPelsPerMeter;//宽度每米像素数(扯蛋的)
  37.     int32_t                biYPelsPerMeter;//高度每米像素数(扯蛋的)
  38.     uint32_t        biClrUsed;                //使用的颜色数(扯蛋的)
  39.     uint32_t        biClrImportant;        //重要的颜色数(扯蛋的)
  40. }BitmapInfoHeader,*BitmapInfoHeaderP;

  41. //=============================================================================
  42. //枚举:BiCompressionType
  43. //描述:biCompression使用的数值。
  44. //-----------------------------------------------------------------------------
  45. typedef enum
  46. {
  47.         Bi_RGB                =0,        //无压缩
  48.         Bi_RLE8                =1,        //RLE8
  49.         Bi_RLE4                =2,        //RLE4
  50.         Bi_BitFields=3        //位域,也就是用“调色板”的位置来存储位域信息
  51. }BiCompressionType,*BiCompressionTypeP;

  52. typedef enum
  53. {
  54.         BitF_R        =0,        //红色的位
  55.         BitF_G        =1,        //绿色的位
  56.         BitF_B        =2,        //蓝色的位
  57.         BitF_X        =3        //透明通道的位
  58. }BitFIndex,*BitFIndexP;

  59. //=============================================================================
  60. //结构:RGBQuad
  61. //描述:四个字节描述红绿蓝的结构,通常用于描述调色板
  62. //-----------------------------------------------------------------------------
  63. typedef struct
  64. {
  65.         uint8_t                B;
  66.         uint8_t                G;
  67.         uint8_t                R;
  68.         uint8_t                X;
  69. }RGBQuad,*RGBQuadP;

  70. //=============================================================================
  71. //结构:RGBTriple
  72. //描述:三个字节描述红绿蓝的结构,通常用于读取24位BMP
  73. //-----------------------------------------------------------------------------
  74. typedef struct
  75. {
  76.         uint8_t                B;
  77.         uint8_t                G;
  78.         uint8_t                R;
  79. }RGBTriple,*RGBTripleP;

  80. typedef enum
  81. {
  82.         TC_AutoFit        =0,        //如果读取的位图文件低于24位则转换为24位,否则转换为32位
  83.         TC_24                =24,//读取的位图文件强制转换为24位
  84.         TC_32                =32        //读取的位图文件强制转换为32位
  85. }TrueColorBits,*TrueColorBitsP;

  86. //=============================================================================
  87. //结构:BitmapPicture
  88. //描述:用于读取BMP文件的结构体
  89. //-----------------------------------------------------------------------------
  90. typedef struct
  91. {
  92.         BitmapFileHeader        BMFH;                        //位图文件头
  93.         BitmapInfoHeader        BMIF;                        //位图信息头
  94.         union
  95.         {
  96.                 RGBQuad                        Palette[256];        //调色板
  97.                 uint32_t                BitFields[4];        //位域
  98.         }AdditionalData;//额外数据
  99.         size_t                                Width;                        //宽度
  100.         size_t                                Height;                        //高度
  101.         size_t                                cbPitch;                //每行字节数
  102.         void                                *pBits;                        //位图数据
  103.         size_t                                cbBits;                        //位图数据大小
  104. }BitmapPicture,*BitmapPictureP;

  105. #pragma pack(pop)

  106. //=============================================================================
  107. //函数:LoadBMP
  108. //描述:读取BMP文件,建立BitmapPicture结构体
  109. //-----------------------------------------------------------------------------
  110. BitmapPictureP LoadBMP(char*szFilePath);

  111. //=============================================================================
  112. //函数:ConvToTrueColor
  113. //描述:将一个已读取的BMP文件转换为真彩色,返回新的位图。
  114. //-----------------------------------------------------------------------------
  115. BitmapPictureP ConvToTrueColor(BitmapPictureP pOrgBMP,TrueColorBits TCBits);

  116. //=============================================================================
  117. //函数:DestroyBMP
  118. //描述:销毁BitmapPicture结构体,释放内存。
  119. //-----------------------------------------------------------------------------
  120. void DestroyBMP(BitmapPictureP pBMP);

  121. #endif // !_BMPFILE_HEADER_
复制代码
bmpfile.c
  1. //=============================================================================
  2. //作者:0xAA55
  3. //网址:http://www.0xaa55.com
  4. //请保留原作者信息,否则视为侵权。
  5. //-----------------------------------------------------------------------------
  6. #include"bmpfile.h"
  7. #include<stdio.h>
  8. #include<malloc.h>
  9. #include<memory.h>

  10. typedef int        shift_t;

  11. #define        CalcPitch(w,b)        ((((w)*(b)-1)/32+1)*4)

  12. //=============================================================================
  13. //函数:LoadBMP
  14. //描述:读取BMP文件,建立BitmapPicture结构体
  15. //-----------------------------------------------------------------------------
  16. BitmapPictureP LoadBMP(char*szFilePath)
  17. {
  18.         FILE*fp=NULL;
  19.         BitmapPictureP pBMP;
  20.        
  21.         //=========================================================================
  22.         //给要返回的结构体分配内存。
  23.         pBMP=(BitmapPictureP)malloc(sizeof(BitmapPicture));
  24.         if(!pBMP)
  25.         {
  26.                 //内存不足
  27.                 goto ErrorHandler;
  28.         }
  29.         memset(pBMP,0,sizeof(BitmapPicture));

  30.         //=========================================================================
  31.         //打开文件
  32.         fp=fopen(szFilePath,"rb");
  33.         if(!fp)
  34.                 goto ErrorHandler;

  35.         //=========================================================================
  36.         //读取文件头
  37.         if(fread(&(pBMP->BMFH),
  38.                 1,sizeof(pBMP->BMFH),fp)!=sizeof(pBMP->BMFH))
  39.         {
  40.                 //读取失败
  41.                 goto ErrorHandler;
  42.         }

  43.         //=========================================================================
  44.         //判断文件头的结构正确性
  45.         if(        pBMP->BMFH.bfType!=BF_BMP||
  46.                 pBMP->BMFH.bfReserved1        ||
  47.                 pBMP->BMFH.bfReserved2)
  48.         {
  49.                 //文件头格式错误
  50.                 goto ErrorHandler;
  51.         }

  52.         //=========================================================================
  53.         //读取信息头
  54.         if(fread(&(pBMP->BMIF),
  55.                 1,sizeof(pBMP->BMIF),fp)!=sizeof(pBMP->BMIF))
  56.         {
  57.                 //读取失败
  58.                 goto ErrorHandler;
  59.         }

  60.         //=========================================================================
  61.         //判断信息头的结构正确性
  62.         if(          pBMP->BMIF.biWidth<=0//宽度必须大于0
  63.                 ||
  64.                 !(pBMP->BMIF.biHeight)//高度必须不为0(顶到下型时,值为负)
  65.                 ||
  66.                 //必须只能是这么几种压缩类型。
  67.                 (pBMP->BMIF.biCompression!=Bi_RGB &&
  68.                  pBMP->BMIF.biCompression!=Bi_RLE8 &&
  69.                  pBMP->BMIF.biCompression!=Bi_RLE4 &&
  70.                  pBMP->BMIF.biCompression!=Bi_BitFields)
  71.                  ||
  72.                 //如果是压缩位图,则必须是底到上型,并且指定大小
  73.                 ((pBMP->BMIF.biCompression==Bi_RLE8 ||
  74.                   pBMP->BMIF.biCompression==Bi_RLE4) &&
  75.                 (pBMP->BMIF.biHeight<0 ||
  76.                 !pBMP->BMIF.biSizeImage))
  77.                 ||
  78.                 //RLE8只能压缩8位BMP
  79.                 (pBMP->BMIF.biCompression==Bi_RLE8 && pBMP->BMIF.biBitCount!=8)
  80.                 ||
  81.                 //RLE4只能压缩4位BMP
  82.                 (pBMP->BMIF.biCompression==Bi_RLE4 && pBMP->BMIF.biBitCount!=4))
  83.         {
  84.                 //文件头格式错误
  85.                 goto ErrorHandler;
  86.         }
  87.        
  88.         pBMP->Width=pBMP->BMIF.biWidth;
  89.         pBMP->Height=pBMP->BMIF.biHeight>=0?
  90.                 pBMP->BMIF.biHeight:-pBMP->BMIF.biHeight;

  91.         //=========================================================================
  92.         //读取调色板
  93.         if(pBMP->BMIF.biBitCount<=8 && pBMP->BMIF.biCompression!=Bi_BitFields)
  94.         {
  95.                 size_t NbPal=pBMP->BMIF.biClrUsed;
  96.                 if(!NbPal)
  97.                         NbPal=(size_t)1<<pBMP->BMIF.biBitCount;
  98.                 fread(pBMP->AdditionalData.Palette,
  99.                         1,sizeof(RGBQuad)*NbPal,fp);
  100.         }
  101.         //或者读取位域
  102.         else if(pBMP->BMIF.biCompression==Bi_BitFields)
  103.         {
  104.                 fread(pBMP->AdditionalData.BitFields,
  105.                         1,sizeof(pBMP->AdditionalData.BitFields),fp);
  106.         }

  107.         //=========================================================================
  108.         //计算位图数据的大小
  109.         if(        pBMP->BMIF.biCompression==Bi_RGB ||
  110.                 pBMP->BMIF.biCompression==Bi_BitFields)
  111.         {
  112.                 pBMP->cbPitch=//每行字节数4字节对齐
  113.                         CalcPitch(pBMP->Width,pBMP->BMIF.biBitCount);
  114.                 pBMP->cbBits=pBMP->cbPitch*pBMP->Height;
  115.         }
  116.         else
  117.                 pBMP->cbBits=pBMP->BMIF.biSizeImage;
  118.        
  119.         //=========================================================================
  120.         //读取位图数据
  121.         pBMP->pBits=malloc(pBMP->cbBits);
  122.         if(!pBMP->pBits)
  123.         {
  124.                 //内存不足
  125.                 goto ErrorHandler;
  126.         }

  127.         if(fread(pBMP->pBits,1,pBMP->cbBits,fp)!=pBMP->cbBits)
  128.         {
  129.                 //读取失败
  130.                 goto ErrorHandler;
  131.         }
  132.        
  133.         //读取完成
  134.         fclose(fp);
  135.         return pBMP;
  136. ErrorHandler:
  137.         if(fp)
  138.                 fclose(fp);
  139.         if(pBMP)
  140.                 DestroyBMP(pBMP);
  141.         return NULL;
  142. }

  143. //=============================================================================
  144. //函数:GetI32Shift
  145. //描述:取得一个32位数右边的0的数量
  146. //-----------------------------------------------------------------------------
  147. static
  148. shift_t GetI32Shift(uint32_t Val)
  149. {
  150.         shift_t NbShift=0;
  151.         if(!Val)
  152.                 return 0;
  153.         while(!(Val&1))
  154.         {
  155.                 NbShift++;
  156.                 Val>>=1;
  157.         }
  158.         return NbShift;
  159. }

  160. //=============================================================================
  161. //函数:GetI32Bits
  162. //描述:取得一个32位数最左边的1的位置
  163. //-----------------------------------------------------------------------------
  164. static
  165. shift_t GetI32Bits(uint32_t Val)
  166. {
  167.         shift_t NbBits=0;
  168.         while(Val)
  169.         {
  170.                 NbBits++;
  171.                 Val>>=1;
  172.         }
  173.         return NbBits;
  174. }

  175. //=============================================================================
  176. //函数:ConvToTrueColor
  177. //描述:将一个已读取的BMP文件转换为真彩色,返回新的位图。
  178. //-----------------------------------------------------------------------------
  179. BitmapPictureP ConvToTrueColor(BitmapPictureP pOrgBMP,TrueColorBits TCBits)
  180. {
  181.         BitmapPictureP pBMP;
  182.         size_t x,y;
  183.         uint8_t*pOrgBitPtr;
  184.         uint8_t*pOrgLinePtr;
  185.         uint8_t*pBitPtr;
  186.         uint8_t*pLinePtr;

  187.         if(        TCBits!=TC_24 &&
  188.                 TCBits!=TC_32 &&
  189.                 TCBits!=TC_AutoFit)
  190.         {
  191.                 //参数不正确
  192.                 return NULL;
  193.         }
  194.        
  195.         //=========================================================================
  196.         //给要返回的结构体分配内存。
  197.         pBMP=(BitmapPictureP)malloc(sizeof(BitmapPicture));
  198.         if(!pBMP)
  199.         {
  200.                 //内存不足
  201.                 goto ErrorHandler;
  202.         }
  203.         memset(pBMP,0,sizeof(BitmapPicture));

  204.         //=========================================================================
  205.         //补充BMP信息
  206.         //填写BMP文件头
  207.         pBMP->BMFH.bfType=BF_BMP;
  208.         pBMP->BMFH.bfOffBits=sizeof(BitmapFileHeader)+sizeof(BitmapInfoHeader);

  209.         //填写BMP信息头
  210.         pBMP->BMIF.biSize=sizeof(BitmapInfoHeader);
  211.         pBMP->BMIF.biWidth=pOrgBMP->BMIF.biWidth;
  212.         pBMP->BMIF.biHeight=pOrgBMP->BMIF.biHeight;
  213.         pBMP->BMIF.biPlanes=pOrgBMP->BMIF.biPlanes;

  214.         if(TCBits==TC_AutoFit)
  215.                 TCBits=pOrgBMP->BMIF.biBitCount>24?TC_32:TC_24;
  216.         if(TCBits==TC_32)
  217.                 pBMP->BMIF.biBitCount=32;
  218.         else if(TCBits==TC_24)
  219.                 pBMP->BMIF.biBitCount=24;

  220.         pBMP->BMIF.biCompression=Bi_RGB;
  221.         pBMP->BMIF.biSizeImage=0;
  222.         pBMP->BMIF.biXPelsPerMeter=pOrgBMP->BMIF.biXPelsPerMeter;
  223.         pBMP->BMIF.biYPelsPerMeter=pOrgBMP->BMIF.biYPelsPerMeter;
  224.         pBMP->BMIF.biClrUsed=0;
  225.         pBMP->BMIF.biClrImportant=0;

  226.         //绝对值尺寸
  227.         pBMP->Width=pOrgBMP->Width;
  228.         pBMP->Height=pOrgBMP->Height;
  229.        
  230.         //计算位图总尺寸
  231.         pBMP->cbPitch=CalcPitch(pBMP->BMIF.biWidth,pBMP->BMIF.biBitCount);
  232.         pBMP->cbBits=pBMP->Height*pBMP->cbPitch;
  233.         pBMP->pBits=malloc(pBMP->cbBits);
  234.         if(!pBMP->pBits)
  235.         {
  236.                 //内存不足
  237.                 goto ErrorHandler;
  238.         }
  239.         memset(pBMP->pBits,0,pBMP->cbBits);

  240.         pBMP->BMFH.bfSize=(uint32_t)(pBMP->BMFH.bfOffBits+pBMP->cbBits);

  241.         //=========================================================================
  242.         //开始转换过程
  243.         //判断压缩类型
  244.         if(pOrgBMP->BMIF.biCompression==Bi_RGB)//无压缩
  245.         {
  246.                 pOrgLinePtr=(uint8_t*)(pOrgBMP->pBits);
  247.                 pLinePtr=(uint8_t*)(pBMP->pBits);
  248.                 //=====================================================================
  249.                 //2、4、16色位图的处理方式一致。
  250.                 if(        pOrgBMP->BMIF.biBitCount==1 ||        //双色位图(通常为黑白)
  251.                         pOrgBMP->BMIF.biBitCount==2 ||        //四色位图(几乎见不到)
  252.                         pOrgBMP->BMIF.biBitCount==4)        //16色位图
  253.                 {
  254.                         uint8_t                LastByte;
  255.                         shift_t                PixelsLast=0;
  256.                         size_t                PalIndex=0;
  257.                         shift_t                PixelsPerBytes;

  258.                         PixelsPerBytes=8/pOrgBMP->BMIF.biBitCount;//每字节像素数
  259.                         for(y=0;y<pBMP->Height;y++)//遍历每一行
  260.                         {
  261.                                 pOrgBitPtr=pOrgLinePtr;
  262.                                 pBitPtr=pLinePtr;
  263.                                 for(x=0;x<pBMP->Width;x++)//遍历每个字节
  264.                                 {
  265.                                         if(!PixelsLast)//如果读完这个字节
  266.                                         {
  267.                                                 PixelsLast=PixelsPerBytes;
  268.                                                 LastByte=*pOrgBitPtr++;//读取新的字节
  269.                                         }
  270.                                         PalIndex=LastByte>>(8-pOrgBMP->BMIF.biBitCount);//查颜色表
  271.                                         LastByte<<=pOrgBMP->BMIF.biBitCount;//上次读取的字节
  272.                                         PixelsLast--;//能取得的像素数
  273.                                         *pBitPtr++=pOrgBMP->AdditionalData.Palette[PalIndex].B;
  274.                                         *pBitPtr++=pOrgBMP->AdditionalData.Palette[PalIndex].G;
  275.                                         *pBitPtr++=pOrgBMP->AdditionalData.Palette[PalIndex].R;
  276.                                         if(TCBits==TC_32)
  277.                                                 *pBitPtr++=pOrgBMP->AdditionalData.Palette[PalIndex].X;
  278.                                 }
  279.                                 pOrgLinePtr+=pOrgBMP->cbPitch;//转到下一行
  280.                                 pLinePtr+=pBMP->cbPitch;
  281.                                 PixelsLast=0;
  282.                         }
  283.                 }
  284.                 //=====================================================================
  285.                 //256色位图,一个像素一个字节
  286.                 else if(pOrgBMP->BMIF.biBitCount==8)
  287.                 {
  288.                         for(y=0;y<pBMP->Height;y++)//遍历每一行
  289.                         {
  290.                                 pOrgBitPtr=pOrgLinePtr;
  291.                                 pBitPtr=pLinePtr;
  292.                                 for(x=0;x<pBMP->Width;x++)//遍历每一列
  293.                                 {
  294.                                         uint8_t Pix8=*pOrgBitPtr++;
  295.                                         *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8].B;
  296.                                         *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8].G;
  297.                                         *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8].R;
  298.                                         if(TCBits==TC_32)
  299.                                                 *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8].X;
  300.                                 }
  301.                                 pOrgLinePtr+=pOrgBMP->cbPitch;//转到下一行
  302.                                 pLinePtr+=pBMP->cbPitch;
  303.                         }
  304.                 }
  305.                 //=====================================================================
  306.                 //没有位域定义时,16位BMP为1:5:5:5
  307.                 else if(pOrgBMP->BMIF.biBitCount==16)
  308.                 {
  309.                         for(y=0;y<pBMP->Height;y++)//遍历每一行
  310.                         {
  311.                                 pOrgBitPtr=pOrgLinePtr;
  312.                                 pBitPtr=pLinePtr;
  313.                                 for(x=0;x<pBMP->Width;x++)//遍历每一列
  314.                                 {
  315.                                         uint16_t Pix16=*(uint16_t*)pOrgBitPtr;
  316.                                         *pBitPtr++=(uint8_t)(((Pix16&0x001F)<<3)|((Pix16&0x001F)>>2));//同时填充高位和低位
  317.                                         *pBitPtr++=(uint8_t)(((Pix16&0x03E0)>>2)|((Pix16&0x03E0)>>7));
  318.                                         *pBitPtr++=(uint8_t)(((Pix16&0x7C00)>>7)|((Pix16&0x7C00)>>12));
  319.                                         if(TCBits==TC_32)
  320.                                                 *pBitPtr++=(Pix16&0x80)?0xFF:0;
  321.                                         pOrgBitPtr+=2;
  322.                                 }
  323.                                 pOrgLinePtr+=pOrgBMP->cbPitch;
  324.                                 pLinePtr+=pBMP->cbPitch;
  325.                         }
  326.                 }
  327.                 //=====================================================================
  328.                 //24位真彩色位图
  329.                 else if(pOrgBMP->BMIF.biBitCount==24)
  330.                 {
  331.                         if(TCBits==TC_24)
  332.                                 memcpy(pBMP->pBits,pOrgBMP->pBits,pOrgBMP->cbBits);//无须转换
  333.                         else//转成32位
  334.                         {
  335.                                 for(y=0;y<pBMP->Height;y++)//遍历每一行
  336.                                 {
  337.                                         pOrgBitPtr=pOrgLinePtr;
  338.                                         pBitPtr=pLinePtr;
  339.                                         for(x=0;x<pBMP->Width;x++)//遍历每一列
  340.                                         {
  341.                                                 *pBitPtr++=*pOrgBitPtr++;
  342.                                                 *pBitPtr++=*pOrgBitPtr++;
  343.                                                 *pBitPtr++=*pOrgBitPtr++;
  344.                                                 *pBitPtr++=0;
  345.                                         }
  346.                                         pOrgLinePtr+=pOrgBMP->cbPitch;
  347.                                         pLinePtr+=pBMP->cbPitch;
  348.                                 }
  349.                         }
  350.                 }
  351.                 //=====================================================================
  352.                 //32位高彩色位图,比24位多了个透明度通道。
  353.                 else if(pOrgBMP->BMIF.biBitCount==32)
  354.                 {
  355.                         if(TCBits==TC_24)//降级
  356.                         {
  357.                                 for(y=0;y<pBMP->Height;y++)//遍历每一行
  358.                                 {
  359.                                         pOrgBitPtr=pOrgLinePtr;
  360.                                         pBitPtr=pLinePtr;
  361.                                         for(x=0;x<pBMP->Width;x++)//遍历每一列
  362.                                         {
  363.                                                 *pBitPtr++=*pOrgBitPtr++;
  364.                                                 *pBitPtr++=*pOrgBitPtr++;
  365.                                                 *pBitPtr++=*pOrgBitPtr++;
  366.                                                 pOrgBitPtr++;
  367.                                         }
  368.                                         pOrgLinePtr+=pOrgBMP->cbPitch;
  369.                                         pLinePtr+=pBMP->cbPitch;
  370.                                 }
  371.                         }
  372.                         else
  373.                                 memcpy(pBMP->pBits,pOrgBMP->pBits,pOrgBMP->cbBits);//无须转换
  374.                 }
  375.                 else
  376.                 {
  377.                         //不认识的BMP格式
  378.                         goto ErrorHandler;
  379.                 }
  380.                 return pBMP;
  381.         }
  382.         //=========================================================================
  383.         //RLE8压缩类型,Run-Length Encode
  384.         else if(pOrgBMP->BMIF.biCompression==Bi_RLE8)
  385.         {
  386.                 size_t cbPixel=(pBMP->BMIF.biBitCount-1)/8+1;//输出的每像素字节数
  387.                 size_t RightBound;//右边界
  388.                
  389.                 //没有画过的像素都是索引0的颜色。
  390.                 pLinePtr=(uint8_t*)(pBMP->pBits);
  391.                 for(y=0;y<pBMP->Height;y++)//遍历每一行
  392.                 {
  393.                         pBitPtr=pLinePtr;
  394.                         for(x=0;x<pBMP->Width;x++)//遍历每一列
  395.                         {
  396.                                 *pBitPtr++=pOrgBMP->AdditionalData.Palette[0].B;
  397.                                 *pBitPtr++=pOrgBMP->AdditionalData.Palette[0].G;
  398.                                 *pBitPtr++=pOrgBMP->AdditionalData.Palette[0].R;
  399.                                 if(TCBits==TC_32)
  400.                                         *pBitPtr++=pOrgBMP->AdditionalData.Palette[0].X;
  401.                         }
  402.                         pLinePtr+=pBMP->cbPitch;
  403.                 }

  404.                 //然后开始准备绘图
  405.                 pOrgBitPtr=(uint8_t*)(pOrgBMP->pBits);
  406.                 pLinePtr=(uint8_t*)(pBMP->pBits);
  407.                 RightBound=(size_t)(pOrgBMP->pBits)+pOrgBMP->cbBits;
  408.                 pBitPtr=pLinePtr;
  409.                 while((size_t)pOrgBitPtr<RightBound)
  410.                 {
  411.                         if(*pOrgBitPtr)//单个像素复制模式
  412.                         {
  413.                                 uint8_t NbNextPix=*pOrgBitPtr++;//要复制的次数
  414.                                 uint8_t Pix8=*pOrgBitPtr++;//像素值
  415.                                 while(NbNextPix--)
  416.                                 {
  417.                                         *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8].B;
  418.                                         *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8].G;
  419.                                         *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8].R;
  420.                                         if(TCBits==TC_32)
  421.                                                 *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8].X;
  422.                                 }
  423.                         }
  424.                         else//转义字节
  425.                         {
  426.                                 pOrgBitPtr++;
  427.                                 if(*pOrgBitPtr==0)//转义0:行结尾
  428.                                 {
  429.                                         pOrgBitPtr++;
  430.                                         pLinePtr+=pBMP->cbPitch;
  431.                                         pBitPtr=pLinePtr;
  432.                                 }
  433.                                 else if(*pOrgBitPtr==1)//转义1:位图结尾
  434.                                         break;
  435.                                 else if(*pOrgBitPtr==2)//转义2:下一个像素的偏移
  436.                                 {
  437.                                         pBitPtr+=cbPixel**++pOrgBitPtr;//放荡不羁的代码只为好玩
  438.                                         pBitPtr+=*++pOrgBitPtr*pBMP->cbPitch;
  439.                                         pLinePtr+=*pOrgBitPtr++*pBMP->cbPitch;
  440.                                 }
  441.                                 else//转义3-0xFF:绝对模式
  442.                                 {
  443.                                         uint8_t NbCopy=*pOrgBitPtr++;//需要复制的像素数
  444.                                         uint8_t NbCopied=0;//已经复制的像素数
  445.                                         while(NbCopied++<NbCopy)
  446.                                         {
  447.                                                 uint8_t Pix8=*pOrgBitPtr++;//像素值
  448.                                                 *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8].B;
  449.                                                 *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8].G;
  450.                                                 *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8].R;
  451.                                                 if(TCBits==TC_32)
  452.                                                         *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8].X;
  453.                                         }
  454.                                         pOrgBitPtr+=NbCopy&1;//要复制的像素数据是以字对齐的
  455.                                 }
  456.                         }
  457.                 }
  458.                 return pBMP;
  459.         }
  460.         //=========================================================================
  461.         //RLE8压缩类型
  462.         else if(pOrgBMP->BMIF.biCompression==Bi_RLE4)
  463.         {
  464.                 size_t cbPixel=(pBMP->BMIF.biBitCount-1)/8+1;
  465.                 size_t RightBound;
  466.                
  467.                 //没有画过的像素都是索引0的颜色。
  468.                 pLinePtr=(uint8_t*)(pBMP->pBits);
  469.                 for(y=0;y<pBMP->Height;y++)//遍历每一行
  470.                 {
  471.                         pBitPtr=pLinePtr;
  472.                         for(x=0;x<pBMP->Width;x++)//遍历每一列
  473.                         {
  474.                                 *pBitPtr++=pOrgBMP->AdditionalData.Palette[0].B;
  475.                                 *pBitPtr++=pOrgBMP->AdditionalData.Palette[0].G;
  476.                                 *pBitPtr++=pOrgBMP->AdditionalData.Palette[0].R;
  477.                                 if(TCBits==TC_32)
  478.                                         *pBitPtr++=pOrgBMP->AdditionalData.Palette[0].X;
  479.                         }
  480.                         pLinePtr+=pBMP->cbPitch;
  481.                 }

  482.                 //然后开始准备绘图
  483.                 pOrgBitPtr=(uint8_t*)(pOrgBMP->pBits);
  484.                 pLinePtr=(uint8_t*)(pBMP->pBits);
  485.                 RightBound=(size_t)(pOrgBMP->pBits)+pOrgBMP->cbBits;
  486.                 pBitPtr=pLinePtr;
  487.                 while((size_t)pOrgBitPtr<RightBound)
  488.                 {
  489.                         if(*pOrgBitPtr)//单个像素复制模式
  490.                         {
  491.                                 uint8_t NbNextPix=*pOrgBitPtr++;//要复制的次数
  492.                                 uint8_t Pix8=*pOrgBitPtr++;//像素值
  493.                                 while(NbNextPix--)
  494.                                 {
  495.                                         //RLE4模式下,一个字节两个像素交替出现。
  496.                                         *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8>>4].B;
  497.                                         *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8>>4].G;
  498.                                         *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8>>4].R;
  499.                                         if(TCBits==TC_32)
  500.                                                 *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8>>4].X;
  501.                                         if(!NbNextPix--)
  502.                                                 break;
  503.                                         *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8&0x0F].B;
  504.                                         *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8&0x0F].G;
  505.                                         *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8&0x0F].R;
  506.                                         if(TCBits==TC_32)
  507.                                                 *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8&0x0F].X;
  508.                                 }
  509.                         }
  510.                         else//转义字节
  511.                         {
  512.                                 pOrgBitPtr++;
  513.                                 if(*pOrgBitPtr==0)//转义0:行结尾
  514.                                 {
  515.                                         pOrgBitPtr++;
  516.                                         pLinePtr+=pBMP->cbPitch;
  517.                                         pBitPtr=pLinePtr;
  518.                                 }
  519.                                 else if(*pOrgBitPtr==1)//转义1:位图结尾
  520.                                         break;
  521.                                 else if(*pOrgBitPtr==2)//转义2:下一个像素的偏移
  522.                                 {
  523.                                         pBitPtr+=cbPixel**++pOrgBitPtr;
  524.                                         pBitPtr+=*++pOrgBitPtr*pBMP->cbPitch;
  525.                                         pLinePtr+=*pOrgBitPtr++*pBMP->cbPitch;
  526.                                 }
  527.                                 else//转义3-0xFF:绝对模式
  528.                                 {
  529.                                         uint8_t NbCopy=*pOrgBitPtr++;//需要复制的像素数
  530.                                         uint8_t NbCopied=0;//已经复制的像素数
  531.                                         while(NbCopied++<NbCopy)
  532.                                         {
  533.                                                 uint8_t Pix8=*pOrgBitPtr++;//像素值
  534.                                                 //RLE4模式下,一个字节两个像素交替出现。
  535.                                                 *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8>>4].B;
  536.                                                 *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8>>4].G;
  537.                                                 *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8>>4].R;
  538.                                                 if(TCBits==TC_32)
  539.                                                         *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8>>4].X;
  540.                                                 if(!(NbCopied++<NbCopy))
  541.                                                         break;
  542.                                                 *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8&0x0F].B;
  543.                                                 *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8&0x0F].G;
  544.                                                 *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8&0x0F].R;
  545.                                                 if(TCBits==TC_32)
  546.                                                         *pBitPtr++=pOrgBMP->AdditionalData.Palette[Pix8&0x0F].X;
  547.                                         }
  548.                                         pOrgBitPtr+=(NbCopy&3)?1:0;//要复制的像素数据是以字对齐的
  549.                                 }
  550.                         }
  551.                 }
  552.                 return pBMP;
  553.         }
  554.         //=========================================================================
  555.         //位域,占用调色板的位置,通常用在16位颜色上表示每个位的意义。
  556.         else if(pOrgBMP->BMIF.biCompression==Bi_BitFields)
  557.         {
  558.                 size_t cbPixel=(pOrgBMP->BMIF.biBitCount-1)/8+1;//每个像素字节数
  559.                 uint32_t PixVal;//像素值
  560.                 //每种颜色的位域低位(S=Shift)
  561.                 shift_t BS=GetI32Shift(pOrgBMP->AdditionalData.BitFields[BitF_B]);
  562.                 shift_t GS=GetI32Shift(pOrgBMP->AdditionalData.BitFields[BitF_G]);
  563.                 shift_t RS=GetI32Shift(pOrgBMP->AdditionalData.BitFields[BitF_R]);
  564.                 shift_t XS=GetI32Shift(pOrgBMP->AdditionalData.BitFields[BitF_X]);
  565.                 //每种颜色的位域位数
  566.                 shift_t BBits=GetI32Bits(pOrgBMP->AdditionalData.BitFields[BitF_B])-BS;
  567.                 shift_t GBits=GetI32Bits(pOrgBMP->AdditionalData.BitFields[BitF_G])-GS;
  568.                 shift_t RBits=GetI32Bits(pOrgBMP->AdditionalData.BitFields[BitF_R])-RS;
  569.                 shift_t XBits=GetI32Bits(pOrgBMP->AdditionalData.BitFields[BitF_X])-XS;
  570.                
  571.                 pOrgLinePtr=(uint8_t*)(pOrgBMP->pBits);
  572.                 pLinePtr=(uint8_t*)(pBMP->pBits);

  573.                 for(y=0;y<pBMP->Height;y++)//遍历每一行
  574.                 {
  575.                         pOrgBitPtr=pOrgLinePtr;
  576.                         pBitPtr=pLinePtr;
  577.                         for(x=0;x<pBMP->Width;x++)//遍历每一列
  578.                         {
  579.                                 int Fill;
  580.                                 uint8_t XVal,RVal,GVal,BVal;

  581.                                 PixVal=*(uint32_t*)pOrgBitPtr;//取得像素值
  582.                                 pOrgBitPtr+=cbPixel;//转到下一个像素
  583.                                
  584.                                 //取得当前像素值每个域的颜色值
  585.                                 BVal=(PixVal & pOrgBMP->AdditionalData.BitFields[BitF_B])>>BS;
  586.                                 GVal=(PixVal & pOrgBMP->AdditionalData.BitFields[BitF_G])>>GS;
  587.                                 RVal=(PixVal & pOrgBMP->AdditionalData.BitFields[BitF_R])>>RS;
  588.                                 XVal=(PixVal & pOrgBMP->AdditionalData.BitFields[BitF_X])>>RS;

  589.                                 //填充蓝色值
  590.                                 *pBitPtr=0;Fill=8;
  591.                                 while(Fill>0)
  592.                                 {
  593.                                         Fill-=BBits;
  594.                                         *pBitPtr|=BVal<<Fill;
  595.                                 }
  596.                                 pBitPtr++;

  597.                                 //填充绿色值
  598.                                 *pBitPtr=0;Fill=8;
  599.                                 while(Fill>0)
  600.                                 {
  601.                                         Fill-=GBits;
  602.                                         *pBitPtr|=GVal<<Fill;
  603.                                 }
  604.                                 pBitPtr++;

  605.                                 //填充红色值
  606.                                 *pBitPtr=0;Fill=8;
  607.                                 while(Fill>0)
  608.                                 {
  609.                                         Fill-=RBits;
  610.                                         *pBitPtr|=RVal<<Fill;
  611.                                 }
  612.                                 pBitPtr++;

  613.                                 //如果要输出32位位图,填充透明色值。
  614.                                 if(TCBits==TC_32)
  615.                                 {
  616.                                         *pBitPtr=0;
  617.                                         if(XBits)
  618.                                         {
  619.                                                 Fill=8;
  620.                                                 while(Fill>0)
  621.                                                 {
  622.                                                         Fill-=XBits;
  623.                                                         *pBitPtr|=XVal<<Fill;
  624.                                                 }
  625.                                         }
  626.                                         pBitPtr++;
  627.                                 }
  628.                         }
  629.                         pOrgLinePtr+=pOrgBMP->cbPitch;//转到下一行
  630.                         pLinePtr+=pBMP->cbPitch;
  631.                 }
  632.                 return pBMP;
  633.         }
  634.         //必须只能是这几种压缩类型,否则报错:不支持的压缩类型
  635. ErrorHandler:
  636.         if(pBMP)
  637.                 DestroyBMP(pBMP);
  638.         return NULL;
  639. }

  640. //=============================================================================
  641. //函数:DestroyBMP
  642. //描述:销毁BitmapPicture结构体,释放内存。
  643. //-----------------------------------------------------------------------------
  644. void DestroyBMP(BitmapPictureP pBMP)
  645. {
  646.         if(pBMP->pBits)
  647.                 free(pBMP->pBits);
  648.         free(pBMP);
  649. }
复制代码
基本所有的BMP都能读取了,无论是1,2,4,8,16,24,32,还是带位域的X1R5G5B5、R5G6B5、X4R4G4B4、X8R8G8B8等都能读取。无论是RLE4还是RLE8也都能读取。脱离Windows可以使用。
20150204070831.png
BIN: ReadBMP.exe (72 KB, 下载次数: 2)
SRC: ReadBMP.7z (1.73 MB, 下载次数: 10)
回复

使用道具 举报

1

主题

60

回帖

201

积分

用户组: 中·技术宅

UID
4683
精华
0
威望
0 点
宅币
140 个
贡献
0 次
宅之契约
0 份
在线时间
31 小时
注册时间
2019-2-11
发表于 2019-5-10 20:47:03 | 显示全部楼层
哇,收藏了。
回复

使用道具 举报

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-3-29 17:40 , Processed in 0.044309 second(s), 35 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表