https://www.cnblogs.com/Easy999000/articles/17293649.html
前言
在之前的开发当中,一直使用.net自带的库生成图片验证码.老代码也使用了好多年了.但是到了.netcore时代..net要开始跨平台了.开发的系统要考虑到既可以部署到Windows系统上,也可以部署到Linux系统上(centeros,ubuntu).
.net内部自带的图形类库依赖于Windows的一些系统组件,想要同时兼容windows系统又要兼容Linux系统,变得非常困难.
.net已经在官方文档明确提出,不建议在Linux系统上使用.net自带的图形类库,但是在netcore6.0框架及之前,可以强行开启(报错不负责). netcore7.0及之后的版本,彻底放弃Linux的图形类库功能.
为了防止系统升级后功能受到影响,所以项目决定提前升级图片验证码的功能.
这里采用.net官方推荐的一个框架.SkiaSharp.
实现
验证码做了混淆处理,对文字的位置,角度,颜色,做了变换.
加入了带有颜色的干扰线.
可以实现简单的图片识别程序的防范.
/// <summary>
/// 图片验证码
/// </summary>
public class ImageVerificationCode
{
public ImageVerificationCode(int Width, int Height)
{
// crate a surface
var info = new SKImageInfo(Width, Height);
Surface = SKSurface.Create(info);
///设置字体,解决乱码
var fontManager = SKFontManager.Default;
EmojiTypeface = fontManager.MatchCharacter('赵');
Random1 = new Random();
}
SKSurface Surface;
SKTypeface EmojiTypeface;
Random Random1;
/// <summary>
/// 背景色
/// </summary>
public byte BackColorR = 185;
/// <summary>
/// 背景色
/// </summary>
public byte BackColorG = 185;
/// <summary>
/// 背景色
/// </summary>
public byte BackColorB = 185;
/// <summary>
/// 防靠色偏差值
/// </summary>
public byte BackOffset = 40;
/// <summary>
/// 字体大小
/// </summary>
int TextSize = 30;
/// <summary>
/// R限制范围
/// </summary>
public (byte begin, byte end, byte length) BoundsR
{
get
{
return Bounds(BackColorR);
}
}
/// <summary>
/// R限制范围
/// </summary>
public (byte begin, byte end, byte length) BoundsG
{
get
{
return Bounds(BackColorG);
}
}
/// <summary>
/// R限制范围
/// </summary>
public (byte begin, byte end, byte length) BoundsB
{
get
{
return Bounds(BackColorB);
}
}
/// <summary>
/// 颜色取值,限制范围
/// </summary>
/// <param name="Value"></param>
/// <returns></returns>
private (byte begin, byte end, byte length) Bounds(byte Value)
{
(byte begin, byte end, byte length) res = (0, 0, 0);
res.begin = (byte)Math.Max(0, Value - BackOffset);
res.end = (byte)Math.Min(255, Value + BackOffset);
res.length = (byte)(res.end - res.begin);
return res;
}
/// <summary>
/// 清除图像,保留背景色
/// </summary>
public void Clear()
{
// the the canvas and properties
var canvas = Surface.Canvas;
// make sure the canvas is blank
canvas.Clear(new SKColor(BackColorR, BackColorG, BackColorB));
}
/// <summary>
/// 写文字
/// </summary>
/// <param name="Text"></param>
public void WriteText(string Text)
{
var canvas = Surface.Canvas;
var xPoint = 6;///x点
var yPoint = (Surface.Canvas.DeviceClipBounds.Height + TextSize) / 2; ///y点
// draw some text
var paint = new SKPaint
{
Color = SKColors.Black,
IsAntialias = true,
Style = SKPaintStyle.Fill,
TextAlign = SKTextAlign.Left,
TextSize = TextSize,
TextEncoding = SKTextEncoding.Utf8,
Typeface = EmojiTypeface,
StrokeWidth = 3
// TextSkewX = 3
};
for (int i = 0; i < Text.Length; i++)
{
///偏移
int xOffset = Random1.Next(-TextSize * 2 / 10, 1);///x偏移
int yOffset = Random1.Next(-3, 3);///y偏移
int angleOffset = Random1.Next(-15, 15);///角度偏移
paint.Color = RandColoe();///随机颜色
canvas.RotateDegrees(angleOffset, xPoint + xOffset, yPoint + yOffset);
canvas.DrawText(Text[i].ToString(), xPoint + xOffset, yPoint + yOffset, paint);
canvas.RotateDegrees(-angleOffset, xPoint + xOffset, yPoint + yOffset);
// xPoint = xPoint + xOffset + TextSize;
xPoint = xPoint + TextSize + xOffset;
}
}
/// <summary>
/// 混淆
/// </summary>
public void Confuse(uint Count)
{
// the the canvas and properties
var canvas = Surface.Canvas;
for (int i = 0; i < Count; i++)
{
int x = Random1.Next(0, canvas.DeviceClipBounds.Width);
int y = Random1.Next(0, canvas.DeviceClipBounds.Height);
int radius = Random1.Next(TextSize, TextSize * 2);
var paint = new SKPaint
{
Color = RandColoe(),///随机颜色
IsAntialias = true,
Style = SKPaintStyle.Stroke,
TextAlign = SKTextAlign.Left,
TextSize = TextSize,
TextEncoding = SKTextEncoding.Utf8,
Typeface = EmojiTypeface,
StrokeWidth = 1
// TextSkewX = 3
};
canvas.DrawCircle(x, y, radius, paint);
}
}
/// <summary>
/// 生成和背景具有区分的随机颜色
/// </summary>
/// <returns></returns>
private SKColor RandColoe()
{
///随机颜色,以背景色为基准,,取随机值,防止靠色
///0 128 256
///r值
var r = Random1.Next(0, 255 - BoundsR.length);
if (r > BoundsR.begin && r < BoundsR.end)
{
r = (r + BoundsR.length) % 256;
}
///g值
var g = (r + Random1.Next(50, 190)) % 256;
if (g > BoundsG.begin && g < BoundsG.end)
{
g = (g + BoundsG.length) % 256;
}
///b值
var b = (g + Random1.Next(50, 190)) % 256;
if (b > BoundsB.begin && b < BoundsB.end)
{
b = (b + BoundsB.length) % 256;
}
return new SKColor((byte)r, (byte)g, (byte)b);
}
/// <summary>
/// 获取图片流,png格式
/// </summary>
/// <returns></returns>
public byte[] GetImg()
{
MemoryStream stream;
// save the file
using (var image = Surface.Snapshot())
using (var data = image.Encode(SKEncodedImageFormat.Png, 100))
{
return data.ToArray();
}
}
/// <summary>
/// 一键生成验证图片
/// </summary>
/// <returns></returns>
public byte[] CreateVerificationImage(string Text)
{
Clear();
WriteText(Text);
Confuse(4);
var stream = GetImg();
return stream;
}
}
public IActionResult img2()
{
ImageVerificationCode t1 = new ImageVerificationCode(135,40);
t1.Clear();
t1.WriteText("eB4FJ");
t1.Confuse(5);
var img= t1.GetImg();
return File(img, "image/Png");
}
文档更新时间: 2023-09-03 18:03 作者:admin