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;