Recently, I received a task at work to develop a page verification code function. I consulted some online information and combined with my previous drawing knowledge, I implemented the following solution. The generated verification code looks like this:
Problems to be solved:
1. How to randomly generate pictures
to generate System.Drawing.Bitmap objects, and use System.Drawing.Graphics to draw into the bitmap objects.
2. How to pass image data through parameters in the WebService method
to output the Bitmap object into a byte stream, and WebMothod uses a byte array to return the byte stream.
Example:
1. Use VS.NET 2003 to create an ASP.NET Webservice project. The default Service name is MyService, and a WebMethod named GenerateVerifyImage is added to MyService. The code of this method is as follows:
/// <summary>
/// Generate image verification code
/// </summary>
/// <param name="nLen">The length of the verification code</param>
/// <param name="strKey">Output parameters, content of verification code</param>
/// <returns>Image byte stream</returns>
[WebMethod]
public byte[] GenerateVerifyImage(int nLen,ref string strKey)
{
int nBmpWidth = 13*nLen+5;
int nBmpHeight = 25;
System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(nBmpWidth,nBmpHeight);
// 1. Generate random background color
int nRed,nGreen,nBlue; // The ternary color of the background
System.Random rd = new Random((int)System.DateTime.Now.Ticks);
nRed = rd.Next(255)%128+128;
nGreen = rd.Next(255)%128+128;
nBlue = rd.Next(255)%128+128;
// 2. Fill the bitmap background
System.Drawing.Graphics graph = System.Drawing.Graphics.FromImage(bmp);
graph.FillRectangle(new SolidBrush(System.Drawing.Color.FromArgb(nRed,nGreen,nBlue))
,0
,0
,nBmpWidth
,nBmpHeight);
// 3. Draw interference lines, using a slightly darker color than the background
int nLines = 3;
System.Drawing.Pen pen = new System.Drawing.Pen(System.Drawing.Color.FromArgb(nRed-17,nGreen-17,nBlue-17),2);
for(int a =0;a< nLines;a++)
{
int x1 = rd.Next() % nBmpWidth;
int y1 = rd.Next() % nBmpHeight;
int x2 = rd.Next() % nBmpWidth;
int y2 = rd.Next() % nBmpHeight;
graph.DrawLine(pen,x1,y1,x2,y2);
}
// The character set used can be expanded at any time and the probability of characters appearing can be controlled
string strCode = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// 4. Loop to obtain characters and draw them
string strResult = "";
for(int i=0;i<nLen;i++)
{
int x = (i*13 + rd.Next(3));
int y = rd.Next(4) + 1;
// Determine the font
System.Drawing.Font font = new System.Drawing.Font("Courier New",
12 + rd.Next()%4,
System.Drawing.FontStyle.Bold);
char c = strCode[rd.Next(strCode.Length)]; // Get random characters
strResult += c.ToString();
// Draw characters
graph.DrawString(c.ToString(),
font,
new SolidBrush(System.Drawing.Color.FromArgb(nRed-60+y*3,nGreen-60+y*3,nBlue-40+y*3)),
x,
y);
}
// 5. Output byte stream
System.IO.MemoryStream bstream = new System.IO.MemoryStream();
bmp.Save(bstream,System.Drawing.Imaging.ImageFormat.Jpeg);
bmp.Dispose();
graph.Dispose();
strKey = strResult;
byte[] byteReturn = bstream.ToArray();
bstream.Close();
return byteReturn;
}
2. Test the WebMethod, add a WebForm, reference the above WebService, and the reference name is imagesvr. Add code in Page_Load:
...
imagesvr.MyService imgsvr = new imagesvr.MyService();
string strKey = "";
byte[] data = imgsvr.GenerateVerifyImage(5,ref strKey);
Response.OutputStream.Write(data,0,data.Length);
...
3. Run. Each time the WebForm is refreshed, a newly generated image verification code will be displayed, and the output parameter strKey of the function saves the actual content of the verification code, which can be saved in the Session for verification.
After developing the picture verification code last time, based on the suggestions of some friends, based on the principle that the verification code is easy to recognize (for people), difficult to crack, and beautiful, the verification code generation algorithm has been improved, and the image filter method has been used to filter the pictures. The verification code is subjected to anti-cracking interference, and the result picture example is as follows:
The filter effect mainly uses the wave algorithm, which produces a superposition effect by processing the sine waveform of the X-axis and Y-axis. The main description of the algorithm is as follows:
private const double PI = 3.1415926535897932384626433832795;
private const double PI2 = 6.283185307179586476925286766559;
/// <summary>
/// Sinusoidal wave distorted picture
/// </summary>
/// <param name="srcBmp"></param>
/// <param name="bXDir"></param>
/// <param name="nMultValue">Amplitude multiple of the waveform</param>
/// <param name="dPhase">Start phase of the waveform, value range [0-2*PI)</param>
/// <returns></returns>
public System.Drawing.Bitmap TwistImage(Bitmap srcBmp,bool bXDir,double dMultValue,double dPhase)
{
System.Drawing.Bitmap destBmp = new Bitmap(srcBmp.Width,srcBmp.Height);
// Fill the bitmap background with white
System.Drawing.Graphics graph = System.Drawing.Graphics.FromImage(destBmp);
graph.FillRectangle(new SolidBrush(System.Drawing.Color.White),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 ? (PI2*(double)j)/dBaseAxisLen : (PI2*(double)i)/dBaseAxisLen;
dx += dPhase;
double dy = Math.Sin(dx);
// Get the color of the current point
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;
}
The example picture at the beginning is the superposition of two waveform effects. The two effects are for the X-axis direction and the Y-axis direction respectively. If you cancel the filling of the edge background color, you can see the impact of the algorithm on the graphics, as shown below:
The verification code generated in this way looks a lot like the verification code on the Google site. Of course, if you are interested, you can also add other filter effects, such as stretching, rotation, mosaic, etc. But please note that the more complex the website verification code is, the better. You must find a balance between speed and security.