背景

我们在.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)));
}

生成的验证码效果

image.png

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)));
}

生成的验证码效果

image.png

测试时生成图片的格式都设置为 jpeg ,图片质量都设置为75,输出的为base64。

image.png
100次耗时200次耗时300次耗时base64长度
System.Drawing (win)00.033055300.078989800.13499372578
SixLabors.ImageSharp (win)00.455211301.048591101.52900782808
SkiaSharp (win)00.037875200.082289100.11094862161
System.Drawing (linux)00.031433100.044951700.07481792649
SixLabors.ImageSharp (linux)00.649084101.115560301.79467872805
SkiaSharp (linux)00.035963400.072241200.12508672155

Linux 下的测试基于 Docker

按性能排序 System.Drawing > SkiaSharp > SixLabors.ImageSharp

  • System.Drawing 不管是Window平台还是Linux平台,性能都是最好的,并且在Linux下速度更快。
  • SkiaSharp 因为底层使用的还是C++的库,所以整体性能也非常不错,与 System.Drawing 非常接近。
  • SixLabors.ImageSharp 因为是纯C#原生实现,所以性能是最差的,耗时非常长。

三种方案生成的图片尺寸差距不大,从兼容性和支持上看,建议优先选择 SkiaSharp。 System.Drawing 虽然性能最好但微软已经明确不再支持非Windows平台,性能优势虽然还是比较明显,但针对当前的验证码场景,耗时差异非常小。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注