防机器人提交表单
以下脚本使自动工具难以提交表单。此基本脚本涉及的步骤包括:创建绘图空间、分配颜色、填充背景、绘制字符、添加失真以及将图像输出到浏览器。

引言
以下脚本使自动工具难以提交表单。此基本脚本涉及的步骤包括:创建绘图空间、分配颜色、填充背景、绘制字符、添加失真以及将图像输出到浏览器。
使用 GDI+ 进行绘图
GDI+ 是 .NET 应用程序的全能绘图模型。GDI+ 在 .NET 中有多种用途,包括将文档写入打印机、在 Windows 应用程序中显示图形以及在网页中渲染图形。使用 GDI+ 代码绘制图形比使用静态图像文件速度慢。但是,它为您提供了更大的自由度,并实现了早期 Web 开发平台(如经典 ASP)中不可能实现(或非常困难)的几个可能性。例如,您可以创建包含用户特定信息的丰富图形,并且可以根据数据库中的记录即时渲染图表和图形。GDI+ 编程的核心是 System.Drawing.Graphics
类。Graphics
类封装了一个 GDI+ 绘图表面,无论是窗口、打印文档还是内存中的位图。ASP.NET 开发人员很少需要绘制窗口或打印文档,因此最后一个选项是最实用的。要在 ASP.NET 中使用 GDI+,您需要遵循四个步骤:
- 创建您将在其中执行所有绘图操作的内存位图。
- 为图像创建 GDI+ 图形上下文。这将为您提供所需的
System.Drawing.Graphics
对象。 - 使用
Graphics
对象的方法执行绘图。您可以绘制和填充线条和形状,甚至可以从现有文件中复制位图内容。 - 使用
Response.OutputStream
属性将图像的二进制数据写入浏览器。
在接下来的几节中,您将看到几个使用 GDI+ 的网页示例。在继续之前,您可能需要确保已导入以下命名空间:
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
System.Drawing
命名空间定义了许多绘图的基本要素,包括画笔、笔刷和位图。默认情况下,Visual Studio 会将 using
语句添加到您所有网页中,以导入这些命名空间。System.Drawing.Drawing2D
命名空间添加了其他有用的细节,例如灵活的 GraphicsPath
类,而 System.Drawing.Imaging
包含 ImageFormat
命名空间,该命名空间允许您选择在将位图渲染到客户端时使用的图形格式。
简单绘图
以下示例演示了最简单的 GDI+ 页面。所有工作都在 Page.Load
事件处理程序中执行。第一步是通过创建 System.Drawing.Bitmap
类的实例来创建内存位图。创建此对象时,您需要在构造函数参数中指定图像的宽度和高度(以像素为单位)。您应该尽可能减小尺寸。较大的位图不仅会在代码执行期间消耗额外的服务器内存,还会增加发送到客户端的渲染内容的尺寸,从而减慢传输速度。
// Create the in-memory bitmap where you will draw the image.
// This bitmap is 300 pixels wide and 50 pixels high.
Bitmap image = new Bitmap(300, 50);
下一步是为图像创建 GDI+ 图形上下文,该上下文由 System.Drawing.Graphics
对象表示。此对象提供了允许您在内存位图上绘制内容的方法。要从现有 Bitmap
对象创建 Graphics
对象,只需使用 static Graphics.FromImage()
方法,如下所示:
Graphics g = Graphics.FromImage(image);
现在是时候进行有趣的部分了。使用 Graphics
类的各种方法,您可以绘制文本、形状和图像到位图上。在此示例中,绘图代码非常简单。它使用 Graphics
对象的 FillRectangle()
方法以纯白色背景填充图形。
// Draw a solid white rectangle.
// Start from point (1, 1).
// Make it 298 pixels wide and 48 pixels high.
g.FillRectangle(Brushes.White, 1, 1, 298, 48);
FillRectangle()
方法需要几个参数。第一个参数设置颜色,接下来的两个参数设置起始点,最后两个参数设置宽度和高度。在测量像素时,点 (0, 0) 是图像的左上角,以 (X, Y) 坐标表示。X 坐标向右增加,Y 坐标向下增加。在当前示例中,图像宽度为 300 像素,高度为 50 像素,这意味着点 (300, 50) 是右下角。在此示例中,FillRectangle()
方法并没有完全填充整个位图。相反,它在四周留出了 1 像素宽的边框。由于您没有在此区域绘制任何内容,因此这些像素将具有默认颜色(对于渲染为 GIF 格式的位图,该颜色为黑色)。下一部分绘图代码会渲染一个静态标签消息。要做到这一点,您需要创建一个 System.Drawing.Font
对象来表示您要使用的字体。这不应与您与 ASP.NET 控件一起使用的 FontInfo
对象混淆,后者用于指定网页的请求字体。与 FontInfo
不同,Font
表示一个单一的、特定的字体(包括字体类型、大小和样式),该字体安装在当前计算机上。创建 Font
对象时,您需要指定字体名称、磅值和样式,如下所示:
Font font = new Font("Impact", 20, FontStyle.Regular);
***由于此图像是在服务器上生成的,因此您可以在创建图形时使用服务器安装的任何字体。客户端不需要安装相同的字体,因为客户端接收的是已渲染的图像文本。要渲染文本,您需要使用 Graphics
对象的 DrawString()
方法。与 FillRectangle()
对象一样,您需要指定绘图开始的坐标。此点表示文本块的左上角。在本例中,使用了点 (10, 5),这意味着距离左侧 10 像素,距离顶部 5 像素。
g.DrawString("This is a test.", font, Brushes.Blue, 10, 5);
图像完成后,您可以使用 Image.Save()
方法将其发送到浏览器。从概念上讲,您将图像“保存”到浏览器的响应流中。然后,它会被发送到客户端并在浏览器中显示。使用此技术时,您的图像将替换任何其他网页数据,并绕过 Web 控件模型。
// Render the image to the output stream.
image.Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Gif);
您可以将图像保存到任何有效的流中,包括 FileStream
。此技术允许您将动态生成的图像保存到磁盘,以便以后在其他网页中使用。最后,您应该在完成后显式释放图像和图形上下文,因为它们都占用了某些非托管资源,如果不显式释放,这些资源不会立即被释放。您可以通过调用 Dispose()
方法来释放资源,如下所示:
g.Dispose();
image.Dispose();
防机器人图像生成器代码
public partial class RndImg : System.Web.UI.UserControl
{
private StringBuilder str = new StringBuilder();
private bool ABrush = true;
public bool DefaultRandomBrush
{
get { return ABrush; }
set { ABrush = value; }
}
private int backden = 500;
public int BackgroundDensity
{
get { return backden; }
set { backden = value; }
}
public string Output()
{
return Session["Out"].ToString();
}
public void Fresh(object sender, EventArgs e) //For redraw bot-proof image
{
Page_Load(sender, e);
}
protected void Page_Load(object sender, EventArgs e)
{
float temp = 0;
Random rnd = new Random(unchecked((int)DateTime.Now.Ticks));
char ch = '1';
Bitmap image = new Bitmap(180, 60);
Graphics g = Graphics.FromImage(image);
g.FillRectangle(Brushes.WhiteSmoke, 1, 1, 178, 58);
Font font = new Font("Monotype Corsiva", 30, FontStyle.Italic);
SizeF size = new SizeF();
backbround(g, 180,60);
Brush[] myBrush ={Brushes.Red,
Brushes.Blue,
Brushes.DarkBlue,
Brushes.Violet,
Brushes.Tomato,
Brushes.Black,
Brushes.Chocolate,
Brushes.Brown};
SolidBrush mysBrush;
for (int i = 0; i < 4; i++)
{
ch = Convert.ToChar((int)((rnd.NextDouble() * 25) + 65));
if (ABrush == false)
{
mysBrush = new SolidBrush
(Color.FromArgb((int)(rnd.NextDouble() * 255),
(int)(rnd.NextDouble() * 255),
(int)(rnd.NextDouble() * 255)));
g.DrawString(ch.ToString(), font,
mysBrush, temp, (int)(rnd.NextDouble() * 20));
}
else
{
g.DrawString(ch.ToString(), font,
myBrush[(int)(rnd.NextDouble() * myBrush.Length)],
temp, (int)(rnd.NextDouble() * 20));
}
size = g.MeasureString(ch.ToString(), font);
temp += size.Width;
str.Append(ch);
}
image.Save(Server.MapPath("")+@"\a32166g9.gif", ImageFormat.Gif);
Page.Unload += new EventHandler(Page_Unload);
}
void Page_Unload(object sender, EventArgs e)
{
Session["Out"] = str.ToString();
}
private void backbround(Graphics gr, int width, int hieght)//
{
Random rnd = new Random(unchecked((int)DateTime.Now.Ticks));
int x2 = 0, y2 = 0;
int x = 0, y = 0;
for (int i = 0; i < backden; i++)
{
x = (int)(rnd.NextDouble() * width);
y = (int)(rnd.NextDouble() * hieght);
x2 = (int)(rnd.NextDouble() * 5);
y2 = (int)(rnd.NextDouble() * 5);
Pen p = new Pen(Color.FromArgb((int)(rnd.NextDouble() * 255),
(int)(rnd.NextDouble() * 255),
(int)(rnd.NextDouble() * 255)));
gr.DrawLine(p, new Point(x, y), new Point(x + x2, y + y2));
}
}
}
历史
- 2008 年 4 月 4 日:首次发布