请教BMP位图色深的转换算法。如将24bit转换为16bit,8bit,以及如何反转

解决方案 »

  1.   

    24bit的BMP每个像素点三个字节,按BGR顺序,16bit的BMP有565和555两种,就是每个像素占两个字节,从高位到低位按RGB顺序各点5,6,5位或5,5,5位。到于8bit还要有个调色板的。
      

  2.   

    here is some code,FYI
        /*
        //功能如下:
        1. 8位位图仍然保存为8位位图
        2. 16位位图将被保存为24位位图.16位位图只用于16位增强显示模式, 不在不同的系统间进行传递.
        3. 24位位图仍然被保存为24位位图.
        4. 32位Ddb位图将被保存为24位位图.
        5. 对于16色即4位位图, 不作处理.
        */
    //将Ddb位图保存成Dib位图:被保存的区域由, x, y, nWidth, nHeight来定义int    CDisplayModeView::SaveBmp(char *lpFilePath,int nWidth,int nHeight,int nType)
    {
        CDisplayModeDoc* pDoc = GetDocument();
        CDisplayModeApp *app=(CDisplayModeApp *)AfxGetApp();
        ASSERT_VALID(pDoc);
        if(m_nCountMathod<0)
            return 0;
        int i,j,nScanLine;
            m_pBMI=new BITMAPINFO;
        
        FILE *file = NULL;
        
        file = fopen(lpFilePath, "wb");
        
        if(file==NULL)
        {
            fclose(file);
            delete []m_pBMI;
            
            return -1;
        }
        if(m_bTmpSrcImg==NULL)
        {
            fclose(file);
            delete []m_pBMI;
            return -1;
        }
        switch(nType)
        {
        case 1://color
            {
                nScanLine=nWidth*4;
                if(nScanLine & 3)
                    nScanLine=(nScanLine &~3) +4 ;            DWORD dwSaveWidthBytes ;//= CalcDibWidthBytes(w, m_nBitCount); 
        
                //每行字节数必须被4整除
                if(pDoc->m_DIB.GetBitCount() ==8)
    //                dwSaveWidthBytes=((nWidth * 8 + 31) / 32) * 4;
                    dwSaveWidthBytes=((nWidth * 24 + 31) / 32) * 4;
                else
                    dwSaveWidthBytes=((nWidth * 24 + 31) / 32) * 4;
                //DIB位图数据大小, 以字节为单位
                DWORD dwDibBitsSize = dwSaveWidthBytes * nHeight; 
                //计算整个Dib文件的大小dwFileSize
                DWORD dwFileSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwDibBitsSize; 
                if(pDoc->m_DIB.GetBitCount() == 8) dwFileSize += (256 * sizeof(RGBQUAD));             //计算位图信息到位图数据间的偏移量(字节)
                DWORD dwOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); 
                //if(m_nBitCount == 8) 
    //            if(pDoc->m_DIB.GetBitCount() ==8)
    //                dwOffBits += (256 * sizeof(RGBQUAD)); 
                m_pBMI->bmiHeader.biBitCount=24;//位图的每个象素的为数,1位对应的颜色总数为2,4--16,8--256,24--16777216
                m_pBMI->bmiHeader.biClrImportant=0;//指定对于显示该位图比较重要的颜色索引个数,若值为0,则所有的颜色都是重要的。
                m_pBMI->bmiHeader.biClrImportant=0;//位图实际使用的颜色数
                m_pBMI->bmiHeader.biCompression=0;//压宿方式
                m_pBMI->bmiHeader.biClrUsed =0;
                m_pBMI->bmiHeader.biHeight=nHeight;
                m_pBMI->bmiHeader.biWidth=nWidth;
                m_pBMI->bmiHeader.biPlanes=1;//表示目标设备的位平面数
                m_pBMI->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
                m_pBMI->bmiHeader.biXPelsPerMeter=0;//表示目标设备的水平分辨率
                m_pBMI->bmiHeader.biYPelsPerMeter=0;//表示目标设备的垂直分辨率
                m_pBMI->bmiHeader.biSizeImage =0;//nWidth*nHeight*4;            BITMAPFILEHEADER bmh;//位图文件头结构
                LPBITMAPINFOHEADER    lpBl;//指向位图信息结构的指针
                RGBQUAD rgb[256];
                DWORD dwDibSize;
                lpBl=(LPBITMAPINFOHEADER)m_pBMI;
                                        
                if(lpBl==NULL)
                {
                    delete[] m_pBMI;
                    fclose(file);
                    return -2;            }
                dwDibSize=*(LPDWORD)lpBl+256*sizeof(RGBQUAD)+sizeof(BITMAPFILEHEADER);            DWORD dwBmBitsSize;//BMP文件信息结构所占的字节数
                dwBmBitsSize=nScanLine*nHeight;// lpBl->biWidth*lpBl->biHeight*4;//存储时位图所有象素所占的字节数
                                        
                dwDibSize+=dwBmBitsSize;
                lpBl->biSizeImage=dwBmBitsSize;//位图所有象素所占的字节总数            //填充BITMAPFILEHEADER结构
                bmh.bfType=0x4d42;
                bmh.bfSize=dwFileSize;//+sizeof(BITMAPFILEHEADER);//文件总长度            bmh.bfReserved1=0;
                bmh.bfReserved2=0;
                bmh.bfOffBits=dwOffBits;//(DWORD)sizeof(BITMAPFILEHEADER)+lpBl->biSize +256*sizeof(RGBQUAD);//            //填充BITMAPINFOHEADER结构:8位仍然保存为8位, 其它均被保存为24位.最低显示模式为8位.
            
                            long dbWidth;
                dbWidth=((nWidth * 32 + 15) / 16) * 2;
                //palette
                for(i=0;i<256;i++)
                {
                    rgb[i].rgbBlue=i;
                    rgb[i].rgbGreen=i;
                    rgb[i].rgbRed=i;
                    rgb[i].rgbReserved =0;
                }
                //对于16位和32位位图, 由于数据需要重组, 所以需要重新分配内存                //指向Dib实际像素数据的指针, 
                BYTE* pbyDibBits = new BYTE[dwDibBitsSize]; 
                if (pbyDibBits == NULL)    return -1; 
                //数据索引基数
                DWORD dwBaseIndex =0;// y * m_nDdbWidthBytes + ((m_nBitCount == 16) ? (x + x) : (4 * x)); 
                DWORD dwIndexDib = (nHeight - 1) * dwSaveWidthBytes;             for(i=0;i<nHeight;i++)
                {
                    //指向Ddb内存数据的指针(行)
                    BYTE* pbyDdbData = m_bTmpSrcImg + dwBaseIndex;                 //指向Dib内存数据的指针(行)
                    BYTE* pbyDibData = pbyDibBits + dwIndexDib;                 for(j=0;j<nWidth;j++)
                    {
                        *pbyDibData++ = *pbyDdbData++;     //蓝色
                        *pbyDibData++ = *pbyDdbData++;     //绿色
                        *pbyDibData++ = *pbyDdbData++;     //红色
                        pbyDdbData++; 
                    }
                    dwBaseIndex += dbWidth; 
                    dwIndexDib -= dwSaveWidthBytes; 
                }
                fwrite((LPSTR)&bmh, sizeof(BITMAPFILEHEADER), 1, file);//文件头
                fwrite(lpBl,sizeof(BITMAPINFOHEADER), 1, file);//信息头
                //fwrite(rgb,sizeof(RGBQUAD)*256,1,file);//RGB
                fwrite(pbyDibBits,(long)dwDibBitsSize, 1, file);//数据
                fclose(file);
                delete[] pbyDibBits;
                delete[] m_pBMI;
                break;
            }
      

  3.   

    case 2://gray
            {
                int j,nScanLine;
                nScanLine=nWidth*4;
                if(nScanLine & 3)
                    nScanLine=(nScanLine &~3) +4 ;
                //被保存位图每行的字节数
                DWORD dwSaveWidthBytes ;//= CalcDibWidthBytes(w, m_nBitCount); 
                
                //每行字节数必须被4整除
                //if(pDoc->m_DIB.GetBitCount() ==8)
                //    dwSaveWidthBytes=((nWidth * 8 + 31) / 32) * 4;
                //else
                //    dwSaveWidthBytes=((nWidth * 24 + 31) / 32) * 4;
                dwSaveWidthBytes=((nWidth * 8 + 31) / 32) * 4;
                //DIB位图数据大小, 以字节为单位
                DWORD dwDibBitsSize = dwSaveWidthBytes * nHeight; 
                //计算整个Dib文件的大小dwFileSize
                DWORD dwFileSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwDibBitsSize; 
                //if(pDoc->m_DIB.GetBitCount() == 8) 
                dwFileSize += (256 * sizeof(RGBQUAD));             //计算位图信息到位图数据间的偏移量(字节)
                DWORD dwOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); 
                //if(m_nBitCount == 8) 
                //if(pDoc->m_DIB.GetBitCount() ==8)
                    dwOffBits += (256 * sizeof(RGBQUAD)); 
                m_pBMI->bmiHeader.biBitCount=8;//位图的每个象素的为数,1位对应的颜色总数为2,4--16,8--256,24--16777216
                m_pBMI->bmiHeader.biClrImportant=0;//指定对于显示该位图比较重要的颜色索引个数,若值为0,则所有的颜色都是重要的。
                m_pBMI->bmiHeader.biClrImportant=0;//位图实际使用的颜色数
                m_pBMI->bmiHeader.biCompression=BI_RGB;//压宿方式
                m_pBMI->bmiHeader.biClrUsed =0;
                m_pBMI->bmiHeader.biHeight=nHeight;
                m_pBMI->bmiHeader.biWidth=nWidth;
                m_pBMI->bmiHeader.biPlanes=1;//表示目标设备的位平面数
                m_pBMI->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
                m_pBMI->bmiHeader.biXPelsPerMeter=0;//表示目标设备的水平分辨率
                m_pBMI->bmiHeader.biYPelsPerMeter=0;//表示目标设备的垂直分辨率
                m_pBMI->bmiHeader.biSizeImage =0;//nWidth*nHeight;            BITMAPFILEHEADER bmh;//位图文件头结构
                LPBITMAPINFOHEADER    lpBl;//指向位图信息结构的指针
                RGBQUAD rgb[256];
                DWORD dwDibSize;
                lpBl=(LPBITMAPINFOHEADER)m_pBMI;
                                        
                if(lpBl==NULL)
                {
                    delete[] m_pBMI;
                    fclose(file);
                    return -2;            }
                dwDibSize=*(LPDWORD)lpBl+256*sizeof(RGBQUAD)+sizeof(BITMAPFILEHEADER);            DWORD dwBmBitsSize;//BMP文件信息结构所占的字节数
                dwBmBitsSize=dwSaveWidthBytes*nHeight;// lpBl->biWidth*lpBl->biHeight*4;//存储时位图所有象素所占
                                        
                dwDibSize+=dwBmBitsSize;
                lpBl->biSizeImage=dwBmBitsSize;//位图所有象素所占的字节总数            bmh.bfType=0x4d42;
                bmh.bfSize=dwFileSize;//dwDibSize;//+sizeof(BITMAPFILEHEADER);//文件总长度            bmh.bfReserved1=0;
                bmh.bfReserved2=0;
                bmh.bfOffBits=dwOffBits;//sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); ;//(DWORD)sizeof(BITMAPFILEHEADER)+lpBl->biSize +256*sizeof(RGBQUAD);//
                //palette
                for(int i=0;i<256;i++)
                {
                    rgb[i].rgbBlue=i;
                    rgb[i].rgbGreen=i;
                    rgb[i].rgbRed=i;
                    rgb[i].rgbReserved =0;
                }
                
                
                LPBYTE lpNew;//,lp1;//,lp2,
                lpNew=(LPBYTE)malloc((long)nWidth*nHeight);
                for (i=0;i<nHeight;i++)
                    for (j=0;j<nWidth;j++)
                    {
                        *(lpNew+(long)i*nWidth+j)=*(m_bTmpSrcImg+(long)i*nScanLine+j*4);
                    }            fwrite((LPSTR)&bmh, sizeof(BITMAPFILEHEADER), 1, file);//文件头
                fwrite(lpBl,sizeof(BITMAPINFOHEADER), 1, file);//信息头
                fwrite(rgb,sizeof(RGBQUAD)*256,1,file);//RGB
                fwrite(lpNew,(long)nHeight*nWidth, 1, file);//数据
                fclose(file);
                delete[] m_pBMI;
                free(lpNew);
                break;            
            }
        }    
        return 1;
    }