gdi与gdi+绘图效率

With this one you're reading, I'm starting a series of articles focused on creating and manipulating graphics in .Net using GDI+ library starting at the most basic level of knowledge in this area. I'll post all the source code in Visual Basic.net, as it is my preferred language, although the code would look much similar and is really easy to translate from VB.net to C# using one of the many excellent online translators (for example,

通过阅读您正在阅读的这篇文章,我将开始一系列文章,着重于使用GDI +库在.Net中创建和处理图形的文章,从该领域的最基本知识开始。 我会将所有源代码都发布在Visual Basic.net中,因为它是我的首选语言,尽管该代码看起来非常相似,并且使用许多出色的在线翻译器之一(实际上是从VB.net到C#的翻译)非常容易(对于例,

this one).这个 )。

介绍 (Introduction)

Microsoft在Windows XP中引入了GDI +,作为GDI的改进和替代。 Windows的所有早期版本中都存在GDI(图形设备接口),它是OS的核心组件,负责表示图形对象并将其传输到输出设备(例如监视器和打印机)。 请注意,GDI不负责绘制窗口,菜单和其他Windows OS核心图形对象(这些功能在用户子系统中)。

As said, Windows XP replaced the old GDI libraries with GDI+, which improved GDI by adding new features and optimizing existing features. MSDN defines GDI+ as "the portion of the Windows XP operating system or Windows Server 2003 operating system that provides two-dimensional vector graphics, imaging, and typography". The .Net Framework graphics system uses GDI+ through the System.Drawing namespace.

如上所述,Windows XP用GDI +代替了旧的GDI库,它通过添加新功能和优化现有功能来改进GDI。 MSDN将GDI +定义为“ Windows XP操作系统或Windows Server 2003操作系统中提供二维矢量图形,图像和排版的部分”。 .Net Framework图形系统通过System.Drawing命名空间使用GDI +。

旧版图形? (Legacy graphics?)

MSDN将GDI +描述为旧版图形系统。 是真的吗 好吧,用严格的术语来说,Microsoft已经引入了几个新的图形库和渲染引擎,例如DirectX(可能是Windows现有的最强大的图形引擎)。 但是事实是DirectX的对象模型非常复杂,在实际情况下,使用GDI +足以绘制涉及笔,画笔,背景,渐变,路径,文本渲染等的2D图形。当然,GDI +自Windows XP以来,所有版本的Windows都支持Windows XP,甚至在Windows 8刚刚发布的今天,它仍然是Redmond OS的重要组成部分。

与设备无关 (Device-independient)

GDI和GDI +的主要特征是它们都是与设备无关的。 这意味着,如果要绘制某些东西(例如,带有蓝色边框和白色文本的红色圆圈),则将使用相同的指令集在监视器上进行绘制并在打印机上进行打印。 图形系统负责与适当的系统驱动程序进行通信,以将您的指令“翻译”为驱动程序可以理解的内容。 显然,这对程序员来说是一个很大的优势。

设备上下文和图形对象 (The Device Context and the Graphics object)

过去,当我们使用GDI编程时,我们想绘制一些东西,我们要做的第一件事是将设备上下文获取到我们要绘制的设备上。 设备上下文(通常称为DC)是一种结构,它定义了一组图形对象及其关联的属性以及影响输出的图形模式。 因此,例如,如果我们想将某些东西绘制到Windows窗体中,则需要通过其Handle(或hWnd)将DC传递给该窗体。 出于绘画目的,我们可以为视频显示,打印机和内存打开DC(以绘制到内存位图中)。

All of these operations involved the use of several Windows API functions, and many times the work was painful. Now, the .Net Framework has simplified it all and gives to us the Graphics object that is very close to a DC, but lets us deal with it as a managed class with simple methods and properties.

所有这些操作都涉及多个Windows API函数的使用,并且很多时候工作很痛苦。 现在,.Net Framework简化了所有操作,并为我们提供了非常接近DC的Graphics对象,但让我们将其作为具有简单方法和属性的托管类来处理。

GDI +的一部分 (Parts of GDI+)

正如MSDN所说,GDI +服务分为以下3大类:

2-D vector graphics. These are primitive graphics such as lines, curves and figures, that can be specified by sets of points in a coordinate system. For example, a straight line is specified by its two endpoints, while a rectangle is specified by a point defining its upper-left corner and 2 numbers defining its width and height. 2D矢量图形。 这些是原始图形,例如直线,曲线和图形,可以通过坐标系中的点集来指定。 例如,一条直线由其两个端点指定,而矩形由一个定义其左上角的点和两个数字定义其宽度和高度。
Imaging. There are certain kinds of pictures which are difficult (or impossible) to display using only 2-D vector graphics. For example, think of a high resolution picture of a leaping lion to hunt antelope in full African savannah. This is not possible to represent (or at least it is extremely difficult) with vector graphics. So these images are treated as bitmaps, which are arrays of numbers representing individual colored dots. 成像。 有某些类型的图片仅使用2维矢量图形很难(或不可能)显示。 例如,想像一下一幅高分辨率的图片,上面有一只跳跃的狮子在非洲大草原上猎杀羚羊。 这不可能用矢量图形表示(或至少非常困难)。 因此,这些图像被视为位图,它们是代表单个彩色点的数字数组。
Typography. Typography is the display of text in a variety of fonts, sizes, and styles. GDI+ provides extensive support for this complex task. One of the new features in GDI+ (not present in GDI) is subpixel antialiasing, which gives text rendered on an LCD screen a smoother appearance. 版式。 印刷术是显示各种字体,大小和样式的文本。 GDI +为这项复杂的任务提供了广泛的支持。 亚像素抗锯齿功能是GDI +中的一项新功能(GDI中未提供),它可以使在LCD屏幕上呈现的文本看起来更平滑。

图形类 (The Graphics class)

As this article is being eminently theoretical, and because I would like the following one to be much more practical, it is essential to enter deeper into the heart of the whole system of graphical manipulation in GDI+ with .Net: the System.Drawing.Graphics class.

由于本文的理论性很强,并且由于我希望以下文章更加实用,因此必须使用.Net深入研究GDI +中的图形处理整个系统的核心: System.Drawing.Graphics类。

You can think of the Graphics object as a canvas on which you are about to paint a picture. But in this picture, besides painting straight lines, curves, colors, dots, shapes, etc, you will be able to perform complex transformations anytime. You can rotate, scale, shake, paint again and transform again the times you want. Finally, you can show your picture to the world (usually on a screen, but it could be on a printer) or save it to a bitmap for posterity.

您可以将Graphics对象视为要在其上绘制图片的画布。 但是在这张图片中,除了绘制直线,曲线,颜色,点,形状等外,您还可以随时执行复杂的变换。 您可以再次旋转,缩放,摇动,绘制并再次变换所需的时间。 最后,您可以向世界展示您的图片(通常在屏幕上,但也可以在打印机上),也可以将其保存到位图中以供后代使用。

But, how can you obtain a Graphics object to start drawing? The Graphics class has no public constructors, so you cannot create a new Graphics object from scratch. This is for a good reason: a Graphics object is closely related to a drawing surface, so you need to access first the drawing surface (for example, a form, a control or a printer) and then obtain a Graphics object that the drawing surface will provide to you.

但是,如何获取Graphics对象开始绘制? Graphics类没有公共构造函数,因此您不能从头开始创建新的Graphics对象。 这是有充分理由的:Graphics对象与图形表面密切相关,因此您需要首先访问图形表面(例如,窗体,控件或打印机),然后获取图形对象作为图形表面将为您提供。

Let's see some examples.

让我们看一些例子。

Getting a Graphics object to a Form or a Control

获取图形对象到窗体或控件

The class System.Windows.Forms.Control implements the CreateGraphics function, that is just what you need to get a Graphics object to draw on the control. The class System.Windows.Forms.Form, as it inherits from System.Windows.Forms.Control, has this function too. So, if you want to draw on a Form or a Control, all you need is to call this function, that returns a Graphics object just ready to start drawing.

类System.Windows.Forms.Contr ol实现了CreateGraphics函数,这正是获取Graphics对象以在控件上绘制所需要的。 类System.Windows.Forms.Form, 因为它继承自System.Windows.Forms.Contr ol,也有此功能。 因此,如果要在窗体或控件上进行绘制,则只需调用此函数,该函数将返回一个Graphics对象,该对象准备开始绘制。

But using this method can have a disadvantage: your drawings on the Graphics object will not be persistent, which means that they will disappear as soon as your form or control is beign repainted.

但是使用此方法可能有一个缺点:Graphics对象上的图形将不会持久保存,这意味着一旦重新绘制窗体或控件,它们就会消失。

To test it, let's make a very simple example of what I'm saying. In Visual Studio, create a new VB.net Windows Forms application. Form1 is created by default. Now put a standard Button into the form and move the button to the bottom-right corner. You should have something like this:

为了测试它,让我们举一个非常简单的例子来说明我的意思。 在Visual Studio中,创建一个新的VB.net Windows窗体应用程序。 默认情况下创建Form1。 现在,将一个标准的Button放入表单中,并将该按钮移到右下角。 您应该具有以下内容:

