C#利用GDI+画图的基础实例教程

前言

最近做一个微信公众号服务,有一些简单的图片处理功能。主要就是用户在页面操作,前端做一些立刻显示的效果,然后提交保存时后端真正修改原图。

从程序设计的角度看,GDI包括两部分:一部分是GDI对象,另一部分是GDI函数。GDI对象定义了GDI函数使用的工具和环境变量,而GDI函数使用GDI对象绘制各种图形,在C#中,进行图形程序编写时用到的是GDI+(Graphics Device Interface Plus图形设备接口)版本,GDI+是GDI的进一步扩展,它使我们编程更加方便。

C#中的GDI+就相当于java中的Swing控件,是编写图形界面必不可缺的一个接口。GDI+绘图最大的方便得益于C#的可视化编程,所有的控件只需要自己Drag,然后Place,最后Cilck添加监听方法。真的是too young too simple。

我们的后端是 ASP.NET,也就是 C# 语言了,C# 本身处理图片还是比较方便的,使用 GDI+ 就好,只需要添加 System.Drawing 引用,不需要任何第三方库。于是最近也用到一些比较常用的 GDI+ 图片处理方法,就整理一下做个记录了。

这个题目大概会写几篇文章,第一篇先简单介绍一下 GDI+ 的常用对象,以及一些使用时候的注意事项,后面会挑一些项目中做过的比较有用的处理过程来介绍一下。

废话不多说,开始进入正题。

需要用到的类

使用 GDI+ 画图会用到的几个常用的类有:Graphics、Bitmap、Image。

其中 Graphics 是画板。这个类包含了许多画图的方法,包括画图片(DrawImage),画线(DrawLine),画圆(DrawEllipse、FillEllipse),写字(DrawString)等等。简单说使用这个类可以完成我们需要的大部分工作。

生成一个 Graphics 对象需要用到 Image 或者 Bitmap。

PS: Winform 下可以直接从窗体或控件的事件中引用 Graphics 对象。

比如:

 private void Form1_Paint(object sender, PaintEventArgs e)
 {
  Graphics g = e.Graphics; // 创建画板,这里的画板是由Form提供的.
 }

不过本文讨论的是其他场景,比如 ASP.NET MVC,或单纯的控制台程序。这些时候是没有控件的,所以要用其他方法。

我一般用以下方法:

//
// 摘要:
//  从指定的 System.Drawing.Image 创建新的 System.Drawing.Graphics。
//
// 参数:
// image:
//  从中创建新 System.Drawing.Graphics 的 System.Drawing.Image。
//
// 返回结果:
//  此方法为指定的 System.Drawing.Image 返回一个新的 System.Drawing.Graphics。
//
// 异常:
// T:System.ArgumentNullException:
//  image 为 null。
//
// T:System.Exception:
//  image 具有索引像素格式,或者格式未定义。
public static Graphics FromImage(Image image);

其中的参数可以传入 Image 或 Bitmap,因为 Bitmap 是继承自 Image 的。

如何创建画板

如果是要对原图进行处理,比如旋转图片,添加文字等,可以直接通过原图片获得画板对象。

Image img = Image.FromFile(imgPath);
Graphics graphics = Graphics.FromImage(img);

如果是要画一个新的图,可以通过要保存的图片宽、高生成画板。

Bitmap bmp = new Bitmap(width, height);
Graphics graph = Graphics.FromImage(bmp);

PS: Graphics 本身是没有提供构造函数来直接生成的。所以我们可以先创建一个需要保存图片大小的 Bitmap 位图对象,然后再获得画板对象。

如何保存画好的图片

通过调用 img.Save(savePath) 或者 bmp.Save(savePath) 即可保存对象。

PS: Bitmap 的 Save 方法是直接继承自 Image 的。

GDI+ 的坐标系

GDI+ 的坐标系是个二维坐标系,不过又有点不一样,它的原点是在左上角的。如下图:

使用 GDI+ 的一些注意事项

这里我忍不住要先吐槽一下,GDI+ 的报错信息不太友好啊。经常只是返回一个“GDI+ 中发生一般性错误。”,不能快速地根据这个错误提示定位问题。比如说没有释放图片资源时想再次访问资源会报这个错误,想要保存图片的文件夹不存在时也是提示这个错误。看不出来区别……

1. 保存到相同路径的文件时要先释放图片资源,否则会报错(GDI+中发生一般性错误)

Image img = Image.FromFile(imgPath);
Bitmap bmp = new Bitmap(img);
Graphics graphics = Graphics.FromImage(bmp);
... // 对图片进行一些处理
img.Dispose(); // 释放原图资源
bmp.Save(imgPath); // 保存到原图
graphics.Dispose(); // 图片处理过程完成,剩余资源全部释放
bmp.Dispose();

2. 使用完的资源记得要释放。可以用 try..catch..finally 或者 using 的方式,这样即使遇到代码运行报错也能及时释放资源,更加保险。

