中易网

详细的GDI(图像设备接口)介绍?

答案:2  悬赏:50  
解决时间 2021-11-15 20:26
详细的GDI(图像设备接口)介绍?
最佳答案
C# GDI+编程之基础篇
一、关于GDI+
从本质上来看,GDI+为开发者提供了一组实现与各种设备(例如监视器,打印机及其它具有图形化能力但不及涉及这些图形细节的设备)进行交互的库函数。GDI+的本质在于,它能够替代开发人员实现与例如显示器及其它外设的交互;而从开发者角度来看,要实现与这些设备的直接交互却是一项艰巨的任务。
下图1展示了GDI+在开发人员与上述设备之间起着重要的中介作用。其中,GDI+为我们“包办”了几乎一切—从把一个简单的字符串“HelloWorld”打印到控制台到绘制直线,矩形甚至是打印一个完整的表单等。

图1.GDI+担当着重要的中介作用
那么,GDI+是如何工作的呢?为了弄清这个问题,让我们来分析一个示例—绘制一条线段。实质上,一条线段就是一个从一个开始位置(X0,Y0)到一个结束位置(Xn,Yn)的一系列像素点的集合。为了画出这样的一条线段,设备(在本例中指显示器)需要知道相应的设备坐标或物理坐标。
然而,开发人员不是直接告诉该设备,而是调用GDI+的drawLine()方法,然后,由GDI+在内存(即“视频内存”)中绘制一条从点A到点B的直线。GDI+读取点A和点B的位置,然后把它们转换成一个像素序列,并且指令监视器显示该像素序列。简言之,GDI+把设备独立的调用转换成了一个设备可理解的形式;或者实现相反方向的转换。
至此,我们已经简单了解了GDI+的工作机理。现在,让我们开始探讨如何实现一些基本的图像操作。
二、图像操作—缩略图,缩放与保存
在本文示例中,我们将实现如下的任务:
1. 创建缩略图。
2. 缩放一个加载的图像。
3. 保存一个操作中的图像。
a) 创建缩略图

缩略图是图像的浓缩版本。典型情况下,一幅缩略图图像的尺寸为80×200像素。在GDI+中,一个图像的缩略图可以通过使用Image类的GetThumbnailImage()方法来创建。其函数原型如下:

public Image GetThumbnailImage (

int thumbWidth,

int thumbHeight,

GetThumbnailImageAbort callback,

IntPtr callbackData

)

第一个参数相应于缩略图的宽度;第二个参数相应于生成的缩略图的高度;第三个参数是一个Image.GetThumbnailImageAbort委托。在 GDI+ 1.0 版中不使用此委托。即便如此,也必须创建一个委托并在该参数中传递对此委托的引用。第四个参数同样没有使用,但是也需要提供以实现兼容性。注意,第四个参数必须为IntPtr.Zero。
如果前两个参数(也就是宽度和高度)都为0的话,那么,GDI+返回一个嵌入式缩略图。否则,使用系统定义尺寸创建该缩略图。例如,如果img是一个图像类的实例,并且使用的宽度和高度都是系统定义的,创建一个缩略图的语句应该如下所示:

Image thumbNailImage = img.GetThumbnailImage(0,0,tnCallBack,IntPtr.Zero);

在此,thumbNailImage包含返回的缩略图,而tnCallback是一个相应于Image.GetThumbnailImageAbort的函数,其定义如下:

//必须调用它,但是没有使用

>publicbool tnCallbackMethod()

...{

return false;

}

b) 缩放一个加载的图像
缩放是放大或缩小一个图像的过程—通过在图像尺寸上乘以缩放因子实现。其中,缩放因子=期望的图像尺寸/当前图像尺寸。例如,要把一个图像放大200%,则当前尺寸必须乘以200%(200%=200/100=2);为了缩小一个图像到25%,则当前尺寸必须乘以25%或0.25(25/100=0.25倍)。
c) 保存图像
保存操作是图像操作中的关键操作之一。在保存一个图像时,图像相应的类型信息也必须进行保存;也就是说,该图像的扩展名在这一过程中具有重要角色。每一种类型相应于一个特定的格式。实质上,在保存一个图像时,根据该格式输出数据是非常必要的。然而,借助于GDI+ API的优势,一个对Image类的Save()方法的简单调用就可以把相应的写数据操作中所有细节省略掉。这个方法使用两个参数—被保存的图像的名字和待保存图像的格式。该格式能够通过ImageFormat类提供的类型来指定。下列表格指定了GDI+支持的各种图像格式。
属性 描述

