1、
CBitmap位图类封装了Windows GDI中的位图和操作位图的成员函数。CPen、CBrush、CFont、CBitmap是常用的Windows GDI对象,和CFont一样,CBitmap也需要且只能通过其初始化函数来初始化之后才能使用,而CPen、CBrush可以直接在其构造函数中进行初始化。
CBitmap常用的初始化函数有LoadBitmap()、CreateCompatibleBitmap()、CreateBitmap()等:
LoadBitmap()加载一个位图资源来初始化位图对象。
CreateCompatibleBitmap()初始化一个位图使之与指定设备描述表兼容。
CreateBitmap()用一个指定宽度、高度和位图模式的依赖于设备的内存位图初始化位图对象。
GetBitmap()可以获得当前的位图信息到一个BITMAP结构。
2、
在窗口上显示bmp图片:一般方法为用该图片初始化CBitmap位图对象,再将这个位图对象选入兼容DC中(相当与绘制到了兼容DC中),再使用BitBlt将兼容DC上内容绘制到当前DC上。
如果要在窗口上显示多张图片或绘制多项内容则一般使用双缓冲技术:将所有图片全部绘制到兼容DC上后再一次性的将兼容DC内容绘制到当前窗口上,而不是一个一个的将图片绘制到当前窗口上。

void CtestDlg::OnPaint()
    {
        CPaintDC dc(this);

        //创建位图对象并加载图片进行初始化
        CBitmap bitmap;
        bitmap.LoadBitmap(IDB_BITMAP1);//参数为图片资源名称

        //获得图片大小等信息
        BITMAP bp;
        bitmap.GetBitmap(&bp);

        //创建与当前DC兼容的DC
        CDC dcCompatible;
        dcCompatible.CreateCompatibleDC(&dc);

        //将位图对象选入到兼容DC中
        CBitmap* pOldBitmap = dcCompatible.SelectObject(&bitmap);

        //将兼容DC中位图绘制到当前DC中
        dc.BitBlt(100, 100, bp.bmWidth, bp.bmHeight, &dcCompatible, 0, 0, SRCCOPY);

        //删除
        dcCompatible.SelectObject(pOldBitmap);
        dcCompatible.DeleteDC();
        bitmap.DeleteObject();
    }

保存窗口上的内容到位图对象:有时候需要保存窗口上指定区域的内容以供后面使用,如再将其显示到窗口上。eg:

void CFangDaDlg::ScreenShot()
{
    CPaintDC dc(this);

    //创建位图对象并初始化,使之与当前DC兼容
    CBitmap m_MemBitmap;
    m_MemBitmap.CreateCompatibleBitmap(&dc, 280, 320);//m_MemBitmap是CBitmap对象 

    //创建与当前DC兼容的DC
    CDC dcCompatible; 
    dcCompatible.CreateCompatibleDC(&dc);  

    //将位图选入到兼容DC中
    CBitmap* pOldBitmap = dcCompatible.SelectObject(&m_MemBitmap);  

    //绘制窗口内容到兼容DC中,窗口内容即绘制到位图对象m_MemBitmap中
    dcCompatible.BitBlt(0, 0, 280, 320, &dc, 100, 100, SRCCOPY);

    dcCompatible.SelectObject(pOldBitmap);
    dcCompatible.DeleteDC();
    m_MemBitmap.DeleteObject();
}

从以上可知,我们一般绘图的时候不是直接将图片绘制到窗口DC上,而是先将图片绘制到兼容DC上,再通过兼容DC将图片内容绘制到窗口DC上,保存窗口上内容到CBitmap位图对象亦是如此。而且在创建一个兼容DC后,必须将CBitmap位图对象选入兼容DC后才能向兼容DC绘制。
3、
前面说过,所有的GDI对象类都包含FromHandle静态成员函数用来通过对象句柄获得对象指针从而,而且CDC和CWnd等也包含此静态成员函数。CDC类还有一个成员函数Attach(),它也可以实现通过DC句柄来操作DC对象的功能。CDC::Attach(HDC hDC)的作用是将hDC附加到当前CDC对象,从而获得这个hDC的管理权,这样对当前CDC对象的操作就是对参数hDC的操作。当不需要操作的时候使用CDC::Detach()来分离hDC。例如下边的例子:

void DoubleBufferDraw(HDC hDC)
{
    CDC* pDC = new CDC;
    pDC->Attach(hDC); 
    
    //对pDC进行操作即是对hDC进行操作
    //......

    pDC->Detach();
    delete pDC;
}

4、也可以使用CImage类来绘制图片,只需定义一个CImage对象,然后调用CImage::Load()方法加载一个图片,调用CImage::Draw()方法绘制一个图片。如:

        RECT rectDest;
        rectDest.left = rectDest.top = 0;
        rectDest.right = rectDest.bottom = 100;
        
        CImage img;
        img.Load(_T("back.png"));
        img.Draw(::GetDC(m_hWnd), rectDest);

