ASP.NET登入驗證碼解決方案
阿新 • • 發佈:2019-07-24
目錄
- #驗證碼效果圖
- #程式碼
- 0、html程式碼
- 1、Handler中呼叫驗證碼生成類
- 2、驗證碼圖片繪製生成類
- 3、高斯模糊演算法類
- #注意
- #參考
在web專案中,為了防止登入被暴力破解,需要在登入的時候加入驗證碼驗證,思路是:
1)登入頁面開啟,向 服務端請求生成驗證碼圖片,並將驗證碼字串存入session;
2)登入時將客戶端輸入的驗證碼字串傳到服務端,與session中的驗證碼進行比較,如果驗證碼正確,再進行登入驗證;
#驗證碼效果圖
#程式碼
0、html程式碼
<img id="CaptchaImg" src="PictureHandler.ashx" title="看不清,點一下!"/>
1、Handler中呼叫驗證碼生成類
public void ProcessRequest (HttpContext context) { context.Response.ContentType = "image/jpeg"; Resource.Utility.DrawCaptchaHelper objDrawValidationCode = new Resource.Utility.DrawCaptchaHelper(); objDrawValidationCode.CaptchaLength = 4;//驗證碼字元個數 objDrawValidationCode.IsPixel = true;//隨機噪點 objDrawValidationCode.RandomStringCount = 2; //干擾字元個數 objDrawValidationCode.RandomStringFontSize = 30;//干擾字元字型大小 objDrawValidationCode.FontMinSize = 35;//驗證碼字型的大小的最小值 objDrawValidationCode.FontMaxSize = 40; //驗證碼字型的大小的最大值 //objDrawValidationCode.GaussianDeviation = 3; //預設0,不使用高斯模糊演算法處理影象。 //objDrawValidationCode.BrightnessValue = 5; //明暗度,預設0,是使用明暗度演算法處理影象 objDrawValidationCode.LineCount = 1; //預設3條。 objDrawValidationCode.BezierCount = 2;//預設3條。 //邊框樣式 //objDrawValidationCode.Border = DrawCaptchaHelper.BorderStyle.RoundRectangle; using (MemoryStream ms = new MemoryStream()) { objDrawValidationCode.CreateImage(ms); context.Session["ValidateCode"] = objDrawValidationCode.CaptchaStr;//將驗證碼字串存入session,用於登入驗證 //return File(ms.GetBuffer(), "image/jpeg"); context.Response.BinaryWrite(ms.GetBuffer()); } }
2、驗證碼圖片繪製生成類
#region 驗證碼生成類
/// <summary>
/// 驗證碼生成類
/// </summary>
public class DrawCaptchaHelper
{
#region 定義和初始化配置欄位
//使用者存取驗證碼字串
private string captchaStr = String.Empty;
/// <summary>
/// 獲取系統生成的隨機驗證碼
/// </summary>
public String CaptchaStr
{
get { return captchaStr; }
}
private Int32 captchaLength = 4;
/// <summary>
/// 獲取和設定驗證碼字串的長度
/// </summary>
public Int32 CaptchaLength
{
get { return captchaLength; }
set { captchaLength = value; }
}
Graphics dc = null;
private int bgWidth = 130;
/// <summary>
/// 驗證碼的寬度,預設為130
/// </summary>
public Int32 Width
{
get { return bgWidth; }
set { bgWidth = value; }
}
private int bgHeight = 40;
/// <summary>
/// 驗證碼的高度,預設為40
/// </summary>
public Int32 Height
{
get { return bgHeight; }
set { bgHeight = value; }
}
private int fontMinSize = 15;
/// <summary>
/// 驗證碼字型的最小值,預設為15,建議不小於15畫素
/// </summary>
public Int32 FontMinSize
{
get { return fontMinSize; }
set { fontMinSize = value; }
}
private Int32 fontMaxSize = 20;
/// <summary>
/// 驗證碼字型的最大值,預設為20
/// </summary>
public Int32 FontMaxSize
{
get { return fontMaxSize; }
set { fontMaxSize = value; }
}
private Color[] fontColor = { };
/// <summary>
/// 驗證碼字型的顏色,預設為系統自動生成字型顏色
/// </summary>
public Color[] FontColor
{
get { return fontColor; }
set { fontColor = value; }
}
private Color backColor = Color.FromArgb(243, 255, 255);
/// <summary>
/// 驗證碼的背景色,預設為Color.FromArgb(243, 251, 254)
/// </summary>
public Color BackgroundColor
{
get { return backColor; }
set { backColor = value; }
}
private Int32 bezierCount = 3;
/// <summary>
/// 貝塞爾曲線的條數,預設為3條
/// </summary>
public Int32 BezierCount
{
get { return bezierCount; }
set { bezierCount = value; }
}
private Int32 lineCount = 3;
/// <summary>
/// 直線條數,預設為3條
/// </summary>
public Int32 LineCount
{
get { return lineCount; }
set { lineCount = value; }
}
Random random;
//定義驗證碼字元及出現頻次 ,避免出現 0 o j i l 1 x;
private String charCollection = "2,3,4,5,6,7,8,9,a,s,d,f,g,h,z,c,v,b,n,m,k,q,w,e,r,t,y,u,p,A,S,D,F,G,H,Z,C,V,B,N,M,K,Q,W,E,R,T,Y,U,P";
/// <summary>
/// 隨機字串列表,請使用英文狀態下的逗號分隔。
/// </summary>
public String CharCollection
{
get { return charCollection; }
set { charCollection = value; }
}
private Int32 intCount = 4;
/// <summary>
/// 驗證碼字串個數,預設為4個字元
/// </summary>
public Int32 IntCount
{
get { return intCount; }
set { intCount = value; }
}
private Boolean isPixel = true;
/// <summary>
/// 是否新增噪點,預設新增,噪點顏色為系統隨機生成。
/// </summary>
public Boolean IsPixel
{
get { return isPixel; }
set { isPixel = value; }
}
/// <summary>
/// 隨機背景字串的個數
/// </summary>
public Int32 RandomStringCount { get; set; }
private Int32 randomStringFontSize = 10;
/// <summary>
/// 隨機背景字串的大小
/// </summary>
public Int32 RandomStringFontSize
{
get { return randomStringFontSize; }
set { randomStringFontSize = value; }
}
/// <summary>
/// 邊框樣式
/// </summary>
public enum BorderStyle
{
/// <summary>
/// 無邊框
/// </summary>
None,
/// <summary>
/// 矩形邊框
/// </summary>
Rectangle,
/// <summary>
/// 圓角邊框
/// </summary>
RoundRectangle
}
/// <summary>
/// 設定或獲取邊框樣式
/// </summary>
public BorderStyle Border { get; set; }
private Int32 rotationAngle = 40;
/// <summary>
/// 驗證碼字串隨機轉動的角度的最大值
/// </summary>
public Int32 RotationAngle
{
get { return rotationAngle; }
set { rotationAngle = value; }
}
private Point[] strPoint = null;
private Double gaussianDeviation = 0;
/// <summary>
/// 對驗證碼圖片進行高斯模糊的閥值,如果設定為0,則不對圖片進行高斯模糊,該設定可能會對圖片處理的效能有較大影響
/// </summary>
public Double GaussianDeviation
{
get { return gaussianDeviation; }
set { gaussianDeviation = value; }
}
private Int32 brightnessValue = 0;
/// <summary>
/// 對圖片進行暗度和亮度的調整,如果該值為0,則不調整。該設定會對圖片處理效能有較大影響
/// </summary>
public Int32 BrightnessValue
{
get { return brightnessValue; }
set { brightnessValue = value; }
}
#endregion
#region wq 新增 邊框補(預設1畫素)
int padding = 2;
public int Padding
{
get { return padding; }
set { padding = value; }
}
#endregion
/// <summary>
/// 建構函式,用於初始化常用變數
/// </summary>
public DrawCaptchaHelper()
{
random = new Random(Guid.NewGuid().GetHashCode());
strPoint = new Point[captchaLength + 1];
if (gaussianDeviation < 0) gaussianDeviation = 0;
}
/// <summary>
/// 生成驗證碼
/// </summary>
/// <param name="target">用於儲存圖片的一般位元組序列</param>
public MemoryStream CreateImage(MemoryStream target)
{
//新增 wq ,否則後面報錯
if (strPoint.Length != captchaLength)
{
strPoint = new Point[captchaLength + 1];//wq 新增,原因是:建構函式預設初始化5個元素,假如new後,又改了validationCodeCount的數值,則該數字需要重新初始化
}
//新增 wq ,否則圖片的畫布太小
if (fontMaxSize >= (bgHeight / 5) * 4)
{
//throw new ArgumentException("字型最大值引數FontMaxSize與驗證碼高度相近,這會導致描繪驗證碼字串時出錯,請重新設定引數!");
AdjustBitmapSize();
}
Bitmap bit = new Bitmap(bgWidth + 1, bgHeight + 1);
//寫字串
dc = Graphics.FromImage(bit);
dc.SmoothingMode = SmoothingMode.HighQuality;
dc.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; ;
dc.InterpolationMode = InterpolationMode.HighQualityBilinear;
dc.CompositingQuality = CompositingQuality.HighQuality;
dc.Clear(Color.White);
//畫驗證碼背景,例如,增加早點,新增曲線和直線等
dc.DrawImageUnscaled(DrawBackground(), 0, 0);
//繪製驗證碼
Bitmap validatecodeImg = DrawRandomString();
//對隨機碼影象上的文字進行波形扭曲(扭曲文字方式1)
validatecodeImg = TwistImage(validatecodeImg, true, 3, 4);
dc.DrawImageUnscaled(validatecodeImg, 0, 0);
//水波紋效果 文字進行波形扭曲 (扭曲文字方式2)
//bit = AdjustRippleEffect(bit, 5);
//對圖片進行高斯模糊
if (gaussianDeviation > 0)
{
GaussianHelper gau = new GaussianHelper();
bit = gau.FilterProcessImage(gaussianDeviation, bit);
}
//進行暗度和亮度處理
if (brightnessValue != 0)
{
//對圖片進行調暗處理
bit = AdjustBrightness(bit, brightnessValue);
}
bit.Save(target, ImageFormat.Gif);
//brush.Dispose();
bit.Dispose();
dc.Dispose();
return target;
}
#region 畫驗證碼背景,例如,增加早點,新增曲線和直線等
/// <summary>
/// 畫驗證碼背景,例如,增加早點,新增曲線和直線等
/// </summary>
/// <returns></returns>
private Bitmap DrawBackground()
{
Bitmap bit = new Bitmap(bgWidth + 1, bgHeight + 1);
Graphics g = Graphics.FromImage(bit);
g.SmoothingMode = SmoothingMode.HighQuality;
g.Clear(Color.White);
Rectangle rectangle = new Rectangle(0, 0, bgWidth, bgHeight);
Brush brush = new SolidBrush(backColor);
g.FillRectangle(brush, rectangle);
//畫噪點
if (isPixel)
{
g.DrawImageUnscaled(DrawRandomPixel(30), 0, 0);
}
//畫干擾字元
g.DrawImageUnscaled(DrawRandBgString(), 0, 0);
//畫曲線
g.DrawImageUnscaled(DrawRandomBezier(bezierCount), 0, 0);
//畫直線
g.DrawImageUnscaled(DrawRandomLine(lineCount), 0, 0);
//畫字元連線線
//dc.DrawImageUnscaled(DrawStringline(), 0, 0);
if (Border == BorderStyle.Rectangle)
{
//繪製邊框
g.DrawRectangle(new Pen(Color.FromArgb(90, 87, 46)), 0, 0, bgWidth, bgHeight);
}
else if (Border == BorderStyle.RoundRectangle)
{
//畫圓角
DrawRoundRectangle(g, rectangle, Color.FromArgb(90, 87, 46), 1, 3);
}
else
{
//沒有邊框
}
return bit;
}
#endregion
#region 畫正弦曲線
private Bitmap DrawTwist(Bitmap bmp, Int32 tWidth, Int32 tHeight, float angle, Color color)
{
//為了方便檢視效果,在這裡我定義了一個常量。
//它在定義陣列的長度和for迴圈中都要用到。
int size = bgWidth;
double[] x = new double[size];
Bitmap b = new Bitmap(bmp.Width, bmp.Height);
b.MakeTransparent();
Graphics graphics = Graphics.FromImage(b);
Pen pen = new Pen(color);
//畫正弦曲線的橫軸間距引數。建議所用的值應該是 正數且是2的倍數。
//在這裡採用2。
int val = 2;
float temp = 0.0f;
//把畫布下移100。為什麼要這樣做,只要你把這一句給註釋掉,執行一下程式碼,
//你就會明白是為什麼?
graphics.TranslateTransform(0, 100);
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
for (int i = 0; i < size; i++)
{
//改變tWidth,實現正弦曲線寬度的變化。
//改tHeight,實現正弦曲線高度的變化。
x[i] = Math.Sin(2 * Math.PI * i / tWidth) * tHeight;
graphics.DrawLine(pen, i * val, temp, i * val + val / 2, (float)x[i]);
temp = (float)x[i];
}
graphics.RotateTransform(60, MatrixOrder.Prepend);
//旋轉圖片
// b = KiRotate(b, angle, Color.Transparent);
return b;
}
#endregion
#region 正弦曲線Wave扭曲圖片
/// <summary>
/// 正弦曲線Wave扭曲圖片
/// </summary>
/// <param name="srcBmp">圖片路徑</param>
/// <param name="bXDir">如果扭曲則選擇為True</param>
/// <param name="dMultValue">波形的幅度倍數,越大扭曲的程度越高,一般為3</param>
/// <param name="dPhase">波形的起始相位,取值區間[0-2*PI)</param>
/// <returns></returns>
public Bitmap TwistImage(Bitmap srcBmp, bool bXDir, double dMultValue, double dPhase)
{
System.Drawing.Bitmap destBmp = new Bitmap(srcBmp.Width, srcBmp.Height);
double PI2 = 6.283185307179586476925286766559;
// 將點陣圖背景填充為白色
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);
// 取得當前點的顏色
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;
}
#endregion
#region 圖片任意角度旋轉
/// <summary>
/// 圖片任意角度旋轉
/// </summary>
/// <param name="bmp">原始圖Bitmap</param>
/// <param name="angle">旋轉角度</param>
/// <param name="bkColor">背景色</param>
/// <returns>輸出Bitmap</returns>
public static Bitmap KiRotate(Bitmap bmp, float angle, Color bkColor)
{
int w = bmp.Width;
int h = bmp.Height;
PixelFormat pf;
if (bkColor == Color.Transparent)
{
pf = PixelFormat.Format32bppArgb;
}
else
{
pf = bmp.PixelFormat;
}
Bitmap tmp = new Bitmap(w, h, pf);
Graphics g = Graphics.FromImage(tmp);
g.Clear(bkColor);
g.DrawImageUnscaled(bmp, 1, 1);
g.Dispose();
GraphicsPath path = new GraphicsPath();
path.AddRectangle(new RectangleF(0f, 0f, w, h));
Matrix mtrx = new Matrix();
mtrx.Rotate(angle);
RectangleF rct = path.GetBounds(mtrx);
Bitmap dst = new Bitmap((int)rct.Width, (int)rct.Height, pf);
g = Graphics.FromImage(dst);
g.Clear(bkColor);
g.TranslateTransform(-rct.X, -rct.Y);
g.RotateTransform(angle);
g.InterpolationMode = InterpolationMode.HighQualityBilinear;
g.DrawImageUnscaled(tmp, 0, 0);
g.Dispose();
tmp.Dispose();
return dst;
}
#endregion
#region 隨機生成貝塞爾曲線
/// <summary>
/// 隨機生成貝塞爾曲線
/// </summary>
/// <param name="bmp">一個圖片的例項</param>
/// <param name="lineNum">線條數量</param>
/// <returns></returns>
public Bitmap DrawRandomBezier(Int32 lineNum)
{
Bitmap b = new Bitmap(bgWidth, bgHeight);
b.MakeTransparent();
Graphics g = Graphics.FromImage(b);
g.Clear(Color.Transparent);
g.SmoothingMode = SmoothingMode.HighQuality;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
GraphicsPath gPath1 = new GraphicsPath();
Int32 lineRandNum = random.Next(lineNum);
for (int i = 0; i < (lineNum - lineRandNum); i++)
{
Pen p = new Pen(GetRandomDeepColor(), 3f); //wq,增加貝塞爾曲線的線寬引數
Point[] point = {
new Point(random.Next(1, (b.Width / 10)), random.Next(1, (b.Height))),
new Point(random.Next((b.Width / 10) * 2, (b.Width / 10) * 4), random.Next(1, (b.Height))),
new Point(random.Next((b.Width / 10) * 4, (b.Width / 10) * 6), random.Next(1, (b.Height))),
new Point(random.Next((b.Width / 10) * 8, b.Width), random.Next(1, (b.Height)))
};
gPath1.AddBeziers(point);
g.DrawPath(p, gPath1);
p.Dispose();
}
for (int i = 0; i < lineRandNum; i++)
{
Pen p = new Pen(GetRandomDeepColor());
Point[] point = {
new Point(random.Next(1, b.Width), random.Next(1, b.Height)),
new Point(random.Next((b.Width / 10) * 2, b.Width), random.Next(1, b.Height)),
new Point(random.Next((b.Width / 10) * 4, b.Width), random.Next(1, b.Height)),
new Point(random.Next(1, b.Width), random.Next(1, b.Height))
};
gPath1.AddBeziers(point);
g.DrawPath(p, gPath1);
p.Dispose();
}
return b;
}
#endregion
#region 畫直線
/// <summary>
/// 畫直線
/// </summary>
/// <param name="bmp">一個bmp例項</param>
/// <param name="lineNum">線條個數</param>
/// <returns></returns>
public Bitmap DrawRandomLine(Int32 lineNum)
{
if (lineNum < 0) throw new ArgumentNullException("引數bmp為空!");
Bitmap b = new Bitmap(bgWidth, bgHeight);
b.MakeTransparent();
Graphics g = Graphics.FromImage(b);
g.Clear(Color.Transparent);
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.SmoothingMode = SmoothingMode.HighQuality;
for (int i = 0; i < lineNum; i++)
{
Pen p = new Pen(GetRandomDeepColor());
Point pt1 = new Point(random.Next(1, (b.Width / 5) * 2), random.Next(b.Height));
Point pt2 = new Point(random.Next((b.Width / 5) * 3, b.Width), random.Next(b.Height));
g.DrawLine(p, pt1, pt2);
p.Dispose();
}
return b;
}
#endregion
#region 畫隨機噪點
/// <summary>
/// 畫隨機噪點
/// </summary>
/// <param name="pixNum">噪點的百分比</param>
/// <returns></returns>
public Bitmap DrawRandomPixel(Int32 pixNum)
{
Bitmap b = new Bitmap(bgWidth, bgHeight);
b.MakeTransparent();
Graphics graph = Graphics.FromImage(b);
graph.SmoothingMode = SmoothingMode.HighQuality;
graph.InterpolationMode = InterpolationMode.HighQualityBilinear;
//畫噪點
for (int i = 0; i < (bgHeight * bgWidth) / pixNum; i++)
{
int x = random.Next(b.Width);
int y = random.Next(b.Height);
b.SetPixel(x, y, GetRandomDeepColor());
//下移座標重新畫點
if ((x + 1) < b.Width && (y + 1) < b.Height)
{
//畫圖片的前景噪音點
graph.DrawRectangle(new Pen(Color.Silver), random.Next(b.Width), random.Next(b.Height), 1, 1);
}
}
return b;
}
#endregion
#region 畫隨機字串中間連線
/// <summary>
/// 畫隨機字串中間連線
/// </summary>
/// <returns></returns>
private Bitmap DrawStringline()
{
Bitmap b = new Bitmap(bgWidth, bgHeight);
b.MakeTransparent();
Graphics g = Graphics.FromImage(b);
g.SmoothingMode = SmoothingMode.AntiAlias;
Point[] p = new Point[captchaLength];
for (int i = 0; i < captchaLength; i++)
{
p[i] = strPoint[i];
//throw new Exception(strPoint.Length.ToString());
}
// g.DrawBezier(new Pen(GetRandomDeepColor()), strPoint);
//g.DrawClosedCurve(new Pen(GetRandomDeepColor()), strPoint);
g.DrawCurve(new Pen(GetRandomDeepColor(), 1), strPoint);
return b;
}
#endregion
#region 寫入驗證碼的字串
/// <summary>
/// 寫入驗證碼的字串
/// </summary>
private Bitmap DrawRandomString()
{
if (fontMaxSize >= (bgHeight / 5) * 4)
{
//throw new ArgumentException("字型最大值引數FontMaxSize與驗證碼高度相近,這會導致描繪驗證碼字串時出錯,請重新設定引數!");
AdjustBitmapSize();
}
Bitmap b = new Bitmap(bgWidth, bgHeight);
b.MakeTransparent();
Graphics g = Graphics.FromImage(b);
g.Clear(Color.Transparent);
g.PixelOffsetMode = PixelOffsetMode.Half;
g.SmoothingMode = SmoothingMode.HighQuality;
g.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
g.InterpolationMode = InterpolationMode.HighQualityBilinear;
char[] chars = GetRandomString(captchaLength).ToCharArray();//拆散字串成單字元陣列
captchaStr = new string(chars); //這個類的外部,也可以通過這個引數,獲取到本次的驗證碼字串值。
//設定字型顯示格式
StringFormat format = new StringFormat(StringFormatFlags.NoClip);
format.Alignment = StringAlignment.Center;
format.LineAlignment = StringAlignment.Center;
FontFamily f = new FontFamily(GenericFontFamilies.Monospace);
Int32 charNum = chars.Length;
Point sPoint = new Point();
Int32 fontSize = 9;
for (int i = 0; i < captchaLength; i++)
{
int findex = random.Next(captchaLength + 1);// random.Next(5);
//定義字型
Font textFont = new Font(f, random.Next(fontMinSize, fontMaxSize), FontStyle.Bold);
//定義畫刷,用於寫字串
//Brush brush = new SolidBrush(GetRandomDeepColor());
Int32 textFontSize = Convert.ToInt32(textFont.Size);
fontSize = textFontSize;
var t = (bgWidth / charNum)/2;
Point point = new Point(random.Next((bgWidth / charNum) * (i) + t - 2, (bgWidth / charNum) * (i + 1) -t+ 2), random.Next(bgHeight / 5 + textFontSize / 2, bgHeight - textFontSize / 2));
//如果當前字元X座標小於字型的二分之一大小
if (point.X < textFontSize / 2)
{
point.X = point.X + textFontSize / 2;
}
//防止文字疊加
if (i > 0 && (point.X - sPoint.X < (textFontSize / 2 + textFontSize / 2)))
{
point.X = point.X + textFontSize;
}
//如果當前字元X座標大於圖片寬度,就減去字型的寬度
if (point.X > (bgWidth - textFontSize / 2))
{
point.X = bgWidth - textFontSize / 2;
}
sPoint = point;
float angle = random.Next(-rotationAngle, rotationAngle);//轉動的度數
g.TranslateTransform(point.X, point.Y);//移動游標到指定位置
g.RotateTransform(angle);
//設定漸變畫刷
Rectangle myretang = new Rectangle(0, 1, Convert.ToInt32(textFont.Size), Convert.ToInt32(textFont.Size));
Color c = GetRandomDeepColor();
LinearGradientBrush mybrush2 = new LinearGradientBrush(myretang, c, GetLightColor(c, 120), random.Next(180));
g.DrawString(chars[i].ToString(), textFont, mybrush2, 1, 1, format);
g.RotateTransform(-angle);//轉回去
g.TranslateTransform(-point.X, -point.Y);//移動游標到指定位置,每個字元緊湊顯示,避免被軟體識別
strPoint[i] = point;
textFont.Dispose();
mybrush2.Dispose();
}
return b;
}
#endregion
#region 新增的矯正驗證碼的寬高
private void AdjustBitmapSize()
{
int fSize = fontMaxSize;
int fWidth = fSize + Padding;
int imageWidth = (int)(captchaLength * fWidth) + 4 + Padding * 2;
int imageHeight = fSize * 2 + Padding;
bgWidth = imageWidth;
bgHeight = imageHeight;
}
#endregion
#region 畫干擾背景文字
/// <summary>
/// 畫背景干擾文字
/// </summary>
/// <returns></returns>
private Bitmap DrawRandBgString()
{
Bitmap b = new Bitmap(bgWidth, bgHeight);
String[] randStr = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" };
b.MakeTransparent();
Graphics g = Graphics.FromImage(b);
g.Clear(Color.Transparent);
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.SmoothingMode = SmoothingMode.HighQuality;
g.TextRenderingHint = TextRenderingHint.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBilinear;
//設定字型顯示格式
StringFormat format = new StringFormat(StringFormatFlags.NoClip);
format.Alignment = StringAlignment.Center;
format.LineAlignment = StringAlignment.Center;
FontFamily f = new FontFamily(GenericFontFamilies.Serif);
Font textFont = new Font(f, randomStringFontSize, FontStyle.Underline);
int randAngle = 60; //隨機轉動角度
for (int i = 0; i < RandomStringCount; i++)
{
Brush brush = new System.Drawing.SolidBrush(GetRandomLightColor());
Point pot = new Point(random.Next(randomStringFontSize / 2, bgWidth - randomStringFontSize / 2),
random.Next(randomStringFontSize / 2, bgHeight - randomStringFontSize/2));
//隨機轉動的度數
float angle = random.Next(-randAngle, randAngle);
//轉動畫布
g.RotateTransform(angle);
g.DrawString(randStr[random.Next(randStr.Length)], textFont, brush, pot, format);
//轉回去,為下一個字元做準備
g.RotateTransform(-angle);
//釋放資源
brush.Dispose();
}
textFont.Dispose();
format.Dispose();
f.Dispose();
return b;
}
#endregion
#region 生成隨機字串
/// <summary>
/// 生成隨機字串
/// </summary>
/// <returns></returns>
private string GetRandomString(Int32 textLength)
{
string[] randomArray = charCollection.Split(','); //將字串生成陣列
int arrayLength = randomArray.Length;
string randomString = "";
for (int i = 0; i < textLength; i++)
{
randomString += randomArray[random.Next(0, arrayLength)];
}
//Session["CheckCode"] = randomString;
return randomString; //長度是textLength +1
}
#endregion
#region 內部方法:繪製驗證碼背景
private void DrawBackground(HatchStyle hatchStyle)
{
//設定填充背景時用的筆刷
HatchBrush hBrush = new HatchBrush(hatchStyle, backColor);
//填充背景圖片
dc.FillRectangle(hBrush, 0, 0, this.bgWidth, this.bgHeight);
}
#endregion
#region 根據指定長度,返回隨機驗證碼
/// <summary>
/// 根據指定長度,返回隨機驗證碼
/// </summary>
/// <param >制定長度</param>
/// <returns>隨即驗證碼</returns>
public string Next(int length)
{
this.captchaStr = GetRandomCode(length);
return this.captchaStr;
}
#endregion
#region 內部方法:返回指定長度的隨機驗證碼字串
/// <summary>
/// 根據指定大小返回隨機驗證碼
/// </summary>
/// <param >字串長度</param>
/// <returns>隨機字串</returns>
private string GetRandomCode(int length)
{
StringBuilder sb = new StringBuilder(6);
for (int i = 0; i < length; i++)
{
sb.Append(Char.ConvertFromUtf32(RandomAZ09()));
}
return sb.ToString();
}
#endregion
#region 內部方法:產生隨機數和隨機點
/// <summary>
/// 產生0-9A-Z的隨機字元程式碼
/// </summary>
/// <returns>字元程式碼</returns>
private int RandomAZ09()
{
int result = 48;
Random ram = new Random();
int i = ram.Next(2);
switch (i)
{
case 0:
result = ram.Next(48, 58);
break;
case 1:
result = ram.Next(65, 91);
break;
}
return result;
}
/// <summary>
/// 返回一個隨機點,該隨機點範圍在驗證碼背景大小範圍內
/// </summary>
/// <returns>Point物件</returns>
private Point RandomPoint()
{
Random ram = new Random();
Point point = new Point(ram.Next(this.bgWidth), ram.Next(this.bgHeight));
return point;
}
#endregion
#region 隨機生成顏色值
/// <summary>
/// 生成隨機深顏色
/// </summary>
/// <returns></returns>
public Color GetRandomDeepColor()
{
int nRed, nGreen, nBlue; // nBlue,nRed nGreen 相差大一點 nGreen 小一些
//int high = 255;
int redLow = 160;
int greenLow = 100;
int blueLow = 160;
nRed = random.Next(redLow);
nGreen = random.Next(greenLow);
nBlue = random.Next(blueLow);
Color color = Color.FromArgb(nRed, nGreen, nBlue);
return color;
}
/// <summary>
/// 生成隨機淺顏色
/// </summary>
/// <returns>randomColor</returns>
public Color GetRandomLightColor()
{
int nRed, nGreen, nBlue; //越大顏色越淺
int low = 180; //色彩的下限
int high = 255; //色彩的上限
nRed = random.Next(high) % (high - low) + low;
nGreen = random.Next(high) % (high - low) + low;
nBlue = random.Next(high) % (high - low) + low;
Color color = Color.FromArgb(nRed, nGreen, nBlue);
return color;
}
/// <summary>
/// 生成隨機顏色值
/// </summary>
/// <returns></returns>
public Color GetRandomColor()
{
int nRed, nGreen, nBlue; //越大顏色越淺
int low = 10; //色彩的下限
int high = 255; //色彩的上限
nRed = random.Next(high) % (high - low) + low;
nGreen = random.Next(high) % (high - low) + low;
nBlue = random.Next(high) % (high - low) + low;
Color color = Color.FromArgb(nRed, nGreen, nBlue);
return color;
}
/// <summary>
/// 獲取與當前顏色值相加後的顏色
/// </summary>
/// <param name="c"></param>
/// <returns></returns>
public Color GetLightColor(Color c, Int32 value)
{
int nRed = c.R, nGreen = c.G, nBlue = c.B; //越大顏色越淺
if (nRed + value < 255 && nRed + value > 0)
{
nRed = c.R + 40;
}
if (nGreen + value < 255 && nGreen + value > 0)
{
nGreen = c.G + 40;
}
if (nBlue + value < 255 && nBlue + value > 0)
{
nBlue = c.B + 40;
}
Color color = Color.FromArgb(nRed, nGreen, nBlue);
return color;
}
#endregion
#region 合併圖片
/// <summary>
/// 合併圖片
/// </summary>
/// <param name="maps"></param>
/// <returns></returns>
private Bitmap MergerImg(params Bitmap[] maps)
{
int i = maps.Length;
if (i == 0)
throw new Exception("圖片數不能夠為0");
//建立要顯示的圖片物件,根據引數的個數設定寬度
Bitmap backgroudImg = new Bitmap(i * 12, 16);
Graphics g = Graphics.FromImage(backgroudImg);
//清除畫布,背景設定為白色
g.Clear(System.Drawing.Color.White);
for (int j = 0; j < i; j++)
{
//g.DrawImage(maps[j], j * 11, 0, maps[j].Width, maps[j].Height);
g.DrawImageUnscaled(maps[j], 0, 0);
}
g.Dispose();
return backgroudImg;
}
#endregion
#region 生成不重複的隨機數,該函式會消耗大量系統資源
/// <summary>
/// 生成不重複的隨機數,該函式會消耗大量系統資源
/// </summary>
/// <returns></returns>
private static int GetRandomSeed()
{
byte[] bytes = new byte[4];
System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider();
rng.GetBytes(bytes);
return BitConverter.ToInt32(bytes, 0);
}
#endregion
#region 縮放圖片
/// <summary>
/// 縮放圖片
/// </summary>
/// <param name="bmp">原始Bitmap</param>
/// <param name="newW">新的寬度</param>
/// <param name="newH">新的高度</param>
/// <param name="Mode">縮放質量</param>
/// <returns>處理以後的圖片</returns>
public static Bitmap KiResizeImage(Bitmap bmp, int newW, int newH, InterpolationMode Mode)
{
try
{
Bitmap b = new Bitmap(newW, newH);
Graphics g = Graphics.FromImage(b);
// 插值演算法的質量
g.InterpolationMode = Mode;
g.DrawImage(bmp, new Rectangle(0, 0, newW, newH), new Rectangle(0, 0, bmp.Width, bmp.Height), GraphicsUnit.Pixel);
g.Dispose();
return b;
}
catch
{
return null;
}
}
#endregion
#region 繪製圓角矩形
/// <summary>
/// C# GDI+ 繪製圓角矩形
/// </summary>
/// <param name="g">Graphics 物件</param>
/// <param name="rectangle">Rectangle 物件,圓角矩形區域</param>
/// <param name="borderColor">邊框顏色</param>
/// <param name="borderWidth">邊框寬度</param>
/// <param name="r">圓角半徑</param>
private static void DrawRoundRectangle(Graphics g, Rectangle rectangle, Color borderColor, float borderWidth, int r)
{
// 如要使邊緣平滑,請取消下行的註釋
g.SmoothingMode = SmoothingMode.HighQuality;
// 由於邊框也需要一定寬度,需要對矩形進行修正
//rectangle = new Rectangle(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
Pen p = new Pen(borderColor, borderWidth);
// 呼叫 getRoundRectangle 得到圓角矩形的路徑,然後再進行繪製
g.DrawPath(p, getRoundRectangle(rectangle, r));
}
#endregion
#region 根據普通矩形得到圓角矩形的路徑
/// <summary>
/// 根據普通矩形得到圓角矩形的路徑
/// </summary>
/// <param name="rectangle">原始矩形</param>
/// <param name="r">半徑</param>
/// <returns>圖形路徑</returns>
private static GraphicsPath getRoundRectangle(Rectangle rectangle, int r)
{
int l = 2 * r;
// 把圓角矩形分成八段直線、弧的組合,依次加到路徑中
GraphicsPath gp = new GraphicsPath();
gp.AddLine(new Point(rectangle.X + r, rectangle.Y), new Point(rectangle.Right - r, rectangle.Y));
gp.AddArc(new Rectangle(rectangle.Right - l, rectangle.Y, l, l), 270F, 90F);
gp.AddLine(new Point(rectangle.Right, rectangle.Y + r), new Point(rectangle.Right, rectangle.Bottom - r));
gp.AddArc(new Rectangle(rectangle.Right - l, rectangle.Bottom - l, l, l), 0F, 90F);
gp.AddLine(new Point(rectangle.Right - r, rectangle.Bottom), new Point(rectangle.X + r, rectangle.Bottom));
gp.AddArc(new Rectangle(rectangle.X, rectangle.Bottom - l, l, l), 90F, 90F);
gp.AddLine(new Point(rectangle.X, rectangle.Bottom - r), new Point(rectangle.X, rectangle.Y + r));
gp.AddArc(new Rectangle(rectangle.X, rectangle.Y, l, l), 180F, 90F);
return gp;
}
#endregion
#region 柔化
///<summary>
/// 柔化
/// </summary>
/// <param name="b">原始圖</param>
/// <returns>輸出圖</returns>
public static Bitmap KiBlur(Bitmap b)
{
if (b == null)
{
return null;
}
int w = b.Width;
int h = b.Height;
try
{
Bitmap bmpRtn = new Bitmap(w, h, PixelFormat.Format24bppRgb);
BitmapData srcData = b.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
BitmapData dstData = bmpRtn.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
unsafe
{
byte* pIn = (byte*)srcData.Scan0.ToPointer();
byte* pOut = (byte*)dstData.Scan0.ToPointer();
int stride = srcData.Stride;
byte* p;
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
//取周圍9點的值
if (x == 0 || x == w - 1 || y == 0 || y == h - 1)
{
//不做
pOut[0] = pIn[0];
pOut[1] = pIn[1];
pOut[2] = pIn[2];
}
else
{
int r1, r2, r3, r4, r5, r6, r7, r8, r9;
int g1, g2, g3, g4, g5, g6, g7, g8, g9;
int b1, b2, b3, b4, b5, b6, b7, b8, b9;
float vR, vG, vB;
//左上
p = pIn - stride - 3;
r1 = p[2];
g1 = p[1];
b1 = p[0];
//正上
p = pIn - stride;
r2 = p[2];
g2 = p[1];
b2 = p[0];
//右上
p = pIn - stride + 3;
r3 = p[2];
g3 = p[1];
b3 = p[0];
//左側
p = pIn - 3;
r4 = p[2];
g4 = p[1];
b4 = p[0];
//右側
p = pIn + 3;
r5 = p[2];
g5 = p[1];
b5 = p[0];
//右下
p = pIn + stride - 3;
r6 = p[2];
g6 = p[1];
b6 = p[0];
//正下
p = pIn + stride;
r7 = p[2];
g7 = p[1];
b7 = p[0];
//右下
p = pIn + stride + 3;
r8 = p[2];
g8 = p[1];
b8 = p[0];
//自己
p = pIn;
r9 = p[2];
g9 = p[1];
b9 = p[0];
vR = (float)(r1 + r2 + r3 + r4 + r5 + r6 + r7 + r8 + r9);
vG = (float)(g1 + g2 + g3 + g4 + g5 + g6 + g7 + g8 + g9);
vB = (float)(b1 + b2 + b3 + b4 + b5 + b6 + b7 + b8 + b9);
vR /= 9;
vG /= 9;
vB /= 9;
pOut[0] = (byte)vB;
pOut[1] = (byte)vG;
pOut[2] = (byte)vR;
}
pIn += 3;
pOut += 3;
}// end of x
pIn += srcData.Stride - w * 3;
pOut += srcData.Stride - w * 3;
} // end of y
}
b.UnlockBits(srcData);
bmpRtn.UnlockBits(dstData);
return bmpRtn;
}
catch
{
return null;
}
} // end of KiBlur
#endregion
#region 濾鏡
/// <summary>
/// 紅色濾鏡
/// </summary>
/// <param name="bitmap">Bitmap</param>
/// <param name="threshold">閥值 -255~255</param>
/// <returns></returns>
public System.Drawing.Bitmap AdjustToRed(System.Drawing.Bitmap bitmap, int threshold)
{
for (int y = 0; y < bitmap.Height; y++)
{
for (int x = 0; x < bitmap.Width; x++)
{
// 取得每一個 pixel
var pixel = bitmap.GetPixel(x, y);
var pR = pixel.R + threshold;
pR = Math.Max(pR, 0);
pR = Math.Min(255, pR);
// 將改過的 RGB 寫回
// 只寫入紅色的值 , G B 都放零
System.Drawing.Color newColor = System.Drawing.Color.FromArgb(pixel.A, pR, 0, 0);
bitmap.SetPixel(x, y, newColor);
}
}
// 回傳結果
return bitmap;
}
/// <summary>
/// 綠色濾鏡
/// </summary>
/// <param name="bitmap">一個圖片例項</param>
/// <param name="threshold">閥值 -255~+255</param>
/// <returns></returns>
public System.Drawing.Bitmap AdjustToGreen(System.Drawing.Bitmap bitmap, int threshold)
{
for (int y = 0; y < bitmap.Height; y++)
{
for (int x = 0; x < bitmap.Width; x++)
{
// 取得每一個 pixel
var pixel = bitmap.GetPixel(x, y);
//判斷是否超過255 如果超過就是255
var pG = pixel.G + threshold;
//如果小於0就為0
if (pG > 255) pG = 255;
if (pG < 0) pG = 0;
// 將改過的 RGB 寫回
// 只寫入綠色的值 , R B 都放零
System.Drawing.Color newColor = System.Drawing.Color.FromArgb(pixel.A, 0, pG, 0);
bitmap.SetPixel(x, y, newColor);
}
}
// 回傳結果
return bitmap;
}
/// <summary>
/// 藍色濾鏡
/// </summary>
/// <param name="bitmap">一個圖片例項</param>
/// <param name="threshold">閥值 -255~255</param>
/// <returns></returns>
public System.Drawing.Bitmap AdjustToBlue(System.Drawing.Bitmap bitmap, int threshold)
{
for (int y = 0; y < bitmap.Height; y++)
{
for (int x = 0; x < bitmap.Width; x++)
{
// 取得每一個 pixel
var pixel = bitmap.GetPixel(x, y);
//判斷是否超過255 如果超過就是255
var pB = pixel.B + threshold;
//如果小於0就為0
if (pB > 255) pB = 255;
if (pB < 0) pB = 0;
// 將改過的 RGB 寫回
// 只寫入藍色的值 , R G 都放零
System.Drawing.Color newColor = System.Drawing.Color.FromArgb(pixel.A, 0, 0, pB);
bitmap.SetPixel(x, y, newColor);
}
}
// 回傳結果
return bitmap;
}
/// <summary>
/// 調整 RGB 色調
/// </summary>
/// <param name="bitmap"></param>
/// <param name="thresholdRed">紅色閥值</param>
/// <param name="thresholdBlue">藍色閥值</param>
/// <param name="thresholdGreen">綠色閥值</param>
/// <returns></returns>
public System.Drawing.Bitmap AdjustToCustomColor(System.Drawing.Bitmap bitmap, int thresholdRed, int thresholdGreen, int thresholdBlue)
{
for (int y = 0; y < bitmap.Height; y++)
{
for (int x = 0; x < bitmap.Width; x++)
{
// 取得每一個 pixel
var pixel = bitmap.GetPixel(x, y);
//判斷是否超過255 如果超過就是255
var pG = pixel.G + thresholdGreen;
//如果小於0就為0
if (pG > 255) pG = 255;
if (pG < 0) pG = 0;
//判斷是否超過255 如果超過就是255
var pR = pixel.R + thresholdRed;
//如果小於0就為0
if (pR > 255) pR = 255;
if (pR < 0) pR = 0;
//判斷是否超過255 如果超過就是255
var pB = pixel.B + thresholdBlue;
//如果小於0就為0
if (pB > 255) pB = 255;
if (pB < 0) pB = 0;
// 將改過的 RGB 寫回
// 只寫入綠色的值 , R B 都放零
System.Drawing.Color newColor = System.Drawing.Color.FromArgb(pixel.A, pR, pG, pB);
bitmap.SetPixel(x, y, newColor);
}
}
return bitmap;
}
#endregion
#region 圖片去色(圖片黑白化)
/// <summary>
/// 圖片去色(圖片黑白化)
/// </summary>
/// <param name="original">一個需要處理的圖片</param>
/// <returns></returns>
public static Bitmap MakeGrayscale(Bitmap original)
{
//create a blank bitmap the same size as original
Bitmap newBitmap = new Bitmap(original.Width, original.Height);
//get a graphics object from the new image
Graphics g = Graphics.FromImage(newBitmap);
g.SmoothingMode = SmoothingMode.HighQuality;
//create the grayscale ColorMatrix
ColorMatrix colorMatrix = new ColorMatrix(new float[][]
{
new float[] {.3f, .3f, .3f, 0, 0},
new float[] {.59f, .59f, .59f, 0, 0},
new float[] {.11f, .11f, .11f, 0, 0},
new float[] {0, 0, 0, 1, 0},
new float[] {0, 0, 0, 0, 1}
});
//create some image attributes
ImageAttributes attributes = new ImageAttributes();
//set the color matrix attribute
attributes.SetColorMatrix(colorMatrix);
//draw the original image on the new image
//using the grayscale color matrix
g.DrawImage(original, new Rectangle(0, 0, original.Width, original.Height),
0, 0, original.Width, original.Height, GraphicsUnit.Pixel, attributes);
//dispose the Graphics object
g.Dispose();
return newBitmap;
}
#endregion
#region 增加或減少亮度
/// <summary>
/// 增加或減少亮度
/// </summary>
/// <param name="img">System.Drawing.Image Source </param>
/// <param name="valBrightness">0~255</param>
/// <returns></returns>
public System.Drawing.Bitmap AdjustBrightness(System.Drawing.Image img, int valBrightness)
{
// 讀入欲轉換的圖片並轉成為 Bitmap
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(img);
for (int y = 0; y < bitmap.Height; y++)
{
for (int x = 0; x < bitmap.Width; x++)
{
// 取得每一個 pixel
var pixel = bitmap.GetPixel(x, y);
// 判斷 如果處理過後 255 就設定為 255 如果小於則設定為 0
var pR = ((pixel.R + valBrightness > 255) ? 255 : pixel.R + valBrightness) < 0 ? 0 : ((pixel.R + valBrightness > 255) ? 255 : pixel.R + valBrightness);
var pG = ((pixel.G + valBrightness > 255) ? 255 : pixel.G + valBrightness) < 0 ? 0 : ((pixel.G + valBrightness > 255) ? 255 : pixel.G + valBrightness);
var pB = ((pixel.B + valBrightness > 255) ? 255 : pixel.B + valBrightness) < 0 ? 0 : ((pixel.B + valBrightness > 255) ? 255 : pixel.B + valBrightness);
// 將改過的 RGB 寫回
System.Drawing.Color newColor = System.Drawing.Color.FromArgb(pixel.A, pR, pG, pB);
bitmap.SetPixel(x, y, newColor);
}
}
// 回傳結果
return bitmap;
}
#endregion
#region 浮雕效果
/// <summary>
/// 浮雕效果
/// </summary>
/// <param name="src">一個圖片例項</param>
/// <returns></returns>
public Bitmap AdjustToStone(Bitmap src)
{
// 依照 Format24bppRgb 每三個表示一 Pixel 0: 藍 1: 綠 2: 紅
BitmapData bitmapData = src.LockBits(new Rectangle(0, 0, src.Width, src.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
unsafe
{
// 抓住第一個 Pixel 第一個數值
byte* p = (byte*)(void*)bitmapData.Scan0;
// 跨步值 - 寬度 *3 可以算出畸零地 之後跳到下一行
int nOffset = bitmapData.Stride - src.Width * 3;
for (int y = 0; y < src.Height; ++y)
{
for (int x = 0; x < src.Width; ++x)
{
// 為了理解方便 所以特地在命名
int r, g, b;
// 先取得下一個 Pixel
var q = p + 3;
r = Math.Abs(p[2] - q[2] + 128);
r = r < 0 ? 0 : r;
r = r > 255 ? 255 : r;
p[2] = (byte)r;
g = Math.Abs(p[1] - q[1] + 128);
g = g < 0 ? 0 : g;
g = g > 255 ? 255 : g;
p[1] = (byte)g;
b = Math.Abs(p[0] - q[0] + 128);
b = b < 0 ? 0 : b;
b = b > 255 ? 255 : b;
p[0] = (byte)b;
// 跳去下一個 Pixel
p += 3;
}
// 跨越畸零地
p += nOffset;
}
}
src.UnlockBits(bitmapData);
return src;
}
#endregion
#region 水波紋效果
/// <summary>
/// 水波紋效果
/// </summary>
/// <param name="src"></param>
/// <param name="nWave">坡度</param>
/// www.it165.net
/// <returns></returns>
public Bitmap AdjustRippleEffect(Bitmap src, short nWave)
{
int nWidth = src.Width;
int nHeight = src.Height;
// 透過公式進行水波紋的取樣
PointF[,] fp = new PointF[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 = (float)newX;
pt[x, y].X = (int)newX;
}
else
{
fp[x, y].X = (float)0.0;
pt[x, y].X = 0;
}
if (newY > 0 && newY < nHeight)
{
fp[x, y].Y = (float)newY;
pt[x, y].Y = (int)newY;
}
else
{
fp[x, y].Y = (float)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;
}
#endregion
#region 調整曝光度值
/// <summary>
/// 調整曝光度值
/// </summary>
/// <param name="src">原圖</param>
/// <param name="r"></param>
/// <param name="g"></param>
/// <param name="b"></param>
/// <returns></returns>
public Bitmap AdjustGamma(Bitmap src, double r, double g, double b)
{
// 判斷是不是在0.2~5 之間
r = Math.Min(Math.Max(0.2, r), 5);
g = Math.Min(Math.Max(0.2, g), 5);
b = Math.Min(Math.Max(0.2, b), 5);
// 依照 Fo