Bmp 指定BMP格式。

Emf 指定EMF(增强的元文件格式)。

Exif 指定EXIF格式。

Gif 指定GIF格式。

Guid 指定一个GUID结构,用于描述ImageFormatobject。

Icon 指定Windows图标格式。

Jpeg 指定JPEG格式。

MemoryBmp 指定内存位图格式。

Png 指定PNG格式。

Tiff 指定TIFF格式。

Wmf 指定WMF(Windows元文件格式)。

其中,Emf和Wmf是特定于Windows系统的。
假定你想使用名字“checker.gif”保存一个图像,那么,相应的实现语句将是:

curImage.Save(“checker.gif”,ImageFormat.Gif);

这里,curImage对应于Image类的实例。
在下一节中,我将对前面开发的这个应用程序进行扩展。
三、实际开发中的图像操作
下面,我们来讨论实际中的使用情况。我将在本文示例应用程序中添加下列功能:
1. 以用户指定的格式保存图像。

2. 根据从菜单下选择的百分比放大图像。

3. 创建一个加载图像的略缩图。
相应的菜单操作如下所示:
mnuSave—文件菜单下保存图像的子菜单。

mnu200Zoom—放大图像200%。

mnuThumbNail—创建图像的一个略缩图。
下面是处理菜单项mnuSave的Click事件相应的方法:

private void mnuSave_Click(object sender,System.EventArgs e)

...{

//如果图像已经创建

if(curImage == null)

return;

//调用SaveFileDialog对话框

SaveFileDialog saveDlg = new SaveFileDialog();

saveDlg.Title = "Save Image As";

saveDlg.OverwritePrompt = true;

saveDlg.CheckPathExists = true;

saveDlg.Filter =

"Bitmap File(*.bmp)|*.bmp|" +

"Gif File(*.gif)|*.gif|" +

"JPEG File(*.jpg)|*.jpg|" +

"PNG File(*.png)|*.png" ;

saveDlg.ShowHelp = true;

//如果选择,则进行保存

if(saveDlg.ShowDialog() == DialogResult.OK)

...{

//得到用户选择的文件名

string fileName = saveDlg.FileName;

//得到文件扩展名

string strFilExtn =fileName.Remove(0,fileName.Length - 3);

//保存文件

switch(strFilExtn)

...{

case "bmp":

curImage.Save(fileName, ImageFormat.Bmp);

break;

case "jpg":

curImage.Save(fileName, ImageFormat.Jpeg);

break;

case "gif":

curImage.Save(fileName, ImageFormat.Gif);

break;

case "tif":

curImage.Save(fileName, ImageFormat.Tiff);

break;

case "png":

curImage.Save(fileName, ImageFormat.Png);

break;

default:

break;

}

}

}

首先,以可接收的扩展名显示这个保存对话框。然后,由从该对话框返回的文件名检索相应的扩展名。最后,根据该扩展名,使用相应的图像格式参数调用Save()方法。
接下来,我们分析菜单项mnu200Zoom相应的处理器。首先,让我们在应用程序级添加下列以粗体显示的一行:

private double curZoom=1.0;

private Image curImage=null;//用于存储当前图像

private int i = 0;//用于把屏幕重画操作与缩略图绘制部分区别开来

然后,必须对mnuLoad处理代码作少许调整,如下所示:

private void mnuLoad_Click(object sender,System.EventArgs e)

...{

//创建OpenFileDialog

OpenFileDialog opnDlg = new OpenFileDialog();

//设置一个图像类型过滤器

opnDlg.Filter =

"All Image files|*.bmp;*.gif;*.jpg;*.ico;"+

"*.emf;,*.wmf|Bitmap Files(*.bmp;*.gif;*.jpg;"+

"*.ico)|*.bmp;*.gif;*.jpg;*.ico|"+

"Meta Files(*.emf;*.wmf;*.png)|*.emf;*.wmf;*.png";

opnDlg.Title = "打开图像文件";

opnDlg.ShowHelp = true;

//如果OK,选择它

if(opnDlg.ShowDialog() == DialogResult.OK)

...{

//读取当前选择的文件名

curFileName = opnDlg.FileName;

//使用Image.FromFile创建图像对象

try

...{

curImage = Image.FromFile(curFileName);

}

catch(Exception exp)

...{

MessageBox.Show(exp.Message);

}

}

//改变AutoScrollMinSize属性

this.AutoScrollMinSize = new Size

((int)(curImage.Width * curZoom),

(int)(curImage.Height * curZoom));

i++;

//重新绘制表单

Invalidate();

}

