|
Posted on 2006-08-22 03:00 大大毛 阅读(748) 评论(0) 编辑 收藏 所属分类: ASP.NET
网页中需要用到这样的功能,参照网上的介绍,做了一个放在这里备查。 效果图:
为了方便调用,写成了一个类(RandomCodeImage.cs)。
using
System;
using
System.Drawing;


/**/
///
<summary>
///
随机检验码图像模糊度
///
</summary>
public
enum
RandomCodeImageMistily
{
None
=
0
,
General,
Deep
}
/**/
///
<summary>
///
生成随机校验码图象
///
ddm,2006-8-22
///
</summary>
public
class
RandomCodeImage
{
//
随机数
Random random
=
null
;
//
字体
private
string
fontName
=
null
;
//
字体大小
private
int
fontSize
=
0
;
//
校验码长度
private
int
codeLength
=
0
;
//
间距
private
int
codeSpace
=
0
;
//
校验码
private
string
code
=
null
;
//
字体
private
Font font
=
null
;
//
模糊度
private
RandomCodeImageMistily mistily
=
RandomCodeImageMistily.General;


public
RandomCodeImage()
{
this
.random
=
new
Random();
this
.fontName
=
"
Arial
"
;
this
.fontSize
=
12
;
this
.codeLength
=
4
;
this
.codeSpace
=
0
;
}
/**/
///
<summary>
///
设置/获取字体
///
</summary>
public
string
FontName
{

get
{
return
this
.fontName;
}
set
{
this
.fontName
=
value;
}
}
/**/
///
<summary>
///
设置/获取字体大小
///
</summary>
public
int
FontSize
{

get
{
return
this
.fontSize;
}
set
{
this
.fontSize
=
value;
}
}
/**/
///
<summary>
///
设置/获取校验码的长度
///
</summary>
public
int
CodeLength
{

get
{
return
this
.codeLength;
}
set
{
this
.codeLength
=
value;
}
}
/**/
///
<summary>
///
设置/获取检验码的间距
///
</summary>
public
int
CodeSpace
{

get
{
return
this
.codeSpace;
}
set
{
this
.codeSpace
=
value;
}
}
/**/
///
<summary>
///
设置/获取检验码
///
</summary>
public
string
Code
{

get
{

if
(
this
.code
==
null
)
{
//
生成检验码
this
.code
=
this
.createRandomCode();
}
return
this
.code;
}
set
{
this
.code
=
value;
}
}
public
RandomCodeImageMistily Mistily
{

set
{
this
.mistily
=
value;
}
}
/**/
///
<summary>
///
获取检验码生成的图像
///
</summary>
public
System.Drawing.Bitmap getCodeImage()
{


if
(
this
.code
==
null
)
{
//
生成检验码
this
.code
=
this
.createRandomCode();
}
return
this
.createCodeImage();
}
/**/
///
<summary>
///
获取检验码生成的图像
///
</summary>
///
<param name="mistily">
输出图像的模糊度
</param>
public
System.Drawing.Bitmap getCodeImage(RandomCodeImageMistily mistily)
{
this
.mistily
=
mistily;
return
this
.getCodeImage();
}
/**/
///
<summary>
///
创建随机检验码
///
</summary>
protected
string
createRandomCode()
{
System.Text.StringBuilder codeBuilder
=
new
System.Text.StringBuilder();

int
ascii
=
0
;

for
(
int
i
=
0
; i
<
this
.codeLength; i
++
)
{
//
0-9,A-Z一共36个
ascii
=
this
.random.Next()
%
36
;


if
(ascii
<
10
)
{
//
数字
ascii
+=
48
;
 }
else
{
//
大写字母
ascii
+=
55
;
}
codeBuilder.Append((
char
)ascii);
}
return
codeBuilder.ToString();
}
/**/
///
<summary>
///
创建代码图像
///
</summary>
private
System.Drawing.Bitmap createCodeImage()
{
Bitmap tmpImage
=
null
, resultImage
=
null
;
Graphics tmpG
=
null
, resultG
=
null
;
float
charWidth
=
0f, charHeight
=
0f;
int
imageWidth
=
0
, imageHeight
=
0
;
SizeF size
=
SizeF.Empty;
//
噪音
int
noiseNum
=
0
;

//
生成字体
this
.font
=
new
Font(
this
.fontName,
this
.fontSize, (FontStyle.Bold
|
FontStyle.Italic), GraphicsUnit.Point);


using
(tmpImage
=
new
Bitmap(
1
,
1
))
{

using
(tmpG
=
Graphics.FromImage(tmpImage))
{
//
获得code的输出宽度
for
(
int
i
=
0
; i
<
this
.code.Length; i
++
)
{

size
=
tmpG.MeasureString(code.Substring(i,
1
), font);
charWidth
+=
size.Width;
charHeight
=
Math.Max(charHeight, size.Height);

}
}
}
//
输出字符的大小
imageWidth
=
(
int
)Math.Ceiling(charWidth);
imageHeight
=
(
int
)Math.Ceiling(charHeight);
//
加入间距
imageWidth
=
imageWidth
+
this
.code.Length
*
this
.codeSpace
+
this
.codeSpace;
imageHeight
=
imageHeight
+
2
*
this
.codeSpace;
//
生成输出图像
resultImage
=
new
Bitmap(imageWidth, imageHeight);
//
画刷,线性颜色渐变画刷,渲染区域是整个图片,从Blue渐变到Pruple,从X轴方面1.2弧度,渐变受角度影响
Brush brush
=
new
System.Drawing.Drawing2D.LinearGradientBrush(
new
Rectangle(
0
,
0
, resultImage.Width, resultImage.Height), Color.Blue, Color.Purple,
1.2f
,
true
);

using
(resultG
=
Graphics.FromImage(resultImage))
{
//
填充背景色
resultG.Clear(Color.White);
//
resultG.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
switch
(
this
.mistily)
{
case
RandomCodeImageMistily.Deep:
noiseNum
=
resultImage.Width
*
resultImage.Height
/
30
;
break
;
case
RandomCodeImageMistily.General:
noiseNum
=
resultImage.Width
*
resultImage.Height
/
50
;
break
;
default
:
noiseNum
=
0
;
break
;
}
//
画背景噪音线
for
(
int
i
=
0
; i
<
noiseNum; i
++
)
{
//
随机坐标
int
x1
=
random.Next(resultImage.Width);
int
x2
=
random.Next(resultImage.Width);
int
y1
=
random.Next(resultImage.Height);
int
y2
=
random.Next(resultImage.Height);
//
画噪音线
resultG.DrawLine(
new
Pen(Color.Silver), x1, y1, x2, y2);
}
//
画背景噪音点
for
(
int
i
=
0
; i
<
noiseNum
*
20
; i
++
)
{
//
随机坐标
int
x
=
random.Next(resultImage.Width);
int
y
=
random.Next(resultImage.Height);
//
画噪音点
resultG.DrawEllipse(
new
Pen(Color.FromArgb(random.Next())), x, y,
1
,
1
);
}
//
输出字符
charWidth
=
charHeight
=
this
.codeSpace;

for
(
int
i
=
0
; i
<
this
.code.Length; i
++
)
{
resultG.DrawString(
this
.code.Substring(i,
1
), font, brush, charWidth, charHeight);
//
起始X坐标
charWidth
=
charWidth
+
resultG.MeasureString(
this
.code.Substring(i,
1
), font).Width
+
this
.codeSpace;
}
//
画图片边框
resultG.DrawRectangle(
new
Pen(Color.SaddleBrown),
0
,
0
, resultImage.Width
-
1
, resultImage.Height
-
1
);
}
return
resultImage;
}
}
该类实现功能: 能够返回一个随机码检验图片(Image对象),这样可以进行第2次处理。 属性: FontName,字体; FontSize,字体大小(point); CodeLength,随机生成的检验码长度; CodeSpace,字间距; Code,校验码,如果通过setter设置了该属性,则类不会随机生成新的检验码; Mistily,模糊度,效果不是很好。
在ASP页面中(例ShowCodeImage.aspx)调用类:
protected void Page_Load(object sender, EventArgs e) { //初始化类 RandomCodeImage r = new RandomCodeImage(); //设置字体大小 r.FontSize = 10; //r.FontName = "Times Now Roman"; //设置字间距 r.CodeSpace = 2; //获取图像 System.Drawing.Image image = r.getCodeImage(); //输出图像 System.IO.MemoryStream ms = new System.IO.MemoryStream(); image.Save(ms, System.Drawing.Imaging.ImageFormat.Png); image.Dispose(); Response.ContentType = "image/Png"; Response.BinaryWrite(ms.ToArray());
//将code放入Session或Cokie用于提交检验 Session.Add("ddm", r.Code); }
最后在最终需要显示的ASP页面中加以引用:
<img src="ShowCodeImage.aspx" alt="验证图片"/> 后记: 在计算字符输出宽度时遇到了麻烦,输出时经常不对头,直到逐步的拆解代码才找到原因。MS在输出字符时,由于各个字符是不等宽的(比如 I 就比较窄),因此在输出时必须先用 Graphics.MeasureString() 方法来计算宽度,但是实际上采用不同的输出方式得到的结果是不同的。如:1.在输出时采用一次性输出整个字符串;2.逐个字符的输出。可以发现各字符的输出宽度之和 要远大于 整个字符串的输出宽度,如果没有考虑到这点就容易产生输出无法定位的情况。
|