zoukankan      html  css  js  c++  java
  • BMP位图结构与操作(转)

    CSDN里面,大家经常问起有关BMP位图的相关操作问题,我在此贴一篇我收集的文章,向大家透彻讲解一下BMP位图的结构以及在VC下的具体操作,希望对初学者有所帮助!  :)

    ---- 用普通方法显示BMP位图,占内存大,速度慢,在图形缩小时,失真严重,在低颜色位数的设备上显示高颜色位数的图形图形时失真大。本文采用视频函数显示BMP位图,可以消除以上的缺点。 

    ---- 一、BMP文件结构 

    ---- 1. BMP文件组成 

    ---- BMP文件由文件头、位图信息头、颜色信息和图形数据四部分组成。 

    ---- 2. BMP文件头 

    ---- BMP文件头数据结构含有BMP文件的类型、文件大小和位图起始位置等信息。 

    ---- 其结构定义如下: 

    typedef struct tagBITMAPFILEHEADER

    {

    WORDbfType;   // 位图文件的类型,必须为BM

    DWORD   bfSize;   // 位图文件的大小,以字节为单位

    WORDbfReserved1;  // 位图文件保留字,必须为0

    WORDbfReserved2;  // 位图文件保留字,必须为0

    DWORD   bfOffBits; // 位图数据的起始位置,以相对于位图

    // 文件头的偏移量表示,以字节为单位

    } BITMAPFILEHEADER;

    ---- 3. 位图信息头 

    BMP位图信息头数据用于说明位图的尺寸等信息。

    typedef struct tagBITMAPINFOHEADER{

       DWORD  biSize;   // 本结构所占用字节数

       LONGbiWidth;  // 位图的宽度,以像素为单位

       LONGbiHeight; // 位图的高度,以像素为单位

       WORD   biPlanes; // 目标设备的级别,必须为1

       WORD   biBitCount// 每个像素所需的位数,必须是1(双色),

      // 4(16色),8(256色)或24(真彩色)之一

       DWORD  biCompression;   // 位图压缩类型,必须是 0(不压缩),

      // 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一

       DWORD  biSizeImage; // 位图的大小,以字节为单位

       LONGbiXPelsPerMeter; // 位图水平分辨率,每米像素数

       LONGbiYPelsPerMeter;  // 位图垂直分辨率,每米像素数

       DWORD  biClrUsed;// 位图实际使用的颜色表中的颜色数

       DWORD  biClrImportant;// 位图显示过程中重要的颜色数

    } BITMAPINFOHEADER;

    ---- 4. 颜色表 

    ---- 颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。RGBQUAD结构的定义如下: 

    typedef struct tagRGBQUAD {

    BYTErgbBlue;// 蓝色的亮度(值范围为0-255)

    BYTErgbGreen;   // 绿色的亮度(值范围为0-255)

    BYTErgbRed; // 红色的亮度(值范围为0-255)

    BYTErgbReserved;// 保留,必须为0

    } RGBQUAD;

    颜色表中RGBQUAD结构数据的个数有biBitCount来确定:

    当biBitCount=1,4,8时,分别有2,16,256个表项;

    当biBitCount=24时,没有颜色表项。

       位图信息头和颜色表组成位图信息,BITMAPINFO结构定义如下:

    typedef struct tagBITMAPINFO {

       BITMAPINFOHEADER bmiHeader;   // 位图信息头

       RGBQUAD  bmiColors[1];  // 颜色表

    } BITMAPINFO;

    ---- 5. 位图数据 

    ---- 位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数: 

    当biBitCount=1时,8个像素占1个字节;

    当biBitCount=4时,2个像素占1个字节;

    当biBitCount=8时,1个像素占1个字节;

    当biBitCount=24时,1个像素占3个字节;

    Windows规定一个扫描行所占的字节数必须是 4的倍数(即以long为单位),不足的以0填充, 

    一个扫描行所占的字节数计算方法: DataSizePerLine= (biWidth* biBitCount+31)/8; 

    // 一个扫描行所占的字节数 DataSizePerLine= DataSizePerLine/4*4; // 字节数必须是4的倍数 

    位图数据的大小(不压缩情况下): DataSize= DataSizePerLine* biHeight; 

    ---- 二、BMP位图一般显示方法 

    ---- 1. 申请内存空间用于存放位图文件 

    ---- GlobalAlloc(GHND,FileLength); 

    ---- 2. 位图文件读入所申请内存空间中 

    ---- LoadFileToMemory( mpBitsSrc,mFileName); 

    ---- 3. 在OnPaint等函数中用创建显示用位图 

    ---- 用CreateDIBitmap()创建显示用位图,用CreateCompatibleDC()创建兼容DC, 

    ---- 用SelectBitmap()选择显示位图。 

    ---- 4. 用BitBlt或StretchBlt等函数显示位图 

    ---- 5. 用DeleteObject()删除所创建的位图 

    ---- 以上方法的缺点是: 1)显示速度慢; 2) 内存占用大; 3) 位图在缩小显示时图形失真大,(可通过安装字体平滑软件来解决); 4) 在低颜色位数的设备上(如256显示模式)显示高颜色位数的图形(如真彩色)图形失真严重。 

    ---- 三、BMP位图缩放显示 

    ---- 用DrawDib视频函数来显示位图,内存占用少,速度快,而且还可以对图形进行淡化(Dithering )处理。淡化处理是一种图形算法,可以用来在一个支持比图像所用颜色要少的设备上显示彩色图像。BMP位图显示方法如下: 

    ---- 1. 打开视频函数DrawDibOpen(),一般放在在构造函数中 

    ---- 2. 申请内存空间用于存放位图文件 

    ---- GlobalAlloc(GHND,FileLength); 

    ---- 3. 位图文件读入所申请内存空间中 

    ---- LoadFileToMemory( mpBitsSrc,mFileName); 

    ---- 4. 在OnPaint等函数中用DrawDibRealize(),DrawDibDraw()显示位图 

    ---- 5. 关闭视频函数DrawDibClose(),一般放在在析构函数中 

    ---- 以上方法的优点是: 1)显示速度快; 2) 内存占用少; 3) 缩放显示时图形失真小,4) 在低颜色位数的设备上显示高颜色位数的图形图形时失真小; 5) 通过直接处理位图数据,可以制作简单动画。

    ---- 四、CViewBimap类编程要点 

    ---- 1. 在CViewBimap类中添加视频函数等成员 

    HDRAWDIB  m_hDrawDib;  // 视频函数

    HANDLEmhBitsSrc; // 位图文件句柄(内存)

    LPSTR mpBitsSrc;  // 位图文件地址(内存)

    BITMAPINFOHEADER  *mpBitmapInfo;   // 位图信息头

    ---- 2. 在CViewBimap类构造函数中添加打开视频函数 

    ---- m_hDrawDib= DrawDibOpen(); 

    ---- 3. 在CViewBimap类析构函数中添加关闭视频函数 

    if( m_hDrawDib != NULL)

      {

      DrawDibClose( m_hDrawDib);

      m_hDrawDib = NULL;

      }

    ---- 4. 在CViewBimap类图形显示函数OnPaint中添加GraphicDraw() 

    voidCViewBitmap::OnPaint()

    {

    CPaintDC dc(this); // device context for painting

    GraphicDraw( );

    }

     

    voidCViewBitmap::GraphicDraw( void )

    {

    CClientDC  dc(this); // device context for painting

    BITMAPFILEHEADER  *pBitmapFileHeader;

    ULONG  bfoffBits= 0;

    CPoint  Wid;

     

    // 图形文件名有效 (=0 BMP)

    if( mBitmapFileType <  ID_BITMAP_BMP ) return;

     

    // 图形文件名有效 (=0 BMP)

    // 准备显示真彩位图

    pBitmapFileHeader= (BITMAPFILEHEADER *) mpBitsSrc;

    bfoffBits= pBitmapFileHeader->bfOffBits;

     

    // 使用普通函数显示位图

     

    if( m_hDrawDib == NULL || mDispMethod == 0)

      {

      HBITMAP hBitmap=::CreateDIBitmap(dc.m_hDC,

    mpBitmapInfo, CBM_INIT, mpBitsSrc+bfoffBits,

      (LPBITMAPINFO) mpBitmapInfo,DIB_RGB_COLORS);  

    // 建立位图

    HDC hMemDC=::CreateCompatibleDC(dc.m_hDC);// 建立内存

    HBITMAP hBitmapOld= SelectBitmap(hMemDC, hBitmap);  // 选择对象

    // 成员CRect mDispR用于指示图形显示区域的大小.

    // 成员CPoint mPos用于指示图形显示起始位置坐标.

    if( mPos.x  > (mpBitmapInfo- >biWidth - mDispR.Width() ))

    mPos.x= mpBitmapInfo->biWidth - mDispR.Width() ;

      if( mPos.y  > (mpBitmapInfo- >biHeight- mDispR.Height()))

    mPos.y= mpBitmapInfo- >biHeight- mDispR.Height();

      if( mPos.x <  0 ) mPos.x= 0;

      if( mPos.y <  0 ) mPos.y= 0;

     

      if( mFullViewTog == 0)

    {

    // 显示真彩位图

    ::BitBlt(dc.m_hDC,0,0, mDispR.Width(), mDispR.Height(), 

    hMemDC,mPos.x,mPos.y, SRCCOPY);

    } else {

    ::StretchBlt(dc.m_hDC,0,0, mDispR.Width(), mDispR.Height(),

    hMemDC,0,0, mpBitmapInfo- >biWidth, mpBitmapInfo- 

    >biHeight, SRCCOPY);

    }

      // 结束显示真彩位图

      ::DeleteObject(SelectObject(hMemDC,hBitmapOld));  

    // 删 除 位 图

      } else {

     

      // 使用视频函数显示位图

     

      if( mPos.x  > (mpBitmapInfo- >biWidth - mDispR.Width() ))

    mPos.x= mpBitmapInfo- >biWidth - mDispR.Width() ;

      if( mPos.y  > (mpBitmapInfo- >biHeight- mDispR.Height()))

    mPos.y= mpBitmapInfo- >biHeight- mDispR.Height();

      if( mPos.x <  0 ) mPos.x= 0;

      if( mPos.y <  0 ) mPos.y= 0;

     

      // 显示真彩位图

      DrawDibRealize( m_hDrawDib, dc.GetSafeHdc(), TRUE);

     

      if( mFullViewTog == 0)

    {

    Wid.x= mDispR.Width();

    Wid.y= mDispR.Height();

    // 1:1 显示时, 不能大于图形大小

    if( Wid.x  > mpBitmapInfo- >biWidth ) 

    Wid.x = mpBitmapInfo- >biWidth;

    if( Wid.y  > mpBitmapInfo- >biHeight) 

    Wid.y = mpBitmapInfo- >biHeight;

     

    DrawDibDraw( m_hDrawDib, dc.GetSafeHdc()

    , 0, 0, Wid.x, Wid.y,

    mpBitmapInfo, (LPVOID) (mpBitsSrc+bfoffBits),

    mPos.x, mPos.y, Wid.x, Wid.y, DDF_BACKGROUNDPAL);

    } else {

    DrawDibDraw( m_hDrawDib, dc.GetSafeHdc(),

    0, 0, mDispR.Width(), mDispR.Height(),

    mpBitmapInfo, (LPVOID) (mpBitsSrc+bfoffBits),

    0, 0, mpBitmapInfo- >biWidth, mpBitmapInfo- >biHeight,

    DDF_BACKGROUNDPAL);

    }

      }

    return;

    }

    ---- 五、使用CViewBimap类显示BMP位图 

    ---- 1. 在Visual C++5.0中新建一个名称为mymap工程文件,类型为MFC AppWizard[exe]。在编译运行通过后,在WorkSpace(如被关闭,用Alt_0打开)点击ResourceView,点击Menu左侧的+符号展开Menu 条目,双击IDR_MAINFRAME条目,进入菜单资源编辑,在'“查看(V)”下拉式菜单(英文版为View下拉式菜单)的尾部添加“ViewBitmap”条目,其ID为ID_VIEW_BITMAP。 

    ---- 2. 在Visual C++5.0中点击下拉式菜单Project- >Add To project- >Files...,将Bitmap0.h 和Bitmap0.cpp添加到工程文件中。 

    ---- 3. 在Visual C++5.0中按Ctrl_W进入MFC ClassWizard,选择类名称为CMainFrame,ObjectIDs: ID_VIEW_BITMAP,Messages选择Command,然后点击Add Fucction按钮,然后输入函数名为OnViewBima p。在添加OnViewBimap后,在Member functions: 中点击OnViewBimap条目,点击Edit Code按钮编辑程序代码。代码如下: 

    void CMainFrame::OnViewBitmap()

    {

    // TODO: Add your command handler code here

    CViewBitmap  *pViewBitmap= NULL;

    pViewBitmap= new CViewBitmap( "BITMAP.BMP", this);

    pViewBitmap- >ShowWindow( TRUE);

    }

    ---- 并在该程序的头部添加#include "bitmap0.h",然后编译运行。 

    ---- 4. 找一个大一点的真彩色的BMP位图,将它拷贝到BITMAP.BMP中。 

    ---- 5. 运行时,点击下拉式菜单“查看(V)- >ViewBitmap”(英文版为View- > ViewBitmap)即可显示BITMAP.BMP位图。 

    ---- 六、CViewBimap类功能说明 

    ---- 1. 在客户区中带有水平和垂直滚动条。在位图大小大于显示客户区时,可以使用滚动条;在位图大小小于显示客户区或全屏显示时,滚动条无效。 

    ---- 2. 在客户区中底部带有状态条。状态条中的第一格为位图信息,第二格为位图显示方法,可以是使用普通函数或使用视频函数。在第二格区域内点击鼠标,可在两者之间接换。第三格为位图显示比例,可以是1;1显示或全屏显示。在第三格区域内点击鼠标,可在两者之间接换。在全屏显示时,如果位图比客户区小,则对位图放大; 如果位图比客户区大,则对位图缩小。 

    ---- 3. 支持文件拖放功能。可以从资源管理器中拖动一个位图文件到客户区,就可以显示该位图。 

    ---- 程序调试通过后,可以找一个较大的真彩色位图或调整客户区比位图小,在全屏显示方式下,比较使用普通函数与使用视频函数的差别。可以看出,位图放大时两者差别不大,但在位图缩小时,两者差别明显; 使用视频函数时位图失真小,显示速度快。 

    ---- 还可以从控制面板中将屏幕显示方式从真彩色显示模式切换到256色显示模式,再比较使用普通函数与使用视频函数显示同一个真彩色位图的差别。现在可以体会到使用视频函数的优越性了吧。 

    ---- 在全屏显示时,位图的xy方向比例不相同,如要保持相同比例,可在显示程序中加以适当调整即可位图的淡入淡出显示


    我们经常在AboutBox中显示一幅关于公司或自己讯息的位图,有没有想过让这幅位图有更酷的效果?比如加上淡入淡出效果?只要有了这个CAlphaCtrl控件就可以轻松实现。
    CAlphaCtrl是从CStatic继承而来。使用时只要把CalphaCtrl加入窗体,然后调用LoadAlphaBitmap(UINT uID, int iTimer)函数就可以实现位图的淡入淡出。其中uID是位图的资源ID,iTimer是位图显示时间间隔,值愈小显示愈快。
    下面就来说一说CalphaCtrl是如何实现的。关键的一个实现函数是一个win32 API: AlphaBlend,此函数可以实现图像的透明显示,相关的参数和资料请自行参阅MSDN,值得注意的是使用此函数时要链接到msimg32.lib库。 

    第一步,我们先在CalphaCtrl类中增加几个Data Member:CBitmap Bmp; 

    BOOL bCanPaint; UINT nBmpID; int nTimer;
    第二步,在CalphaCtrl类中增加一个Member Function: 

    void AlphaDisplay(CDC &pDC, CClientDC &dc, BLENDFUNCTION& rBlendProps, int width, int heigh, byte nLevel)
    {
            //nLevel是透明度,0表示不显示,255则完全显示
            rBlendProps.SourceConstantAlpha = nLevel;
           AlphaBlend( dc.m_hDC, 0, 0, width, heigh, pDC.m_hDC, 0, 0, 
            width, heigh, rBlendProps );
    }
    第三步,增加一个名为tdDisplay的全局函数,此函数为一个线程函数,用于位图的显示。 

    UINT tdDisplay(LPVOID lpParam)
    {
            CAlphaCtrl* AlphaCtrl = (CAlphaCtrl*)lpParam;        CClientDC dc(AlphaCtrl);
            CDC pDC;
            pDC.CreateCompatibleDC(&dc); 
            pDC.SelectObject(&AlphaCtrl->Bmp);        BLENDFUNCTION rBlendProps;
            rBlendProps.BlendOp = AC_SRC_OVER;
            rBlendProps.BlendFlags = 0;
            rBlendProps.AlphaFormat = 0;     BITMAP bmInfo;
            ::GetObject( AlphaCtrl->Bmp.m_hObject, sizeof(BITMAP), &bmInfo );
            INT nWidth, nHeigh;
            nWidth = bmInfo.bmWidth;
            nHeigh = bmInfo.bmHeight;AlphaCtrl->SetWindowPos(NULL, 0, 0, nWidth, nHeigh, SWP_NOMOVE);
          int i = 0;
            while(i <= 255)
            {
            AlphaCtrl->AlphaDisplay(pDC, dc, rBlendProps, nWidth, nHeigh, i);
            i += 5;
            Sleep(AlphaCtrl->nTimer);
            }
          AlphaCtrl->bCanPaint = 1; //Make OnPaint Word
           AfxEndThread(0);
            return 0;
    }
    第四步,现在万事俱备,加上初始化函数:

                   BOOL LoadAlphaBitmap(UINT uID, int iTimer)
            {
            int i = Bmp.LoadBitmap(uID);
            
            if(i)
            {
            AfxBeginThread(tdDisplay, this);
            nBmpID = uID;
            nTimer = iTimer;
            return 1;
            }
            else
            {
            TRACE("Load Bitmap Failed\n");
            return 0;
            }
            
            return 1;
            }
    包含透明色的位图的绘制方法有多种,最简单的方法是调用现成的函数:TransparentBlt,也可以通过自己的代码实现类似TransparentBlt的功能,实现过程也有两种形式,一种是事先做一张掩码位图,另一种是动态生成掩码位图。本文将介绍动态生成掩码位图绘制具有透明区域位图的方法。

    一、TransparentBlt 函数的使用 

    TransparentBlt 函数在Windows98/Windows2000以上版本运行,系统中需要包含 Msimg32.dll,使用时可以链接 Msimg32.lib。
    Windows98下的TransparentBlt会产生资源泄漏,所以不建议在WIN98下使用该函数。
    TransparentBlt函数原型如下: 

    BOOL TransparentBlt(

    HDC hdcDest,      // 目标DC

    int nXOriginDest,   // 目标X偏移

    int nYOriginDest,   // 目标Y偏移

    int nWidthDest,     // 目标宽度

    int hHeightDest,    // 目标高度

    HDC hdcSrc,         // 源DC

    int nXOriginSrc,    // 源X起点

    int nYOriginSrc,    // 源Y起点

    int nWidthSrc,      // 源宽度

    int nHeightSrc,     // 源高度

    UINT crTransparent  // 透明色,COLORREF类型

    );

    使用示例: 

    CBitmap FootballBMP;

    FootballBMP.LoadBitmap(IDB_FOOTBALLBMP);

    CDC ImageDC;

    ImageDC.CreateCompatibleDC(pDC);

    CBitmap *pOldImageBMP = ImageDC.SelectObject(&FootballBMP);

    TransparentBlt(pDC->m_hDC, 0, 0, 218, 199, ImageDC.m_hDC, 0, 0, 218, 199, RGB(0,0,0xff));

    ImageDC.SelectObject(pOldImageBMP);

    二、实现TransparentBlt函数

    为了理解具有透明色位图的绘制过程,我们来亲手建立一个具有同TransparentBlt功能一致的实验函数,称之为TransparentBlt2。

    实验素材:有两张位图:bk.bmp是背景位图,football.bmp包含透明区域,透明色为蓝色RGB(0,0,0xff)
    实验目的:以bk.bmp为背景,将football.bmp绘制到背景中。


    2.1 透明位图绘制原理
    假设football.bmp ->载入 HBITMAP hImageBMP -> 选入 HDC hImageDC

    2.1.1 生成单色掩码位图,透明区域为白色(全1),非透明区域为黑色(全0) 

    HBITMAP hMaskBMP = CreateBitmap(nWidthDest, nHeightDest, 1, 1, NULL); // 建立单色位图

    SetBkColor(hImageDC, RGB(0,0,0xff)); // 设置背景色为蓝色

    BitBlt(hMaskDC, 0, 0, nWidthDest, nHeightDest, hImageDC, 0, 0, SRCCOPY); // 拷贝到hMaskDC

    这样足球位图中蓝色区域在掩码位图中成了白色,其它区域为黑色。


    2.1.2 设置背景色为黑色,前景色为白色,将掩码位图与足球位图相"与" 

    SetBkColor(hImageDC, RGB(0,0,0));

    SetTextColor(hImageDC, RGB(255,255,255));

    BitBlt(hImageDC, 0, 0, nWidthDest, nHeightDest, hMaskDC, 0, 0, SRCAND);

    这样,掩码位图中背景色(黑色)的区域在hImageBMP中被保留,前景色(白色)的部分变为黑色。 

    2.1.3 设置背景色为白色,前景色为黑色,将掩码位图与背景进行“与”运算

    SetBkColor(hdcDest,RGB(255,255,255));

    SetTextColor(hdcDest,RGB(0,0,0));

    BitBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hMaskDC, 0, 0, SRCAND);

    掩码中白色区域(数据与1相“与”结果不变)使背景保持不变,黑色区域变成黑色。
    2.1.4 将hImageBMP与背景进行“或”运算 

    BitBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hImageDC, 0, 0, SRCPAINT);

    这样就将位图绘制到背景上了。

    2.2 TransparentBlt2函数全部实现代码

    void TransparentBlt2( HDC hdcDest,      // 目标DC

                                          int nXOriginDest,   // 目标X偏移

                                          int nYOriginDest,   // 目标Y偏移

                                          int nWidthDest,     // 目标宽度

                                          int nHeightDest,    // 目标高度

                                          HDC hdcSrc,         // 源DC

                                          int nXOriginSrc,    // 源X起点

                                          int nYOriginSrc,    // 源Y起点

                                          int nWidthSrc,      // 源宽度

                                          int nHeightSrc,     // 源高度

                                          UINT crTransparent  // 透明色,COLORREF类型

                                          )

    {

            HBITMAP hOldImageBMP, hImageBMP = CreateCompatibleBitmap(hdcDest, nWidthDest, nHeightDest);  // 创建兼容位图

            HBITMAP hOldMaskBMP, hMaskBMP = CreateBitmap(nWidthDest, nHeightDest, 1, 1, NULL);            // 创建单色掩码位图

            HDC            hImageDC = CreateCompatibleDC(hdcDest);

            HDC            hMaskDC = CreateCompatibleDC(hdcDest);

            hOldImageBMP = (HBITMAP)SelectObject(hImageDC, hImageBMP);

            hOldMaskBMP = (HBITMAP)SelectObject(hMaskDC, hMaskBMP);

     

            // 将源DC中的位图拷贝到临时DC中

            if (nWidthDest == nWidthSrc && nHeightDest == nHeightSrc)

                   BitBlt(hImageDC, 0, 0, nWidthDest, nHeightDest, hdcSrc, nXOriginSrc, nYOriginSrc, SRCCOPY);

            else

                   StretchBlt(hImageDC, 0, 0, nWidthDest, nHeightDest, 

                                          hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, SRCCOPY);

     

            // 设置透明色

            SetBkColor(hImageDC, crTransparent);

     

            // 生成透明区域为白色,其它区域为黑色的掩码位图

            BitBlt(hMaskDC, 0, 0, nWidthDest, nHeightDest, hImageDC, 0, 0, SRCCOPY);

     

            // 生成透明区域为黑色,其它区域保持不变的位图

            SetBkColor(hImageDC, RGB(0,0,0));

            SetTextColor(hImageDC, RGB(255,255,255));

            BitBlt(hImageDC, 0, 0, nWidthDest, nHeightDest, hMaskDC, 0, 0, SRCAND);

     

            // 透明部分保持屏幕不变,其它部分变成黑色

            SetBkColor(hdcDest,RGB(255,255,255));

            SetTextColor(hdcDest,RGB(0,0,0));

            BitBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hMaskDC, 0, 0, SRCAND);

     

            // "或"运算,生成最终效果

            BitBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hImageDC, 0, 0, SRCPAINT);

     

            // 清理、恢复  

            SelectObject(hImageDC, hOldImageBMP);

            DeleteDC(hImageDC);

            SelectObject(hMaskDC, hOldMaskBMP);

            DeleteDC(hMaskDC);

            DeleteObject(hImageBMP);

            DeleteObject(hMaskBMP);

    }
    2.3 TransparentBlt的另外一个版本:TransparentBltU

    TransparentBltU是Christian Graus 在WinDEV发表的一个函数,功能与TransparentBlt一致,以下是全部实现代码: 

    bool TransparentBltU(

         HDC dcDest,         // handle to Dest DC

         int nXOriginDest,   // x-coord of destination upper-left corner

         int nYOriginDest,   // y-coord of destination upper-left corner

         int nWidthDest,     // width of destination rectangle

         int nHeightDest,    // height of destination rectangle

         HDC dcSrc,          // handle to source DC

         int nXOriginSrc,    // x-coord of source upper-left corner

         int nYOriginSrc,    // y-coord of source upper-left corner

         int nWidthSrc,      // width of source rectangle

         int nHeightSrc,     // height of source rectangle

         UINT crTransparent  // color to make transparent

      )

    {

         if (nWidthDest < 1) return false;

         if (nWidthSrc < 1) return false;

         if (nHeightDest < 1) return false;

         if (nHeightSrc < 1) return false;

     

         HDC dc = CreateCompatibleDC(NULL);

         HBITMAP bitmap = CreateBitmap(nWidthSrc, nHeightSrc, 1, GetDeviceCaps(dc,

                                                                  BITSPIXEL), NULL);

     

         if (bitmap == NULL)

         {

             DeleteDC(dc);    

             return false;

         }

     

         HBITMAP oldBitmap = (HBITMAP)SelectObject(dc, bitmap);

     

         if (!BitBlt(dc, 0, 0, nWidthSrc, nHeightSrc, dcSrc, nXOriginSrc,

                                                             nYOriginSrc, SRCCOPY))

         {

             SelectObject(dc, oldBitmap); 

             DeleteObject(bitmap);        

             DeleteDC(dc);                

             return false;

         }

     

         HDC maskDC = CreateCompatibleDC(NULL);

         HBITMAP maskBitmap = CreateBitmap(nWidthSrc, nHeightSrc, 1, 1, NULL);

     

         if (maskBitmap == NULL)

         {

             SelectObject(dc, oldBitmap); 

             DeleteObject(bitmap);        

             DeleteDC(dc);                

             DeleteDC(maskDC);            

             return false;

         }

     

         HBITMAP oldMask =  (HBITMAP)SelectObject(maskDC, maskBitmap);

     

         SetBkColor(maskDC, RGB(0,0,0));

         SetTextColor(maskDC, RGB(255,255,255));

         if (!BitBlt(maskDC, 0,0,nWidthSrc,nHeightSrc,NULL,0,0,BLACKNESS))

         {

             SelectObject(maskDC, oldMask); 

             DeleteObject(maskBitmap);      

             DeleteDC(maskDC);              

             SelectObject(dc, oldBitmap);   

             DeleteObject(bitmap);          

             DeleteDC(dc);                  

             return false;

         }

     

         SetBkColor(dc, crTransparent);

         BitBlt(maskDC, 0,0,nWidthSrc,nHeightSrc,dc,0,0,SRCINVERT);

     

         SetBkColor(dc, RGB(0,0,0));

         SetTextColor(dc, RGB(255,255,255));

         BitBlt(dc, 0,0,nWidthSrc,nHeightSrc,maskDC,0,0,SRCAND);

     

         HDC newMaskDC = CreateCompatibleDC(NULL);

         HBITMAP newMask;

         newMask = CreateBitmap(nWidthDest, nHeightDest, 1,

                                        GetDeviceCaps(newMaskDC, BITSPIXEL), NULL);

     

         if (newMask == NULL)

         {

             SelectObject(dc, oldBitmap);

             DeleteDC(dc);

             SelectObject(maskDC, oldMask);

             DeleteDC(maskDC);

              DeleteDC(newMaskDC);

             DeleteObject(bitmap);     

             DeleteObject(maskBitmap); 

             return false;

         }

     

         SetStretchBltMode(newMaskDC, COLORONCOLOR);

         HBITMAP oldNewMask = (HBITMAP) SelectObject(newMaskDC, newMask);

         StretchBlt(newMaskDC, 0, 0, nWidthDest, nHeightDest, maskDC, 0, 0,

                                                   nWidthSrc, nHeightSrc, SRCCOPY);

     

         SelectObject(maskDC, oldMask);

         DeleteDC(maskDC);

         DeleteObject(maskBitmap); 

     

         HDC newImageDC = CreateCompatibleDC(NULL);

         HBITMAP newImage = CreateBitmap(nWidthDest, nHeightDest, 1,

                                        GetDeviceCaps(newMaskDC, BITSPIXEL), NULL);

     

         if (newImage == NULL)

         {

             SelectObject(dc, oldBitmap);

             DeleteDC(dc);

             DeleteDC(newMaskDC);

             DeleteObject(bitmap);     

             return false;

         }

     

         HBITMAP oldNewImage = (HBITMAP)SelectObject(newImageDC, newImage);

         StretchBlt(newImageDC, 0, 0, nWidthDest, nHeightDest, dc, 0, 0, nWidthSrc,

                                                              nHeightSrc, SRCCOPY);

     

         SelectObject(dc, oldBitmap);

         DeleteDC(dc);

         DeleteObject(bitmap);     

     

         BitBlt( dcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,

                                                          newMaskDC, 0, 0, SRCAND);

     

         BitBlt( dcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,

                                                       newImageDC, 0, 0, SRCPAINT);

     

         SelectObject(newImageDC, oldNewImage);

         DeleteDC(newImageDC);

         SelectObject(newMaskDC, oldNewMask);

         DeleteDC(newMaskDC);

         DeleteObject(newImage);   

         DeleteObject(newMask);    

     

         return true;

    }

  • 相关阅读:
    python2文件转换为exe可执行文件
    pycharm下 os.system os.popen执行命令返回有中文乱码
    python 虚拟环境
    git commit之后,想撤销commit
    Android Dialog使用举例
    Builder模式在Java中的应用(转)
    AngularJS promise()
    给你一个承诺
    AngularJs 用户登录验证模块(demo)参考总结
    推荐 15 个 Angular.js 应用扩展指令(参考应用)
  • 原文地址:https://www.cnblogs.com/zlintokyo/p/2169646.html
Copyright © 2011-2022 走看看