Now, let's put some code into the Button1.Click event handler. Double-click on the button to open the Code Window. Button1_Click is created by default. Put this code inside the Button1_Click method:

现在,让我们将一些代码放入Button1.Click事件处理程序中。 双击按钮以打开“代码窗口”。 默认情况下创建Button1_Click。 将此代码放入Button1_Click方法中:

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.ClickUsing g As Graphics = Me.CreateGraphicsg.DrawEllipse(Pens.Black, New Rectangle(10, 10, 100, 100))End Using
End Sub

Even if you've never worked with System.Drawing classes, this code is very easy to understand. First, we called the Form's CreateGraphics function to get a ready-to-use Graphics object. Then, we called the DrawEllipse method of the Graphics object to draw a black circle on the Form starting at (10,10) coordinates and with a width and height of 100 pixels.

即使您从未使用过System.Drawing类,此代码也非常易于理解。 首先,我们调用了Form的CreateGraphics函数来获取一个现成的Graphics对象。 然后,我们调用Graphics对象的DrawEllipse方法,以从(10,10)坐标开始并以100像素的宽度和高度在Form上绘制一个黑色圆圈。

If you run your project and click on the button, you should have something like this:

如果您运行项目并单击按钮,则应该具有以下内容:

Now, minimize the Form and then restore it. What happened? The circle has disappeared. But, why? Well, each time that your form (or any part of it) needs to be repainted, it is responding to the WM_PAINT system message by calling BeginPaint to obtain a device context, wrapping this device context with a managed Graphics class and passing this class to your drawing code in the PaintEventArgs which are provided first to the OnPaint protected method and then, in turn, to the Paint event. So the graphics on your form are overriden by the graphics of the Graphics object provided in the Paint event.

现在,最小化窗体,然后将其还原。 发生了什么? 圈子不见了。 但为什么? 嗯,每次需要重新绘制表单(或其任何部分)时,它都会通过调用BeginPaint获取设备上下文,使用托管Graphics类包装该设备上下文并将此类传递给WM_PAINT系统消息进行响应。 PaintEventArgs中的绘图代码,该代码首先提供给OnPaint受保护的方法,然后提供给Paint事件。 因此,窗体上的图形会被Paint事件中提供的Graphics对象的图形覆盖。

Fortunately, the solution here is very simple. If you want to draw persistent graphics on a form or control, then use the Graphics object provided in the Paint event. Let's try! Edit your form's code and write this code in the form's Paint event:

幸运的是,这里的解决方案非常简单。 如果要在窗体或控件上绘制持久图形,请使用Paint事件中提供的Graphics对象。 我们试试吧! 编辑表单的代码,并将此代码写入表单的Paint事件中:

Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Painte.Graphics.DrawEllipse(Pens.Black, New Rectangle(10, 10, 100, 100))
End Sub

Now, run the project. The circle is there from the beginning, because it is drawn every time that the form paints itself. Minimize the form and restore it: the circle is still there.

现在,运行项目。 圆圈从一开始就存在,因为每次表格绘制时都会画一个圆圈。 最小化表格并恢复它:圆圈仍然存在。

Well, now you know how to get a valid Graphics object to draw on a form or control and you have the ability to make your graphics persistent.

好了,现在您知道了如何获取有效的Graphics对象以在窗体或控件上进行绘制,并且可以使图形持久化。

Getting a Graphics object to a printer

将图形对象获取到打印机

Although is not a very common task to draw directly on a printer using a Graphics object, in fact it can be done and is as easy as doing it on a Form. You can do it, for example, with a PrintDocument component, which provides a Graphics object in the parameters of its PrintPage event.

尽管使用Graphics对象直接在打印机上绘制不是一项很常见的任务,但实际上它可以完成,并且与在Form上一样容易。 例如,您可以使用PrintDocument组件执行此操作,该组件在其PrintPage事件的参数中提供Graphics对象。

If you want to test it, continue with the previous Visual Studio project and simply put a PrintDocument component from the Toolbox into your Form. Switch to code view and edit the PrintPage event of the PrintDocument object. Write this code:

如果要测试它,请继续上一个Visual Studio项目,只需将工具箱中的PrintDocument组件放入窗体中即可。 切换到代码视图并编辑PrintDocument对象的PrintPage事件。 编写这段代码:

