分享

将24位位图转换8位位图

 arm_embed 2012-11-24
 

将24位位图转换8位位图

分类: GDI 243人阅读 评论(0) 收藏 举报
bmpTest.h   :介绍BMP文件的格式及结构定义
bmpTest.cpp : 24bitBMP颜色数据到256色位图颜色数据的转换函数实现,具体算法可参考以 前的一个帖子
bmpTransfer.cpp  :  读入一个24bitBMP文件,转换成一个256色BMP文件的程序

编译完成后得到的程序,如bmpTransfer.exe
执行  bmpTransfer file1 file2
file1是24bit的BMP位图源文件名,file2是新生成的256色位图文件名

可以用windows画板程序查看结果,似乎比直接用画板程序将24bitBMP存成256色BMP文件的转换效果要好哦。


bmpTest.h


  1. /************* 
  2.    bmpTest.h 
  3. **************/  
  4. #ifndef __BMPTEST_H_  
  5. #define __BMPTEST_H_  
  6.   
  7. #include <stdio.h>  
  8.   
  9. typedef unsigned char  BYTE;  
  10. typedef unsigned short WORD;  
  11.   
  12.   
  13. // BMP图像各部分说明如下  
  14.   
  15. /*********** 
  16.     第一部分    位图文件头 
  17. 该结构的长度是固定的,为14个字节,各个域的依次如下: 
  18.     2byte   :文件类型,必须是0x4d42,即字符串"BM"。 
  19.     4byte   :整个文件大小 
  20.     4byte   :保留字,为0 
  21.     4byte   :从文件头到实际的位图图像数据的偏移字节数。 
  22. *************/  
  23.   
  24. typedef struct  
  25. {  
  26.     long imageSize;  
  27.     long blank;  
  28.     long startPosition;  
  29.     void show(void)  
  30.     {  
  31.         printf("BMP Head:\n");  
  32.         printf("Image Size:%d\n",imageSize);  
  33.         printf("Image Data Start Position : %d\n",startPosition);  
  34.     }  
  35. }BmpHead;  
  36.   
  37. /********************* 
  38.     第二部分    位图信息头 
  39. 该结构的长度也是固定的,为40个字节,各个域的依次说明如下: 
  40.     4byte   :本结构的长度,值为40 
  41.     4byte   :图像的宽度是多少象素。 
  42.     4byte   :图像的高度是多少象素。 
  43.     2Byte   :必须是1。 
  44.     2Byte   :表示颜色时用到的位数,常用的值为1(黑白二色图)、4(16色图)、8(256色图)、24(真彩色图)。 
  45.     4byte   :指定位图是否压缩,有效值为BI_RGB,BI_RLE8,BI_RLE4,BI_BITFIELDS。Windows位图可采用RLE4和RLE8的压缩格式,BI_RGB表示不压缩。 
  46.     4byte   :指定实际的位图图像数据占用的字节数,可用以下的公式计算出来: 
  47.               图像数据 = Width' * Height * 表示每个象素颜色占用的byte数(即颜色位数/8,24bit图为3,256色为1) 
  48.               要注意的是:上述公式中的biWidth'必须是4的整数倍(不是biWidth,而是大于或等于biWidth的最小4的整数倍)。 
  49.               如果biCompression为BI_RGB,则该项可能为0。 
  50.     4byte   :目标设备的水平分辨率。 
  51.     4byte   :目标设备的垂直分辨率。 
  52.     4byte   :本图像实际用到的颜色数,如果该值为0,则用到的颜色数为2的(颜色位数)次幂,如颜色位数为8,2^8=256,即256色的位图 
  53.     4byte   :指定本图像中重要的颜色数,如果该值为0,则认为所有的颜色都是重要的。 
  54. ***********************************/  
  55. typedef struct   
  56. {  
  57.     long    Length;  
  58.     long    width;  
  59.     long    height;  
  60.     WORD    colorPlane;  
  61.     WORD    bitColor;  
  62.     long    zipFormat;   
  63.     long    realSize;  
  64.     long    xPels;  
  65.     long    yPels;  
  66.     long    colorUse;  
  67.     long    colorImportant;  
  68.     void show(void)  
  69.     {        
  70.         printf("infoHead Length:%d\n",Length);  
  71.         printf("width&height:%d*%d\n",width,height);    
  72.         printf("colorPlane:%d\n",colorPlane);  
  73.         printf("bitColor:%d\n",bitColor);  
  74.         printf("Compression Format:%d\n",zipFormat);  
  75.         printf("Image Real Size:%d\n",realSize);  
  76.         printf("Pels(X,Y):(%d,%d)\n",xPels,yPels);  
  77.         printf("colorUse:%d\n",colorUse);        
  78.         printf("Important Color:%d\n",colorImportant);  
  79.     }  
  80. }InfoHead;  
  81.   
  82. /*************************** 
  83.     第三部分    调色盘结构 
  84.     对于256色BMP位图,颜色位数为8,需要2^8 = 256个调色盘; 
  85.     对于24bitBMP位图,各象素RGB值直接保存在图像数据区,不需要调色盘,不存在调色盘区 
  86.     rgbBlue:   该颜色的蓝色分量。 
  87.     rgbGreen:  该颜色的绿色分量。 
  88.     rgbRed:    该颜色的红色分量。 
  89.     rgbReserved:保留值。 
  90. ************************/  
  91. typedef struct  
  92. {  
  93.          BYTE   rgbBlue;  
  94.          BYTE   rgbGreen;  
  95.          BYTE   rgbRed;  
  96.          BYTE   rgbReserved;  
  97.          void show(void)  
  98.          {  
  99.             printf("Mix Plate B,G,R:%d %d %d\n",rgbBlue,rgbGreen,rgbRed);   
  100.          }  
  101. }RGBMixPlate;  
  102.   
  103. /**************************** 
  104.     第四部分    图像数据区 
  105.     对于用到调色板的位图,图像数据就是该象素颜色在调色板中的索引值; 
  106.     对于真彩色图,图像数据就是实际的R、G、B值。 
  107.         2色图,用1位就可以表示该象素的颜色,所以1个字节可以表示8个象素。 
  108.         16色图,用4位可以表示一个象素的颜色,所以1个字节可以表示2个象素。 
  109.         256色图,1个字节刚好可以表示1个象素。 
  110.         真彩色图,3个字节才能表示1个象素。         
  111. ****************************/  
  112.   
  113.   
  114. //将24bit的象素颜色数据转换为256色图的图像数据(即索引值)  
  115. int Transfer(WORD *color24bit, int len, BYTE *Index, RGBMixPlate *mainColor);  
  116.   
  117. #endif  



