GDI
GDI 是 Graphics Device Interface 的缩写,含义是图形设备接口,它的主要任务是负责系统与绘图程序之间的信息交换,处理所有 Windows 程序的图形输出。
在 Windows 操作系统下,绝大多数具备图形界面的应用程序都离不开 GDI,我们利用 GDI 所提供的众多 API 就可以方便的在屏幕、打印机及其它输出设备上输出图形、文本等操作。
GDI 具有如下特点:
- 不允许程序直接访问物理显示硬件,通过称为“设备环境”的抽象接口间接访问显示硬件
- 程序需要与显示硬件(显示器、打印机等) 进行通讯时,必须首先获得与特定窗口相关联的设备环境
- 用户无需关心具体的物理设备类型
- Windows 参考设备环境的数据结构完成数据的输出
GDI 函数
GDI 函数大致可分类为:
- 设备上下文函数(如 GetDC、CreateDC、DeleteDC)
- 画线函数(如 LineTo、Polyline、Arc)
- 填充画图函数(如 Ellipse、FillRect、Pie)
- 画图属性函数(如 SetBkColor、SetBkMode、SetTextColor)
- 文本、字体函数(如 TextOut、GetFontData)
- 位图函数(如 SetPixel、BitBlt、StretchBlt)
- 坐标函数(如 DPtoLP、LPtoDP、ScreenToClient、ClientToScreen)
- 映射函数(如 SetMapMode、SetWindowExtEx、SetViewportExtEx)
- 元文件函数(如 PlayMetaFile、SetWinMetaFileBits)
- 区域函数(如 FillRgn、FrameRgn、InvertRgn)
- 路径函数(如 BeginPath、EndPath、StrokeAndFillPath)
- 裁剪函数(如 SelectClipRgn、SelectClipPath)
GDI+
GDI+ 是 GDI 的后续版本,最早于 2000 年随 Windows 2000 一起推出,后来又被包装进 .NET 框架的托管类库中,成为 .NET 中窗体绘图的主要工具。
GDI+ 主要提供了以下三类服务:
- 二维矢量图形:GDI+ 提供了存储图形基元自身信息的类(或结构体)、存储图形基元绘制方式信息的类以及实际进行绘制的类;
- 图像处理:大多数图片都难以划定为直线和曲线的集合,无法使用二维矢量图形方式进行处理。因此,GDI+ 为我们提供了 Bitmap、Image 等类。它们可用于显示、操作和保存 BMP、JPG、GIF 等图像。
- 文字显示:GDI+ 支持使用各种字体、字号和样式来显示文本。
GDI 接口是基于函数的,而 GDI+ 是基于 C++ OO 的编程接口,因此使用起来比 GDI 要方便。因为 GDI+ 实际上是 GDI 的封装和扩展,所以执行效率一般要低于 GDI。
GDI 和 GDI+ 的区别
GDI 的核心是设备上下文,GDI 函数都依赖于设备上下文句柄,其编程方式是基于句柄的;GDI+ 无需时刻依赖于句柄或设备上下文,用户只需创建一个 Graphics 对象,就可以用面向对象的方式调用其成员函数进行图形操作,编程方式是基于对象的。
GDI 在使用设备上下文绘制线条之前,必须先调用 SelectObject 以使钢笔对象和设备上下文关联。其后,在设备上下文中绘制的所有线条均使用该钢笔,直到选择另一支不同的钢笔为止。GDI 中有当前位置的概念,所以在使用 GDI 绘制线条前应该先使用MoveTo 移动当前位置,再使用 LineTo 画线。
CPen pen(PS_SOLID, 1, RGB(255, 0, 0));
dc.SelectObject(pen.GetSafeHandle());
dc.MoveTo(0, 0);
dc.LineTo(100, 100);
在 GDI+ 中,只需将 Pen 对象直接作为参数传递给 Graphics 类的 DrawLine 等方法即可,而不必使 Pen 对象与 Graphics 对象关联。且 GDI+ 中则没有当前位置的概念,画线函数中可以直接指定起点和终点。
Pen myPen(Color::Red);
graphics.DrawLine(&myPen, 0, 0, rect.right, 0);
GDI+ 新特性
- 改进了颜色管理
GDI+ 不仅提供了更多可供选择使用的颜色,使其支持 Alpha 通道合成运算,而且还保持了与其他颜色的兼容性。 - 绘图支持反锯齿
通过设置 GDI+ 对象的相关属性,GDI+ 可以与相关的显示驱动程序搭配完成图形绘制时的反锯齿功能,使得绘制的图形更加平滑、美观,而整个过程是由 GDI+ 对象自动计算完成的。 - 提供渐变画刷
GDI+ 拓展了 GDI 的功能,提供线性渐变和路径渐变画刷来填充图形、路径和区域,甚至也可用来绘制直线、曲线等。 - 独立的路径对象
GDI+ 使用 Graphics 对象来进行绘图操作,并将路径操作从 Graphics 对象分离出来,提供一个 Graphics 类供用户使用,用户不必担心对象会受到 Graphics 对象操作的影响,从而可以使用同一个操作对象进行多次的路径绘制操作。 - 样条曲线
GDI+ 封装了绘制基数样条曲线和贝塞尔样条曲线的方法。 - 变形和矩阵运算
GDI+ 提供了功能强大的 Matrix 类来实现矩阵的旋转,错切、平移、比例等变换操作,以便产生复杂的新图形。 - 多图片格式的支持
GDI+ 改进了图形处理能力,通过 GDI+,用户能够访问多种格式的图片文件,转换文件格式等,还能进行图像重新着色、色彩修正、消除走样等图像处理。
Direct2D
Direct2D 是一个基于 Direct3D 的 2D 图形 API,可以利用硬件加速特性来提供高性能、高质量的 2D 渲染。而且十分方便的是,Direct2D 与 GDI,GDI+ 和 D3D 都是可以交互的。一项技术总是有其受众面,看看微软怎么说的:
- 大型企业级本机应用程序开发人员。
- 创建供下游开发人员使用的控件工具包和库的开发人员。
- 需要对二维图形进行服务器端呈现的开发人员。
- 使用 Direct3D 图形,并且需要在菜单、用户界面 (UI) 元素和抬头显示器 (HUD) 中使用高性能的简单二维和文本呈现的开发人员。
在 Direct2D 架构的右下方,有一个软件光栅化(software rasterizer),假如显卡不支持硬件加速,那么 Direct2D 可以使用软件方式渲染,即便是这样,其效果还是要优于 GDI。
视觉效果
使用 Direct2D 渲染出来的效果要比 GDI 要好的多。因为 Direct2D 使用基于图元的反锯齿效果(这样会使线条更加的平滑),而且在渲染二维图元的时候,完全支持透明和 Alpha 混合。以下是对比的照片:
显然,右边的 Direct2D 的线条效果要好于左边的 GDI。
demo
- GDI
正弦曲线 - GDI+
渐变色,Alpha混合 - D2D
螺旋路径动画
GDI 绘图代码:
void CChildView::_drawWithGDI( CPaintDC& dc )
{
CRect rect;
GetClientRect(&rect