GDI基础(3):绘制图片
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(, , bp.bmWidth, bp.bmHeight, &dcCompatible, , , SRCCOPY); //删除
dcCompatible.SelectObject(pOldBitmap);
dcCompatible.DeleteDC();
bitmap.DeleteObject();
}
保存窗口上的内容到位图对象:有时候需要保存窗口上指定区域的内容以供后面使用,如再将其显示到窗口上。eg:
void CFangDaDlg::ScreenShot()
{
CPaintDC dc(this); //创建位图对象并初始化,使之与当前DC兼容
CBitmap m_MemBitmap;
m_MemBitmap.CreateCompatibleBitmap(&dc, , );//m_MemBitmap是CBitmap对象 //创建与当前DC兼容的DC
CDC dcCompatible;
dcCompatible.CreateCompatibleDC(&dc); //将位图选入到兼容DC中
CBitmap* pOldBitmap = dcCompatible.SelectObject(&m_MemBitmap); //绘制窗口内容到兼容DC中,窗口内容即绘制到位图对象m_MemBitmap中
dcCompatible.BitBlt(, , , , &dc, , , 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 = ;
rectDest.right = rectDest.bottom = ; 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() == )
{
int i;
int j;
for (i = ; i < pImage->GetWidth(); i++)
{
for (j = ; j < pImage->GetHeight(); j++)
{
byte *pByte = (byte *)pImage->GetPixelAddress(i, j);
pByte[] = pByte[] * pByte[] / ;
pByte[] = pByte[] * pByte[] / ;
pByte[] = pByte[] * pByte[] / ;
}
} }
GlobalFree(hNew);
}
// 释放资源
::FreeResource(hImgData);
return true;
} RECT rectDest;
rectDest.left = rectDest.top = ;
rectDest.right = rectDest.bottom = ; 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(), , , nWidth, nHeight, hdcScreen, , , 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 //复制模式
);
最后一个参数dwRop为复制模式(或叫做光栅操作模式),可以为以下取值:
SRCCOPY:将源矩形区域直接拷贝到目标矩形区域。
BLACKNESS:表示使用与物理调色板的索引0相关的色彩来填充目标矩形区域,(对缺省的物理调色板而言,该颜色为黑色)。
DSTINVERT:表示使目标矩形区域颜色取反。
NOTSRCCOPY:将源矩形区域颜色取反,于拷贝到目标矩形区域。
MERGECOPY:表示使用布尔型的AND(与)操作符将源矩形区域的颜色与特定模式组合一起。\
........
CDC::StretchBlt()在BitBlt()的基础上增加了绘制时的放缩功能:如果目标矩形区域比源矩形区域大或小,则BitBlt()不会对源矩形区域进行拉伸或压缩, StretchBlt()则多了两个参数来指示源矩形区域大小,在复制时可以自动拉伸和压缩源像素区域,以适合目的矩形区域的尺寸。
BOOL StretchBlt(
int xDest, //目标矩形区域左上角x坐标
int yDest, //目标矩形区域左上角y坐标
int nWidthDest, //目标矩形区域逻辑宽度
int nHeightDest, //目标矩形区域逻辑高度
CDC* pSrcDC, //源设备上下文
int xSrc, //源矩形区域左上角z坐标
int ySrc, //源矩形区域左上角y坐标
int nSrcWidth, //源矩形区域宽度
int nSrcHeight, //源矩形区域宽度
DWORD dwRop //复制模式
);
CDC::TransparentBlt()在StretchBlt()的基础上增加了对于指定颜色绘制时的过滤:其最后一个参数用来指定要过滤的颜色,即遇到这种颜色就绘制透明来替代,eg:\
dc.TransparentBlt(, , , , srcDC, , , , , RGB(0xff,,));//设置红色为透明色,即过滤掉红色
CDC::AlphaBlend()在StretchBlt()的基础上增加了绘制时透明的效果:其最后一个参数用来设置绘制时的透明效果。
BOOL AlphaBlend(
int xDest,
int yDest,
int nDestWidth,
int nDestHeight,
CDC* pSrcDC,
int xSrc,
int ySrc,
int nSrcWidth,
int nSrcHeight,
BLENDFUNCTION blend
);
7、调色板
8、刷新率
我们常说的屏幕刷新率为70Hz,分辨率为640×480,意思是说电子束每秒重复扫描屏幕70次,每行要扫描640个象素,一共有480行。
fps与刷新率类似,动态画面是由一帧一帧的画面组成的,fps就是指画面每秒刷新的帧数。一般游戏的帧数最低应保持30以上,否则会出现画面不流畅的现象,而电影、电视中的帧数一般为24、25。
9、透明
可以使用上面说到的CDC::AlphaBlend()来使绘制图片的时候产生透明效果,效果如图所示:

