C#的GDI+是处理图形绘制和图片操作的核心技术,通过System.Drawing命名空间下的相关类,我们可以实现动态生成图片、绘制图形、添加文字或图片水印等功能,在验证码生成、图片处理工具开发等场景中应用十分广泛。

GDI+绘图基础准备
使用GDI+绘图前,需要先引入对应的命名空间,核心命名空间为System.Drawing,如果是在.NET Core或.NET 5及以上版本开发,还需要额外安装System.Drawing.Common NuGet包,安装完成后即可使用相关绘图类。
核心绘图类说明
Bitmap:表示位图对象,是绘图的基础载体,我们可以创建新的Bitmap对象作为画布,也可以加载已有的图片作为画布Graphics:绘图上下文对象,所有的绘制操作都需要通过该类的方法完成,比如绘制线条、文字、图形等Brush:画刷类,用于填充图形内部或者绘制文字,常用的有SolidBrush(纯色画刷)、LinearGradientBrush(渐变画刷)等Pen:画笔类,用于绘制线条、图形边框,可设置颜色、宽度、样式等属性Font:字体类,用于设置绘制文字的字体、大小、样式
动态生成图片的实现步骤
动态生成图片的核心流程是创建Bitmap画布,获取对应的Graphics对象,然后通过Graphics的方法绘制内容,最后保存图片到指定路径或者输出到流中。
生成基础纯色背景图片
下面的示例会生成一个宽400、高200的纯色背景图片,并在图片上绘制一段文字:
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
public class ImageGenerator
{
public void GenerateBaseImage()
{
// 创建宽400、高200的位图对象作为画布
using (Bitmap bitmap = new Bitmap(400, 200))
{
// 获取位图的绘图上下文对象
using (Graphics graphics = Graphics.FromImage(bitmap))
{
// 设置绘图质量,让绘制的内容更清晰
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
// 用浅蓝色填充整个画布
using (SolidBrush bgBrush = new SolidBrush(Color.LightBlue))
{
graphics.FillRectangle(bgBrush, 0, 0, bitmap.Width, bitmap.Height);
}
// 绘制文字
using (Font font = new Font("微软雅黑", 16, FontStyle.Bold))
{
using (SolidBrush textBrush = new SolidBrush(Color.DarkRed))
{
// 文字绘制位置,居中显示
StringFormat format = new StringFormat
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center
};
graphics.DrawString("动态生成的图片", font, textBrush, new RectangleF(0, 0, bitmap.Width, bitmap.Height), format);
}
}
}
// 保存图片到指定路径,格式为PNG
bitmap.Save(@"D:test_image.png", System.Drawing.Imaging.ImageFormat.Png);
}
}
}
生成带图形的复杂图片
除了绘制文字,我们还可以在画布上绘制矩形、圆形、线条等基础图形,下面的示例会在画布上绘制一个红色边框的矩形和一个蓝色填充的圆形:
public void GenerateComplexImage()
{
using (Bitmap bitmap = new Bitmap(500, 300))
{
using (Graphics graphics = Graphics.FromImage(bitmap))
{
// 填充白色背景
graphics.Clear(Color.White);
// 绘制红色边框矩形,左上角坐标(50,50),宽200,高150,边框宽度3
using (Pen redPen = new Pen(Color.Red, 3))
{
graphics.DrawRectangle(redPen, 50, 50, 200, 150);
}
// 绘制蓝色填充圆形,圆心坐标(350,150),半径80
using (SolidBrush blueBrush = new SolidBrush(Color.Blue))
{
graphics.FillEllipse(blueBrush, 350 - 80, 150 - 80, 160, 160);
}
}
bitmap.Save(@"D:complex_image.png", System.Drawing.Imaging.ImageFormat.Png);
}
}
给图片添加水印的实现方法
给图片添加水印分为文字水印和图片水印两种,核心思路都是先加载原始图片作为画布,再在画布的指定位置绘制水印内容,最后保存处理后的图片。
添加文字水印
文字水印通常用于标注版权信息、来源等,我们可以设置文字的颜色、透明度、旋转角度,让水印更美观且不影响原图观看:
public void AddTextWatermark(string originalImagePath, string outputPath, string watermarkText)
{
// 加载原始图片
using (Image originalImage = Image.FromFile(originalImagePath))
{
// 创建和原始图片同尺寸的位图对象
using (Bitmap watermarkedBitmap = new Bitmap(originalImage.Width, originalImage.Height))
{
using (Graphics graphics = Graphics.FromImage(watermarkedBitmap))
{
// 先绘制原始图片
graphics.DrawImage(originalImage, 0, 0, originalImage.Width, originalImage.Height);
// 设置文字水印的字体和画刷,设置画刷透明度实现半透明效果
using (Font font = new Font("微软雅黑", 20, FontStyle.Bold))
{
using (SolidBrush textBrush = new SolidBrush(Color.FromArgb(100, Color.Gray)))
{
// 设置水印旋转角度,这里旋转30度
graphics.RotateTransform(30);
// 循环绘制水印,覆盖整个图片
for (int x = -originalImage.Width; x < originalImage.Width * 2; x += 200)
{
for (int y = -originalImage.Height; y < originalImage.Height * 2; y += 100)
{
graphics.DrawString(watermarkText, font, textBrush, x, y);
}
}
}
}
}
// 保存带水印的图片
watermarkedBitmap.Save(outputPath, System.Drawing.Imaging.ImageFormat.Png);
}
}
}
添加图片水印
图片水印通常是企业的logo等小图片,我们可以调整水印图片的透明度,然后放置在原图的右下角等位置:
public void AddImageWatermark(string originalImagePath, string watermarkImagePath, string outputPath)
{
// 加载原始图片和水印图片
using (Image originalImage = Image.FromFile(originalImagePath))
using (Image watermarkImage = Image.FromFile(watermarkImagePath))
{
using (Bitmap watermarkedBitmap = new Bitmap(originalImage.Width, originalImage.Height))
{
using (Graphics graphics = Graphics.FromImage(watermarkedBitmap))
{
// 绘制原始图片
graphics.DrawImage(originalImage, 0, 0, originalImage.Width, originalImage.Height);
// 设置水印图片的透明度,通过调整颜色矩阵实现
float[][] colorMatrixElements = {
new float[] {1, 0, 0, 0, 0},
new float[] {0, 1, 0, 0, 0},
new float[] {0, 0, 1, 0, 0},
new float[] {0, 0, 0, 0.5f, 0}, // 透明度设置为0.5
new float[] {0, 0, 0, 0, 1}
};
ColorMatrix colorMatrix = new ColorMatrix(colorMatrixElements);
using (ImageAttributes imageAttributes = new ImageAttributes())
{
imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
// 水印图片放置在原图右下角,距离右边和下边各20像素
int x = originalImage.Width - watermarkImage.Width - 20;
int y = originalImage.Height - watermarkImage.Height - 20;
graphics.DrawImage(watermarkImage, new Rectangle(x, y, watermarkImage.Width, watermarkImage.Height), 0, 0, watermarkImage.Width, watermarkImage.Height, GraphicsUnit.Pixel, imageAttributes);
}
}
watermarkedBitmap.Save(outputPath, System.Drawing.Imaging.ImageFormat.Png);
}
}
}
注意事项
- 所有实现了
IDisposable接口的对象,比如Bitmap、Graphics、Brush等,都要使用using语句包裹,避免内存泄漏 - 加载外部图片时,要确保图片路径正确,且程序有对应的读写权限,避免抛出文件操作异常
- 在高并发场景下使用GDI+绘图时,要注意线程安全,尽量避免多个线程同时操作同一个绘图对象
- 如果是在Web项目中使用,输出图片到响应流时,要设置正确的Content-Type,比如
image/png