try..catch...finally:把释放资源的代码写到 finally 代码段里。

Image img = Image.FromFile(imgPath);
Bitmap bmp = new Bitmap(img);
Graphics graphics = Graphics.FromImage(bmp);
try
{
 ...
}
catch (System.Exception ex)
{
 throw ex;
}
finally
{
 graphics.Dispose();
 bmp.Dispose();
 img.Dispose();
}

using:使用 using 语句创建的资源会在离开 using 代码段时自动释放该资源。

/// <summary>
/// 缩放图像
/// </summary>
/// <param name="originalImagePath">原图路径</param>
/// <param name="destWidth">目标图宽度</param>
/// <param name="destHeight">目标图高度</param>
/// <returns></returns>
public Bitmap GetThumbnail(string originalImagePath, int destWidth, int destHeight)
{
 using (Image imgSource = Image.FromFile(originalImagePath))
 {
  return GetThumbnail(imgSource, destWidth, destHeight);
 }
}

3. 要保存图片的文件夹一定要是已经存在的,否则会报错(GDI+中发生一般性错误)

eg:假设图片要保存到 D:\test\output.png

 string directory = @"D:\test\";
 string fileName = "output.png";
 // 检查文件夹是否存在,不存在则先创建
 if (!Directory.Exists(directory))
 {
  Directory.CreateDirectory(directory);
 }
 bmp.Save(directory + fileName);

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • C#控件picturebox实现画图功能

    本文实例为大家分享了C# picturebox实现画图功能的具体代码,供大家参考,具体内容如下 在Form上添加 一个pictureBox,一个button控件 如图所示: 这样我们的绘画面板就弄好了,把pictureBox的dock属性设置为fill,按键为清屏的作用. private Point p1, p2;//定义两个点(启点,终点) private static bool drawing=false;//设置一个启动标志 private void pictureBox1_MouseDo

  • 使用C#实现在屏幕上画图效果的代码实例

    以下这段C#代码实现的功能是在屏幕上画图的效果!具体代码如下: 复制代码 代码如下: //DllImport所在的名字空间 using System.Runtime.InteropServices;[DllImport("User32.dll")]public extern static System.IntPtr GetDC(System.IntPtr hWnd);  private void button19_Click(object sender, EventArgs e){  

  • C#画图之饼图折线图的实现方法

    本文实例讲述了C#画图之饼图折线图的实现方法,是C#程序设计中非常实用的技巧.分享给大家供大家参考.具体方法分析如下: 显示图像的控件定义如下: public PlaceHolder PlaceHolder1; 各个图像的类别名称如下: PictureType    图形种类    5    chChartTypeBarClustered    簇状条形图    0    NULL PictureType    图形种类    7    chChartTypeBarClustered3D   

  • C#控件picturebox实现图像拖拽和缩放

    本文实例为大家分享了C# picturebox实现图像拖拽和缩放的具体代码,供大家参考,具体内容如下 1.核心步骤: ①新建Point类型全局变量mouseDownPoint,记录拖拽过程中鼠标位置: ②MouseDown事件记录Cursor位置: ③MouseMove事件计算移动矢量,并更新pictureBox1.Location. 代码: private void pictureBox1_MouseDown(object sender, MouseEventArgs e) { if (e.B

  • c# 给button添加不规则的图片以及用pictureBox替代button响应点击事件的方法

    1.Flat button 用这个方法,前提是要把button的type设置为Flat 复制代码 代码如下: button1.TabStop = false;button1.FlatAppearance.BorderSize = 0;button1.FlatAppearance.BorderColor = Color.FromArgb(0, 255, 255, 255); //设置边框的颜色Transparentbutton1.FlatAppearance.MouseOverBackColor

  • C#利用GDI+画图的基础实例教程

    前言 最近做一个微信公众号服务,有一些简单的图片处理功能.主要就是用户在页面操作,前端做一些立刻显示的效果,然后提交保存时后端真正修改原图. 从程序设计的角度看,GDI包括两部分:一部分是GDI对象,另一部分是GDI函数.GDI对象定义了GDI函数使用的工具和环境变量,而GDI函数使用GDI对象绘制各种图形,在C#中,进行图形程序编写时用到的是GDI+(Graphics Device Interface Plus图形设备接口)版本,GDI+是GDI的进一步扩展,它使我们编程更加方便. C#中的G

  • Android利用OpenGLES绘制天空盒实例教程

    前言 天空盒这个效果最早是在腾讯的实景地图里看到的,当时觉得很牛逼,但是没有想过自己去实现以下.最近这段时间对opengl很有兴趣,顺便就搞了这个天空盒,话不多说,先上效果. 天空盒的原理就是在三维空间中放置一个正方体,然后将我们的相机放置在正方体内,当我们的视点转动,相机跟着转动.我们就可以看到相应的景色的变换了,天空盒本质上是一个立方体. OpenGL 关于什么是OpenGL,什么是OpenGLES就不细说了,不了解的就自行百度吧,我们主要是关注代码.整个项目采用了Kotlin + Ndk的

  • C#利用GDI+绘制旋转文字等效果实例

    本文实例讲述了C#利用GDI+绘制旋转文字等效果的方法,是非常实用的技巧.分享给大家供大家参考之用.具体如下: C#中利用GDI+绘制旋转文本的文字,网上有很多资料,基本都使用矩阵旋转的方式实现.但基本都只提及按点旋转,若要实现在矩形范围内旋转文本,资料较少.经过琢磨,可以将矩形内旋转转化为按点旋转,不过需要经过不少的计算过程.利用下面的类可以实现该功能. 具体实现代码如下: using System; using System.Collections.Generic; using System

  • Yii2 rbac权限控制之菜单menu实例教程

    在上篇文章给大家介绍了yii2搭建完美后台并实现rbac权限控制实例教程中完美实现了yii2的后台搭建和rbac权限控制,如果你还没有实现,请先看上文再回来参考本文,因为本文是在上文的基础上进行完善和补充. 部分小伙们纷纷反映,最后菜单menu怎么控制权限呀,看不懂,搞不定,而且你那貌似没搞完,瞎忽悠!确实没那么全,今天看我们如何实现菜单完美权限化.先罗列下主要讲的内容,不需要的没必要看下去,只为分享给有需要的人. 利用menu表添加菜单 左侧菜单结果adminlte完美呈现 菜单前面自定义ic

  • Spring MVC+FastJson+Swagger集成的完整实例教程

    基础部分 1. FastJson 简介 Fastjson是一个Java库,可用于将Java对象转换为JSON表示.它也可以被用来将一个JSON字符串转换成一个等效的Java对象.在转换速度上应该是最快的,几乎成为了项目的标配(在ajax请求和接口开发时一般都会用fastjson而不再使用jackson). GitHub: https://github.com/alibaba/fastjson (本地下载) 特性: 在服务器端和android客户端提供最佳性能 提供简单toJSONString()

  • Spring MVC+FastJson+hibernate-validator整合的完整实例教程

    一:hibernate-validator 基础 1. 简介: 通过使用注解Annotations 给类或者类的属性加上约束(constraint),在运行期检查属性值的合法性. 2. 作用: 在API接口开发中参数校验是非常重要的事情,因为客户端很可能会少传参数,或者值不合法,甚至参数值是恶意的,所以对客户端传来的参数的合法性就必须要校验了,其中将参数值的校验规则通过注解的形式注解到属性上是一种比较优雅的方式. 3. 常用的约束注解 @Null 被注释的元素必须为 null @NotNull

  • python绘图模块之利用turtle画图

    模块之turtle 小故事 前两天朋友说:"常文啊!听说你会python,那能不能用python画一些好看的图呢?"然后我特意去学了一下turtle模块,现在给大家分享一下. 一.什么是turtle Turtle是python内嵌的绘制线.圆以及其他形状(包括文本)的图形模块. 二.turtle函数的使用 import turtle turtle.pendown() # 放下画笔 turtle.penup() # 抬起画笔 turtle.pensize(int) # 设置画笔宽度,值为

  • Python并发编程实例教程之线程的玩法

    目录 一.线程基础以及守护进程 二.线程锁(互斥锁) 三.线程锁(递归锁) 四.死锁 五.队列 六.相关面试题 七.判断数据是否安全 八.进程池 & 线程池 总结 一.线程基础以及守护进程 线程是CPU调度的最小单位 全局解释器锁 全局解释器锁GIL(global interpreter lock) 全局解释器锁的出现主要是为了完成垃圾回收机制的回收机制,对不同线程的引用计数的变化记录的更加精准. 全局解释器锁导致了同一个进程中的多个线程只能有一个线程真正被CPU执行. GIL锁每执行700条指

  • Leaflet 基础入门教程示例

    目录 什么是Webgis? 什么是Leaflet? 在Vue中安装Leaflet,与其他依赖 在App.vue中使用 初始化地图 chinaProvider地图瓦片 addControls使用工具集 attribution创建自定义版权 Marker创建点 创建线 Polygon创建三角形 Popup弹窗&Tooltip提示 Geojson区域描边 总结 什么是Webgis? webGis又称之为网络地理信息系统,GIS的全名是Geographic Information System,它是在计

  • Bootstrap零基础入门教程(三)

    什么是 Bootstrap? Bootstrap 是一个用于快速开发 Web 应用程序和网站的前端框架.Bootstrap 是基于 HTML.CSS.JAVASCRIPT 的. 历史 Bootstrap 是由 Twitter 的 Mark Otto 和 Jacob Thornton 开发的.Bootstrap 是 2011 年八月在 GitHub 上发布的开源产品. 写到这里,这篇从零开始学Bootstrap(3)我想写以下几个内容: 1. 基于我对Bootstrap的理解,做一个小小的总结.

随机推荐