可以使用SetLayeredWindowAttributes()函数来设置整个窗口显示时的透明度,它会使整个窗口框架(包括其上的子控件)透明,代码及效果如下所示:
BOOL CMFCApplication10Dlg::OnInitDialog()
{
....... // TODO: 在此添加额外的初始化代码 //添加WS_EX_LAYERED属性
LONG NewLong = GetWindowLong(m_hWnd, GWL_EXSTYLE) | WS_EX_LAYERED;
SetWindowLong(m_hWnd, GWL_EXSTYLE, NewLong); // 取得SetLayeredWindowAttributes函数指针
typedef BOOL(WINAPI * SLWA)(HWND, COLORREF, BYTE, DWORD);
SLWA pFun = NULL;
HINSTANCE m_hInst = LoadLibrary(_T("User32.DLL"));
if (m_hInst)
{
pFun = (SLWA)GetProcAddress(m_hInst, "SetLayeredWindowAttributes");
if (pFun)
{
int degree = ;//透明度:0-255
pFun(m_hWnd, RGB(, , ), degree, LWA_ALPHA);
} FreeLibrary(m_hInst);
} .......
}

GDI基础(3):绘制图片的更多相关文章
- VB6 GDI+ 入门教程[6] 图片
http://vistaswx.com/blog/article/category/tutorial/page/2 VB6 GDI+ 入门教程[6] 图片 2009 年 6 月 19 日 15条评论 ...
- UWP&WP8.1 重新绘制图片 WriteableBitmap用法 图片转byte[]数组,byte[]数组转图片
---恢复内容开始--- WriteableBitmap 是UWP和WP8.1绘制图片的,重组图片的最重要方法.方法较为简单,方法多样性. 通过查看文档,WriteableBitmap的继承性是 ...
- html5 绘制图片 drawImage
要在绘图上下文中绘制图片,可以使用 drawImage 方法.该方法有三种不同的参数: drawImage(image,dx,dy) drawImage(image,dx,dy,dw,dh) d ...
- 使用html5 canvas绘制图片
注意:本文属于<html5 Canvas绘制图形入门详解>系列文章中的一部分.如果你是html5初学者,仅仅阅读本文,可能无法较深入的理解canvas,甚至无法顺畅地通读本文.请点击上述链 ...
- Android Canvas使用drawBitmap绘制图片
1.基本的绘制图片方法 //Bitmap:图片对象,left:偏移左边的位置,top: 偏移顶部的位置 drawBitmap(Bitmap bitmap, float left, float top, ...
- android中Canvas使用drawBitmap绘制图片
1.主要的绘制图片方法 //Bitmap:图片对象,left:偏移左边的位置,top: 偏移顶部的位置 drawBitmap(Bitmap bitmap, float left, float ...
- GDI+基础(3)
常用图形绘制 <%@ Page ContentType="image/gif" Language="C#" %> <!--ContentTyp ...
- Direct2D WIC绘制图片
绘制图片需要用到WIC,WIC的功能包括: 编解码图片.也可以自定义图片解码插件. 读取图片元数据. 图像处理(最高支持每通道32位). 内置支持一些流行的格式.包括:BMP v5, GIF 89a/ ...
- lufylegend库 LGraphics绘制图片
lufylegend库 LGraphics绘制图片 <!DOCTYPE html> <html lang="en"> <head> <me ...
随机推荐
- linux同步机制
很早之前就接触过同步这个概念了,但是一直都很模糊,没有深入地学习了解过,近期有时间了,就花时间研习了一下<linux内核标准教程>和<深入linux设备驱动程序内核机制>这两本 ...
- 对于装office 365时,visio不兼容的解决
先将office 365装好,之后从这个网址下载visio安装即可,但是没有 激活码,需要自己激活: 网址:链接: https://pan.baidu.com/s/1OqONPuJ0eumrpts-X ...
- TZOJ 3209 后序遍历(已知中序前序求后序)
描述 在数据结构中,遍历是二叉树最重要的操作之一.所谓遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问. 这里给出三种遍历算法. 1.中序遍历的递归算法定义: ...
- 解决在Mac的Vmware Fusion中装win7系统和mac原生系统直接切换win7系统分辨率变化的问题
虚拟机 - 设置 - 显示屏 - 全屏显示retina (此选项钩去掉)
- jstl的forEach详解(转)
<c:forEach>标签用于通用数据循环,它有以下属性 属 性 描 述 是否必须 缺省值 items 进行循环的项目 否 无 begin 开始条件 否 0 end 结束条件 否 集合中的 ...
- Python爬虫项目--爬取猫眼电影Top100榜
本次抓取猫眼电影Top100榜所用到的知识点: 1. python requests库 2. 正则表达式 3. csv模块 4. 多进程 正文 目标站点分析 通过对目标站点的分析, 来确定网页结构, ...
- idea中快捷键设置为eclipse中快捷键
打开file-settings,然后搜索key,在keymap中选择eclipse (1) (2)
- Swift 错误记录
最近几天开始学习Swift,作为一个从 OC 转到 Swift 的程序员,我一直以为很简单.但是现在学习一个星期之后,发现问题还是蛮多的! 最大的问题就是 太特么 不习惯了!!!!!!!!!! 好吧, ...
- Kafka基本使用
Kafka基本使用 官网地址 http://kafka.apache.org/ 一切应以官网文档为准. 安装 download里下载要安装的版本.或者直接wget该网址.如wget http:/ ...
- 更换Grade源为阿里云解决下载慢问题
作为程序员,即写的了代码也得翻得上围墙. 现在包管理工具(Maven/grade)的便捷性让人大快朵颐,再也不需要到处找jar包. 如果你没梯子又苦苦无法加快下载速度,不如按照以下设置一下. 对单个项 ...