完成的步骤 NET生成动态验证码
前言
验证码就是在图片上写几个字,然后对这些字做特殊处理,比如扭曲、旋转、修改字的位置,然后加上一些线条或者加上一些特效,这样这些字就可以被人类正常识别,但是机器很难识别,从而达到防止爬行动物和机器人的效果。
验证码通常用于网站,是防止爬虫和机器人入侵的好方法。过去,在中创建验证码时。NET,我们通常使用系统。绘制创建“正常”验证码。
在之前的博客中。NET中,提出了一种更好的水印生成方法,即如何对图片进行水印。基于之前的博客,本文将进一步探讨使用Direct2D创建验证码。
系统的传统实践。图画
前提条件:参考系统。绘制或安装NuGet包:系统。绘图。常见:
包引用包含='系统。drawing.common ' version=' 4 . 5 . 1 '/首先创建一个包含几个单词的图片(基本操作):
byte[] GetImage(int width,int height,string text){使用(var bitmap=new Bitmap(width,height))使用(var g=Graphics)。FromImage(位图)){ var r=new Random();g . Clear(ColorFromHsl(r . NextDouble(),1.0f,0.8f,0x ff));var笔刷=新的SolidBrush(颜色。黑色);var fontSize=宽度/文本。长度;var font=新字体(FontFamily。GenericSerif,fontSize,FontStyle。粗体,图形单位。像素);for(var I=0;我发短信。长度;i ) {画笔。color=color from HSL(r . NextDouble(),1.0f,0.3f,0xff);float x=i * fontSizefloat y=r.Next(0,height-font size);g .拉绳(文字[i]。ToString(),字体,画笔,x,y);}//添加一些其他效果。var ms=new memory stream();位图。保存(毫秒,图像格式。png);返回ms . ToArray();}}效果(Gif由LINQPad多次生成,但实际上是静态图片):
然后添加一些行:
使用(var pen=new Pen(画笔,3)){ for(var I=0;i4;i) {钢笔。color=color from HSL(r . NextDouble(),1.0f,0.4f,0xff);var p1=新点(下一个(宽度),下一个(高度));var p2=新点(下一个(宽度),下一个(高度));g .画线(钢笔,p1,p2);}}效果(Gif由LINQPad多次生成,但实际上是静态图片):
我还能做什么?
不幸的是,还有很多事情可以做。即使添加了线条,机器仍然可以轻松识别它们。
然而,Edi。王还在博客中发布了一个用于生成验证码的NuGet包:Edi。验证码,最新版本是1.3.1:
包参考包括=' edi.captcha '版本=' 1 . 3 . 1 '/此包基于System。画图,加入失真效果和一些随机的x坐标偏移量,大大增加了AI识别的难度。
用法:
验证码结果=验证码图像生成器。GetImage(200,100,' HELLO ');验证码结果的定义如下:
公共类验证码结果{公共字符串验证码{ get设置;} public byte[]CaptchaByteData { get;设置;}公共字符串CaptchBase64Data=Convert。tobase64 string(CaptchaByteData);公共日期时间时间戳{ get设置;}}生成的效果如下(Gif由LINQPad多次生成,但实际上是静态图片):
Direct2D
在之前的博客中,已经有过关于Direct2D的简单介绍。这里就不介绍了。
从最简单的图片开始写:
byte[] SaveD2DBitmap(int宽度、int高度、字符串文本){ 0使用新wic .imagegfactory2();使用var d2d=新d2d .工厂();使用var wicBitmap=新WIC .位图(wic,宽度,高度WIC .WIC,格式32bppPBGRA .BitmapCreateCacheOption。CacheOnDemand);使用var目标=新D2D .wirendertarget(d2d,wicBitmap,新d2d .RenderTargetProperties());使用var dwriteFactory=new SharpDX .DirectWrite。工厂();使用var brush=新的SolidColorBrush(目标,颜色。黄色);var r=new Random();目标. BeginDraw();目标clear(colorformhsl(r . NextFloat(0,1),1.0f,0.3f));var textFormat=new DWrite .文本格式(dwriteFactory,Times New Roman,DWrite .字体粗细。粗体,粗体。字体样式。正常,宽度/文本。长度);for(int charIndex=0;定位文本。长度;charIndex){ 0使用定义变量布局=新DWrite .文本布局(目录,文本[charIndex].ToString(),textFormat,float .最大值,浮点.MaxValue);var layoutSize=new Vector2(布局。度量。宽度,布局。度量标准。高度);使用var b2=新的LinearGradientBrush(目标,新D2D .linegradientbrush属性{起点=矢量2 .Zero,EndPoint=layoutSize,},新渐变停止集合(target,new[]{新渐变停止{位置=0.0f,Color=来自HSL的颜色(r .下一个浮点(0,1,1.0f,0.8f))},新渐变停止{位置=1.0f,Color=来自HSL的颜色(r .下一个浮点(0,1,1,1.0f,0.8f) },});var位置=新向量2(charIndex *宽度/文本).长度,r.NextFloat(0,高度-布局。度量。高度));目标变换=矩阵3x2 .翻译(-layoutSize/2) * //文字旋转和扭曲效果,取消注释以下两行代码//矩阵x2 .偏斜(r.NextFloat(0,0.5f),r.NextFloat(0,0.5f)) * //Matrix3x2 .旋转(r.NextFloat(0,MathF .PI * 2)) * Matrix3x2 .翻译(位置layoutSize/2);目标绘图文本布局(矢量2 .零,布局,B2);} //其它效果在这里插入目标EndDraw();使用(var编码器=新WIC .位图编码器(wic威奇ContainerFormatGuids。Png))使用(var ms=新内存流()){编码器.初始化(毫秒);使用(var框架=新WIC .BitmapFrameEncode(编码器)){ frame .初始化();框架设置大小(位图).尺寸,宽度,位图。尺寸。高度);var pixelFormat=wicBitmap .像素格式;框架设置像素格式(参考像素格式);框架写入源(WicBitmap);框架commit();}编码器commit();返回ToArray女士();}}使用方式:
byte[]captchaBytes=保存的d2dbitmap(200,100,' Hello ');效果(Gif是由LINQPad生成多次截图而来,实际为静态图):
可以注意到Direct2D生成的文字没有系统。图画那样的锯齿。
如果取消里面的两行注释,可以得到更加扭曲和旋转的效果(Gif是由LINQPad生成多次截图而来,实际为静态图):
然后加入线条:
for(var I=0;i4;i){目标.Transform=Matrix3x2 .身份;刷子. color=来自HSL的颜色(r . NextFloat(0,1),1.0f,0.3f);目标。画线(下一个向量2 .零,新矢量2(宽度,高度)),下一个矢量2(矢量2)。零,新Vector2(宽度,高度)),画笔,3.0f);}效果(Gif是由LINQPad生成多次截图而来,实际为静态图):
Direct2D的骚操作
Direct2D中内置了许多特效,如阴影(阴影)等,这里我们需要用到的是位移特效(位移)和水流特效(湍流),为了实现特效,需要加入一个位图层,整体代码如下:
byte[] SaveD2DBitmap(int宽度、int高度、字符串文本){ 0使用新wic .imagegfactory2();使用var d2d=新d2d .工厂();使用var wicBitmap=新WIC .位图(wic,宽度,高度WIC .WIC,格式32bppPBGRA .BitmapCreateCacheOption。CacheOnDemand);使用var目标=新D2D .wirendertarget(d2d,wicBitmap,新d2d .RenderTargetProperties());使用var dwriteFactory=new SharpDX .DirectWrite。工厂();使用定义变量笔刷=新D2D .SolidColorBrush(目标,颜色。黄色);使用定义变量编码器=新WIC .PngBitmapEncoder(wic);//PngBitmapEncoder使用var ms=新内存流();使用无功直流=目标值.查询界面2d。设备上下文();使用var bmpLayer=新D2D .位图1(直流,目标。新D2D的像素大小。位图属性1(新D2D .像素格式D2D .AlphaMode。预乘),d2d .桌面宽度d2d .身高D2D .BitmapOptions。目标));var r=new Random();编码器。初始化(毫秒);D2D .Image oldTarget=dc .目标;{ dc .Target=bmpLayer华盛顿. BeginDraw();var textFormat=new DWrite .文本格式(dwriteFactory,Times New Roman,DWrite .字体粗细。粗体,粗体。字体样式。正常,宽度/文本。长度);for(int charIndex=0;定位文本。长度;charIndex){ 0使用定义变量布局=新DWrite .文本布局(目录,文本[charIndex].ToString(),textFormat,float .最大值,浮点.MaxValue);var layoutSize=new Vector2(布局。度量。宽度,布局。度量标准。高度);使用var b2=新D2D .新D2D特区linegradientbrush属性{起点=矢量2 .零,端点=layoutSize,},新D2D .gradientstopcollution(DC,新[] {新D2D .新GradientStop {位置=0.0f,颜色=colorformhsl(r . next float(0,1),1.0f,0.8f) } .GradientStop{ Position=1.0f,Color=colorformhsl(r . NextFloat(0,1),1.0f,0.8f) },});var位置=新向量2(charIndex *宽度/文本).长度,r.NextFloat(0,高度-布局。度量。高度));华盛顿变换=矩阵3x2 .翻译(-layoutSize/2) * Matrix3x2 .偏斜(r.NextFloat(0,0.5f),r.NextFloat(0,0.5f)) * //Matrix3x2 .旋转(r.NextFloat(0,MathF .PI * 2)) * Matrix3x2 .翻译(位置layoutSize/2);华盛顿绘图文本布局(矢量2 .零,布局,B2);} for(var I=0;i4;i) {目标.Transform=Matrix3x2 .身份;刷子. color=来自HSL的颜色(r . NextFloat(0,1),1.0f,0.3f);目标。画线(下一个向量2 .零,新矢量2(宽度,高度)),下一个矢量2(矢量2)。零,新Vector2(宽度,高度)),画笔,3.0f);}目标EndDraw();}颜色背景=ColorFromHsl(r.NextFloat(0,1),1.0f,0.3f);//for(var FrameID=-10;frameId 10frameId) { dc .目标=空使用定义变量位移=新D2D .效果位移图(DC);位移SetInput(0,bmpLayer,true);位移。比例尺=100.0f//数学ABS(FrameID)* 10.0 f;新D2D .效果。湍流(直流);位移SetInputEffect(1,湍流);华盛顿目标=旧目标华盛顿. BeginDraw();华盛顿。清晰(背景);华盛顿DrawImage(位移);华盛顿EndDraw();使用(var框架=新WIC .BitmapFrameEncode(编码器)){ frame .初始化();框架设置大小(位图).尺寸,宽度,位图。尺寸。高度);var pixelFormat=wicBitmap .像素格式;框架设置像素格式(参考像素格式);框架写入源(WicBitmap);框架commit();} }编码器commit();返回ToArray女士();}注意此代码使用了使用定义变量语句,是C# 8.0的使用声明功能,可以用使用(var)语句代替。
效果如下(Gif是由LINQPad生成多次截图而来,实际为静态图):
在此基础上,(感谢Direct2D/WIC)经过较小的改动,即可生成一个动态的可交换的图像格式图片。
只要略微修改以上代码:
将PngBitmapEncoder改成GifBitmapEncoder *然后将下面的为循环取消注释将位移。比例尺=100.0f改成位移。比例=数学ABS(FrameID)* 10.0 f;即可看到以下效果(直接生成,非截图):
结论
最终的代码生成效果可以在这里下载,用LINQPad 6打开。
本文采用SharpDX作为C#到DirectX的转换层。坏消息是上图使用的SharpDX已经停止维护,但是还没有找到替换库(可能是因为太好用了)。
我曾经在游戏中使用Direct2D,但是最近越来越多的使用Direct2D来解决实际问题。由于Direct2D的高价值和高性能,实际上Direct2D无处不在,浏览器/Word/Excel等日常软件与Direct2D深度融合。相信Direct2D可以用在更多的场景中。
摘要
以上就是本文的全部内容。希望本文的内容对大家的学习或工作有一定的参考价值。谢谢你的支持。
版权声明:完成的步骤 NET生成动态验证码是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。