using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Web;
using deDogs.Validation;
using System.Configuration;
using System.Web.SessionState;
namespace deDogs
{
namespace Captcha
{
public class CaptchaDisplay : IDisposable
{
public CaptchaDisplay(int width)
{
this.fonts = new string[] { "Times New Roman", "Georgia", "Arial", "Comic Sans MS" };
this.sizes = new int[] { 36, 48, 60, 72 };
this.characterSet = @"ABDEFGHJKLMNQRTYZabdefghkmnqryz23456789*#@%$";
this.colr = new Brush[] { Brushes.Black };
this.backgroundColor = Brushes.White;
this.salt = new char[] { 'g', '-', '$', 'k', '5', '?', 'O' };
this._bitMap = new Bitmap(width, (int)(width * .32F));
}
public CaptchaDisplay() { }
protected class CaptchaChars
{
public CaptchaChars() { }
public CaptchaChars(string character, CaptchaRegion region)
{
this.character = character;
this.region = region;
this.memoryStream = new MemoryStream();
}
public MemoryStream memoryStream { get; set; }
public string character;
public CaptchaRegion region;
public int angle { get; set; }
}
protected class CaptchaRegion
{
public CaptchaRegion() { }
public CaptchaRegion(float x, float y, float width, float height)
{
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public float x { get; set; }
public float y { get; set; }
public float width { get; set; }
public float height { get; set; }
}
public Bitmap _bitMap;
Brush color(Random rnd)
{
return colr[rnd.Next(0, colr.Length)];
}
PinTumblerLock pinTumblerLock;
public char[] salt { get; private set; }
public string[] characters;
public string characterSet;
public string[] fonts { get; set; }
public int[] sizes { get; set; }
public Brush[] colr;
public Brush backgroundColor;
public PinTumblerLock LockKey
{
get
{
return pinTumblerLock;
}
set
{
pinTumblerLock = value;
}
}
public void GetCharacters()
{
Random rnd = new Random();
int numChars = rnd.Next(4, 7);
this.characters = new string[numChars];
for (var i = 0; i < numChars; i++)
{
this.characters[i] = this.characterSet.Substring(rnd.Next(0, this.characterSet.Length), 1);
}
}
public void CaptchaImage()
{
Random rnd = new Random();
CaptchaChars captchaChar;
List<CaptchaChars> captchaChars = new List<CaptchaChars>();
CharacterRange[] cR = { new CharacterRange(0, 1) };
StringFormatFlags flags = StringFormatFlags.NoWrap | StringFormatFlags.NoClip;
StringFormat sF = new StringFormat(flags);
sF.SetMeasurableCharacterRanges(cR);
RectangleF displayRectangleF = new RectangleF(0, 0, this._bitMap.Width, this._bitMap.Height);
Font largeFont;
int width = 80, height = 80;
for (var c = 0; c < characters.Length; c++)
{
HttpContext.Current.Trace.Write(characters[c]);
int angle = rnd.Next(0, 30);
angle = (angle % 2 == 0) ? -angle : angle;
captchaChar = new CaptchaChars(characters[c], new CaptchaRegion(0, 0, width, height));
captchaChar.angle = angle;
using (Bitmap bitMap = new Bitmap(width, height, PixelFormat.Format32bppArgb))
{
using (Graphics g = Graphics.FromImage(bitMap))
{
Rectangle rect = new Rectangle(new Point(0, 0), new Size(bitMap.Width, bitMap.Height));
g.FillRectangle(this.backgroundColor, rect);
largeFont = new Font(this.fonts[rnd.Next(0, this.fonts.Length)], this.sizes[rnd.Next(0, this.sizes.Length)], GraphicsUnit.Pixel);
Region[] charRegion = g.MeasureCharacterRanges(characters[c], largeFont, displayRectangleF, sF);
g.DrawString(characters[c], largeFont, colr[rnd.Next(0, colr.Length)], displayRectangleF);
bitMap.Save(captchaChar.memoryStream, ImageFormat.Jpeg);
captchaChars.Add(captchaChar);
}
}
}
this.Display(captchaChars);
}
void Display(List<CaptchaChars> c)
{
using (Graphics mainGraphic = Graphics.FromImage(this._bitMap))
{
StringBuilder charSet = new StringBuilder();
Rectangle rect = new Rectangle(new Point(0, 0), new Size(this._bitMap.Width, this._bitMap.Height));
mainGraphic.FillRectangle(this.backgroundColor, rect);
int newX = 0;
float bwidth, bheight = 0;
foreach (CaptchaChars m in c)
{
bwidth = m.region.width;
bheight = m.region.height;
Bitmap bitMap = new Bitmap(m.memoryStream);
using (Graphics g = Graphics.FromImage(bitMap))
{
Rotate(m, g);
g.DrawImage(bitMap, 0, 0);
mainGraphic.DrawImage(bitMap, newX, 0);
newX += (int)m.region.width;
charSet.Append(m.character);
}
}
//Crop image bounding selected characters
this._bitMap = this._bitMap.Clone(new Rectangle(0, 0, newX, (int)bheight), PixelFormat.Format32bppArgb);
Lockup(charSet.ToString());
Distort();
Decorate();
}
}
private void Lockup(string key)
{
PinTumblerLock lockup = new PinTumblerLock(key, (ConfigurationManager.AppSettings["Tumblers"]));
}
public char[] SaltKey(char[] key)
{
int len = key.Length;
for (int i = 0; i < len; i++)
{
key[i] ^= this.salt[i];
}
return key;
}
public char[] SaltKey(string[] key)
{
char[] c = string.Join(string.Empty, key).ToCharArray();
return this.SaltKey(c);
}
void Rotate(CaptchaChars c, Graphics g)
{
g.TranslateTransform(c.region.width / 2, c.region.height / 2);
g.RotateTransform(c.angle);
g.TranslateTransform(-c.region.width / 2, -c.region.height / 2);
}
protected void Distort()
{
Random rnd = new Random();
double distort = rnd.Next(5, 20) * (rnd.Next(10) == 1 ? 1 : -1);
int width = this._bitMap.Width;
int height = this._bitMap.Height;
using (Bitmap copy = (Bitmap)this._bitMap.Clone())
{
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
// Adds a simple wave
int newX = (int)(x + (distort * Math.Sin(Math.PI * y / 84.0)));
int newY = (int)(y + (distort * Math.Cos(Math.PI * x / 44.0)));
if (newX < 0 || newX >= width) newX = 0;
if (newY < 0 || newY >= height) newY = 0;
this._bitMap.SetPixel(x, y, copy.GetPixel(newX, newY));
}
}
}
}
protected void Decorate()
{
using (Graphics g = Graphics.FromImage(this._bitMap))
{
Random rnd = new Random();
int width = this._bitMap.Width;
int height = this._bitMap.Height;
// Draw lines between original points to screen.
g.DrawCurve(new Pen(color(rnd), 3.0F), Points(5, rnd).ToArray());
foreach (Point pt in Points(5, rnd))
{
g.DrawRectangle(new Pen(color(rnd), 3.0F), new Rectangle(pt, new Size(rnd.Next(5, 20), rnd.Next(5, 20))));
}
}
}
protected List<Point> Points(int pts, Random rnd)
{
List<Point> points = new List<Point>();
int width = this._bitMap.Width - 20;
int height = this._bitMap.Height - 20;
for (int i = 0; i < pts; i++)
{
points.Add(new Point(rnd.Next(0, width), rnd.Next(0, height)));
}
return points;
}
public void Dispose()
{
this._bitMap.Dispose();
this._bitMap = null;
}
}
}
}