Private Sub PrintDocument1_PrintPage(sender As System.Object, e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPageWith e.Graphics.PageUnit = GraphicsUnit.Millimeter.DrawEllipse(Pens.Black, New Rectangle(30, 30, 50, 50))End Withe.HasMorePages = False
End Sub

Now, modify your Button1_Click event to print the document:

现在,修改Button1_Click事件以打印文档:

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.ClickMe.PrintDocument1.Print()
End Sub

As you can see, the "e" parameter has a .Graphics property that is a valid Graphics object to the printer. What we are doing here is change the page unit of the Graphics object to millimeters, and then draw a circle at 3 cm from the left and top borders of the page, and with a width and height of 5 cm. If you run your project and click the button, then you should obtain that circle in your default printer.

如您所见,“ e”参数具有.Graphics属性,该属性是打印机的有效Graphics对象。 我们在这里所做的是将Graphics对象的页面单位更改为毫米,然后在距页面的左边界和顶边界3 cm处绘制一个圆圈,宽度和高度为5 cm。 如果运行项目并单击按钮,则应该在默认打印机中获得该圆圈。

Getting a Graphics object to an in-memory bitmap

将Graphics对象获取到内存中的位图

Earlier I said that is not a common task to draw directly on the Graphics object of a printer. This is because is much common to edit a in-memory bitmap and then print the bitmap. Create images from scratch (or edit existing images) is a very easy task with System.Drawing. Let's see it modifying your Button1_Click event:

之前我曾说过,直接在打印机的Graphics对象上绘制并不是常见的任务。 这是因为编辑内存位图然后打印位图是很常见的。 使用System.Drawing从头开始创建图像(或编辑现有图像)是一项非常简单的任务。 让我们看看它如何修改Button1_Click事件:

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.ClickUsing bmp As Bitmap = New Bitmap(50, 50)Using g As Graphics = Graphics.FromImage(bmp)g.Clear(Color.White)g.DrawEllipse(Pens.Black, New Rectangle(10, 10, 30, 30))End Usingbmp.Save("c:\testbitmap.png", Imaging.ImageFormat.Png)End Using
End Sub

Now let's explain this code. First we create a new in-memory bitmap with a width and height of 50 pixels. Then we get a valid Graphics object to the bitmap using the FromImage static function of the System.Drawing.Graphics class. After, we set the background of the bitmap to a solid white color, and finally we draw a circle starting at (10,10) pixels and with a width and height of 30 pixels. Finally, we save the bitmap to disk in .png format.

现在让我们解释一下这段代码。 首先,我们创建一个新的内存中位图,其宽度和高度为50像素。 然后,使用System.Drawing.Graphics类的FromImage静态函数将有效的Graphics对象获得到位图。 之后,我们将位图的背景设置为纯白色,最后绘制一个以(10,10)像素为起点,宽度和高度为30像素的圆圈。 最后,我们将位图以.png格式保存到磁盘。

If you run your project and click the button, you should obtain a "c:\testbitmap.png" that should look exactly like this:

如果您运行项目并单击按钮,则应获得一个“ c:\ testbitmap.png”,其外观应完全如下所示:

As you can see, in-memory creation and manipulation of bitmaps is very easy.

如您所见,在内存中创建和操作位图非常容易。

结论 (Conclusion)

在本文中,我已经解释了GDI和GDI +的起源,并讨论了其一些特征。 我还介绍了Graphics类,它是.Net中所有绘图操作的基础,而System.Drawing是使用GDI +的名称空间。 在下一篇文章中,我将详细解释坐标系。 一旦开始绘制,这是必不可少的步骤,以准确地知道我们绘制的方式和位置。

参考资料 (References)

GDI on Wikipedia维基百科上的GDI GDI+ on msdnmsdn上的GDI + GDI on msdnmsdn上的GDI DirectX Development SiteDirectX开发站点 The System.Drawing.Graphics class on msdnmsdn上的System.Drawing.Graphics类 Bob Powell's GDI+ FAQ Bob Powell的GDI +常见问题解答

翻译自: https://www.experts-exchange.com/articles/11371/Drawing-with-NET-and-GDI-Part-1-The-Basics.html

gdi与gdi+绘图效率

gdi与gdi+绘图效率_.NET和GDI +进行绘图[第1部分:基础知识]相关推荐

  1. cimage和gdi绘图效率比较_GDI+和GDI绘图性能对比实验

    龙源期刊网 http://www.qikan.com.cn GDI+ 和 GDI 绘图性能对比实验 作者:王克茹 来源:<科技创新与应用> 2013 年第 25 期 摘 要:本文通过完全相 ...

  2. python 3d绘图 拖动_使用python-matplotlib连续3D绘图(即图形更新)?

    我有一个模拟计算每次模拟迭代的表面数据. 我想连续将该数据绘制为同一窗口的表面图(在每次迭代中更新图),以便了解它是如何演变的并检查算法. 我的想法是创建一个类来初始化窗口/绘图,然后从模拟循环内部重 ...

  3. 机械制图国家标准的绘图模板_如何使用p5js构建绘图应用

    机械制图国家标准的绘图模板 The theme for week #5 of the Weekly Coding Challenge is: 每周编码挑战第5周的主题是: 创建绘图应用程序 (Crea ...

  4. python 3d绘图 汉字_完美解决Python matplotlib绘图时汉字显示不正常的问题

    Matplotlib是一个很好的作图软件,但是python下默认不支持中文,所以需要做一些修改,方法如下: 1.在python安装目录的Lib目录下创建ch.py文件. 文件中代码为: 保存,以后通过 ...

  5. ps画画模糊笔刷_心得:关于Photoshop笔刷一些使用基础知识的讲解

    前言 这期本来是一个游戏场景设计的命题,但是既然大家对笔刷效 果比较感兴趣,加上很多身边朋友也都有一些笔刷使用的错误, 这次就做一个笔刷主题的分享. 关于笔刷的个人理解 我想,在大家看我试验各种笔刷效 ...

  6. python单词统计、给定一个段落()_数训营第一课笔记:Python基础知识

    1.help()和dir()函数 help()函数与dir()函数都是帮助函数: help()函数能够提供详细的帮助信息,dir()函数仅是简单的罗列可用的方法. 2.基础数据结构 基础数据类型:数值 ...

  7. hazelcast 使用_使用HazelCast进行Hibernate缓存:JPA缓存基础知识

    hazelcast 使用 HazelCast的最大功能之一就是对Hibernate第二级缓存的支持 . JPA具有两个级别的缓存. 一级缓存在事务期间缓存对象的状态. 通过两次查询相同的对象,您必须获 ...

  8. 中音萨克斯指法表图_初学萨克斯一定要了解这6点基础知识

    萨克斯管是一种色彩性很强的乐器,它的声音独特,带有神秘的色彩,音色十分迷人,是一种比较接近人声特点的乐器,因此吸引到越来越多的人喜欢上萨克斯.那么新手在初学阶段关于萨克斯一定要了解这6点基础知识. 一 ...

  9. MySQL工作中的实际用_总结工作中经常用到的mysql基础知识

    总结工作中经常用到的mysql基础知识 发布时间:2020-06-08 11:27:30 来源:51CTO 阅读:217 作者:三月 本文主要给大家介绍工作中经常用到的mysql基础知识,文章内容都是 ...

  10. unity ui 概述_通过此概述了解Unity 2D和Platformer基础知识

    unity ui 概述 If you're shopping around for a 2D game engine, you've undoubtedly come across Unity. Di ...

最新文章

  1. html ajax put请求,javascript – PUT Ajax请求
  2. QT安装由问题的,安装后发现有些控件标签名显示不了
  3. android SQLite数据库的使用
  4. Spark记录-Scala数据类型
  5. rest端点_REST:使用Controller端点?
  6. 机器学习实战(六)AdaBoost元算法
  7. MySQL Python教程(1)
  8. js配置打印机属性_你还在为如何设置打印机而烦恼吗?一招教你快速共享打印机!...
  9. c语言自动选课,C语言实现简单学生选课管理系统
  10. 2021华为软挑再探——代码实现
  11. 使用Loadrunner进行性能测试
  12. MIDAS分布应用程序中的几个问题
  13. Rational Rose 7.0安装及科学使用教程
  14. 将源码打包成deb软件包
  15. java流重定向如何分类,Java 文件流與標准流之間的重定向
  16. 浅谈信息安全等级保护与ISO27000系列标准的异同
  17. Android UI详解之布局管理器(一)
  18. 2021最新微信域名链接检测工具 微信域名拦截检测接口
  19. 【Android工具】更新观影渠道,安卓、iOS、PC三端通用,免费电影在线观看
  20. 全网最全面工作流引擎Flowable完整教程之多实例会签

热门文章

  1. gds文件 导出_GaussDB 200使用GDS服务导入导出数据
  2. 联想服务器 重装系统u盘启动,联想U盘重装系统解决方法
  3. 算法工程师13——机器学习强化
  4. 跳转gridview
  5. 《Java解惑》系列——01表达式之谜——谜题09:半斤
  6. 第三章直接耦合多级放大电路
  7. 软件工程作业7.8.9
  8. esp32拍照传输到手机android,esp32-cam拍照上传云平台教程
  9. 以太坊parity2.72节点客户端部署安装
  10. MP2888AGU-0030-Z 烧录