C# 绘制验证码图片

一、需求

         为.Net Core Web Api 项目的前端登录页面绘制一张验证码图片,验证码图片包含4位由字母或数字组成的验证码,且需要具有纹底和干扰线增强验证码的识别难度。

二、绘图所需的类

        绘制图片需要使用 GDI+ ,GDI+(Graphics Device Interface Plus)是C#编程语言中的一个图形绘制类库,该类库库提供了一系列与图形绘制相关的类。

        现实中为了得到一幅画,我们需要准备画纸、绘画工具、颜料等,最后由画家使用这些材料在画纸上描绘出图形,文字等元素。

       GDI+ 中的类是对现实绘画的抽象,可以分为以下几种:

1、画纸类

BitMap(int width, int height)

BitMap是Image类的子类,图像由许多像素点组成的,BitMap对象便是以像素点来表示图像。

创建一个长度为300px,宽度为100px的图像对象(默认像素点为黑色)

BitMap image = new BitMap(300,100);
//创建了一张长300px,宽100px的纯黑色基础图像。

2、画面元素类

(1)点 Point (int x, int y)

创建一个点对象,该点的坐标为(x, y)

Point point = new Point(0,0);

补充:坐标原点 (0,0) 在屏幕左上角。

(2)矩形 Rectangle (int x, int y, int width, int height)

创建一个矩形对象,该矩形左上顶点与坐标原点 (0, 0)重合,宽度为300px,高度为100px。

Rectangle rectangle = new Rectangle(0, 0, 300, 100);
(3)字体 Font(string familyName, float emSize, System.Drawing.FontStyle style)

创建字体对象并设置字体家族、字号大小、风格等属性

Font font = new Font("Georgia", 30, (FontStyle.Bold | FontStyle.Italic)); 
//字体属性:微软雅黑,字号30,加粗,斜体

3、绘画工具类

(1)纹理刷 TextureBrush (Image image)

创建一个带有纹理的画刷对象,纹理从指定的图片中提取。

Image TextTureImage = Image.FromFile("./StaticDataSource/TextTure.jpg");

TextureBrush textureBrush = new TextureBrush(TextTureImage);

TextTure.jpg如下:

(2)线性变化刷 LinearGradientBrush(Point point1, Point point2,Color color1, Color color2)

创建一个颜色渐变的画刷对象,用此画刷书写可以写出颜色渐变的文字。

LinearGradientBrush brush = new LinearGradientBrush(new Point(0, 0), new Point(300, 100), Color.Blue, Color.DarkRed);

补充:渐变方向为左上角(point1)到右下角(point2),渐变颜色由蓝色(Blue)到暗红(DarkRed)。

4、画家类Graphics

Graphics的方法如下:

(1)static Graphics FromImage(Image image)

该方法返回graphics对象,该graphics对象与参数image对象绑定,调用graphics对象的方法可以往image对象输入画面元素。

BitMap image = new BitMap(300,100);

Graphics graphics = Graphics.FromImage(image);//绑定基础图像image

备注:可以理解为画家与画纸绑定后,画家才能使用绘画工具在画纸上作画。

(2)void FillRectangle (TextureBrush textureBrush, Rectangle rectangle)

画家使用纹理刷(textureBrush),在画纸上刷出一个矩形(rectangle)。

(3)DrawString(string s,Font font, Brush brush, float x, float y)

画家使用画刷(brush),在纸上的指定坐标点(x, y),写下字符串s,且字体样式为font。

三、代码实现

1、后端接口

[HttpGet]
public ActionResult GetCaptchaImage() {

    //创建基础图像,宽300px,高100px
    Bitmap image = new Bitmap(300, 100);

    //将基础图像和画家对象绑定
    Graphics graphics = Graphics.FromImage(image);

    //创建纹理刷
    Image TextTureImage = Image.FromFile("./StaticDataSource/TextTure.jpg");
    TextureBrush textureBrush = new TextureBrush(TextTureImage);

    //创建一个矩形,矩形的左上顶点坐标为(0,0),右下顶点坐标为(300,100)
    Rectangle rectangle = new Rectangle(0, 0, 300, 100);

    //画家使用纹理刷,在基础图像上刷出一个矩形            
    graphics.FillRectangle(textureBrush, rectangle);

    //创建渐变画刷
    LinearGradientBrush brush = new LinearGradientBrush(new Point(0, 0),new Point(300,100), Color.Blue, Color.DarkRed);
    
    //自定义的GenerateCode方法生成验证码数据,此处为["J","j","F","5"]
    ArrayList codeList = GenerateCode();

    int x = 40;
    foreach (string code in codeList)
    {
        //画家使用渐变画刷书写字符code,字符字体为font,字符坐标为(x,30)
        graphics.DrawString(code, font, brush, x, 30);

        //字符的横坐标需要增加,否则字符会叠在一起
        x += 60;
    }

    //在验证码上画2根不同颜色的干扰线,需要4个点,2支笔
    Point p1 = new Point(0, 70);
    Point p2 = new Point(300, 60);
    Pen pen1 = new Pen(Color.Green, 2);//设置笔的颜色和宽度
    
    Point p3 = new Point(0, 50);
    Point p4 = new Point(300, 60);
    Pen pen2 = new Pen(Color.Gray, 2);

    //画家使用pen1,画第1条干扰线
    graphics.DrawLine(pen1, p1, p2);

    //画家使用pen2,画第2条干扰线
    graphics.DrawLine(pen2, p3, p4);

    MemoryStream stream = new MemoryStream();
    
    //完成绘制,将图像image以.png格式保存到内存流stream中
    image.Save(stream, ImageFormat.Png);

    //销毁graphics对象和笔对象
    graphics.Dispose();
    pen1.Dispose();
    pen2.Dispose();
    
    //往redis中存验证码字符串并设置过期时间,用于登录时校验验证码,此处省略。
   
    //将stream转为字节流数组返给前端
    return Ok(stream.ToArray());
}

private ArrayList GenerateCode()
{
    ArrayList code = new ArrayList();
    string[] chars = 
    { 
        "A","B","C","D","E","F","G","H","I","J","K","L",
        "M","N","P","Q","R","S","T","U","V","W","X","Y","Z",
        "a","b","c","d","e","f","g","h","i","j","k","l",
        "m","n","p","q","r","s","t","u","v","w","x","y","z",
        "1","2","3","4","5","6","7","8","9"
    };
    Random random = new Random();
    for (int i = 0; i <4; i++) { 
        int j = random.Next(0,chars.Length);
        code.Add(chars[j]);
    }
    return code;
}

2、前端Vue3

<img :src="codeUrl" @click="getCode"/>

<script lang="ts" setup>
    const getCode = async () => {
        await axios.get('https://localhost:7106/Captcha/GetCaptchaImage')
        .then(res => { codeUrl.value = "data:image/gif;base64," + res.data })
    }
</script>

注意:前端需要添加 "data:image/gif;base64," 前缀,将后端返回的字节数组转为base64字符串,才能被<image>标签识别为图片。

四、补充

        绘制图片需要用到多种GDI+中的类型,初学时比较难以理解。本文为求通俗易懂使用了较多的个人理解,表述上没有官方文档严谨,建议读者以微软官方文档为准。

        微软官方文档地址:

Bitmap Class (System.Drawing) | Microsoft Learn

  • 36
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值