You've already forked lazarus-ccr
captcha: Initial commit
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@8111 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
62
components/captcha/README.txt
Normal file
62
components/captcha/README.txt
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
--------------------------------------------------------------------------------
|
||||||
|
Visual CAPTCHA component for Lazarus
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Description
|
||||||
|
-----------
|
||||||
|
|
||||||
|
The component TCaptcha descends from TGraphicControl and contains its own drawing
|
||||||
|
routine. Just place it on the form and use it. It displays a random string with
|
||||||
|
slanted characters and overlaid lines.
|
||||||
|
|
||||||
|
The method Verify() checks whether a user-provided string matches the
|
||||||
|
captcha string and returns true.
|
||||||
|
|
||||||
|
There are several properties to define its behaviour:
|
||||||
|
|
||||||
|
* NumChars: Number of characters in the captcha
|
||||||
|
|
||||||
|
* NumLines: Number of lines drawn over the captcha
|
||||||
|
|
||||||
|
* Font1, Font2: two fonts to be mixed within the captcha randomly
|
||||||
|
|
||||||
|
* MaxAngle: maximum rotation angle for the characters which are rotated by a
|
||||||
|
random angle between -MaxAngle and +MaxAngle
|
||||||
|
|
||||||
|
* Color: the background color of the area of the control covered by the captcha.
|
||||||
|
Character and line colors are selected such that a minimum brightness difference
|
||||||
|
to the background color is achieved.
|
||||||
|
|
||||||
|
* Options: This is a set of the following options which can be combined:
|
||||||
|
* coAlphaUpper: Use uppercase characters as defined by the the UppercaseChars string
|
||||||
|
* coAlphaLower: Use lowercase characters as defined by the LowercaseChars string
|
||||||
|
* coNumeric: Use numeric characters as defined by the NumericChars string
|
||||||
|
(the characters which are hard to distinguish are skipped,
|
||||||
|
zero vs uppercase O, lowercase L vs upper case I)
|
||||||
|
* coCustom: Use special characters as defined by the CustomChars string
|
||||||
|
* coRotated: Characters are rotated
|
||||||
|
* coFont1: Font1 is used
|
||||||
|
* coFont2: Font2 is used
|
||||||
|
* coLines: Lines are drawn over the captcha
|
||||||
|
|
||||||
|
* NewCaptchaEvent: Enumerated property for how to quickly select of a new captcha
|
||||||
|
string at runtime:
|
||||||
|
* nceNone: deactivated; captcha can only be changed by code.
|
||||||
|
* nceClick: a new captcha is created when the user clicks on the control
|
||||||
|
* nceDblClick: a new captcha is created when the user double-clicks on the control.
|
||||||
|
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
|
||||||
|
* Load the package file captcha_pkg.lpk into the Lazarus Package Editor and
|
||||||
|
click "Use" > "Install" to rebuild the Lazarus IDE. When Lazarus restarts you
|
||||||
|
find the new component in the palette "Misc".
|
||||||
|
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
|
||||||
|
LGPL with linking exception, like the Lazarus LCL.
|
||||||
|
See the file COPYING.modifiedLGPL.txt, included in the Lazarus distribution,
|
||||||
|
for details about the license.
|
40
components/captcha/captcha_pkg.lpk
Normal file
40
components/captcha/captcha_pkg.lpk
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<CONFIG>
|
||||||
|
<Package Version="5">
|
||||||
|
<PathDelim Value="\"/>
|
||||||
|
<Name Value="captcha_pkg"/>
|
||||||
|
<Type Value="RunAndDesignTime"/>
|
||||||
|
<Author Value="W. Pamler"/>
|
||||||
|
<CompilerOptions>
|
||||||
|
<Version Value="11"/>
|
||||||
|
<PathDelim Value="\"/>
|
||||||
|
<SearchPaths>
|
||||||
|
<OtherUnitFiles Value="source"/>
|
||||||
|
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
|
||||||
|
</SearchPaths>
|
||||||
|
</CompilerOptions>
|
||||||
|
<Description Value="A visual component which displays a CAPTCHA"/>
|
||||||
|
<License Value="LGPL with linking exception (like Lazarus LCL)"/>
|
||||||
|
<Version Minor="1"/>
|
||||||
|
<Files Count="1">
|
||||||
|
<Item1>
|
||||||
|
<Filename Value="source\captchactrl.pas"/>
|
||||||
|
<HasRegisterProc Value="True"/>
|
||||||
|
<UnitName Value="CaptchaCtrl"/>
|
||||||
|
</Item1>
|
||||||
|
</Files>
|
||||||
|
<CompatibilityMode Value="True"/>
|
||||||
|
<RequiredPkgs Count="1">
|
||||||
|
<Item1>
|
||||||
|
<PackageName Value="LCL"/>
|
||||||
|
</Item1>
|
||||||
|
</RequiredPkgs>
|
||||||
|
<UsageOptions>
|
||||||
|
<UnitPath Value="$(PkgOutDir)"/>
|
||||||
|
</UsageOptions>
|
||||||
|
<PublishOptions>
|
||||||
|
<Version Value="2"/>
|
||||||
|
<UseFileFilters Value="True"/>
|
||||||
|
</PublishOptions>
|
||||||
|
</Package>
|
||||||
|
</CONFIG>
|
22
components/captcha/captcha_pkg.pas
Normal file
22
components/captcha/captcha_pkg.pas
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{ This file was automatically created by Lazarus. Do not edit!
|
||||||
|
This source is only used to compile and install the package.
|
||||||
|
}
|
||||||
|
|
||||||
|
unit captcha_pkg;
|
||||||
|
|
||||||
|
{$warn 5023 off : no warning about unused units}
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
CaptchaCtrl, LazarusPackageIntf;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
procedure Register;
|
||||||
|
begin
|
||||||
|
RegisterUnit('CaptchaCtrl', @CaptchaCtrl.Register);
|
||||||
|
end;
|
||||||
|
|
||||||
|
initialization
|
||||||
|
RegisterPackage('captcha_pkg', @Register);
|
||||||
|
end.
|
89
components/captcha/demo_runtime/capcha_demo.lpi
Normal file
89
components/captcha/demo_runtime/capcha_demo.lpi
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<CONFIG>
|
||||||
|
<ProjectOptions>
|
||||||
|
<Version Value="12"/>
|
||||||
|
<PathDelim Value="\"/>
|
||||||
|
<General>
|
||||||
|
<Flags>
|
||||||
|
<CompatibilityMode Value="True"/>
|
||||||
|
</Flags>
|
||||||
|
<SessionStorage Value="InProjectDir"/>
|
||||||
|
<Title Value="capcha_demo"/>
|
||||||
|
<ResourceType Value="res"/>
|
||||||
|
<UseXPManifest Value="True"/>
|
||||||
|
<XPManifest>
|
||||||
|
<DpiAware Value="True"/>
|
||||||
|
</XPManifest>
|
||||||
|
</General>
|
||||||
|
<BuildModes Count="1">
|
||||||
|
<Item1 Name="Default" Default="True"/>
|
||||||
|
</BuildModes>
|
||||||
|
<PublishOptions>
|
||||||
|
<Version Value="2"/>
|
||||||
|
</PublishOptions>
|
||||||
|
<RunParams>
|
||||||
|
<FormatVersion Value="2"/>
|
||||||
|
<Modes Count="1">
|
||||||
|
<Mode0 Name="default"/>
|
||||||
|
</Modes>
|
||||||
|
</RunParams>
|
||||||
|
<RequiredPackages Count="1">
|
||||||
|
<Item1>
|
||||||
|
<PackageName Value="LCL"/>
|
||||||
|
</Item1>
|
||||||
|
</RequiredPackages>
|
||||||
|
<Units Count="3">
|
||||||
|
<Unit0>
|
||||||
|
<Filename Value="capcha_demo.lpr"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
</Unit0>
|
||||||
|
<Unit1>
|
||||||
|
<Filename Value="main.pas"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
<ComponentName Value="DemoForm"/>
|
||||||
|
<HasResources Value="True"/>
|
||||||
|
<ResourceBaseClass Value="Form"/>
|
||||||
|
</Unit1>
|
||||||
|
<Unit2>
|
||||||
|
<Filename Value="..\source\captchactrl.pas"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
<UnitName Value="CaptchaUnit"/>
|
||||||
|
</Unit2>
|
||||||
|
</Units>
|
||||||
|
</ProjectOptions>
|
||||||
|
<CompilerOptions>
|
||||||
|
<Version Value="11"/>
|
||||||
|
<PathDelim Value="\"/>
|
||||||
|
<Target>
|
||||||
|
<Filename Value="bin\$(TargetCPU)-$(TargetOS)\capcha_demo"/>
|
||||||
|
</Target>
|
||||||
|
<SearchPaths>
|
||||||
|
<IncludeFiles Value="$(ProjOutDir)"/>
|
||||||
|
<OtherUnitFiles Value="..\source"/>
|
||||||
|
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
|
||||||
|
</SearchPaths>
|
||||||
|
<Linking>
|
||||||
|
<Debugging>
|
||||||
|
<DebugInfoType Value="dsDwarf2Set"/>
|
||||||
|
</Debugging>
|
||||||
|
<Options>
|
||||||
|
<Win32>
|
||||||
|
<GraphicApplication Value="True"/>
|
||||||
|
</Win32>
|
||||||
|
</Options>
|
||||||
|
</Linking>
|
||||||
|
</CompilerOptions>
|
||||||
|
<Debugging>
|
||||||
|
<Exceptions Count="3">
|
||||||
|
<Item1>
|
||||||
|
<Name Value="EAbort"/>
|
||||||
|
</Item1>
|
||||||
|
<Item2>
|
||||||
|
<Name Value="ECodetoolError"/>
|
||||||
|
</Item2>
|
||||||
|
<Item3>
|
||||||
|
<Name Value="EFOpenError"/>
|
||||||
|
</Item3>
|
||||||
|
</Exceptions>
|
||||||
|
</Debugging>
|
||||||
|
</CONFIG>
|
24
components/captcha/demo_runtime/capcha_demo.lpr
Normal file
24
components/captcha/demo_runtime/capcha_demo.lpr
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
program capcha_demo;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
uses
|
||||||
|
{$IFDEF UNIX}
|
||||||
|
cthreads,
|
||||||
|
{$ENDIF}
|
||||||
|
{$IFDEF HASAMIGA}
|
||||||
|
athreads,
|
||||||
|
{$ENDIF}
|
||||||
|
Interfaces, // this includes the LCL widgetset
|
||||||
|
Forms, main
|
||||||
|
{ you can add units after this };
|
||||||
|
|
||||||
|
{$R *.res}
|
||||||
|
|
||||||
|
begin
|
||||||
|
RequireDerivedFormResource:=True;
|
||||||
|
Application.Initialize;
|
||||||
|
Application.CreateForm(TDemoForm, DemoForm);
|
||||||
|
Application.Run;
|
||||||
|
end.
|
||||||
|
|
418
components/captcha/demo_runtime/main.lfm
Normal file
418
components/captcha/demo_runtime/main.lfm
Normal file
@ -0,0 +1,418 @@
|
|||||||
|
object DemoForm: TDemoForm
|
||||||
|
Left = 285
|
||||||
|
Height = 385
|
||||||
|
Top = 131
|
||||||
|
Width = 693
|
||||||
|
AutoSize = True
|
||||||
|
Caption = 'Captcha Demo'
|
||||||
|
ClientHeight = 385
|
||||||
|
ClientWidth = 693
|
||||||
|
OnCreate = FormCreate
|
||||||
|
LCLVersion = '2.3.0.0'
|
||||||
|
object SettingsPanel: TPanel
|
||||||
|
Left = 16
|
||||||
|
Height = 239
|
||||||
|
Top = 130
|
||||||
|
Width = 661
|
||||||
|
Align = alBottom
|
||||||
|
AutoSize = True
|
||||||
|
BorderSpacing.Around = 16
|
||||||
|
BevelOuter = bvNone
|
||||||
|
ClientHeight = 239
|
||||||
|
ClientWidth = 661
|
||||||
|
TabOrder = 1
|
||||||
|
object clbBackgroundColor: TColorBox
|
||||||
|
AnchorSideLeft.Control = cmbNewCaptchaEvent
|
||||||
|
AnchorSideTop.Control = SettingsPanel
|
||||||
|
AnchorSideRight.Control = cmbNewCaptchaEvent
|
||||||
|
AnchorSideRight.Side = asrBottom
|
||||||
|
Left = 113
|
||||||
|
Height = 22
|
||||||
|
Top = 0
|
||||||
|
Width = 123
|
||||||
|
Anchors = [akTop, akLeft, akRight]
|
||||||
|
DropDownCount = 32
|
||||||
|
ItemHeight = 16
|
||||||
|
OnChange = clbBackgroundColorChange
|
||||||
|
TabOrder = 0
|
||||||
|
end
|
||||||
|
object lblBackgroundColor: TLabel
|
||||||
|
AnchorSideLeft.Control = SettingsPanel
|
||||||
|
AnchorSideTop.Control = clbBackgroundColor
|
||||||
|
AnchorSideTop.Side = asrCenter
|
||||||
|
Left = 0
|
||||||
|
Height = 15
|
||||||
|
Top = 4
|
||||||
|
Width = 94
|
||||||
|
Caption = 'Background color'
|
||||||
|
end
|
||||||
|
object lblMaxAngle: TLabel
|
||||||
|
AnchorSideLeft.Control = SettingsPanel
|
||||||
|
AnchorSideTop.Control = seMaxAngle
|
||||||
|
AnchorSideTop.Side = asrCenter
|
||||||
|
Left = 0
|
||||||
|
Height = 15
|
||||||
|
Top = 30
|
||||||
|
Width = 55
|
||||||
|
Caption = 'Max angle'
|
||||||
|
end
|
||||||
|
object seMaxAngle: TSpinEdit
|
||||||
|
AnchorSideLeft.Control = cmbNewCaptchaEvent
|
||||||
|
AnchorSideTop.Control = clbBackgroundColor
|
||||||
|
AnchorSideTop.Side = asrBottom
|
||||||
|
AnchorSideRight.Control = cmbNewCaptchaEvent
|
||||||
|
AnchorSideRight.Side = asrBottom
|
||||||
|
Left = 113
|
||||||
|
Height = 23
|
||||||
|
Top = 26
|
||||||
|
Width = 123
|
||||||
|
Alignment = taRightJustify
|
||||||
|
Anchors = [akTop, akLeft, akRight]
|
||||||
|
BorderSpacing.Top = 4
|
||||||
|
Increment = 5
|
||||||
|
MaxValue = 90
|
||||||
|
OnChange = seMaxAngleChange
|
||||||
|
TabOrder = 1
|
||||||
|
end
|
||||||
|
object cgOptions: TCheckGroup
|
||||||
|
AnchorSideLeft.Control = clbBackgroundColor
|
||||||
|
AnchorSideLeft.Side = asrBottom
|
||||||
|
AnchorSideTop.Control = SettingsPanel
|
||||||
|
Left = 260
|
||||||
|
Height = 103
|
||||||
|
Top = 0
|
||||||
|
Width = 418
|
||||||
|
AutoFill = True
|
||||||
|
AutoSize = True
|
||||||
|
BorderSpacing.Left = 24
|
||||||
|
Caption = 'Options'
|
||||||
|
ChildSizing.LeftRightSpacing = 16
|
||||||
|
ChildSizing.TopBottomSpacing = 6
|
||||||
|
ChildSizing.HorizontalSpacing = 12
|
||||||
|
ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
|
||||||
|
ChildSizing.EnlargeVertical = crsHomogenousChildResize
|
||||||
|
ChildSizing.ShrinkHorizontal = crsScaleChilds
|
||||||
|
ChildSizing.ShrinkVertical = crsScaleChilds
|
||||||
|
ChildSizing.Layout = cclLeftToRightThenTopToBottom
|
||||||
|
ChildSizing.ControlsPerLine = 4
|
||||||
|
ClientHeight = 83
|
||||||
|
ClientWidth = 414
|
||||||
|
Columns = 4
|
||||||
|
Items.Strings = (
|
||||||
|
'Alpha uppercase'
|
||||||
|
'Alpha lowercase'
|
||||||
|
'Numeric'
|
||||||
|
'Custom'
|
||||||
|
'Rotated'
|
||||||
|
'Font 1'
|
||||||
|
'Font 2'
|
||||||
|
'Lines'
|
||||||
|
)
|
||||||
|
OnItemClick = cgOptionsItemClick
|
||||||
|
TabOrder = 4
|
||||||
|
Data = {
|
||||||
|
080000000202020202020202
|
||||||
|
}
|
||||||
|
object Label6: TLabel
|
||||||
|
Left = 16
|
||||||
|
Height = 25
|
||||||
|
Top = 52
|
||||||
|
Width = 108
|
||||||
|
Caption = ' '
|
||||||
|
end
|
||||||
|
object btnFont1: TButton
|
||||||
|
AnchorSideTop.Side = asrBottom
|
||||||
|
Left = 136
|
||||||
|
Height = 25
|
||||||
|
Top = 52
|
||||||
|
Width = 70
|
||||||
|
AutoSize = True
|
||||||
|
Caption = 'Font 1...'
|
||||||
|
Constraints.MaxWidth = 70
|
||||||
|
OnClick = btnFont1Click
|
||||||
|
TabOrder = 0
|
||||||
|
end
|
||||||
|
object btnFont2: TButton
|
||||||
|
AnchorSideLeft.Side = asrBottom
|
||||||
|
AnchorSideTop.Side = asrBottom
|
||||||
|
Left = 254
|
||||||
|
Height = 25
|
||||||
|
Top = 52
|
||||||
|
Width = 70
|
||||||
|
AutoSize = True
|
||||||
|
BorderSpacing.Left = 8
|
||||||
|
BorderSpacing.Top = 8
|
||||||
|
Caption = 'Font 2...'
|
||||||
|
Constraints.MaxWidth = 70
|
||||||
|
Constraints.MinWidth = 70
|
||||||
|
OnClick = btnFont2Click
|
||||||
|
TabOrder = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
object lblCharCount: TLabel
|
||||||
|
AnchorSideLeft.Control = SettingsPanel
|
||||||
|
AnchorSideTop.Control = seCharCount
|
||||||
|
AnchorSideTop.Side = asrCenter
|
||||||
|
Left = 0
|
||||||
|
Height = 15
|
||||||
|
Top = 57
|
||||||
|
Width = 88
|
||||||
|
Caption = 'Character count:'
|
||||||
|
end
|
||||||
|
object seCharCount: TSpinEdit
|
||||||
|
AnchorSideLeft.Control = cmbNewCaptchaEvent
|
||||||
|
AnchorSideTop.Control = seMaxAngle
|
||||||
|
AnchorSideTop.Side = asrBottom
|
||||||
|
AnchorSideRight.Control = cmbNewCaptchaEvent
|
||||||
|
AnchorSideRight.Side = asrBottom
|
||||||
|
Left = 113
|
||||||
|
Height = 23
|
||||||
|
Top = 53
|
||||||
|
Width = 123
|
||||||
|
Alignment = taRightJustify
|
||||||
|
Anchors = [akTop, akLeft, akRight]
|
||||||
|
BorderSpacing.Top = 4
|
||||||
|
MaxValue = 90
|
||||||
|
OnChange = seCharCountChange
|
||||||
|
TabOrder = 2
|
||||||
|
end
|
||||||
|
object lblLinesCount: TLabel
|
||||||
|
AnchorSideLeft.Control = SettingsPanel
|
||||||
|
AnchorSideTop.Control = seLinesCount
|
||||||
|
AnchorSideTop.Side = asrCenter
|
||||||
|
Left = 0
|
||||||
|
Height = 15
|
||||||
|
Top = 84
|
||||||
|
Width = 61
|
||||||
|
Caption = 'Lines count'
|
||||||
|
end
|
||||||
|
object seLinesCount: TSpinEdit
|
||||||
|
AnchorSideLeft.Control = cmbNewCaptchaEvent
|
||||||
|
AnchorSideTop.Control = seCharCount
|
||||||
|
AnchorSideTop.Side = asrBottom
|
||||||
|
AnchorSideRight.Control = cmbNewCaptchaEvent
|
||||||
|
AnchorSideRight.Side = asrBottom
|
||||||
|
Left = 113
|
||||||
|
Height = 23
|
||||||
|
Top = 80
|
||||||
|
Width = 123
|
||||||
|
Alignment = taRightJustify
|
||||||
|
Anchors = [akTop, akLeft, akRight]
|
||||||
|
BorderSpacing.Top = 4
|
||||||
|
MaxValue = 90
|
||||||
|
OnChange = seLinesCountChange
|
||||||
|
TabOrder = 3
|
||||||
|
end
|
||||||
|
object cmbNewCaptchaEvent: TComboBox
|
||||||
|
AnchorSideLeft.Control = Label1
|
||||||
|
AnchorSideLeft.Side = asrBottom
|
||||||
|
AnchorSideTop.Control = seLinesCount
|
||||||
|
AnchorSideTop.Side = asrBottom
|
||||||
|
AnchorSideRight.Control = seLinesCount
|
||||||
|
AnchorSideRight.Side = asrBottom
|
||||||
|
Left = 113
|
||||||
|
Height = 23
|
||||||
|
Top = 107
|
||||||
|
Width = 123
|
||||||
|
BorderSpacing.Left = 12
|
||||||
|
BorderSpacing.Top = 4
|
||||||
|
ItemHeight = 15
|
||||||
|
ItemIndex = 0
|
||||||
|
Items.Strings = (
|
||||||
|
'none'
|
||||||
|
'Click'
|
||||||
|
'Double Click'
|
||||||
|
)
|
||||||
|
OnChange = cmbNewCaptchaEventChange
|
||||||
|
TabOrder = 5
|
||||||
|
Text = 'none'
|
||||||
|
end
|
||||||
|
object Label1: TLabel
|
||||||
|
AnchorSideLeft.Control = SettingsPanel
|
||||||
|
AnchorSideTop.Control = cmbNewCaptchaEvent
|
||||||
|
AnchorSideTop.Side = asrCenter
|
||||||
|
Left = 0
|
||||||
|
Height = 15
|
||||||
|
Top = 111
|
||||||
|
Width = 101
|
||||||
|
Caption = 'New captcha event'
|
||||||
|
end
|
||||||
|
object edUppercaseChars: TEdit
|
||||||
|
AnchorSideLeft.Control = cmbNewCaptchaEvent
|
||||||
|
AnchorSideRight.Control = cgOptions
|
||||||
|
AnchorSideRight.Side = asrBottom
|
||||||
|
Left = 113
|
||||||
|
Height = 23
|
||||||
|
Top = 135
|
||||||
|
Width = 565
|
||||||
|
Anchors = [akTop, akLeft, akRight]
|
||||||
|
OnChange = edUppercaseCharsChange
|
||||||
|
TabOrder = 6
|
||||||
|
TextHint = 'Upper-case characters to be used'
|
||||||
|
end
|
||||||
|
object Label2: TLabel
|
||||||
|
AnchorSideLeft.Control = SettingsPanel
|
||||||
|
AnchorSideTop.Control = edUppercaseChars
|
||||||
|
AnchorSideTop.Side = asrCenter
|
||||||
|
Left = 0
|
||||||
|
Height = 15
|
||||||
|
Top = 139
|
||||||
|
Width = 60
|
||||||
|
Caption = 'Upper-case'
|
||||||
|
end
|
||||||
|
object Label3: TLabel
|
||||||
|
AnchorSideLeft.Control = SettingsPanel
|
||||||
|
AnchorSideTop.Control = edLowercaseChars
|
||||||
|
AnchorSideTop.Side = asrCenter
|
||||||
|
Left = 0
|
||||||
|
Height = 15
|
||||||
|
Top = 166
|
||||||
|
Width = 60
|
||||||
|
Caption = 'Lower-case'
|
||||||
|
end
|
||||||
|
object edLowercaseChars: TEdit
|
||||||
|
AnchorSideLeft.Control = cmbNewCaptchaEvent
|
||||||
|
AnchorSideTop.Control = edUppercaseChars
|
||||||
|
AnchorSideTop.Side = asrBottom
|
||||||
|
AnchorSideRight.Control = cgOptions
|
||||||
|
AnchorSideRight.Side = asrBottom
|
||||||
|
Left = 113
|
||||||
|
Height = 23
|
||||||
|
Top = 162
|
||||||
|
Width = 565
|
||||||
|
Anchors = [akTop, akLeft, akRight]
|
||||||
|
BorderSpacing.Top = 4
|
||||||
|
OnChange = edLowercaseCharsChange
|
||||||
|
TabOrder = 7
|
||||||
|
TextHint = 'Lower-case characters to be used'
|
||||||
|
end
|
||||||
|
object Label4: TLabel
|
||||||
|
AnchorSideLeft.Control = SettingsPanel
|
||||||
|
AnchorSideTop.Control = edNumericChars
|
||||||
|
AnchorSideTop.Side = asrCenter
|
||||||
|
Left = 0
|
||||||
|
Height = 15
|
||||||
|
Top = 193
|
||||||
|
Width = 77
|
||||||
|
Caption = 'Numeric chars'
|
||||||
|
end
|
||||||
|
object edNumericChars: TEdit
|
||||||
|
AnchorSideLeft.Control = cmbNewCaptchaEvent
|
||||||
|
AnchorSideTop.Control = edLowercaseChars
|
||||||
|
AnchorSideTop.Side = asrBottom
|
||||||
|
AnchorSideRight.Control = cgOptions
|
||||||
|
AnchorSideRight.Side = asrBottom
|
||||||
|
Left = 113
|
||||||
|
Height = 23
|
||||||
|
Top = 189
|
||||||
|
Width = 565
|
||||||
|
Anchors = [akTop, akLeft, akRight]
|
||||||
|
BorderSpacing.Top = 4
|
||||||
|
OnChange = edNumericCharsChange
|
||||||
|
TabOrder = 8
|
||||||
|
TextHint = 'Numeric characters'
|
||||||
|
end
|
||||||
|
object Label5: TLabel
|
||||||
|
AnchorSideLeft.Control = SettingsPanel
|
||||||
|
AnchorSideTop.Control = edCustomChars
|
||||||
|
AnchorSideTop.Side = asrCenter
|
||||||
|
Left = 0
|
||||||
|
Height = 15
|
||||||
|
Top = 220
|
||||||
|
Width = 95
|
||||||
|
Caption = 'Any custom chars'
|
||||||
|
end
|
||||||
|
object edCustomChars: TEdit
|
||||||
|
AnchorSideLeft.Control = cmbNewCaptchaEvent
|
||||||
|
AnchorSideTop.Control = edNumericChars
|
||||||
|
AnchorSideTop.Side = asrBottom
|
||||||
|
AnchorSideRight.Control = cgOptions
|
||||||
|
AnchorSideRight.Side = asrBottom
|
||||||
|
Left = 113
|
||||||
|
Height = 23
|
||||||
|
Top = 216
|
||||||
|
Width = 565
|
||||||
|
Anchors = [akTop, akLeft, akRight]
|
||||||
|
BorderSpacing.Top = 4
|
||||||
|
OnChange = edCustomCharsChange
|
||||||
|
TabOrder = 9
|
||||||
|
TextHint = 'Any other characters to be included'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
object gbVerify: TGroupBox
|
||||||
|
Left = 16
|
||||||
|
Height = 69
|
||||||
|
Top = 25
|
||||||
|
Width = 661
|
||||||
|
Align = alBottom
|
||||||
|
AutoSize = True
|
||||||
|
BorderSpacing.Around = 16
|
||||||
|
Caption = 'Enter CAPTCHA code'
|
||||||
|
ClientHeight = 49
|
||||||
|
ClientWidth = 657
|
||||||
|
TabOrder = 0
|
||||||
|
object edTestCode: TEdit
|
||||||
|
AnchorSideLeft.Control = gbVerify
|
||||||
|
AnchorSideTop.Control = gbVerify
|
||||||
|
AnchorSideTop.Side = asrCenter
|
||||||
|
AnchorSideRight.Control = btnVerify
|
||||||
|
Left = 16
|
||||||
|
Height = 23
|
||||||
|
Top = 13
|
||||||
|
Width = 472
|
||||||
|
Anchors = [akTop, akLeft, akRight]
|
||||||
|
BorderSpacing.Left = 16
|
||||||
|
TabOrder = 0
|
||||||
|
TextHint = 'Enter the CAPTCHA code here'
|
||||||
|
end
|
||||||
|
object btnVerify: TButton
|
||||||
|
AnchorSideLeft.Control = edTestCode
|
||||||
|
AnchorSideLeft.Side = asrBottom
|
||||||
|
AnchorSideTop.Control = gbVerify
|
||||||
|
AnchorSideTop.Side = asrCenter
|
||||||
|
AnchorSideRight.Control = btnTryAgain
|
||||||
|
Left = 500
|
||||||
|
Height = 25
|
||||||
|
Top = 12
|
||||||
|
Width = 56
|
||||||
|
Anchors = [akTop, akRight]
|
||||||
|
AutoSize = True
|
||||||
|
BorderSpacing.Left = 12
|
||||||
|
BorderSpacing.Right = 8
|
||||||
|
BorderSpacing.Bottom = 12
|
||||||
|
Caption = 'Verify'
|
||||||
|
OnClick = btnVerifyClick
|
||||||
|
TabOrder = 1
|
||||||
|
end
|
||||||
|
object btnTryAgain: TButton
|
||||||
|
AnchorSideTop.Control = gbVerify
|
||||||
|
AnchorSideTop.Side = asrCenter
|
||||||
|
AnchorSideRight.Control = gbVerify
|
||||||
|
AnchorSideRight.Side = asrBottom
|
||||||
|
Left = 564
|
||||||
|
Height = 25
|
||||||
|
Top = 12
|
||||||
|
Width = 77
|
||||||
|
Anchors = [akTop, akRight]
|
||||||
|
AutoSize = True
|
||||||
|
BorderSpacing.Right = 16
|
||||||
|
Caption = 'Try again!'
|
||||||
|
OnClick = btnTryAgainClick
|
||||||
|
TabOrder = 2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
object Bevel1: TBevel
|
||||||
|
Left = 0
|
||||||
|
Height = 4
|
||||||
|
Top = 110
|
||||||
|
Width = 693
|
||||||
|
Align = alBottom
|
||||||
|
Shape = bsBottomLine
|
||||||
|
end
|
||||||
|
object FontDialog: TFontDialog
|
||||||
|
MinFontSize = 0
|
||||||
|
MaxFontSize = 0
|
||||||
|
Left = 496
|
||||||
|
Top = 288
|
||||||
|
end
|
||||||
|
end
|
192
components/captcha/demo_runtime/main.pas
Normal file
192
components/captcha/demo_runtime/main.pas
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
unit main;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, ColorBox,
|
||||||
|
StdCtrls, Spin, CaptchaCtrl;
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ TDemoForm }
|
||||||
|
|
||||||
|
TDemoForm = class(TForm)
|
||||||
|
Bevel1: TBevel;
|
||||||
|
btnTryAgain: TButton;
|
||||||
|
btnFont1: TButton;
|
||||||
|
btnFont2: TButton;
|
||||||
|
btnVerify: TButton;
|
||||||
|
cgOptions: TCheckGroup;
|
||||||
|
clbBackgroundColor: TColorBox;
|
||||||
|
cmbNewCaptchaEvent: TComboBox;
|
||||||
|
edNumericChars: TEdit;
|
||||||
|
edCustomChars: TEdit;
|
||||||
|
edUppercaseChars: TEdit;
|
||||||
|
edLowercaseChars: TEdit;
|
||||||
|
edTestCode: TEdit;
|
||||||
|
FontDialog: TFontDialog;
|
||||||
|
gbVerify: TGroupBox;
|
||||||
|
Label1: TLabel;
|
||||||
|
Label2: TLabel;
|
||||||
|
Label3: TLabel;
|
||||||
|
Label4: TLabel;
|
||||||
|
Label5: TLabel;
|
||||||
|
Label6: TLabel;
|
||||||
|
lblBackgroundColor: TLabel;
|
||||||
|
lblMaxAngle: TLabel;
|
||||||
|
lblCharCount: TLabel;
|
||||||
|
lblLinesCount: TLabel;
|
||||||
|
SettingsPanel: TPanel;
|
||||||
|
seMaxAngle: TSpinEdit;
|
||||||
|
seCharCount: TSpinEdit;
|
||||||
|
seLinesCount: TSpinEdit;
|
||||||
|
procedure btnTryAgainClick(Sender: TObject);
|
||||||
|
procedure Button1Click(Sender: TObject);
|
||||||
|
procedure btnFont1Click(Sender: TObject);
|
||||||
|
procedure btnFont2Click(Sender: TObject);
|
||||||
|
procedure btnVerifyClick(Sender: TObject);
|
||||||
|
procedure cgOptionsItemClick(Sender: TObject; Index: integer);
|
||||||
|
procedure clbBackgroundColorChange(Sender: TObject);
|
||||||
|
procedure cmbNewCaptchaEventChange(Sender: TObject);
|
||||||
|
procedure edCustomCharsChange(Sender: TObject);
|
||||||
|
procedure edNumericCharsChange(Sender: TObject);
|
||||||
|
procedure edLowercaseCharsChange(Sender: TObject);
|
||||||
|
procedure edUppercaseCharsChange(Sender: TObject);
|
||||||
|
procedure FormCreate(Sender: TObject);
|
||||||
|
procedure seMaxAngleChange(Sender: TObject);
|
||||||
|
procedure seCharCountChange(Sender: TObject);
|
||||||
|
procedure seLinesCountChange(Sender: TObject);
|
||||||
|
private
|
||||||
|
FCaptcha: TCaptcha;
|
||||||
|
|
||||||
|
public
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
DemoForm: TDemoForm;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
{$R *.lfm}
|
||||||
|
|
||||||
|
{ TDemoForm }
|
||||||
|
|
||||||
|
procedure TDemoForm.FormCreate(Sender: TObject);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
Randomize;
|
||||||
|
|
||||||
|
FCaptcha := TCaptcha.Create(self);
|
||||||
|
FCaptcha.Width := Width;
|
||||||
|
FCaptcha.Parent := self;
|
||||||
|
FCaptcha.Color := clWhite;
|
||||||
|
FCaptcha.NumChars := 8;
|
||||||
|
FCaptcha.Align := alClient;
|
||||||
|
FCaptcha.BorderSpacing.Around := 6;
|
||||||
|
FCaptcha.CustomChars := 'äöü:';
|
||||||
|
FCaptcha.NumericChars := '0123';
|
||||||
|
FCaptcha.Options := FCaptcha.Options - [coAlphaUpper, coAlphaLower, coNumeric];
|
||||||
|
|
||||||
|
clbBackgroundColor.Selected := FCaptcha.Color;
|
||||||
|
seMaxAngle.Value := FCaptcha.MaxAngle;
|
||||||
|
seCharCount.Value := FCaptcha.NumChars;
|
||||||
|
seLinesCount.Value := FCaptcha.NumLines;
|
||||||
|
edUpperCaseChars.Text := FCaptcha.UppercaseChars;
|
||||||
|
edLowercaseChars.Text := FCaptcha.LowercaseChars;
|
||||||
|
edNumericChars.Text := FCaptcha.NumericChars;
|
||||||
|
edCustomChars.Text := FCaptcha.CustomChars;
|
||||||
|
for i := 0 to cgOptions.Items.Count-1 do
|
||||||
|
cgOptions.Checked[i] := TCaptchaOption(i) in FCaptcha.Options;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDemoForm.seMaxAngleChange(Sender: TObject);
|
||||||
|
begin
|
||||||
|
FCaptcha.MaxAngle := seMaxAngle.Value;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDemoForm.seCharCountChange(Sender: TObject);
|
||||||
|
begin
|
||||||
|
FCaptcha.NumChars := seCharCount.Value;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDemoForm.seLinesCountChange(Sender: TObject);
|
||||||
|
begin
|
||||||
|
FCaptcha.NumLines := seLinesCount.Value;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDemoForm.clbBackgroundColorChange(Sender: TObject);
|
||||||
|
begin
|
||||||
|
FCaptcha.Color := clbBackgroundColor.Selected;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDemoForm.cmbNewCaptchaEventChange(Sender: TObject);
|
||||||
|
begin
|
||||||
|
FCaptcha.NewCaptchaEvent := TNewCaptchaEvent(cmbNewCaptchaEvent.ItemIndex);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDemoForm.edCustomCharsChange(Sender: TObject);
|
||||||
|
begin
|
||||||
|
FCaptcha.CustomChars := edCustomChars.Text;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDemoForm.edNumericCharsChange(Sender: TObject);
|
||||||
|
begin
|
||||||
|
FCaptcha.NumericChars := edNumericChars.Text;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDemoForm.edLowercaseCharsChange(Sender: TObject);
|
||||||
|
begin
|
||||||
|
FCaptcha.LowercaseChars := edLowercaseChars.Text;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDemoForm.edUppercaseCharsChange(Sender: TObject);
|
||||||
|
begin
|
||||||
|
FCaptcha.UppercaseChars := edUppercaseChars.Text;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDemoForm.btnTryAgainClick(Sender: TObject);
|
||||||
|
begin
|
||||||
|
FCaptcha.NewCaptcha;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDemoForm.Button1Click(Sender: TObject);
|
||||||
|
begin
|
||||||
|
FCaptcha.AutoSize := not FCaptcha.AutoSize;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDemoForm.btnFont1Click(Sender: TObject);
|
||||||
|
begin
|
||||||
|
FontDialog.Font.Assign(FCaptcha.Font1);
|
||||||
|
if FontDialog.Execute then
|
||||||
|
FCaptcha.Font1 := FontDialog.Font;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDemoForm.btnFont2Click(Sender: TObject);
|
||||||
|
begin
|
||||||
|
FontDialog.Font.Assign(FCaptcha.Font2);
|
||||||
|
if FontDialog.Execute then
|
||||||
|
FCaptcha.Font2 := FontDialog.Font;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDemoForm.btnVerifyClick(Sender: TObject);
|
||||||
|
begin
|
||||||
|
if FCaptcha.Verify(edTestCode.Text) then
|
||||||
|
ShowMessage('Valid.')
|
||||||
|
else
|
||||||
|
ShowMessage('NOT valid.' + LineEnding + 'The correct code would have been: "' + FCaptcha.Text + '"');
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDemoForm.cgOptionsItemClick(Sender: TObject; Index: integer);
|
||||||
|
begin
|
||||||
|
if cgOptions.Checked[Index] then
|
||||||
|
FCaptcha.Options := FCaptcha.Options + [TCaptchaOption(Index)]
|
||||||
|
else
|
||||||
|
FCaptcha.Options := FCaptcha.Options - [TCaptchaOption(Index)]
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
1
components/captcha/images/make_res.bat
Normal file
1
components/captcha/images/make_res.bat
Normal file
@ -0,0 +1 @@
|
|||||||
|
lazres ../source/captcha_images.res tcaptcha.png tcaptcha_150.png tcaptcha_200.png
|
BIN
components/captcha/images/tcaptcha-screenshot.png
Normal file
BIN
components/captcha/images/tcaptcha-screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
BIN
components/captcha/images/tcaptcha.png
Normal file
BIN
components/captcha/images/tcaptcha.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
components/captcha/images/tcaptcha_150.png
Normal file
BIN
components/captcha/images/tcaptcha_150.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
BIN
components/captcha/images/tcaptcha_200.png
Normal file
BIN
components/captcha/images/tcaptcha_200.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
149
components/captcha/images/tcaptcha_200.svg
Normal file
149
components/captcha/images/tcaptcha_200.svg
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
width="32"
|
||||||
|
height="32"
|
||||||
|
id="svg2"
|
||||||
|
sodipodi:version="0.32"
|
||||||
|
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||||
|
version="1.0"
|
||||||
|
sodipodi:docname="tcaptcha_200.svg"
|
||||||
|
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||||
|
inkscape:export-filename="D:\Prog_Lazarus\wp-git\Captcha_Component\images\tcaptcha_200.png"
|
||||||
|
inkscape:export-xdpi="144"
|
||||||
|
inkscape:export-ydpi="144"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="22.283453"
|
||||||
|
inkscape:cx="19.498774"
|
||||||
|
inkscape:cy="15.661846"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:guide-bbox="true"
|
||||||
|
inkscape:window-width="2560"
|
||||||
|
inkscape:window-height="1017"
|
||||||
|
inkscape:window-x="-8"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:snap-bbox="true"
|
||||||
|
inkscape:bbox-paths="true"
|
||||||
|
inkscape:bbox-nodes="true"
|
||||||
|
inkscape:snap-bbox-edge-midpoints="true"
|
||||||
|
inkscape:snap-bbox-midpoints="true"
|
||||||
|
inkscape:object-paths="true"
|
||||||
|
inkscape:snap-intersection-paths="true"
|
||||||
|
inkscape:snap-smooth-nodes="true"
|
||||||
|
inkscape:snap-midpoints="true"
|
||||||
|
inkscape:snap-object-midpoints="true"
|
||||||
|
inkscape:document-rotation="0"
|
||||||
|
inkscape:pagecheckerboard="0">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid2409"
|
||||||
|
visible="true"
|
||||||
|
enabled="true"
|
||||||
|
spacingx="0.5"
|
||||||
|
spacingy="0.5"
|
||||||
|
empspacing="2"
|
||||||
|
snapvisiblegridlinesonly="true"
|
||||||
|
originx="0"
|
||||||
|
originy="0" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Ebene 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
|
||||||
|
d="m 23.778199,13.878703 -8.485283,8.485282 H 12.464442 L 8.2218252,18.121319 16.707106,9.636038 h 2.82843 z"
|
||||||
|
id="rect875"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccc" />
|
||||||
|
<rect
|
||||||
|
style="opacity:0.9;fill:#000000;stroke-width:1.99937;stroke-linecap:round;stroke-linejoin:round;paint-order:markers fill stroke"
|
||||||
|
id="rect853"
|
||||||
|
width="28"
|
||||||
|
height="28"
|
||||||
|
x="2"
|
||||||
|
y="2"
|
||||||
|
rx="6121.7002"
|
||||||
|
ry="0" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.372304"
|
||||||
|
x="-3.9211442"
|
||||||
|
y="18.060839"
|
||||||
|
id="text857"
|
||||||
|
transform="rotate(-22.87353)"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan855"
|
||||||
|
x="-3.9211442"
|
||||||
|
y="18.060839"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#ffff00;stroke-width:0.372304">a</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.462961"
|
||||||
|
x="21.717392"
|
||||||
|
y="8.9995241"
|
||||||
|
id="text861"
|
||||||
|
transform="rotate(14.80282)"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan859"
|
||||||
|
x="21.717392"
|
||||||
|
y="8.9995241"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#ff0000;stroke-width:0.462961">5</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#ff00ff;fill-opacity:1;stroke:none;stroke-width:0.382719"
|
||||||
|
x="9.09375"
|
||||||
|
y="29.832031"
|
||||||
|
id="text865"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan863"
|
||||||
|
x="9.09375"
|
||||||
|
y="29.832031"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#ff00ff;stroke-width:0.382719">M</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:#00ff00;stroke:#00ffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 3,6 26,8"
|
||||||
|
id="path867" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#00ff00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="M 6,28 29,22"
|
||||||
|
id="path869" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#ffaaaa;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="M 10,3 29,27"
|
||||||
|
id="path871" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 6.6 KiB |
BIN
components/captcha/source/captcha_images.res
Normal file
BIN
components/captcha/source/captcha_images.res
Normal file
Binary file not shown.
674
components/captcha/source/captchactrl.pas
Normal file
674
components/captcha/source/captchactrl.pas
Normal file
@ -0,0 +1,674 @@
|
|||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
This unit implements a CAPTCHA component for Lazarus.
|
||||||
|
|
||||||
|
AUTHOR: Werner Pamler
|
||||||
|
|
||||||
|
LICENSE: LGPL with linking exception (like Lazarus LCL)
|
||||||
|
See the file COPYING.modifiedLGPL.txt, included in the Lazarus
|
||||||
|
distribution, for details about the license.
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
|
||||||
|
unit CaptchaCtrl;
|
||||||
|
|
||||||
|
{$mode OBJFPC}{$H+}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, Graphics, Controls;
|
||||||
|
|
||||||
|
type
|
||||||
|
TCaptchaChar = record
|
||||||
|
Character: String; // Character (must be a string for UTF8)
|
||||||
|
Angle: Integer; // Rotation angle of character, in degrees
|
||||||
|
Position: TPoint; // Position of character within buffer bitmap (for TextOut)
|
||||||
|
FontIndex: Integer; // Index of font to be used
|
||||||
|
Color: TColor; // Random color of the character
|
||||||
|
end;
|
||||||
|
TCaptchaCharArray = array of TCaptchaChar;
|
||||||
|
|
||||||
|
TCaptchaLine = record
|
||||||
|
StartPt: TPoint; // Random start point of the line
|
||||||
|
EndPt: TPoint; // Random end point of the line
|
||||||
|
Color: TColor; // Random line color
|
||||||
|
end;
|
||||||
|
TCaptchaLineArray = array of TCaptchaLine;
|
||||||
|
|
||||||
|
TCaptchaOption = (
|
||||||
|
coAlphaUpper, coAlphaLower, coNumeric, coCustom,
|
||||||
|
coRotated, coFont1, coFont2, coLines
|
||||||
|
);
|
||||||
|
TCaptchaOptions = set of TCaptchaOption;
|
||||||
|
TCaptchaCharsOption = coAlphaUpper..coCustom;
|
||||||
|
|
||||||
|
TNewCaptchaEvent = (nceNone, nceClick, nceDblClick);
|
||||||
|
|
||||||
|
const
|
||||||
|
DEFAULT_CAPTCHA_OPTIONS = [
|
||||||
|
coAlphaUpper, coAlphaLower, coNumeric, coCustom,
|
||||||
|
coRotated, coFont1, coFont2, coLines
|
||||||
|
];
|
||||||
|
DEFAULT_CAPTCHA_NUMCHARS = 10;
|
||||||
|
DEFAULT_CAPTCHA_NUMLINES = 30;
|
||||||
|
|
||||||
|
type
|
||||||
|
TCaptcha = class(TGraphicControl)
|
||||||
|
private
|
||||||
|
FBuffer: TBitmap;
|
||||||
|
FCaptchaChars: TCaptchaCharArray;
|
||||||
|
FCaptchaLines: TCaptchaLineArray;
|
||||||
|
FValidChars: array[TCaptchaCharsOption] of string;
|
||||||
|
FFonts: array[0..1] of TFont;
|
||||||
|
FInitialized: Boolean;
|
||||||
|
FMaxAngle: Integer;
|
||||||
|
FNewCaptchaEvent: TNewCaptchaEvent;
|
||||||
|
FNumChars: Integer;
|
||||||
|
FNumLines: Integer;
|
||||||
|
FOptions: TCaptchaOptions;
|
||||||
|
function GetCaptchaText: String;
|
||||||
|
function GetFont(AIndex: Integer): TFont;
|
||||||
|
function GetValidChars(AIndex: Integer): String;
|
||||||
|
procedure SetFont(AIndex: Integer; const AValue: TFont);
|
||||||
|
procedure SetMaxAngle(const AValue: Integer);
|
||||||
|
procedure SetNumChars(const AValue: Integer);
|
||||||
|
procedure SetNumLines(const AValue: Integer);
|
||||||
|
procedure SetOptions(const AValue: TCaptchaOptions);
|
||||||
|
procedure SetValidChars(AIndex: Integer; const AValue: String);
|
||||||
|
protected
|
||||||
|
function AlmostBackgroundColor(AColor: TColor): Boolean;
|
||||||
|
procedure CreateNewCaptcha(ANumChars, ANumLines: Integer; KeepText,KeepLines: Boolean);
|
||||||
|
procedure DrawBuffer;
|
||||||
|
procedure InitAngles;
|
||||||
|
procedure InitCharPos(KeepVertPos: boolean);
|
||||||
|
procedure InitFontIndex;
|
||||||
|
procedure InitLineColors;
|
||||||
|
procedure InitLines(ACount: Integer; KeepExisting: Boolean);
|
||||||
|
procedure InitText(ACount: Integer; KeepExisting: Boolean);
|
||||||
|
procedure InitTextColors;
|
||||||
|
protected
|
||||||
|
procedure CalculatePreferredSize(var PreferredWidth, PreferredHeight: integer;
|
||||||
|
WithThemeSpace: Boolean); override;
|
||||||
|
procedure Click; override;
|
||||||
|
procedure DblClick; override;
|
||||||
|
procedure Paint; override;
|
||||||
|
procedure Resize; override;
|
||||||
|
procedure SetColor(AValue: TColor); override;
|
||||||
|
public
|
||||||
|
constructor Create(AOwner: TComponent); override;
|
||||||
|
destructor Destroy; override;
|
||||||
|
procedure NewCaptcha;
|
||||||
|
function Verify(const AText: String): Boolean;
|
||||||
|
property Text: String read GetCaptchaText;
|
||||||
|
published
|
||||||
|
property CustomChars: String index ord(coCustom) read GetValidChars write SetValidChars;
|
||||||
|
property Font1: TFont index 0 read GetFont write SetFont;
|
||||||
|
property Font2: TFont index 1 read GetFont write SetFont;
|
||||||
|
property Options: TCaptchaOptions read FOptions write SetOptions default DEFAULT_CAPTCHA_OPTIONS;
|
||||||
|
property LowercaseChars: String index ord(coAlphaLower) read GetValidChars write SetValidChars;
|
||||||
|
property MaxAngle: Integer read FMaxAngle write SetMaxAngle default 60;
|
||||||
|
property NumericChars: String index ord(coNumeric) read GetValidChars write SetValidChars;
|
||||||
|
property NewCaptchaEvent: TNewCaptchaEvent read FNewCaptchaEvent write FNewCaptchaEvent default nceNone;
|
||||||
|
property NumChars: Integer read FNumChars write SetNumChars default DEFAULT_CAPTCHA_NUMCHARS;
|
||||||
|
property NumLines: Integer read FNumLines write SetNumLines default DEFAULT_CAPTCHA_NUMLINES;
|
||||||
|
property UppercaseChars: String index ord(coAlphaUpper) read GetValidChars write SetValidChars;
|
||||||
|
|
||||||
|
property Align;
|
||||||
|
property AutoSize default true;
|
||||||
|
property BorderSpacing;
|
||||||
|
property Color default clBlack;
|
||||||
|
property OnClick;
|
||||||
|
property OnDblClick;
|
||||||
|
property OnMouseDown;
|
||||||
|
property OnMouseEnter;
|
||||||
|
property OnMouseLeave;
|
||||||
|
property OnMouseUp;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure Register;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
{$R captcha_images.res}
|
||||||
|
|
||||||
|
uses
|
||||||
|
LCLIntf, Types, GraphUtil, Math, LazUTF8;
|
||||||
|
|
||||||
|
{ Component registration }
|
||||||
|
|
||||||
|
procedure Register;
|
||||||
|
begin
|
||||||
|
RegisterComponents('Misc', [TCaptcha]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ Utility functions }
|
||||||
|
|
||||||
|
function RotatePoint(const APoint: TPoint; Angle: Double): TPoint;
|
||||||
|
var
|
||||||
|
sinphi, cosphi: Double;
|
||||||
|
begin
|
||||||
|
Angle := DegToRad(Angle);
|
||||||
|
SinCos(angle, sinphi, cosphi);
|
||||||
|
Result.X := Round( cosphi * APoint.X + sinphi * APoint.Y);
|
||||||
|
Result.Y := Round(-sinphi * APoint.X + cosphi * APoint.Y);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function RotateRect(const Width, Height: Integer; Angle: Double): TRect;
|
||||||
|
var
|
||||||
|
P0, P1, P2, P3: TPoint;
|
||||||
|
begin
|
||||||
|
P0 := Point(0, 0);
|
||||||
|
P1 := RotatePoint(Point(0, Height), Angle);
|
||||||
|
P2 := RotatePoint(Point(Width, 0), Angle);
|
||||||
|
P3 := RotatePoint(Point(Width, Height), Angle);
|
||||||
|
Result.Left := MinValue([P0.X, P1.X, P2.X, P3.X]);
|
||||||
|
Result.Top := MinValue([P0.Y, P1.Y, P2.Y, P3.Y]);
|
||||||
|
Result.Right := MaxValue([P0.X, P1.X, P2.X, P3.X]);
|
||||||
|
Result.Bottom := MaxValue([P0.Y, P1.Y, P2.Y, P3.Y]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ TCaptcha }
|
||||||
|
|
||||||
|
constructor TCaptcha.Create(AOwner: TComponent);
|
||||||
|
begin
|
||||||
|
inherited;
|
||||||
|
with GetControlClassDefaultSize do
|
||||||
|
SetInitialBounds(0, 0, 300, 100);
|
||||||
|
AutoSize := true;
|
||||||
|
Color := clBlack;
|
||||||
|
|
||||||
|
FBuffer := TBitmap.Create;
|
||||||
|
FBuffer.PixelFormat := pf32bit;
|
||||||
|
|
||||||
|
FFonts[0] := TFont.Create;
|
||||||
|
FFonts[0].Size := 36;
|
||||||
|
|
||||||
|
FFonts[1] := TFont.Create;
|
||||||
|
{$IF DEFINED(MSWindows)}
|
||||||
|
FFonts[1].Name := 'Courier New';
|
||||||
|
{$ELSEIF DEFINED(Linux)}
|
||||||
|
FFonts[1].Name := 'FreeMono';
|
||||||
|
{$ELSEIF DEFINED(Darwin)}
|
||||||
|
Fronts[1].Name := 'Courier';
|
||||||
|
{$IFEND}
|
||||||
|
FFonts[1].Size := 36;
|
||||||
|
|
||||||
|
FOptions := DEFAULT_CAPTCHA_OPTIONS;
|
||||||
|
FMaxAngle := 60;
|
||||||
|
FNumChars := DEFAULT_CAPTCHA_NUMCHARS;
|
||||||
|
FNumLines := DEFAULT_CAPTCHA_NUMLINES;
|
||||||
|
FValidChars[coAlphaUpper] := 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||||
|
FValidChars[coAlphaLower] := 'abcdefghijklmnopqrstuvwxyz';
|
||||||
|
FValidChars[coNumeric] := '0123456789';
|
||||||
|
FValidChars[coCustom] := '';
|
||||||
|
FInitialized := false;
|
||||||
|
|
||||||
|
// Do not call Randomize at runtime to facilitate debugging.
|
||||||
|
if (csDesigning in ComponentState) then
|
||||||
|
Randomize;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TCaptcha.Destroy;
|
||||||
|
begin
|
||||||
|
Finalize(FCaptchaChars);
|
||||||
|
Finalize(FCaptchaLines);
|
||||||
|
FreeAndNil(FFonts[0]);
|
||||||
|
FreeAndNil(FFonts[1]);
|
||||||
|
FreeAndNil(FBuffer);
|
||||||
|
inherited;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TCaptcha.AlmostBackgroundColor(AColor: TColor): Boolean;
|
||||||
|
const
|
||||||
|
TOLERANCE = 64;
|
||||||
|
var
|
||||||
|
colorH, colorL, colorS: Byte;
|
||||||
|
bgColorH, bgColorL, bgColorS: Byte;
|
||||||
|
begin
|
||||||
|
ColorToHLS(ColorToRGB(AColor), colorH, colorL, colorS);
|
||||||
|
ColorToHLS(ColorToRGB(Self.Color), bgColorH, bgColorL, bgColorS);
|
||||||
|
Result := abs(colorL - bgColorL) < TOLERANCE;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCaptcha.CalculatePreferredSize(
|
||||||
|
var PreferredWidth, PreferredHeight: integer;
|
||||||
|
WithThemeSpace: Boolean);
|
||||||
|
begin
|
||||||
|
inherited;
|
||||||
|
|
||||||
|
CreateNewCaptcha(FNumChars, FNumLines, true, true);
|
||||||
|
|
||||||
|
PreferredWidth := FBuffer.Width;
|
||||||
|
PreferredHeight := 0;
|
||||||
|
if (coFont1 in FOptions) then
|
||||||
|
begin
|
||||||
|
FBuffer.Canvas.Font.Assign(FFonts[0]);
|
||||||
|
PreferredHeight := FBuffer.Canvas.TextHeight('Tg');
|
||||||
|
end;
|
||||||
|
if (coFont2 in FOptions) then
|
||||||
|
begin
|
||||||
|
FBuffer.Canvas.Font.Assign(FFonts[1]);
|
||||||
|
PreferredHeight := Max(PreferredHeight, FBuffer.Canvas.TextHeight('Tg'));
|
||||||
|
end;
|
||||||
|
PreferredHeight := 3*PreferredHeight div 2;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCaptcha.Click;
|
||||||
|
begin
|
||||||
|
inherited;
|
||||||
|
if FNewCaptchaEvent = nceClick then
|
||||||
|
NewCaptcha;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCaptcha.CreateNewCaptcha(ANumChars, ANumLines: Integer;
|
||||||
|
KeepText, KeepLines: Boolean);
|
||||||
|
begin
|
||||||
|
if not KeepText then
|
||||||
|
FCaptchaChars := nil;
|
||||||
|
FCaptchaLines := nil;
|
||||||
|
InitText(ANumChars, KeepText);
|
||||||
|
InitTextColors; // after InitText
|
||||||
|
InitAngles;
|
||||||
|
InitCharPos(false);
|
||||||
|
InitLines(ANumLines, KeepLines); // after InitCharPos
|
||||||
|
InitLineColors; // after InitLines
|
||||||
|
DrawBuffer;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCaptcha.DblClick;
|
||||||
|
begin
|
||||||
|
inherited;
|
||||||
|
if FNewCaptchaEvent = nceDblClick then
|
||||||
|
NewCaptcha;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCaptcha.DrawBuffer;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
if not Assigned(FBuffer) then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
// Fill the buffer background in the requested color.
|
||||||
|
FBuffer.Canvas.Brush.Color := Self.Color;
|
||||||
|
FBuffer.Canvas.Brush.Style := bsSolid;
|
||||||
|
FBuffer.Canvas.FillRect(0, 0, FBuffer.Width, FBuffer.Height);
|
||||||
|
|
||||||
|
// Draw the captcha characters to the buffer bitmap
|
||||||
|
if (FOptions * [coAlphaUpper, coAlphaLower, coNumeric, coCustom] <> []) and
|
||||||
|
(FOptions * [coFont1, coFont2] <> []) then
|
||||||
|
begin
|
||||||
|
FBuffer.Canvas.Brush.Style := bsClear;
|
||||||
|
for i := 0 to High(FCaptchaChars) do
|
||||||
|
with FCaptchaChars[i] do
|
||||||
|
begin
|
||||||
|
FBuffer.Canvas.Font.Assign(FFonts[FontIndex]);
|
||||||
|
FBuffer.Canvas.Font.Color := Color;
|
||||||
|
if coRotated in FOptions then
|
||||||
|
FBuffer.Canvas.Font.Orientation := Angle * 10
|
||||||
|
else
|
||||||
|
FBuffer.Canvas.Font.Orientation := 0;
|
||||||
|
FBuffer.Canvas.TextOut(Position.X, Position.Y, Character);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Draw the captcha lines
|
||||||
|
if coLines in FOptions then
|
||||||
|
begin
|
||||||
|
for i := 0 to High(FCaptchaLines) do
|
||||||
|
with FCaptchaLines[i] do
|
||||||
|
begin
|
||||||
|
FBuffer.Canvas.Pen.Color := Color;
|
||||||
|
FBuffer.Canvas.Line(StartPt.X, StartPt.Y, EndPt.X, EndPt.Y);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TCaptcha.GetFont(AIndex: Integer): TFont;
|
||||||
|
begin
|
||||||
|
Result := FFonts[AIndex];
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TCaptcha.GetCaptchaText: string;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
Result := '';
|
||||||
|
for i := 0 to High(FCaptchaChars) do
|
||||||
|
Result := Result + FCaptchaChars[i].Character;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TCaptcha.GetValidChars(AIndex: Integer): String;
|
||||||
|
begin
|
||||||
|
Result := FValidChars[TCaptchaCharsOption(AIndex)];
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCaptcha.InitAngles;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
for i := 0 to High(FCaptchaChars) do
|
||||||
|
FCaptchaChars[i].Angle := Random(FMaxAngle*2) - FMaxAngle;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Calculates the character positions and stores them in the ChaptchaChars array
|
||||||
|
When KeepVertPos is false, the vertical position of the characters is selected
|
||||||
|
randomly within the height of the control. Otherwise the already stored
|
||||||
|
vertical positions are used. }
|
||||||
|
procedure TCaptcha.InitCharPos(KeepVertPos: Boolean);
|
||||||
|
var
|
||||||
|
x: Integer;
|
||||||
|
i: Integer;
|
||||||
|
R: TRect;
|
||||||
|
ext: TSize;
|
||||||
|
w, h: Integer;
|
||||||
|
fnt: TFont;
|
||||||
|
maxHeight: Integer;
|
||||||
|
begin
|
||||||
|
maxHeight := 0;
|
||||||
|
x := 0;
|
||||||
|
for i := 0 to High(FCaptchaChars) do
|
||||||
|
begin
|
||||||
|
// Set character font
|
||||||
|
fnt := FFonts[FCaptchaChars[i].FontIndex];
|
||||||
|
FBuffer.Canvas.Font.Assign(fnt);
|
||||||
|
|
||||||
|
// Get character size
|
||||||
|
ext := FBuffer.Canvas.TextExtent(FCaptchaChars[i].Character);
|
||||||
|
|
||||||
|
// Rotate the character and get the bounds of the enclosing rectangle.
|
||||||
|
// The rotation occurs around the upper left corner of the character.
|
||||||
|
if coRotated in FOptions then
|
||||||
|
R := RotateRect(ext.CX, ext.CY, FCaptchaChars[i].Angle)
|
||||||
|
else
|
||||||
|
// unrotated: add some extra space for better legibility
|
||||||
|
R := Rect(0, 0, ext.CX * 6 div 5, ext.CY);
|
||||||
|
w := R.Right - R.Left;
|
||||||
|
h := R.Bottom - R.Top;
|
||||||
|
|
||||||
|
// Horizontal drawing coordinate
|
||||||
|
FCaptchaChars[i].Position.X := x - R.Left;
|
||||||
|
|
||||||
|
// Vertical drawing coordinate: randomly inside control
|
||||||
|
if not KeepVertPos then
|
||||||
|
begin
|
||||||
|
if Self.Height > h then
|
||||||
|
FCaptchaChars[i].Position.Y := Max(0, Random(Height - h) - R.Top)
|
||||||
|
else
|
||||||
|
FCaptchaChars[i].Position.Y := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Find max y coordinate needed to enclose the entire text
|
||||||
|
maxHeight := Max(maxHeight, FCaptchaChars[i].Position.Y + h);
|
||||||
|
// Next drawing position
|
||||||
|
x := x + w;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Set size of the bitmap buffer so that the entire captcha is enclosed.
|
||||||
|
FBuffer.SetSize(x, maxHeight);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCaptcha.InitFontIndex;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
if FOptions * [coFont1, coFont2] = [coFont1] then
|
||||||
|
for i := 0 to High(FCaptchaChars) do
|
||||||
|
FCaptchaChars[i].FontIndex := 0
|
||||||
|
else
|
||||||
|
if FOptions * [coFont1, coFont2] = [coFont2] then
|
||||||
|
for i := 0 to High(FCaptchaChars) do
|
||||||
|
FCaptchaChars[i].FontIndex := 1
|
||||||
|
else
|
||||||
|
for i := 0 to High(FCaptchaChars) do
|
||||||
|
FCaptchaChars[i].FontIndex := Random(2);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Pick random color for a line.
|
||||||
|
Make sure that the color is not too close to the background color. }
|
||||||
|
procedure TCaptcha.InitLineColors;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
// Line colors
|
||||||
|
if (FOptions * [coLines] <> []) then
|
||||||
|
for i := 0 to High(FCaptchaLines) do
|
||||||
|
repeat
|
||||||
|
FCaptchaLines[i].Color := TColor(Random($FFFFFF));
|
||||||
|
until not AlmostBackgroundColor(FCaptchaLines[i].Color);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCaptcha.InitLines(ACount: Integer; KeepExisting: Boolean);
|
||||||
|
var
|
||||||
|
i, n: Integer;
|
||||||
|
begin
|
||||||
|
if coLines in FOptions then
|
||||||
|
begin
|
||||||
|
if KeepExisting then
|
||||||
|
n := Length(FCaptchaLines)
|
||||||
|
else
|
||||||
|
n := 0;
|
||||||
|
SetLength(FCaptchaLines, ACount);
|
||||||
|
for i := n to High(FCaptchaLines) do
|
||||||
|
begin
|
||||||
|
// Select random start and end points
|
||||||
|
FCaptchaLines[i].StartPt := Point(
|
||||||
|
Random(FBuffer.Width),
|
||||||
|
Random(FBuffer.Height)
|
||||||
|
);
|
||||||
|
FCaptchaLines[i].EndPt := Point(
|
||||||
|
Random(FBuffer.Width),
|
||||||
|
Random(FBuffer.Height)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Select random line color
|
||||||
|
repeat
|
||||||
|
FCaptchaLines[i].Color := TColor(Random($FFFFFF));
|
||||||
|
until not AlmostBackgroundColor(FCaptchaLines[i].Color);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCaptcha.InitText(ACount: Integer; KeepExisting: Boolean);
|
||||||
|
var
|
||||||
|
i, j, n: Integer;
|
||||||
|
ok: Boolean;
|
||||||
|
validChars: String;
|
||||||
|
co: TCaptchaCharsOption;
|
||||||
|
begin
|
||||||
|
if (FOptions * [coAlphaUpper, coAlphaLower, coNumeric, coCustom] <> []) and
|
||||||
|
(FOptions * [coFont1, coFont2] <> []) then
|
||||||
|
begin
|
||||||
|
// Prepare character list for captcha
|
||||||
|
validChars := '';
|
||||||
|
for co in TCaptchaCharsOption do
|
||||||
|
if co in FOptions then
|
||||||
|
validChars := validChars + FValidChars[co];;
|
||||||
|
// Remove characters which are hard to distinguish
|
||||||
|
if FOptions * [coAlphaUpper, coAlphaLower] = [coAlphaUpper, coAlphaLower] then
|
||||||
|
begin
|
||||||
|
i := Pos('I', validChars); // Remove upper-case I
|
||||||
|
if i > 0 then Delete(validChars, i, 1);
|
||||||
|
i := Pos('l', validChars); // Remove lower-case L
|
||||||
|
if i > 0 then Delete(validChars, i, 1);
|
||||||
|
end;
|
||||||
|
if FOptions * [coAlphaUpper, coNumeric] = [coAlphaUpper, coNumeric] then
|
||||||
|
begin
|
||||||
|
i := Pos('O', validChars); // Remove upper-case O
|
||||||
|
if i > 0 then Delete(validChars, i, 1);
|
||||||
|
i := Pos('0', validChars); // Remove number zero
|
||||||
|
if i > 0 then Delete(validChars, i, 1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
if KeepExisting then
|
||||||
|
n := Length(FCaptchaChars)
|
||||||
|
else
|
||||||
|
n := 0;
|
||||||
|
// Get random captcha characters, but keep previously assigned chars.
|
||||||
|
SetLength(FCaptchaChars, ACount);
|
||||||
|
for i := n to High(FCaptchaChars) do
|
||||||
|
begin
|
||||||
|
// Pick random character from the validChars. Take care of UTF8.
|
||||||
|
FCaptchaChars[i].Character := UTF8Copy(validChars, random(UTF8Length(validChars)) + 1, 1);
|
||||||
|
|
||||||
|
// Pick one of the fonts
|
||||||
|
if FOptions * [coFont1, coFont2] = [coFont1] then
|
||||||
|
FCaptchaChars[i].FontIndex := 1
|
||||||
|
else
|
||||||
|
if FOptions * [coFont1, coFont2] = [coFont2] then
|
||||||
|
FCaptchaChars[i].FontIndex := 2
|
||||||
|
else
|
||||||
|
FCaptchaChars[i].FontIndex := Random(2);
|
||||||
|
|
||||||
|
if KeepExisting then
|
||||||
|
begin
|
||||||
|
// Set random text color
|
||||||
|
repeat
|
||||||
|
FCaptchaChars[i].Color := TColor(Random($FFFFFF));
|
||||||
|
until not AlmostbackgroundColor(FCaptchaChars[i].Color);
|
||||||
|
|
||||||
|
// Set random rotation angle
|
||||||
|
if (coRotated in FOptions) then
|
||||||
|
FCaptchaChars[i].Angle := Random(FMaxAngle*2) - FMaxAngle;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end else
|
||||||
|
SetLength(FCaptchaChars, 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Pick random color for a character.
|
||||||
|
Make sure that the color is not too close to the background color. }
|
||||||
|
procedure TCaptcha.InitTextColors;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
// Character colors
|
||||||
|
if (FOptions * [coAlphaUpper, coAlphaLower, coNumeric, coCustom] <> []) then
|
||||||
|
for i := 0 to High(FCaptchaChars) do
|
||||||
|
repeat
|
||||||
|
FCaptchaChars[i].Color := TColor(Random($FFFFFF));
|
||||||
|
until not AlmostbackgroundColor(FCaptchaChars[i].Color);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCaptcha.NewCaptcha;
|
||||||
|
begin
|
||||||
|
CreateNewCaptcha(FNumChars, FNumLines, false, false);
|
||||||
|
Invalidate;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCaptcha.Paint;
|
||||||
|
begin
|
||||||
|
Canvas.Draw((Width - FBuffer.Width) div 2, (Height - FBuffer.Height) div 2, FBuffer);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCaptcha.Resize;
|
||||||
|
begin
|
||||||
|
inherited;
|
||||||
|
if Assigned(FBuffer) and not FInitialized then
|
||||||
|
begin
|
||||||
|
CreateNewCaptcha(FNumChars, FNumLines, false, false);
|
||||||
|
FInitialized := true;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCaptcha.SetColor(AValue: TColor);
|
||||||
|
begin
|
||||||
|
if AValue = Color then
|
||||||
|
exit;
|
||||||
|
inherited SetColor(AValue);
|
||||||
|
InitTextColors;
|
||||||
|
InitLineColors;
|
||||||
|
DrawBuffer;
|
||||||
|
Invalidate;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCaptcha.SetFont(AIndex: Integer; const AValue: TFont);
|
||||||
|
begin
|
||||||
|
if FFonts[AIndex].IsEqual(AValue) then
|
||||||
|
exit;
|
||||||
|
FFonts[AIndex].Assign(AValue);
|
||||||
|
InitFontIndex;
|
||||||
|
InitCharPos(true);
|
||||||
|
DrawBuffer;
|
||||||
|
Invalidate;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCaptcha.SetMaxAngle(const AValue: Integer);
|
||||||
|
begin
|
||||||
|
if AValue = FMaxAngle then
|
||||||
|
exit;
|
||||||
|
FMaxAngle := AValue;
|
||||||
|
InitAngles;
|
||||||
|
InitCharPos(true);
|
||||||
|
DrawBuffer;
|
||||||
|
Invalidate;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCaptcha.SetNumChars(const AValue: Integer);
|
||||||
|
begin
|
||||||
|
if AValue = FNumChars then
|
||||||
|
exit;
|
||||||
|
FNumChars := AValue;
|
||||||
|
InitText(FNumChars, true);
|
||||||
|
InitAngles;
|
||||||
|
InitCharPos(false);
|
||||||
|
InitLines(FNumLines, false);
|
||||||
|
DrawBuffer;
|
||||||
|
Invalidate;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCaptcha.SetNumLines(const AValue: Integer);
|
||||||
|
begin
|
||||||
|
if AValue = FNumLines then
|
||||||
|
exit;
|
||||||
|
FNumLines := AValue;
|
||||||
|
InitLines(FNumLines, true);
|
||||||
|
DrawBuffer;
|
||||||
|
Invalidate;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCaptcha.SetOptions(const AValue: TCaptchaOptions);
|
||||||
|
var
|
||||||
|
oldOptions: TCaptchaOptions;
|
||||||
|
begin
|
||||||
|
if AValue = FOptions then
|
||||||
|
exit;
|
||||||
|
oldOptions := FOptions;
|
||||||
|
FOptions := AValue;
|
||||||
|
if (oldOptions * [coAlphaUpper, coAlphaLower, coNumeric, coCustom] <>
|
||||||
|
AValue * [coAlphaUpper, coAlphaLower, coNumeric, coCustom])
|
||||||
|
then
|
||||||
|
InitText(FNumChars, false);
|
||||||
|
if (oldOptions * [coFont1, coFont2] <> AValue * [coFont1, coFont2]) then
|
||||||
|
begin
|
||||||
|
InitFontIndex;
|
||||||
|
InitCharPos(false);
|
||||||
|
end;
|
||||||
|
if (oldOptions * [coRotated] <> AValue * [coRotated]) then
|
||||||
|
begin
|
||||||
|
InitAngles;
|
||||||
|
InitCharPos(true);
|
||||||
|
end;
|
||||||
|
if oldOptions * [coLines] <> AValue * [coLines] then
|
||||||
|
InitLines(FNumLines, true);
|
||||||
|
DrawBuffer;
|
||||||
|
Invalidate;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCaptcha.SetValidChars(AIndex: Integer; const AValue: String);
|
||||||
|
begin
|
||||||
|
if FValidChars[TCaptchaCharsOption(AIndex)] = AValue then
|
||||||
|
exit;
|
||||||
|
FValidChars[TCaptchaCharsOption(AIndex)] := AValue;
|
||||||
|
NewCaptcha;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TCaptcha.Verify(const AText: String): Boolean;
|
||||||
|
begin
|
||||||
|
Result := (AText = GetCaptchaText);
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
Reference in New Issue
Block a user