在前端开发的时候,常用的一个需求就是图形验证码,那么如果后端使用Delphi开发,随机生成一个验证码图片,是如何实现呢?
其实如果是VCL,就是调用TBitMap对象来实现,TBitMap有详细的Canvas操作函数,具体的操作参见Delphi的帮助文档。
直接上源代码如下:
{*******************************************************
生成验证码图片: 2023-04-07
作者:sensor(老吴)QQ:910731685
将生成的图片转换成png格式,减少传输数据量。
如果是BMP图片,样本:19KB,转换成png后大小为:3KB
*******************************************************}
unit uSZHN_VerifyCode;
interface
uses
System.Classes,
System.SysUtils,
VCL.Graphics,
System.UIConsts,
System.UITypes,
Vcl.ExtCtrls,
// Vcl.Imaging.jpeg,
Vcl.Imaging.pngimage,
System.Types;
type
// 生成验证码组件
TSZHN_GenerateVerifyCode = class
private const
// 定义字典表,不要零(0),因为零和字母O样子太接近
arrStr: array [0 .. 42] 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; // 背景随机线条数
FXRandomLen: integer; // X的随机值长度
FYRandomLen: integer; // Y的随机值长度
// 画出验证码函数
function VerifyCodeDrawImg(BMP : TBitmap): 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 MinFontSize: integer read FMinFontSize write FMinFontSize;
property RandomLineCount: integer read FRandomLineCount write FRandomLineCount;
property XRandomLen: integer read FXRandomLen write FXRandomLen;
property YRandomLen: integer read FYRandomLen write FYRandomLen;
end;
//外部调用函数, ImageStream 参数返回的是生成的验证码图片数据流,结果为验证码字符串
function Create_VerifyCode(ImageStream: TStream): string;
implementation
//外部调用函数, ImageStream 参数返回的是生成的验证码图片数据流,结果为验证码字符串
function Create_VerifyCode(ImageStream: TStream): string;
var
SZHN_GenerateVerifyCode : TSZHN_GenerateVerifyCode;
begin
SZHN_GenerateVerifyCode := TSZHN_GenerateVerifyCode.Create;
try
SZHN_GenerateVerifyCode.GetVerifyCodeAndImage(ImageStream, Result);
finally
SZHN_GenerateVerifyCode.Free;
end;
end;
constructor TSZHN_GenerateVerifyCode.Create();
begin
inherited;
FBitmapWidth := 120;
FBitmapHeight := 40;
FCodeCount := 4;
FMinFontSize := 4;
FRandomLineCount := 10;
FXRandomLen := 5;
FYRandomLen := 4;
end;
// 获取验证码和图片的流数据
procedure TSZHN_GenerateVerifyCode.GetVerifyCodeAndImage(ImageStream: TStream;
var VerifyCode: string);
var
BMP : TBitmap;
PNG : TPNGImage;
begin
BMP := TBitmap.Create;
PNG := TPNGImage.Create;
try
// 默认 宽120,高40
BMP.Width := FBitmapWidth;
BMP.Height:= FBitmapHeight;
//画验证码图,返回的是图形字符串
VerifyCode := VerifyCodeDrawImg(BMP);
//转换成png格式
PNG.Assign(BMP);
PNG.CompressionLevel := 9; //最高压缩率 0..9
PNG.SaveToStream(ImageStream); //保存成 Stream ,以便可以传递给前端(Base64)
finally
FreeAndNil(BMP);
FreeAndNil(PNG);
end;
end;
// 画出验证码函数
function TSZHN_GenerateVerifyCode.VerifyCodeDrawImg(BMP : TBitmap): string;
var
I, j, k: integer;
X, Y, W, H: integer;
vLeft: integer;
strResult: string;
//随机颜色函数
function RandomColor : TColor;
begin
Result := Random($FF) shl 16 + Random($FF) shl 8 + Random($FF);
end;
//随机生成字体名字,内置6种字体随机切换
function Random_FontName: string;
var
FontNames : Tarray;
begin
SetLength(FontNames,6);
FontNames[0] := 'Microsoft JhengHei UI';
FontNames[1] := '宋体';
FontNames[2] := 'Microsoft YaHei UI';
FontNames[3] := 'Ink Free';
FontNames[4] := 'Malgun Gothic';
FontNames[5] := 'Cascadia Code';
Randomize;
Result := FontNames[Random(1000000) mod 6];
end;
begin
// 随机获取字符,默认4个字符
For j := 1 to FCodeCount do
begin
Randomize;
k := Random(1000000) mod 43;
strResult := strResult + trim(arrStr[k]);
end;
vLeft := 5;
//设置背景颜色
BMP.Canvas.Brush.Style := bsSolid;
BMP.Canvas.Brush.Color := RandomColor;
BMP.Canvas.FillRect(TRect.Create(0, 0, FBitmapWidth, FBitmapHeight));
// 随机画10条线
for j := 1 to FRandomLineCount do
begin
Randomize;
BMP.Canvas.Brush.Style := bsCross;
BMP.Canvas.Pen.Color := RandomColor;
BMP.Canvas.Pen.Width := 1;
BMP.Canvas.Pen.Mode := pmXor;
BMP.Canvas.MoveTo(Random(FBitmapWidth), Random(FBitmapHeight));
BMP.Canvas.LineTo(Random(FBitmapWidth), Random(FBitmapHeight));
end;
for I := 1 to length(strResult) do
begin
Randomize;
// 随机字体颜色,这里暂时不用每个字符一个随机颜色
BMP.Canvas.Font.Color := RandomColor;
//设置字体名字
BMP.Canvas.Font.Name := Random_FontName;
// 字体大小
BMP.Canvas.Font.Size := Random(8) + FMinFontSize;
if BMP.Canvas.Font.Size < (FMinFontSize + 5) then
BMP.Canvas.Font.Size := BMP.Canvas.Font.Size + 5;
if Random(2) = 1 then
BMP.Canvas.Font.Style := [TFontStyle.fsBold]
else
BMP.Canvas.Font.Style := [TFontStyle.fsItalic];
begin
X := Random(FXRandomLen) + vLeft;
Y := Random(FYRandomLen);
W := BMP.Canvas.TextWidth(strResult[I]);
H := BMP.Canvas.TextHeight(strResult[I]);
BMP.Canvas.TextOut(X,Y,strResult[I]);
vLeft := X + W + 1;
end;
end;
Result := strResult; // 返回值 ,验证码字符串
end;
end.
具体使用代码:
uses
uSZHN_VerifyCode;
var
sVerifyCode : string; //验证码字符串
TM : TMemoryStream; //验证码图片数据流信息
begin
TM := TMemoryStream.Create;
sVerifyCode := Create_VerifyCode(TM);
TM.SaveToFile('C:\Temp\1.png'); //可以保存成文件
Image1.Picture.LoadFromFile('C:\Temp\1.png'); //可以直接在Image1中显示出来
TM.Free;
end;