前言: 本文章抄袭自本人刚刚买的《ASP.NET 3.5从入门到精通》这本书,此书介绍在 http://www.china-pub.com/44991 ,本文章95%与此书的内容完全一样,另5%是我改正一些失误以后加上去的,该书原示例代码只能运行在IE核心的浏览器上,非IE核心浏览器上运行会出现些显示问题,本人更改了其中的一些代码。本文章经历昨晚本人五个小时的手打而成(且还未打完,下班回去继续打,想不到我的打字速度退化得这么快,郁闷!!!),俗话说:好记性不如烂笔头,把书的内容手打出来,对手,对脑,都有好处!!!
![](https://yqfile.alicdn.com/img_31fd33a750d914eb5880614e53b0acea.gif?x-oss-process=image/resize,w_1400/format,webp)
![](https://yqfile.alicdn.com/img_62058d0f7daf9e590a0ad710bb0e370e.gif?x-oss-process=image/resize,w_1400/format,webp)
10.4 应用实例
10.4.1 饼图
统计图是信息管理系统常用的功能,常用的有饼图、柱形图、拆线图等。饼图用来表示各部分比例,柱形图用来表示各部分的比较,拆线图用来表示发展趋势,另外还有其他一些具有特殊功能的图示。本小节将以二维饼图为例说明通过.NET GDI+来绘制统计图的原理。
本例实现效果很简单,即根据给予的一组数据计算出各个数据项的比例,并分别用不同颜色表示,组成一个圆饼,如下图所示:
![](https://yqfile.alicdn.com/img_6688c06f05bb0d4fa1a88510d013fe4d.jpg?x-oss-process=image/resize,w_1400/format,webp)
用户可以使用FillPie来绘制饼块,多个饼块拼接在一起就形成了圆饼效果。其基本算法就是每个部分角度的计算,在总共360°的条件下,每个部分会占多少度。为了方便起见,本例的数据源采用数组,在实例应用过程中,数组数据可以来自数据库,具体代码如下:
Code
int[] arr = {100,35,115,125,75,120 };
// 原书中没有这句,表示不同的颜色
Color[] colors = { Color.BlueViolet,Color.Yellow,Color.Green,Color.Gray,Color.Blue,Color.Purple};
Bitmap bmp = new Bitmap(400,400); // 创建一个图像
Graphics g = Graphics.FromImage(bmp); // 创建Graphics 对象
g.Clear(Color.White); // 白色背景
g.DrawString("本书上半年销售情况", new Font("黑体",16), Brushes.Black, new PointF(5,5)); // 标题
float length = 200;
float currentAngle = 0; // 当前饼块的角度
float totalAngle = 0; // 已画完的饼块的角度和
float totalValues = 0; // 所有值总和
// 所有值求和
foreach (int i in arr)
{
totalValues += i;
}
// 开始画饼块
for (int i = 0; i < arr.Length;i++ )
{
currentAngle = arr[i] / totalValues * 360; // 计算当前饼块角度
g.FillPie(new SolidBrush(colors[i]), 100, 50, length, length, totalAngle, currentAngle); // 填充饼块
// 画饼块边界
g.DrawPie(Pens.Black, 100, 50, length, length, totalAngle, currentAngle);
totalAngle += currentAngle;
}
// 原书示例代码中没有,没有这句则在非IE浏览器会出错
Response.ContentType = "image/GIF";
// 将图形加载到Response中
bmp.Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Gif);
g.Dispose();
上面代码粘贴到Page_Load中,运行页面就可以看到效果中的样子。如果想在饼块的各个部分添加说明文字,可以使用DrawString绘制文字,或者在图的空白处显示图例说明,图例可以使用FillRectangle绘制矩形区域。
10.4.2 水印
在网络中发布资源时,比如图片,很多时候需要保护版权,即在图片上显示版权信息。要实现这样的效果,最简单有效的办法就是给图片添加水印(WaterMark),它和人民币中的水印原理一样,不容易涂改。通过制图软件一张一张地添加水印在技术上固然可行,但是工作量庞大,有时无法适应快速反应的要求,在实际操作中很少采用。在ASP.NET网站中,用户可以利用本小节的知识来实现自动添加水印。这里讲述两种水印:图像水印和文字水印。
图像水印就是在要保护的图片中加入另一个作为水印的图片,即两个图片合二为一,基基本原理就是将一个图片绘制到另一个图片当中,形成一个图片。比如有个风景图片,为了表示版权信息,用户希望在图片的右下角添加说明,如图:
![](https://yqfile.alicdn.com/img_f5c7b96e12cbcfc4bdbe49b6ebe6ed85.jpg?x-oss-process=image/resize,w_1400/format,webp)
在实现代码以前,用户需要先准备好一个作为水印的图片tg029.jpg,一张 需要添加水印的图片Element.jpg。下面的代码利用了Graphics的DrawImage方法将tg029.jpg绘制到Element.jpg中去。
Code
string file = Server.MapPath("~/Element.jpg");
string mark = Server.MapPath("~/tg029.jpg");
// 需要添加水印的图像
System.Drawing.Image img = System.Drawing.Image.FromFile(file);
// 水印图像
System.Drawing.Image imgMark = System.Drawing.Image.FromFile(mark);
// 创建Graphics对象
Graphics g = Graphics.FromImage(img);
// 将水印图像绘制到目标图像中去
g.DrawImage(imgMark,img.Width-imgMark.Width,img.Height-imgMark.Height);
// 原书示例代码中没有,没有这句则在非IE浏览器会出错
Response.ContentType = "image/JPEG";
//将图像加载到Response中
img.Save(Response.OutputStream,System.Drawing.Imaging.ImageFormat.Jpeg);
g.Dispose();
其实,添加水印并没有破坏Element.jpg原图,只是在内存中形成新的图像对象,然后存入响应流中,并发送到客户端显示。这样做即保护了版权,又不损坏原图。
有些时候人们喜欢用图片上加文字的方式来保护版权,参考如下图:
这里可以用DrawString方法来向图片绘制文本。为了使文字不至于影响图片效果,可以将其颜色设置为谈灰色,并适当调整透明度,参考代码如下:
Code
string file = Server.MapPath("~/Element.jpg");
System.Drawing.Image img = System.Drawing.Image.FromFile(file);
// 写文字的笔刷,透明度为100,淡灰色
Brush b = new SolidBrush(Color.FromArgb(100,Color.LightGray));
// 字体设置
FontFamily ff = new FontFamily("华文琥珀");
Font f = new Font(ff, 100, FontStyle.Bold);
// 文字区域左上角坐标
float x = 50;
float y = 50;
Graphics g = Graphics.FromImage(img);
//设置Graphics对象
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
// 文字
g.DrawString("牛腩制作",f,b,new PointF(x,y));
// 原书示例代码中没有,没有这句则在非IE浏览器会出错
Response.ContentType = "image/JPEG";
//将图像加载到Response中
img.Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
g.Dispose();
如果是批量处理图片水印,则反复调用上述代码即可。当然,用户也可以设计出更美观的水印效果,并使用上述方法添加到图片中去。
10.4.3 缩略图
Web应用中最薄弱的环节就是传输,即速度问题。图片格式的数据往往比较大,所以网络中并不适合传输较大的图片。除了采用压缩格式(比如GIF,JPEG等)传输外,还可以使用缩略图的方式加快浏览速度,也可以节省页面空间。使用Image类中的GetThumbnailImage方法可以很方便地生成缩略图,如下面的代码示例:
Code
// 取消操作回调
private bool ThumbnailCallback()
{
return false;
}
// 产生缩略图
private void Thumb(string imgPath, string thumbPath)
{
System.Drawing.Image.GetThumbnailImageAbort myCallback = new System.Drawing.Image.GetThumbnailImageAbort(ThumbnailCallback);
System.Drawing.Image img = System.Drawing.Image.FromFile(imgPath); // 通过文件构造
//生成缩略图
System.Drawing.Image myThumbnail = img.GetThumbnailImage(100,50,myCallback, IntPtr.Zero);
myThumbnail.Save(thumbPath); // 保存缩略图
}
用户可以简单地写一个测试脚本:
Thumb(Server.MapPath(
"
~/Element.jpg
"
), Server.MapPath(
"
~/Element_small.jpg
"
));
程序运行后,即生成了100*100规格的缩略图。如果要批量生成缩略图,多次调用Thumb方法即可。
10.5 本章小结
本章学习了ASP.NET网站中图形绘制的知识,重点在于Graphics对象的使用,由基本图形进而扩展到复杂图形的绘制,最后通过几个实际应用来加深理解。
当然,图形操作最适合于Windows应用程序,由于System.Drawing是.NET基类库的一部分,所以本章内容在Windows应用程序中仍可以适用。