编程技巧15法之三

    技术2022-05-11  111

     

    1.         如何替换HBITMAP中的颜色值

    #define COLORREF2RGB(Color) (Color & 0xff00) | ((Color >> 16) & 0xff) /

                                                 | ((Color << 16) & 0xff0000)

     

    HBITMAP ReplaceColor (HBITMAP hBmp,COLORREF cOldColor,COLORREF cNewColor)

    {

        HBITMAP RetBmp=NULL;

        if (hBmp)

        {   

            HDC BufferDC=CreateCompatibleDC(NULL);       // 源位图DC

            if (BufferDC)

            {

                SelectObject(BufferDC,hBmp);         // 选入DC中

               

                HDC DirectDC=CreateCompatibleDC(NULL);      // 目标DC

                if (DirectDC)

                {

                    // 获取源位图大小

                    BITMAP bm;

                    GetObject(hBmp, sizeof(bm), &bm);

                   

                    // 初始化BITMAPINFO信息,以便使用CreateDIBSection

                    BITMAPINFO RGB32BitsBITMAPINFO;

                    ZeroMemory(&RGB32BitsBITMAPINFO,sizeof(BITMAPINFO));

                    RGB32BitsBITMAPINFO.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);

                    RGB32BitsBITMAPINFO.bmiHeader.biWidth=bm.bmWidth;

                    RGB32BitsBITMAPINFO.bmiHeader.biHeight=bm.bmHeight;

                    RGB32BitsBITMAPINFO.bmiHeader.biPlanes=1;

                    RGB32BitsBITMAPINFO.bmiHeader.biBitCount=32;

                    UINT * ptPixels;   

     

                    HBITMAP DirectBitmap= CreateDIBSection(DirectDC,

                                                  (BITMAPINFO *)&RGB32BitsBITMAPINFO,

                                                  DIB_RGB_COLORS,(void **)&ptPixels, NULL, 0);

                    if (DirectBitmap)

                    {

                        HGDIOBJ PreviousObject=SelectObject(DirectDC, DirectBitmap);

                        BitBlt(DirectDC,0,0,bm.bmWidth,bm.bmHeight,BufferDC,0,0,SRCCOPY);

     

                        // 转换 COLORREF 为 RGB

                        cOldColor=COLORREF2RGB(cOldColor);

                        cNewColor=COLORREF2RGB(cNewColor);

     

                        // 替换颜色

                        for (int i=((bm.bmWidth*bm.bmHeight)-1);i>=0;i--)

                        {

                            if (ptPixels[i]==cOldColor) ptPixels[i]=cNewColor;

                        }

                       

                        // 修改位图 DirectBitmap

                        SelectObject(DirectDC,PreviousObject);

                       

                        // 完成

                        RetBmp=DirectBitmap;

                    }

                    // 释放DC

                    DeleteDC(DirectDC);

                }

                // 释放DC

                DeleteDC(BufferDC);

            }

        }

        return RetBmp;

    }

     

    用法:

    HBITMAP hBmp2 = LoadBitmap(g_hinstance,MAKEINTRESOURCE(IDB_SAMPLEBITMAP));

    HBITMAP hBmp = ReplaceColor(hBmp2,0xff0000,0x00ff00); // 替换蓝色为绿色

     

    ......

     

    DeleteObject(hBmp2);

    DeleteObject(hBmp);

     

    2.         如何转换并保存位图

    //********************************************************************************

    //* 名称:DDBToDIB

    //* 作者:徐景周(jingzhou_xu@163.net)

    //* 功能:设备相关转换为设备无关位图

    //********************************************************************************

    HANDLE CScreenSnapDlg::DDBToDIB( CBitmap& bitmap, DWORD dwCompression /* = BI_RGB */)

    {

        BITMAP                      bm;

        BITMAPINFOHEADER    bi;

        LPBITMAPINFOHEADER  lpbi;

        DWORD                      dwLen;

        HANDLE                      hDIB;

        HANDLE                      handle;

        HDC                                   hDC;

        HPALETTE                     hPal;

     

        CWindowDC                dc( this );

        CPalette                 pal;

        //如果支持调色板的话,则建立它

        if( dc.GetDeviceCaps( RASTERCAPS ) & RC_PALETTE )

        {

            UINT        nSize   = sizeof(LOGPALETTE) + ( sizeof(PALETTEENTRY) * 256 );

            LOGPALETTE* pLP     = (LOGPALETTE*)new BYTE[nSize];

            pLP->palVersion     = 0x300;

            pLP->palNumEntries = (unsigned short)GetSystemPaletteEntries( dc, 0, 255,

            pLP->palPalEntry );

     

            pal.CreatePalette( pLP );

     

            //释放

            delete[] pLP;

        }

     

        ASSERT( bitmap.GetSafeHandle() );

     

        //不支持BI_BITFIELDS类型

        if( dwCompression == BI_BITFIELDS )

            return NULL;

     

        //如果调色板为空,则用默认调色板

        hPal = (HPALETTE) pal.GetSafeHandle();

        if (hPal==NULL)

            hPal = (HPALETTE) GetStockObject(DEFAULT_PALETTE);

     

        //获取位图信息

        bitmap.GetObject(sizeof(bm),(LPSTR)&bm);

     

        //初始化位图信息头

        bi.biSize        = sizeof(BITMAPINFOHEADER);

        bi.biWidth        = bm.bmWidth;

        bi.biHeight         = bm.bmHeight;

        bi.biPlanes         = 1;

        bi.biBitCount        = (unsigned short)(bm.bmPlanes * bm.bmBitsPixel) ;

        bi.biCompression    = dwCompression;

        bi.biSizeImage        = 0;

        bi.biXPelsPerMeter    = 0;

        bi.biYPelsPerMeter    = 0;

        bi.biClrUsed        = 0;

        bi.biClrImportant    = 0;

     

        //计算信息头及颜色表大小

        int nColors = 0;

        if(bi.biBitCount <= 8)

            {

            nColors = (1 << bi.biBitCount);

            }

        dwLen  = bi.biSize + nColors * sizeof(RGBQUAD);

     

        hDC = ::GetDC(NULL);

        hPal = SelectPalette(hDC,hPal,FALSE);

        RealizePalette(hDC);

     

        //为信息头及颜色表分配内存

        hDIB = GlobalAlloc(GMEM_FIXED,dwLen);

     

        if (!hDIB){

            SelectPalette(hDC,hPal,FALSE);

            ::ReleaseDC(NULL,hDC);

            return NULL;

        }

     

        lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);

     

        *lpbi = bi;

     

        //调用 GetDIBits 计算图像大小

        GetDIBits(hDC, (HBITMAP)bitmap.GetSafeHandle(), 0L, (DWORD)bi.biHeight,

                (LPBYTE)NULL, (LPBITMAPINFO)lpbi, (DWORD)DIB_RGB_COLORS);

     

        bi = *lpbi;

     

        //图像的每一行都对齐(32bit)边界

        if (bi.biSizeImage == 0){

            bi.biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8)

                            * bi.biHeight;

     

            if (dwCompression != BI_RGB)

                bi.biSizeImage = (bi.biSizeImage * 3) / 2;

        }

     

        //重新分配内存大小,以便放下所有数据

        dwLen += bi.biSizeImage;

        handle = GlobalReAlloc(hDIB, dwLen, GMEM_MOVEABLE) ;

        if (handle != NULL)

            hDIB = handle;

        else

            {

            GlobalFree(hDIB);

     

            //重选原始调色板

            SelectPalette(hDC,hPal,FALSE);

            ::ReleaseDC(NULL,hDC);

            return NULL;

            }

     

        //获取位图数据

        lpbi = (LPBITMAPINFOHEADER)hDIB;

     

        //最终获得的DIB

        BOOL bGotBits = GetDIBits( hDC, (HBITMAP)bitmap.GetSafeHandle(),

                    0L,                      //扫描行起始处

                    (DWORD)bi.biHeight,      //扫描行数

                    (LPBYTE)lpbi             //位图数据地址

                    + (bi.biSize + nColors * sizeof(RGBQUAD)),

                    (LPBITMAPINFO)lpbi,      //位图信息地址

                    (DWORD)DIB_RGB_COLORS);  //颜色板使用RGB

     

        if( !bGotBits )

        {

            GlobalFree(hDIB);

           

            SelectPalette(hDC,hPal,FALSE);

            ::ReleaseDC(NULL,hDC);

            return NULL;

        }

     

        SelectPalette(hDC,hPal,FALSE);

        ::ReleaseDC(NULL,hDC);

        return hDIB;

    }

     

    //********************************************************************************

    //* 名称:SaveBitmapToFile

    //* 修改:徐景周(jingzhou_xu@163.net)

    //* 功能:保存为位图文件

    //********************************************************************************

    BOOL CScreenSnapDlg::SaveBitmapToFile(HBITMAP hBitmap , CString lpFileName)

    {          

           HDC                            hDC;                                                 //设备描述表 

        int                         iBits;                                                 //当前显示分辨率下每个像素所占字节数

           WORD            wBitCount;                                        //位图中每个像素所占字节数

           DWORD           dwPaletteSize=0,                            //定义调色板大小, 位图中像素字节大小 ,位图文件大小 , 写入文件字节数

                                       dwBmBitsSize,

                                       dwDIBSize, dwWritten;

           BITMAP          Bitmap;        

           BITMAPFILEHEADER   bmfHdr;                                     //位图属性结构   

        BITMAPINFOHEADER   bi;                                           //位图文件头结构      

           LPBITMAPINFOHEADER lpbi;                                    //位图信息头结构    

        HANDLE          fh, hDib, hPal,hOldPal=NULL;       //指向位图信息头结构,定义文件,分配内存句柄,调色板句柄

     

       //计算位图文件每个像素所占字节数

       hDC = CreateDC("DISPLAY",NULL,NULL,NULL);

       iBits = GetDeviceCaps(hDC, BITSPIXEL) *

       GetDeviceCaps(hDC, PLANES);

       DeleteDC(hDC);

       if (iBits <= 1)

          wBitCount = 1;

       else if (iBits <= 4)

          wBitCount = 4;

       else if (iBits <= 8)

          wBitCount = 8;

       else if (iBits <= 24)

          wBitCount = 24;

       //计算调色板大小

       if (wBitCount <= 8)

          dwPaletteSize = (1 << wBitCount) *sizeof(RGBQUAD);

      

       //设置位图信息头结构

       GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap);

       bi.biSize            = sizeof(BITMAPINFOHEADER);

       bi.biWidth           = Bitmap.bmWidth;

       bi.biHeight          = Bitmap.bmHeight;

       bi.biPlanes          = 1;

       bi.biBitCount         = wBitCount;

       bi.biCompression      = BI_RGB;

       bi.biSizeImage        = 0;

       bi.biXPelsPerMeter     = 0;

       bi.biYPelsPerMeter     = 0;

       bi.biClrUsed         = 0;

       bi.biClrImportant      = 0;

     

       dwBmBitsSize = ((Bitmap.bmWidth *

        wBitCount+31)/32)* 4

            *Bitmap.bmHeight ;

     

       //为位图内容分配内存

       hDib  = GlobalAlloc(GHND,dwBmBitsSize+

           dwPaletteSize+sizeof(BITMAPINFOHEADER));

       lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);

       *lpbi = bi;

     

       // 处理调色板  

       hPal = GetStockObject(DEFAULT_PALETTE);

       if (hPal)

       {

              hDC  = ::GetDC(NULL);

              hOldPal = SelectPalette(hDC, (HPALETTE)hPal, FALSE);

           RealizePalette(hDC);

       }

     

       // 获取该调色板下新的像素值

       GetDIBits(hDC, hBitmap, 0, (UINT) Bitmap.bmHeight,

            (LPSTR)lpbi + sizeof(BITMAPINFOHEADER)+dwPaletteSize,

            (LPBITMAPINFO)lpbi, DIB_RGB_COLORS);

     

       //恢复调色板  

       if (hOldPal)

       {

          SelectPalette(hDC, (HPALETTE)hOldPal, TRUE);

          RealizePalette(hDC);

          ::ReleaseDC(NULL, hDC);

       }

     

       //创建位图文件   

           fh = CreateFile(lpFileName, GENERIC_WRITE,

                   0, NULL, CREATE_ALWAYS,

             FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);

     

       if (fh == INVALID_HANDLE_VALUE)

          return FALSE;

     

       // 设置位图文件头

       bmfHdr.bfType = 0x4D42;  // "BM"

       dwDIBSize    = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize; 

       bmfHdr.bfSize = dwDIBSize;

       bmfHdr.bfReserved1 = 0;

       bmfHdr.bfReserved2 = 0;

       bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER)

          + (DWORD)sizeof(BITMAPINFOHEADER)

         + dwPaletteSize;

     

       // 写入位图文件头

       WriteFile(fh, (LPSTR)&bmfHdr, sizeof

           (BITMAPFILEHEADER), &dwWritten, NULL);

       // 写入位图文件其余内容

       WriteFile(fh, (LPSTR)lpbi, dwDIBSize,

       &dwWritten, NULL);

     

       //消除内存分配 

       GlobalUnlock(hDib);

       GlobalFree(hDib);

       CloseHandle(fh);

     

       return TRUE;

    }

     

     

     

    联系方式:

    EMAIL:jingzhou_xu@163.com

    未来工作室(Future Studio)

     


    最新回复(0)