bmpTest.cpp


  1. /*************** 
  2.     bmpTest.cpp 
  3. ****************/  
  4. #include "bmpTest.h"  
  5. #include <string.h>  
  6. #include <assert.h>  
  7.   
  8. //计算平方差的函数  
  9. int PFC(int color1, int color2)  
  10. {  
  11.     int x,y,z;  
  12.     x = (color1 & 0xf) - (color2 & 0xf);  
  13.     y = ((color1>>4) & 0xf) - ((color2>>4) & 0xf);  
  14.     z = ((color1>>8) & 0xf) - ((color2>>8) & 0xf);  
  15.     return (x*x + y*y + z*z);  
  16. };  
  17.   
  18. //直接插入排序  
  19. int Sort1(int *src, int *attach, int n)  
  20. {  
  21.     int cur, cur1;  
  22.     int i,j,k=0;  
  23.     for (i = 1; i < n; i++)  
  24.     {  
  25.         cur     = src[i];  
  26.         cur1 = attach[i];  
  27.         for (j = i - 1; j >= 0; j--)  
  28.         {  
  29.             if (cur > src[j])  
  30.             {  
  31.                 src[j+1]    = src[j];  
  32.                 attach[j+1] = attach[j];  
  33.             }  
  34.             else  
  35.                 break;  
  36.         }  
  37.         src[j+1]  = cur;  
  38.         attach[j+1] = cur1;  
  39.     }  
  40.     return 0;  
  41. }  
  42.   
  43. //快速排序  
  44. int Sort2(int *src, int *attach, int n)  
  45. {  
  46.     if (n <= 12)  
  47.         return Sort1(src, attach, n);  
  48.     int low = 1, high = n - 1;  
  49.     int tmp;  
  50.     while (low <= high)  
  51.     {  
  52.         while (src[low] >= src[0])  
  53.         {  
  54.             if (++low > n - 1)  
  55.                 break;  
  56.         }  
  57.         while (src[high] < src[0])  
  58.         {  
  59.             if (--high < 1)  
  60.                 break;  
  61.         }  
  62.         if (low > high)  
  63.             break;  
  64.         {  
  65.             tmp                = src[low];  
  66.             src[low]        = src[high];  
  67.             src[high]        = tmp;  
  68.             tmp                = attach[low];  
  69.             attach[low]        = attach[high];  
  70.             attach[high]    = tmp;  
  71.         }  
  72.         low++;  
  73.         high--;  
  74.     }  
  75.   
  76.       
  77.     {  
  78.         tmp                = src[low - 1];  
  79.         src[low - 1]    = src[0];  
  80.         src[0]            = tmp;  
  81.         tmp                = attach[low - 1];  
  82.         attach[low - 1]    = attach[0];  
  83.         attach[0]        = tmp;  
  84.     }  
  85.     if (low > 1)  
  86.         Sort2(src, attach, low - 1);  
  87.     if (low < n)  
  88.         Sort2(&src[low], &attach[low], n - low);  
  89.     return 0;  
  90. }  
  91.   
  92. //将24bit的象素颜色数据转换为256色图的图像数据(即索引值)  
  93. int Transfer(WORD *color24bit, int len, BYTE *Index, RGBMixPlate *mainColor)  
  94. {  
  95.     int usedTimes[4096] = {0};  
  96.     int miniColor[4096];  
  97.     for (int i = 0; i < 4096; i++)  
  98.         miniColor[i] = i;  
  99.     i = 0;  
  100.     for (i = 0; i < len; i++)  
  101.     {  
  102.         assert(color24bit[i] < 4096);  
  103.         usedTimes[color24bit[i]]++;  
  104.     }  
  105.   
  106.     int numberOfColors = 0;  
  107.     for (i = 0; i < 4096; i++)  
  108.     {  
  109.         if (usedTimes[i] > 0)  
  110.             numberOfColors++;  
  111.     }  
  112.   
  113.     //对usedTimes进行排序,排序过程中minColor数组(保存了颜色值)也作与useTimes  
  114.     //数组相似的交换  
  115.     Sort2(usedTimes, miniColor, 4096);  
  116.   
  117.     //usedTimes数组中是各颜色使用频率,从高到低排列,显然第numberOfColor个之后的都为0  
  118.     //miniColor数组中是相应的颜色数据  
  119.     //将前256个颜色数据保存到256色位图的调色盘中  
  120.     for (i = 0; i < 256; i++)  
  121.     {  
  122.         mainColor[i].rgbBlue    = (BYTE)((miniColor[i]>>8)<<4);  
  123.         mainColor[i].rgbGreen    = (BYTE)(((miniColor[i]>>4) & 0xf)<<4);  
  124.         mainColor[i].rgbRed        = (BYTE)((miniColor[i] & 0xf)<<4);  
  125.         mainColor[i].rgbReserved = 0;  
  126.     }  
  127.   
  128.     int *colorIndex = usedTimes;//用原来的useTimes数组来保存索引值  
  129.     memset(colorIndex, 0, sizeof(int) * 4096);  
  130.       
  131.     if (numberOfColors <= 256)  
  132.     {  
  133.         for (i = 0; i < numberOfColors; i++)  
  134.             colorIndex[miniColor[i]] = i;  
  135.     }  
  136.     else//为第256之后的颜色在前256种颜色中找一个最接近的  
  137.     {  
  138.         for (i = 0; i < 256; i++)  
  139.             colorIndex[miniColor[i]] = i;  
  140.           
  141.         int index, tmp, tmp1;  
  142.         for (i = 256; i < numberOfColors; i++)  
  143.         {  
  144.             tmp      = PFC(miniColor[0], miniColor[i]);  
  145.             index = 0;  
  146.             for (int j = 1; j < 256; j++)  
  147.             {  
  148.                 tmp1 = PFC(miniColor[j], miniColor[i]);  
  149.                 if (tmp > tmp1)  
  150.                 {  
  151.                     tmp = tmp1;  
  152.                     index = j;  
  153.                 }  
  154.             }  
  155.             colorIndex[miniColor[i]] = index;  
  156.         }  
  157.     }  
  158.     //记录各点颜色数据的索引值,即256色位图的颜色数据  
  159.     for (i = 0; i < len; i++)  
  160.     {  
  161.         assert(colorIndex[color24bit[i]] < 256);  
  162.         Index[i] = colorIndex[color24bit[i]];  
  163.     }  
  164.   
  165.     return 1;        
  166. }  