CImage::Load()有两个重载函数,一个是从指定路径加载图片,一个是从输入流加载图片,当图片包含在项目资源中的时候可以使用第二个方法。如:

//从资源中加载图片
BOOL LoadImageFromResource(CImage *pImage, UINT nResID, LPCTSTR lpTyp)
{
    if (pImage == NULL)
        return false;
    pImage->Destroy();
    // 查找资源
    HRSRC hRsrc = ::FindResource(hInst, MAKEINTRESOURCE(nResID), lpTyp);
    if (hRsrc == NULL)
        return false;
    // 加载资源
    HGLOBAL hImgData = ::LoadResource(hInst, hRsrc);
    if (hImgData == NULL)
    {
        ::FreeResource(hImgData);
        return false;
    }
    // 锁定内存中的指定资源
    LPVOID lpVoid = ::LockResource(hImgData);
    LPSTREAM pStream = NULL;
    DWORD dwSize = ::SizeofResource(hInst, hRsrc);
    HGLOBAL hNew = ::GlobalAlloc(GHND, dwSize);
    LPBYTE lpByte = (LPBYTE)::GlobalLock(hNew);
    ::memcpy(lpByte, lpVoid, dwSize);
    // 解除内存中的指定资源
    ::GlobalUnlock(hNew);
    // 从指定内存创建流对象
    HRESULT ht = ::CreateStreamOnHGlobal(hNew, TRUE, &pStream);
    if (ht != S_OK)
    {
        GlobalFree(hNew);
    }
    else
    {
        // 加载图片
        pImage->Load(pStream);
        if (pImage->GetBPP() == 32)
        {
            int i;
            int j;
            for (i = 0; i < pImage->GetWidth(); i++)
            {
                for (j = 0; j < pImage->GetHeight(); j++)
                {
                    byte *pByte = (byte *)pImage->GetPixelAddress(i, j);
                    pByte[0] = pByte[0] * pByte[3] / 255;
                    pByte[1] = pByte[1] * pByte[3] / 255;
                    pByte[2] = pByte[2] * pByte[3] / 255;
                }
            }

        }
        GlobalFree(hNew);
    }
    // 释放资源
    ::FreeResource(hImgData);
    return true;
}

        RECT rectDest;
        rectDest.left = rectDest.top = 0;
        rectDest.right = rectDest.bottom = 100;
        
        CImage img;
         LoadImageFromResource(&Img, IDB_PNG1, _T("PNG"));
        img.Draw(::GetDC(m_hWnd), rectDest);

还可以利用CImage类来进行窗口的截屏,其可以保存为多种图片格式,如jpeg、png等。以下是使用CImage类来实现屏幕截屏的功能:

bool PrintScreen()
{
    CString strPicName(_T("screen.jpg"));
    HDC hdcScreen = ::GetDC(NULL);
  
     //GetDeviceCaps函数可以获得指定DC的相关信息
    int nBitPerPixel = GetDeviceCaps(hdcScreen, BITSPIXEL);//像素位数
    int nWidth = GetDeviceCaps(hdcScreen, HORZRES);//水平像素总数
    int nHeight = GetDeviceCaps(hdcScreen, VERTRES);//垂直像素总数

    CImage image;
    image.Create(nWidth, nHeight, nBitPerPixel);
    BitBlt(image.GetDC(), 0, 0, nWidth, nHeight, hdcScreen, 0, 0, SRCCOPY);
    ::ReleaseDC(NULL, hdcScreen);
    image.ReleaseDC();
    HRESULT hRes = S_FALSE;
    hRes = image.Save(strPicName, Gdiplus::ImageFormatJPEG);
    if(SUCCEEDED(hRes))
        return true;
    else
        return false;
}

5、GDI+绘图的一个示例流程:
先添加头文件和链接库:
#include <comdef.h> //win32程序必须包含该头文件
#include <GdiPlus.h>
using namespace Gdiplus;
#pragma comment(lib, "gdiplus.lib")
在应用程序初始化InitInstance()之前加上以下三行:
ULONG_PTR gdiplusToken;
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
在OnPaint或OnDraw中添加绘制功能:
Graphics graphics(::GetDC(m_hWnd));
Bitmap background(L"background.png");
graphics.DrawImage(&background, 0, 0, background.GetWidth(), background.GetHeight());

6、BitBlt()系列函数

CDC::BitBlt()函数的功能是将源设备上下文的位块数据复制到当前设备上下文中。函数原型:

BOOL BitBlt(
   int xDest,      //目标矩形区域左上角x坐标
   int yDest,      //目标矩形区域左上角y坐标
   int nWidth,     //目标(源)矩形区域逻辑宽度
   int nHeight,    //目标(源)矩形区域逻辑高度
   CDC* pSrcDC,    //源设备上下文
   int xSrc,       //源矩形区域左上角x坐标
   int ySrc,       //源矩形区域左上角y坐标
   DWORD dwRop     //复制模式
);
View Code

相关文章: