SkiaSharp画的验证码在Linux下无法正常显示
-
SkiaSharp是Google的Skia图形库的.NET封装版,可用于跨移动、服务器和桌面平台绘制 2D 图形。SkiaSharp 可与 OpenGL 一起用于硬件加速渲染。SkiaSharp 最初由 Mono 开发,但现在由 Microsoft 维护,并根据MIT License提供。
-
使用SkiaSharp生成验证码图片示例代码
using SkiaSharp;
using System.Text;
namespace TestApi;
public static class VerificationCodeHelper
{
public static string GetRandomCode(int length)
{
StringBuilder code = new();
string text = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
Random random = new();
for (int i = 0; i < length; i++)
{
code.Append(text[random.Next(0, text.Length)]);
}
return code.ToString();
}
public static byte[] GetVerificationCode(string text)
{
int width = 128;
int height = 45;
Random random = new();
using SKBitmap image = new(width, height, SKColorType.Bgra8888, SKAlphaType.Premul);
using SKCanvas canvas = new(image);
canvas.DrawColor(SKColors.White);
// 画干扰线
// 干扰线占图片面积的比例
decimal distractorLineRate = 0.0005M;
for (int i = 0; i < (width * height * distractorLineRate); i++)
{
using SKPaint _drawStyle = new();
_drawStyle.Color = new(Convert.ToUInt32(random.Next(int.MaxValue)));
canvas.DrawLine(random.Next(0, width), random.Next(0, height), random.Next(0, width), random.Next(0, height), _drawStyle);
}
// 画文本
using SKPaint drawStyle = new();
drawStyle.Color = SKColors.Red;
drawStyle.TextSize = height;
drawStyle.IsAntialias = true; // 抗锯齿
// 文本居中显示
float textWidth = drawStyle.MeasureText(text);
float x = (width - textWidth) / 2;
float y = (height + drawStyle.TextSize) / 2; // 调整Y轴位置以居中
// 绘制每个字符
foreach (char c in text)
{
string character = c.ToString();
float charWidth = drawStyle.MeasureText(character);
float charRotation = random.Next(-15, 15); // 随机旋转角度
canvas.Save();
canvas.RotateDegrees(charRotation, x + charWidth / 2, y - drawStyle.TextSize / 2);
canvas.DrawText(character, x, y, drawStyle);
canvas.Restore();
x += charWidth;
}
// 绘制噪点
for (int i = 0; i < (width * height * 0.6); i++)
{
image.SetPixel(random.Next(0, width), random.Next(0, height), new SKColor(Convert.ToUInt32(random.Next(int.MaxValue))));
}
using var img = SKImage.FromBitmap(image);
using SKData p = img.Encode(SKEncodedImageFormat.Png, 100);
return p.ToArray();
}
}
- 调用示例代码
app.MapGet("/testVerificationCode", (HttpContext httpContext) =>
{
var randomText = VerificationCodeHelper.GetRandomCode(4);
return Results.File(VerificationCodeHelper.GetVerificationCode(randomText), "image/png");
})
.WithName("TestVerificationCode")
.WithOpenApi();
-
Windows下运行效果展示
-
Linux下运行效果展示
检查日志得到,缺少了libSkiaSharp或任意它的分装库:
- 换源并安装libgdiplus(使用的镜像是官方镜像,基于debian12):
#备份旧源文件
cp -rf /etc/apt/sources.list.d /etc/apt/sources.list.d.bak
#删除旧源文件
rm -rf /etc/apt/sources.list.d/*
#创建源文件指向华为云源
cat <<'EOF'> /etc/apt/sources.list.d/huawei-cloud.list
deb https://mirrors.huaweicloud.com/debian/ bookworm main contrib non-free
deb https://mirrors.huaweicloud.com/debian/ bookworm-updates main contrib non-free
deb https://mirrors.huaweicloud.com/debian/ bookworm-backports main contrib non-free
deb https://mirrors.huaweicloud.com/debian-security/ bookworm-security main contrib non-free
EOF
cat <<'EOF'> fix_skiasharp_broke.sh
#!/bin/bash
# 更新包依赖树,确保最新
apt-get update -y
# 安装 libgdiplus 库,这是 System.Drawing.Common 在 Linux 上的依赖
apt-get install -y libgdiplus
# 清理 apt 缓存,减少镜像大小
apt-get clean
# 检查是否存在 /usr/lib/gdiplus.dll 文件,如果不存在,则创建一个指向 libgdiplus.so 的符号链接
# 这是为了兼容某些依赖 gdiplus.dll 的应用
if [ ! -f /usr/lib/gdiplus.dll ]; then
ln -s /usr/lib/libgdiplus.so /usr/lib/gdiplus.dll
fi
EOF
sh fix_skiasharp_broke.sh
-
重启容器并检查运行效果
-
End