From 8964692448bccfa0b52463ba202498fae8c2065c Mon Sep 17 00:00:00 2001 From: biss Date: Tue, 29 Sep 2026 09:33:13 +0800 Subject: [PATCH] =?UTF-8?q?=E9=AA=8C=E8=AF=81=E7=A0=81=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CaptchaKitService.cs | 36 ++++++++++++------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/CaptchaKit.AspNetCore/CaptchaKitService.cs b/src/CaptchaKit.AspNetCore/CaptchaKitService.cs index dead738..c153ae2 100644 --- a/src/CaptchaKit.AspNetCore/CaptchaKitService.cs +++ b/src/CaptchaKit.AspNetCore/CaptchaKitService.cs @@ -147,21 +147,35 @@ public sealed class SkiaTextCaptchaGenerator : ICaptchaGenerator using var bitmap = new SKBitmap(width, 54); using var canvas = new SKCanvas(bitmap); canvas.Clear(new SKColor(244, 248, 252)); - DrawNoise(canvas, width, 54, 16); - using var paint = new SKPaint { IsAntialias = true }; - using var font = new SKFont(SKTypeface.FromFamilyName("Arial", SKFontStyle.Bold), 30); - var spacing = Math.Max(22, (width - 24) / displayText.Length); + DrawNoise(canvas, width, 54, 20); + // Use Skia's portable default typeface instead of relying on a server-installed font such as Arial. + using var font = new SKFont(SKTypeface.Default, 32) { Embolden = true }; + using var outlinePaint = new SKPaint + { + IsAntialias = true, + Color = new SKColor(255, 255, 255), + Style = SKPaintStyle.Stroke, + StrokeWidth = 3 + }; + using var textPaint = new SKPaint + { + IsAntialias = true, + Color = new SKColor(20, 48, 80) + }; + var spacing = Math.Min(34, Math.Max(24, (width - 28) / displayText.Length)); + var startX = width / 2f - (displayText.Length - 1) * spacing / 2f; + var metrics = font.Metrics; + var baseline = (54 - (metrics.Descent - metrics.Ascent)) / 2f - metrics.Ascent; for (var index = 0; index < displayText.Length; index++) { - var x = 12 + index * spacing + RandomNumberGenerator.GetInt32(-2, 3); - var y = 38 + RandomNumberGenerator.GetInt32(-4, 5); - paint.Color = RandomColor(35, 145); + var x = startX + index * spacing + RandomNumberGenerator.GetInt32(-2, 3); + var y = baseline + RandomNumberGenerator.GetInt32(-3, 4); canvas.Save(); canvas.RotateDegrees(RandomNumberGenerator.GetInt32(-20, 21), x, y); - canvas.DrawText(displayText[index].ToString(), x, y, SKTextAlign.Left, font, paint); + canvas.DrawText(displayText[index].ToString(), x, y, SKTextAlign.Center, font, outlinePaint); + canvas.DrawText(displayText[index].ToString(), x, y, SKTextAlign.Center, font, textPaint); canvas.Restore(); } - DrawNoise(canvas, width, 54, 10); using var image = SKImage.FromBitmap(bitmap); using var data = image.Encode(SKEncodedImageFormat.Png, 100); var challenge = new CaptchaChallenge(request.Id, type, request.ExpiresAt, @@ -179,10 +193,6 @@ public sealed class SkiaTextCaptchaGenerator : ICaptchaGenerator } } - private static SKColor RandomColor(int min, int max) => new( - (byte)RandomNumberGenerator.GetInt32(min, max), - (byte)RandomNumberGenerator.GetInt32(min, max), - (byte)RandomNumberGenerator.GetInt32(min, max)); private static byte RandomByte() => RandomNumberGenerator.GetBytes(1)[0]; }