bmpTransfer.cpp

  1. /******************** 
  2.   bmpTransfer.cpp 
  3. ********************/  
  4. #include "bmpTest.h"  
  5. #include <string.h>  
  6.   
  7. int __cdecl main(int argc,char* argv[])  
  8. {  
  9.     if (argc < 3)  
  10.     {  
  11.         printf("Usage:\n");  
  12.         printf("    %s filename1 filename2\n", argv[0]);  
  13.         printf("    filename1 : source 24bit BMP filename    like: xxx.bmp\n");  
  14.         printf("    filename2 : new 256 color BMP filename\n");  
  15.         return -1;  
  16.     }  
  17.     BmpHead  headBMP;  
  18.     InfoHead infoHead;   
  19.     FILE* p;  
  20.     char* filename = argv[1];  
  21.     p = fopen(filename,"rb");  
  22.     if (p == NULL)  
  23.     {  
  24.         printf("!!!file %s open failed.\n", filename);  
  25.     }  
  26.   
  27.     printf("file %s open success.\n",filename);   
  28. /**********   read BMP head ********************/                  
  29.     fseek(p,2,SEEK_CUR);  
  30.     fread(&headBMP,1,12,p);  
  31.     headBMP.show();  
  32.     fread(&infoHead,1,40,p);  
  33.     infoHead.show();  
  34.     if (infoHead.bitColor != 24)  
  35.     {  
  36.         fclose(p);  
  37.         printf("This is not a 24bit BMP file.\n");  
  38.         return -1;  
  39.     }  
  40. /***********  read Image Date  **************/  
  41.     long nData = infoHead.realSize;  
  42.     BYTE* pColorData = new BYTE[nData];  
  43.     fread(pColorData,1,nData,p);  
  44.     printf("last 4 byte of color Data:%x %x %x %x\n",\  
  45.         pColorData[nData-4],pColorData[nData-3],\  
  46.         pColorData[nData-2],pColorData[nData-1]);  
  47.   
  48. /***********  read file over ***************/  
  49.     int leftData = 0;  
  50.     char ch = 0;  
  51.     while (!feof(p))  
  52.     {  
  53.         fread(&ch,1,1,p);  
  54.         leftData++;  
  55.     }  
  56.     if (leftData)  
  57.         printf("%d bytes not read in file.\n", leftData);  
  58.     printf("read file over.\n");     
  59.     if(!fclose(p))  
  60.     {  
  61.         printf("file close.\n");  
  62.     }  
  63. // 24位BMP文件信息都读出来了,可以查看打印信息  
  64.   
  65. /************  24bit到256色的颜色数据转换  *****************/  
  66.     BYTE* Index = new BYTE[nData/3];  
  67.     RGBMixPlate  mainColor[256];  
  68.     memset(mainColor, 0, sizeof(mainColor));  
  69.     WORD* shortColor = new WORD[nData/3];  
  70.     int iRed, iGreen, iBlue;  
  71.     for (int i = 0; i < nData/3; i++)  
  72.     {//取RGB颜色的高4位  
  73.         iRed    = pColorData[i*3]>>4;  
  74.         iGreen    = pColorData[i*3+1]>>4;  
  75.         iBlue    = pColorData[i*3+2]>>4;  
  76.         shortColor[i] = (iRed<<8) + (iGreen<<4) + iBlue;  
  77.     }  
  78.     delete []pColorData;  
  79.     //调用转换函数  
  80.     Transfer(shortColor, nData/3, Index, mainColor);  
  81.   
  82.     delete []shortColor;    
  83. //转换完成,256色位图的调色盘数据(保存在mainColor)和图像数据区的数据(保存在Index中)  
  84.   
  85. /************  写一个新的256色BMP文件  *******************/  
  86.        
  87. //修改一下前面读出的BmpHead和InfoHead的结构信息  
  88.     headBMP.imageSize = 14 + 40 + 4*256 + nData/3;      
  89.                     // 4*256是调色盘的长度,nData/3是图像数据区长度  
  90.     headBMP.startPosition += 4*256;     //新文件加上了调色盘部分  
  91.     infoHead.bitColor = 8;              //颜色位数改为8  
  92.     infoHead.realSize = nData/3;        //图像数据区长度  
  93.           
  94. //写新文件  
  95.     char* newFile = argv[2];  
  96.     FILE *p1 = fopen(newFile,"wb");  
  97.     if (NULL == p1)  
  98.     {  
  99.         printf("open new file failed.\n");  
  100.         return -1;  
  101.     }  
  102.     char hh[2] = {0x42, 0x4D};  
  103.     fwrite(hh,1,2,p1);                //BMP文件开头两字节, 0x4d42 = "BM"  
  104.     fwrite(&headBMP, 1, 12, p1);    //BMP文件头   
  105.     fwrite(&infoHead, 1, 40, p1);    //BMP文件头信息   
  106.     fwrite(mainColor, 1, sizeof(mainColor), p1);//写调色盘信息  
  107.     fwrite(Index, 1, nData/3, p1);  //颜色数据  
  108.     fclose(p1);  
  109.   
  110.     //释放分配的内存  
  111.     delete []Index;  
  112.     return 0;  
  113. }  

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多