我的一个程序中需要将一个24位位图转为8位位图后保存,我的思路是在读取原图后得到原图的图像数据,然后重新申请内存空间,构造新的BITMAPFILEHEADER和BITMAPINFOR结构,里边包括BITMAPINFOHEADER和颜色表,之后是紧跟新的位图信息,然后再保存。我的思路对不对?有没有更好的方法?在生成新的位图数据时,新图每行所占的字节数变了,图像大小变了,那么在构造BITMAPFILEHEADER结构时它的那个bfSize和bfOffBits怎么确定?

解决方案 »

  1.   

    你这其实就是转换成灰度图象,就按你的思路弄就行,只不过把各个象素值重新计算一下,用(R+G+B)/3代替即可。
      

  2.   

    在生成新的位图数据时,新图每行所占的字节数变了,图像大小变了,那么在构造BITMAPFILEHEADER结构时它的那个bfSize和bfOffBits怎么确定?
      

  3.   

    bfsize不就是 width*height 么?
    bfOffBits灰度数据起始地址应该没什么变化吧真彩的255*255*255 size = 3 * width * height,灰度占一个byte,0~255
      

  4.   

    首先bfOffBits是指从头文件到位图数据的偏移量 单位是字节,
    你说改成8位位图(256色)那么这个偏移量就是:
    BITMAPFILEHEADER 14Byte
    BITMAPINFOHEADER 40Byte
    Palette    256*4=1024Byte
                   所以这个bfOffBits=14+40+1024=1078至于bfSize 是整个文件的大小 单位也是字节 
    就是 bfOffBits+biSizeImage(实际的位图数据占用的字节数)
    你的文件是8位的 一个像素一个字节。biSizeImage=biWidth’*biHeight*1需要注意biWidth’是大于biWidth的最小4的整数倍。例如:如你的图像时799*600的 那么biWidth’=800
    biSizeImage=800*600*1=48000
    bfOffBits=1078
    bfSize=1078+48000=49078
      

  5.   

    图像大小没变,bfSize是文件的大小,也就是文件头加上颜色表加上位图数据的大小;bfOffBits是位图数据的开始位置,也就是文件头加上颜色表的大小。
      

  6.   


            HANDLE   hFile   =   ::CreateFile("E:\\bitmap.bmp",GENERIC_READ,FILE_SHARE_READ,   
                  NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);   
            if(hFile   ==   0)   
            {   
                  MessageBox("不能打开文件,请重新选择!");   
            }   
        
              DWORD   dwWriteNum;         
              BITMAPFILEHEADER   Bmp_file_head;   //文件头   
              ReadFile(hFile,&Bmp_file_head,14,&dwWriteNum,NULL);//读取文件头,共14个字节   
        
              if((Bmp_file_head.bfType   !=   'MB')||(dwWriteNum   !=   sizeof(BITMAPFILEHEADER)))   
              {   
                      MessageBox("不是BMP位图文件或数据有误!");   
              }   
        
      BITMAPINFOHEADER   Bmp_info_head;   //信息头   
      ReadFile(hFile,&Bmp_info_head,40,&dwWriteNum,NULL);   
        
      if(dwWriteNum   !=   sizeof(BITMAPINFOHEADER))   
      {   
      MessageBox("读取信息头错误!");   
      }   
        
      //读取24位图像素数据   
      DWORD   Bitmap_bit_len;   
      Bitmap_bit_len   =   Bmp_file_head.bfSize-sizeof(BITMAPFILEHEADER)-sizeof(BITMAPINFOHEADER);   
        
      BYTE   *lpOldBmpData   =   new   BYTE[Bitmap_bit_len];   
      ReadFile(hFile,lpOldBmpData,Bitmap_bit_len,&dwWriteNum,NULL);   
              
      if(dwWriteNum   !=   Bitmap_bit_len)   
      {   
      MessageBox("位图像素数据读取错误!");   
      }   
        
              int       nScanWidth;             //转换后其每行扫描宽度   
              int     nLineWidth;             //将其转换成8位位图后每行宽度(即每行字节数)         
              int       nSrcWidth,nSrcHeight;         
        
              nSrcHeight   =   Bmp_info_head.biHeight;         //原24位位图高度(像素数)   
              nSrcWidth   =   Bmp_info_head.biWidth;             //原24位位图宽度(像素数)   
        
              nLineWidth   =   ((nSrcWidth*3)/4)*4;           
              if(nLineWidth<nSrcWidth*3)         
              nLineWidth=nLineWidth+4;                                 //保证以DWORD对齐(为4的整数倍)(原图象每行字节数)   
                
              nScanWidth=(nSrcWidth/4)*4;         
              if(nScanWidth<nSrcWidth)         
              nScanWidth=nScanWidth+4;                                 //保证以DWORD对齐(为4的整数倍)(转换图象每行像素数)   
        
              //申请8位图的空间   
              int   intnDataLen   =   nScanWidth*nSrcHeight;//+2;     //原图像素数   
        
      BYTE   *   lpNewBmpData   =   new   BYTE[intnDataLen];   
        
      //为8位位图像素赋值   
              for(int   i=0;i<nSrcHeight;i++)           //像素   
        {   
                    for(int   j=0;j<nSrcWidth;j++)             //像素   
            {         
                            BYTE       color[3];         
                            unsigned   int       dwColorTemp;         
                            for(int       s=0;   s<3;   s++)         
                                color[s]=lpOldBmpData[i*nLineWidth+j*3+s];         
        
                          dwColorTemp=unsigned   int(color[2]*0.299+color[1]*0.587+color[0]*0.114);         
                        
                            if(dwColorTemp>255)         
                                  dwColorTemp=255;       
                            if(   dwColorTemp<   0   )   
                                  dwColorTemp   =   0;   
                      //***************the   problem   is   here****************************//   
                            lpNewBmpData[i*nScanWidth+j]=(unsigned   char)dwColorTemp;     
            }         
        }   
                
              //设置8位位图调色板   
      RGBQUAD   *rgbQuad   =   new   RGBQUAD[256];   
      for(i=0;i<256;i++)   
      {   
      rgbQuad[i].rgbBlue   =   i;     
      rgbQuad[i].rgbGreen   =   i;     
      rgbQuad[i].rgbRed   =   i;     
      rgbQuad[i].rgbReserved   =   0;     
      }   
              //设置8位位图文件头   
      BITMAPFILEHEADER   Bmp_new_file_head;   
      Bmp_new_file_head.bfOffBits   =   sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD);   
              Bmp_new_file_head.bfReserved1   =   Bmp_file_head.bfReserved1;   
      Bmp_new_file_head.bfReserved2   =   Bmp_file_head.bfReserved2;   
      Bmp_new_file_head.bfType   =   Bmp_file_head.bfType;   
      Bmp_new_file_head.bfSize   =   Bmp_new_file_head.bfOffBits+intnDataLen;   
        
      //设置8位位图信息头   
      Bmp_info_head.biBitCount=8;   
        
      //关闭24位位图文件   
        if(   !CloseHandle(   hFile   )   )   
                  MessageBox("关闭文件时失败");   
        
        HANDLE   hSaveFile   =   CreateFile("E:\\bitmap_8.bmp",   GENERIC_WRITE,   FILE_SHARE_WRITE,   
                  NULL,   CREATE_ALWAYS,   FILE_ATTRIBUTE_NORMAL,   NULL);   
        
          if(   !hSaveFile   )   
        {   
                      MessageBox(   "创建文件出错");   
        }   
        
              //写位图文件头   
                WriteFile(   hSaveFile,   &Bmp_new_file_head,   sizeof(BITMAPFILEHEADER),   &dwWriteNum,   NULL);   
        
      //写位图信息头   
                WriteFile(   hSaveFile,   &Bmp_info_head,   sizeof(BITMAPINFOHEADER),   &dwWriteNum,   NULL);   
        
      //写位图调色板   
                WriteFile(   hSaveFile,   rgbQuad,   256*sizeof(RGBQUAD),   &dwWriteNum,   NULL);   
        
      //写位图像素数据   
                WriteFile(   hSaveFile,   lpNewBmpData,   intnDataLen,   &dwWriteNum,   NULL);   
        
        //关闭8位位图   
                CloseHandle(   hSaveFile   );