diff --git a/SunnyUI/Controls/UIVerificationCode.cs b/SunnyUI/Controls/UIVerificationCode.cs
new file mode 100644
index 00000000..7d9c4b17
--- /dev/null
+++ b/SunnyUI/Controls/UIVerificationCode.cs
@@ -0,0 +1,167 @@
+/******************************************************************************
+ * SunnyUI 开源控件库、工具类库、扩展类库、多页面开发框架。
+ * CopyRight (C) 2012-2022 ShenYongHua(沈永华).
+ * QQ群:56829229 QQ:17612584 EMail:SunnyUI@QQ.Com
+ *
+ * Blog: https://www.cnblogs.com/yhuse
+ * Gitee: https://gitee.com/yhuse/SunnyUI
+ * GitHub: https://github.com/yhuse/SunnyUI
+ *
+ * SunnyUI.dll can be used for free under the GPL-3.0 license.
+ * If you use this code, please keep this note.
+ * 如果您使用此代码,请保留此说明。
+ ******************************************************************************
+ * 文件名称: UIVerificationCode.cs
+ * 文件说明: 验证码控件
+ * 当前版本: V3.1
+ * 创建日期: 2022-06-11
+ *
+ * 2022-06-11: V3.1.9 增加文件说明
+******************************************************************************/
+
+using System;
+using System.ComponentModel;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+
+namespace Sunny.UI
+{
+ [DefaultEvent("Click")]
+ [DefaultProperty("Text")]
+ [ToolboxItem(true)]
+ public class UIVerificationCode : UIControl
+ {
+ public UIVerificationCode()
+ {
+ SetStyleFlags();
+ fillColor = UIStyles.Blue.PlainColor;
+ Width = 100;
+ Height = 35;
+ }
+
+ public override void SetStyleColor(UIBaseStyle uiColor)
+ {
+ base.SetStyleColor(uiColor);
+ fillColor = uiColor.PlainColor;
+ }
+
+ protected override void OnClick(EventArgs e)
+ {
+ base.OnClick(e);
+ Invalidate();
+ }
+
+ protected override void OnPaintFill(Graphics g, GraphicsPath path)
+ {
+ base.OnPaintFill(g, path);
+
+ var bmp = CreateImage(RandomEx.RandomChars(CodeLength));
+ g.DrawImage(bmp, Width / 2 - bmp.Width / 2, 1);
+ bmp.Dispose();
+ }
+
+ protected override void OnPaintFore(Graphics g, GraphicsPath path)
+ {
+ if (Text != "") Text = "";
+ //base.OnPaintFore(g, path);
+ }
+
+ [DefaultValue(4)]
+ [Description("验证码长度"), Category("SunnyUI")]
+ public int CodeLength { get; set; } = 4;
+
+ [DefaultValue(18)]
+ [Description("验证码字体大小"), Category("SunnyUI")]
+ public int CodeFontSize { get; set; } = 18;
+
+ [DefaultValue(null)]
+ [Description("验证码文字"), Category("SunnyUI")]
+ public string Code { get; private set; }
+
+ ///
+ /// 生成图片
+ ///
+ /// 验证码表达式
+ private Bitmap CreateImage(string code)
+ {
+ Font font = new Font(Font.Name, CodeFontSize);
+ Code = code;
+ SizeF sf = GDI.MeasureString(code, font);
+
+ Bitmap image = new Bitmap((int)sf.Width + 16, Height - 2);
+
+ //创建画布
+ Graphics g = Graphics.FromImage(image);
+ Random random = new Random();
+
+ //图片背景色
+ g.Clear(fillColor);
+
+ //画图片背景线
+ for (int i = 0; i < 6; i++)
+ {
+ int x1 = random.Next(image.Width);
+ int x2 = random.Next(image.Width);
+ int y1 = random.Next(image.Height);
+ int y2 = random.Next(image.Height);
+
+ g.DrawLine(Pens.Black, x1, y1, x2, y2);
+ }
+
+ //画图片的前景噪音点
+ for (int i = 0; i < 50; i++)
+ {
+ int x = random.Next(image.Width);
+ int y = random.Next(image.Height);
+ image.SetPixel(x, y, Color.FromArgb(random.Next()));
+ }
+
+ g.DrawString(code, font, rectColor, image.Width / 2 - sf.Width / 2, image.Height / 2 - sf.Height / 2);
+ var imageex = TwistImage(image, true, 5, 5);
+ font.Dispose();
+ image.Dispose();
+ return imageex;
+ }
+
+ ///
+ ///正弦曲线Wave扭曲图片
+ ///
+ ///图片路径
+ ///如果扭曲则选择为True
+ ///波形的幅度倍数,越大扭曲的程度越高,一般为3
+ ///波形的起始相位,取值区间[0-2*PI)
+ ///
+ private Bitmap TwistImage(Bitmap srcBmp, bool bXDir, double dMultValue, double dPhase)
+ {
+ Bitmap destBmp = new Bitmap(srcBmp.Width, srcBmp.Height);
+
+ // 将位图背景填充为白色
+ Graphics graph = Graphics.FromImage(destBmp);
+ graph.FillRectangle(new SolidBrush(fillColor), 0, 0, destBmp.Width, destBmp.Height);
+ graph.Dispose();
+ double dBaseAxisLen = bXDir ? (double)destBmp.Height : (double)destBmp.Width;
+ for (int i = 0; i < destBmp.Width; i++)
+ {
+ for (int j = 0; j < destBmp.Height; j++)
+ {
+ double dx = 0;
+ dx = bXDir ? (Math.PI * 2 * (double)j) / dBaseAxisLen : (Math.PI * 2 * (double)i) / dBaseAxisLen;
+ dx += dPhase;
+ double dy = Math.Sin(dx);
+
+ // 取得当前点的颜色
+ int nOldX = 0, nOldY = 0;
+ nOldX = bXDir ? i + (int)(dy * dMultValue) : i;
+ nOldY = bXDir ? j : j + (int)(dy * dMultValue);
+ System.Drawing.Color color = srcBmp.GetPixel(i, j);
+ if (nOldX >= 0 && nOldX < destBmp.Width && nOldY >= 0 && nOldY < destBmp.Height)
+ {
+ destBmp.SetPixel(nOldX, nOldY, color);
+ }
+ }
+ }
+
+ return destBmp;
+ }
+ }
+}