【转】DelphiXE10.2.3——跨平台生成验证码图片
Java、PHP、C#等很容易在网上找到生成验证码图片的代码,Delphi却寥寥无几,昨天花了一整天时间,做了个跨平台的验证码,可以用在C/S和B/S端,支持Windows、Linux、Android、IOS等。对于验证码图形的混淆,只做了简单的随机线条生成,并且随机数是使用系统自带的Randomize和Random函数,Randomize随机数初始化函数由于取种子是保存在全局变量中,虽然是integer类型,但不排除非线程安全问题,所以实际应用中,还需要线程保护。
C/S和B/S上的显示效果:
unit uVerifyCode; interface uses System.Classes, System.SysUtils, FMX.Types, FMX.Objects, FMX.Graphics, System.UIConsts, System.UITypes, {$IFDEF MSWINDOWS}ActiveX, {$ENDIF MSWINDOWS} System.Types; type // 生成验证码组件 TGenerateVerifyCode = class private const // 定义字典表,不要零(0),因为零和字母O样子太接近 arrStr: array [0 .. 34] of char = ( '1','2','3','4','5','6','7','8','9', 'A','B','C','D','E','F','G','H','I', 'J','K','L','M','N','O','P','Q','R', 'S','T','U','V','W','X','Y','Z'); private FBitmapWidth: integer; // 图片宽度 FBitmapHeight: integer; // 图片高度 FCodeCount: integer; // 取验证码字符的个数,默认是4个字符 FFontName: string; // 字体名称 FMinFontSize: integer; // 最小字体大小 FRandomLineCount: integer; // 背景随机线条数 FTransparency: byte; // 背景随机线条的透明度 FXRandomLen: integer; // X的随机值长度 FYRandomLen: integer; // Y的随机值长度 // 画出验证码函数 function VerifyCodeDrawImg(Img: TImage): string; public constructor Create(); procedure GetVerifyCodeAndImage(ImageStream: TStream; var VerifyCode: string); published property Width: integer read FBitmapWidth write FBitmapWidth; property Height: integer read FBitmapHeight write FBitmapHeight; property CodeCount: integer read FCodeCount write FCodeCount; property FontName: string read FFontName write FFontName; property MinFontSize: integer read FMinFontSize write FMinFontSize; property RandomLineCount: integer read FRandomLineCount write FRandomLineCount; property Transparency: byte read FTransparency write FTransparency; property XRandomLen: integer read FXRandomLen write FXRandomLen; property YRandomLen: integer read FYRandomLen write FYRandomLen; end; implementation constructor TGenerateVerifyCode.Create(); begin inherited; FBitmapWidth := 100; FBitmapHeight := 30; FCodeCount := 4; FFontName := '宋体'; FMinFontSize := 15; FRandomLineCount := 100; FTransparency := 200; FXRandomLen := 5; FYRandomLen := 4; end; // 获取验证码和影像的流数据 procedure TGenerateVerifyCode.GetVerifyCodeAndImage(ImageStream: TStream; var VerifyCode: string); var Img: FMX.Objects.TImage; begin {$IFDEF MSWINDOWS}CoInitialize(nil); {$ENDIF MSWINDOWS} Img := FMX.Objects.TImage.Create(nil); try Img.Bitmap := FMX.Graphics.TBitmap.Create(FBitmapWidth, FBitmapHeight); // 宽100,高40 Img.Bitmap.Canvas.BeginScene; VerifyCode := VerifyCodeDrawImg(Img); Img.Bitmap.Canvas.EndScene; Img.Bitmap.SaveToStream(ImageStream); // 写到流中 finally freeandnil(Img); end; end; // 画出验证码函数 function TGenerateVerifyCode.VerifyCodeDrawImg(Img: TImage): string; var I, j, k: integer; X, Y, W, H: Single; vLeft: Single; strResult: RawByteString; begin // 只取4个字符 For j := 1 to FCodeCount do begin Randomize; k := Random(1000000) mod 35; strResult := strResult + trim(arrStr[k]); end; vLeft := 5; Img.Bitmap.Canvas.Font.Family := FFontName; for j := 1 to FRandomLineCount do // 随机画100条线 begin Randomize; Img.Bitmap.Canvas.Stroke.Color := MakeColor(Random(256) and $C0, Random(256) and $C0, Random(256) and $C0, FTransparency); Img.Bitmap.Canvas.DrawLine(pointf(Random(120), Random(50)), pointf(Random(120), Random(50)), 1); end; // 随机字体颜色,这里暂时不用每个字符一个随机颜色 Img.Bitmap.Canvas.Fill.Color := MakeColor((Random(256) and $C0), (Random(256) and $C0), (Random(256) and $C0)); // 背景色反色 Img.Bitmap.Clear(Img.Bitmap.Canvas.Fill.Color xor $FFFFFF); for I := 1 to length(strResult) do begin Randomize; // 字体大小 Img.Bitmap.Canvas.Font.Size := Random(8) + FMinFontSize; if Img.Bitmap.Canvas.Font.Size < (FMinFontSize + 5) then Img.Bitmap.Canvas.Font.Size := Img.Bitmap.Canvas.Font.Size + 5; if Random(2) = 1 then Img.Bitmap.Canvas.Font.Style := [TFontStyle.fsBold] else Img.Bitmap.Canvas.Font.Style := [TFontStyle.fsItalic]; begin X := Random(FXRandomLen) + vLeft; Y := Random(FYRandomLen); W := Img.Bitmap.Canvas.TextWidth(strResult[I]); H := Img.Bitmap.Canvas.TextHeight(strResult[I]); Img.Bitmap.Canvas.FillText(TRectF.Create(X, Y, X + W, Y + H), strResult[I], false, 1, [], TTextAlign.taCenter, TTextAlign.taCenter); vLeft := X + W + 1; end; end; Result := strResult; // 返回值 end; end.
使用方法:
C/S与B/S共同创建方法
var FGenerateVerifyCode: TGenerateVerifyCode; begin FGenerateVerifyCode := TGenerateVerifyCode.Create; end;
一、C/S使用方法:
procedure TForm1.Button1Click(Sender: TObject); var ImageStream: TMemoryStream; VerifyCode: string; begin ImageStream:= TMemoryStream.Create; try GetVerifyCodeAndImage(ImageStream, VerifyCode); Label1.Text:=VerifyCode; ImageStream.Position:=0; Image1.Bitmap.LoadFromStream(ImageStream); finally ImageStream.Free; end; end;
二、B/S使用方法:
1、HTML中加入Img元素
<img src="VerifyCode" id="img-code" class="Verify-Code" style="cursor:pointer" alt="验证码" title="看不清楚?点一下图片刷新">
2、JS代码
$("#img-code").bind( 'click', function () { $(this).attr('src','VerifyCode?t='+Math.random()); });
3、服务端代码
// 获取验证码图片 function TSystemPagePlugin.Method_VerifyCode(Request: TWebRequest; Response: TWebResponse): boolean; VAR VerifyCode: string; begin Response.ContentStream := TMemoryStream.Create; Response.ContentType := 'application/binary;'; // 获取验证码图片和数值 GetVerifyCodeAndImage(Response.ContentStream, VerifyCode); result := true; end;
感谢作者晴空无彩虹无私的分享!