注意,在此新添加的代码分别在原来的图像宽度和高度上乘以放大因子以生成一个放大的图像。然后,必须相应地修改paint事件的处理器。如下所示:

private void Form1_Paint(object sender, PaintEventArgs e)

...{

if (curImage != null && i==0)

...{

Graphics g = this.CreateGraphics();

g.DrawImage(curImage, new Rectangle

(AutoScrollPosition.X,

AutoScrollPosition.Y ,

(int)(this.ClientRectangle.Width * curZoom),

(int)(ClientRectangle.Height * curZoom)));

}

}

该图像应该有根据放大因子的相应的高度和宽度。下面,我们来看一下mnu200Zoom菜单项相应的事件处理器:

private void mnu200_Click(object sender,System.EventArgs e)

...{

if(curImage != null)

...{

curZoom = (double)200/100;

i++;

Invalidate();

}

}

最后,我们来看一下mnuThumbNail菜单项相应的事件处理器:

1private void mnuThumbnail_Click(object sender, EventArgs e)

2...{

3if(curImage != null)

4...{

5i++;

6//回调

7Image.GetThumbnailImageAbort tnCallBack =

8new Image.GetThumbnailImageAbort(tnCallbackMethod);

9//得到缩略图图像

10Image thumbNailImage = curImage.GetThumbnailImage

11(100, 100, tnCallBack, IntPtr.Zero);

12//创建一个Graphics对象

13Graphics tmpg = this.CreateGraphics();

14tmpg.Clear(this.BackColor);

15//画缩略图图像

16tmpg.DrawImage(thumbNailImage, 10, 10, thumbNailImage.Width, thumbNailImage.Height);

17//释放掉Graphics对象

18tmpg.Dispose();

19}

20

21}

22

在此,我们首先创建一个GetThumbnailImageAbort类型的变量并且赋给它值tnCallbackMethod()—这是通过传递给该方法GetThumbnailImageAbort实现的。然后,它创建一个新的Image类的实例以存储GetThumbnailImage方法返回的图像—此后,这个方法将用于把缩略图绘制到屏幕上。
四、小结
在本文中,我仅讨论了.NET C#环境下关于GDI+编程的一些基本的实用操作片断。在以后的文章中,我们将逐渐展开对.NET GDI+编程高级特征的探讨。
全部回答
我暂时保留我的看法!
我要举报
如以上问答内容为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
谁知道幸福树的养殖技巧
为什么用英语形容什么什么学科的老师teacher
我们吵吵闹闹两年了!分分合合很多次。最后还
凯旋门洗车行地址好找么,我有些事要过去
电视剧乌龙闯情关阿秋饰演者,叫什么名字?
框柱b边和h边箍筋级别不一样如何设置
阿拉伯风情建筑特点是什么
醋和白矾治皮肤痒痒吗
天然石材有辐射吗
兴尽意阑是什么意思啊?
我的2012款奥迪A6缸体两侧破了,是不是换个缸
金水区郑州红专社区-离退休人员管理服务站我
后妈为什么要打孩子
全球通号码买了后可以直接在国外使用吗?是否
晋城银行网上银行跨行转账收手续费吗
推荐资讯
如何去小窑湾
隐形眼镜护理液哪个牌子最好?sauflon护理液
桥头派出所地址在什么地方,想过去办事
宝鸡哪里有本帮菜,也就是上海菜 哪位大虾能
东墙处子是什么意思啊?
棘垣的意思是什么?棘垣的释义是什么啊?
脸上色斑怎么解决?
1岁婴儿用手反复抓鼻子和嘴。一看就是不舒服
我是淄博淄川的,想开个小旅馆。大约十间房,
郑州经开区有没有专业做员工餐承包和快餐外卖
鄢沟村委会地址在什么地方,想过去办事
我家宝宝5个多月出幼儿急诊,能洗澡么
手机登qq时,显示手机磁盘不足,清理后重新登
刺客的套装怎么选啊?