背景
我们在.NET Framework 框架下生成图片验证码时,使用的是System.Drawing,但它却只是 Win32 GDI+ 的一层很薄很薄的封装,在其他平台上没有原生对 GDI+ 的实现。
将框架从 .NET Framework 迁移到 .NET Core 后,需要重新选择新的图片处理组件,于是对 .NET Core 下常见的解决方案进行了实现,测试了性能。
方案选择
System.Drawing.Common
微软提供用的 System.Drawing.Common ,代码上基本上不需要修改。但是在非windows 系统时需要 libgdiplus 支持,libgdiplus是mono跨平台项目的对GDI+的跨平台实现。
最新版本的 System.Drawing.Common 已经不支持非window平台了,此次使用了5.0.3版本。
在linux下需要安装 libgdiplus ,在 Dokcerfile 中的添加安装脚本。
RUN apt-get update -y && apt-get install -y apt-utils
RUN apt-get install -y libgdiplus && apt-get install -y libc6-dev
SixLabors.ImageSharp
开源的图片处理库,完全采用C#实现,基本上兼容所有平台。但是他的绘图依赖 SixLabors.ImageSharp.Drawing 从2017到现在一直处于预览版。
https://github.com/SixLabors/ImageSharp
SkiaSharp
开源图片处理库,基于Google 的 Skia实现,兼容服务、桌面、移动等多种平台。针对不同的平台提供的对应的 NativeAssets 包。
https://github.com/mono/SkiaSharp
代码是为了测试功能实现,写的不够优雅,勿喷!!
1、 System.Drawing
Bitmap image = new Bitmap(85, 30);
Graphics g = Graphics.FromImage(image);
g.Clear(Color.White);
// 在图片上写验证码 使用渐变色
LinearGradientBrush brush = new LinearGradientBrush(new Rectangle(0, 0, image.Width, image.Height), Color.Blue, Color.DarkRed, 1.2f, true);
g.DrawString("1 2 3 4", font, brush, 4, 4);
// 在图片上随机画5条随机颜色线
for (int i = 0; i < 5; i++)
{
g.DrawLine(new Pen(Color.FromArgb(random.Next(0, 256), random.Next(0, 256), random.Next(0, 256))), random.Next(image.Width), random.Next(image.Height), random.Next(image.Width), random.Next(image.Height));
}
// 在图片上随机画100个随机颜色点
for (int i = 0; i < 100; i++)
{
image.SetPixel(random.Next(image.Width), random.Next(image.Height), Color.FromArgb(random.Next(0, 256), random.Next(0, 256), random.Next(0, 256)));
}
生成的验证码效果
3、SkiaSharp
var info = new SKImageInfo(85, 30);
var surface = SKSurface.Create(info);
var canvas = surface.Canvas;
canvas.Clear(SKColors.White);
// 在图片上写验证码
SKPaint textPaint = new SKPaint
{
Typeface = GetTypeface(),
IsAntialias = true,
TextAlign = SKTextAlign.Left,
Shader = SKShader.CreateLinearGradient(new SKPoint(0, 0), new SKPoint(info.Width, info.Height), new SKColor[] { SKColors.Blue, SKColors.DarkRed }, SKShaderTileMode.Clamp),
TextSize = 22
};
canvas.DrawText("1 2 3 4", 4, 24, textPaint);
// 在图片上随机画5条线
for (int i = 0; i < 5; i++)
{
canvas.DrawLine(new SKPoint(random.Next(info.Width), random.Next(info.Height)), new SKPoint(random.Next(info.Width), random.Next(info.Height)), new SKPaint() { Color = SKColor.FromHsv(random.Next(0, 256), random.Next(0, 256), random.Next(0, 256)) });
}
// 在图片上随机画100个随机颜色点
for (int i = 0; i < 100; i++)
{
canvas.DrawPoint(new SKPoint(random.Next(info.Width), random.Next(info.Height)), SKColor.FromHsv(random.Next(0, 256), random.Next(0, 256), random.Next(0, 256)));
}
生成的验证码效果
测试时生成图片的格式都设置为 jpeg ,图片质量都设置为75,输出的为base64。
100次耗时 | 200次耗时 | 300次耗时 | base64长度 | |
---|---|---|---|---|
System.Drawing (win) | 00.0330553 | 00.0789898 | 00.1349937 | 2578 |
SixLabors.ImageSharp (win) | 00.4552113 | 01.0485911 | 01.5290078 | 2808 |
SkiaSharp (win) | 00.0378752 | 00.0822891 | 00.1109486 | 2161 |
System.Drawing (linux) | 00.0314331 | 00.0449517 | 00.0748179 | 2649 |
SixLabors.ImageSharp (linux) | 00.6490841 | 01.1155603 | 01.7946787 | 2805 |
SkiaSharp (linux) | 00.0359634 | 00.0722412 | 00.1250867 | 2155 |
Linux 下的测试基于 Docker
按性能排序 System.Drawing > SkiaSharp > SixLabors.ImageSharp
- System.Drawing 不管是Window平台还是Linux平台,性能都是最好的,并且在Linux下速度更快。
- SkiaSharp 因为底层使用的还是C++的库,所以整体性能也非常不错,与 System.Drawing 非常接近。
- SixLabors.ImageSharp 因为是纯C#原生实现,所以性能是最差的,耗时非常长。
三种方案生成的图片尺寸差距不大,从兼容性和支持上看,建议优先选择 SkiaSharp。 System.Drawing 虽然性能最好但微软已经明确不再支持非Windows平台,性能优势虽然还是比较明显,但针对当前的验证码场景,耗时差异非常小。