[C#] 第一次自己作 Captcha(驗證碼) 就上手(2)
2013-03-11
上一篇 ( 第一次自己作 Captcha(驗證碼) 就上手 ) 寫到將字合成到有雜點圖片上面製作自己的Captcha..
甚麼還是會被破解?!
這時候我們試圖再增加難度讓機器人更難去判斷
首先參考這篇文章 濾鏡筆記-漣漪效果 我們來透過液態化效果將文字再合成的更加凌亂..
並且這篇文章,我將字體大小的設置拆成parameter 傳入,不然中文字的算法跟英文是不太一樣的..
/// <summary> /// 製作Captcha /// </summary> /// <param name="text">文字</param> /// <param name="fontName">字體名稱</param> /// <param name="backgroundImagePath">採樣的背景圖</param> /// <param name="width">結果的圖片寬度</param> /// <param name="height">結果的圖片高度</param> /// <param name="fontSize"> 字體大小</param> /// <param name="waterEffect">增加漣漪複雜度 </param> /// <returns></returns>public Bitmap GetCaptcha(string text, string fontName, string backgroundImagePath, int width, int height, int fontSize, short waterEffect = 10)
{ var backImage = new Bitmap(backgroundImagePath); //如果原圖過小 就以原圖大小為主 if (backImage.Width < width || backImage.Height < height) {throw new Exception("結果尺寸不得小於採樣大小的圖片");
}
//隨機取一個位置 並且按造欲需求的大小裁切 //請注意隨機採樣範圍 記得為 圖片寬度-欲取的寬度 高度也是 ,不然會發生裁切超過範圍backImage =
backImage.Clone(
new Rectangle(new Random().Next(0, backImage.Width - width),
new Random().Next(0, backImage.Height - height), width, height), backImage.PixelFormat);Graphics graphics = Graphics.FromImage(backImage);
//合成的文字為黑色 Brush br = new SolidBrush(Color.Black); //將字體畫上圖片 //字體的大小 為 自訂graphics.DrawString(text, new Font(new FontFamily(fontName), fontSize), br, new PointF(0, 0));
//增加複雜度backImage = AdjustRippleEffect(backImage, waterEffect);
return backImage;}
/// <summary> /// 水波紋效果 /// </summary> /// <param name="src"></param> /// <param name="nWave">坡度</param> /// <returns></returns>public Bitmap AdjustRippleEffect(Bitmap src, short nWave)
{ int nWidth = src.Width; int nHeight = src.Height; // 透過公式進行水波紋的採樣 FloatPoint[,] fp = new FloatPoint[nWidth, nHeight]; Point[,] pt = new Point[nWidth, nHeight]; Point mid = new Point();mid.X = nWidth / 2;
mid.Y = nHeight / 2;
double newX, newY; double xo, yo; //先取樣將水波紋座標跟RGB取出for (int x = 0; x < nWidth; ++x)
for (int y = 0; y < nHeight; ++y)
{xo = ((double)nWave * Math.Sin(2.0 * 3.1415 * (float)y / 128.0));
yo = ((double)nWave * Math.Cos(2.0 * 3.1415 * (float)x / 128.0));
newX = (x + xo);
newY = (y + yo);
if (newX > 0 && newX < nWidth) {fp[x, y].X = newX;
pt[x, y].X = (int)newX;}
else {fp[x, y].X = 0.0;
pt[x, y].X = 0;
}
if (newY > 0 && newY < nHeight) {fp[x, y].Y = newY;
pt[x, y].Y = (int)newY;}
else {fp[x, y].Y = 0.0;
pt[x, y].Y = 0;
}
}
//進行合成Bitmap bSrc = (Bitmap)src.Clone();
// 依照 Format24bppRgb 每三個表示一 Pixel 0: 藍 1: 綠 2: 紅 BitmapData bitmapData = src.LockBits(new Rectangle(0, 0, src.Width, src.Height), ImageLockMode.ReadWrite,PixelFormat.Format24bppRgb);
BitmapData bmSrc = bSrc.LockBits(new Rectangle(0, 0, bSrc.Width, bSrc.Height), ImageLockMode.ReadWrite,PixelFormat.Format24bppRgb);
int scanline = bitmapData.Stride;IntPtr Scan0 = bitmapData.Scan0;
IntPtr SrcScan0 = bmSrc.Scan0;
unsafe {byte* p = (byte*)(void*)Scan0;
byte* pSrc = (byte*)(void*)SrcScan0;
int nOffset = bitmapData.Stride - src.Width * 3; int xOffset, yOffset;for (int y = 0; y < nHeight; ++y)
{for (int x = 0; x < nWidth; ++x)
{xOffset = pt[x, y].X;
yOffset = pt[x, y].Y;
if (yOffset >= 0 && yOffset < nHeight && xOffset >= 0 && xOffset < nWidth) {p[0] = pSrc[(yOffset * scanline) + (xOffset * 3)];
p[1] = pSrc[(yOffset * scanline) + (xOffset * 3) + 1];
p[2] = pSrc[(yOffset * scanline) + (xOffset * 3) + 2];
}
p += 3;
}
p += nOffset;
}
}
src.UnlockBits(bitmapData);
bSrc.UnlockBits(bmSrc);
return src;}
private struct FloatPoint
{public double X;
public double Y;
}
中文字展示:
Helper helper=new Helper();var result=helper.GetCaptcha("我是當麻", "微軟正黑體",Server.MapPath("bk.jpg"),120,40,20);
英文:
Helper helper=new Helper();var result = helper.GetCaptcha("ABCDE", "Verdana", Server.MapPath("bk.jpg"), 100, 40, 20, 12);
有沒有覺得人類都快要看不出來了..當你在調高 漣漪影響的幅度會更加連人類都看不出來…
