package captcha import ( "crypto/rand" "image" "math/big" "time" "github.com/fogleman/gg" ) const ( dwImageWidth = 160 dwImageHeight = 40 ) type DwellingCaptcha struct { Captcha } func NewDwellingCaptcha(expiration time.Duration) *DwellingCaptcha { return &DwellingCaptcha{ Captcha: Captcha{ Answer: GenerateAnswer(), ExpireIn: ExpireDate(expiration)}} } func (c *DwellingCaptcha) GenerateImage() *image.Image { ctx := gg.NewContext(dwImageWidth, dwImageHeight) // fill background ctx.SetRGB255(0x0a, 0x0a, 0x0a) ctx.Clear() // draw text ctx.SetRGB255(0xf5, 0xf5, 0xf5) ctx.Scale(4.0, 2.7) ctx.DrawStringAnchored(string(c.GetAnswer()), 20, 5, .5, .5) // draw lines and points ctx.SetRGB255(0x9f, 0x2b, 0x68) for i := 0; i < 16; i++ { x0, _ := rand.Int(rand.Reader, big.NewInt(int64(ctx.Height()))) x1, _ := rand.Int(rand.Reader, big.NewInt(int64(ctx.Height()))) ctx.SetLineWidth(2) r, _ := rand.Int(rand.Reader, big.NewInt(int64(4))) ctx.DrawPoint(float64(x0.Int64()), float64(x1.Int64()), float64(r.Int64())) ctx.DrawLine(float64(x0.Int64()), 0, float64(ctx.Height()), float64(x1.Int64())) ctx.Stroke() } for i := 0; i < 16; i++ { x0, _ := rand.Int(rand.Reader, big.NewInt(int64(ctx.Height()))) x1, _ := rand.Int(rand.Reader, big.NewInt(int64(ctx.Height()))) ctx.SetLineWidth(2) ctx.DrawLine(0, float64(x0.Int64()), float64(x1.Int64()), float64(ctx.Height())) r, _ := rand.Int(rand.Reader, big.NewInt(int64(4))) ctx.DrawPoint(float64(x0.Int64()), float64(x1.Int64()), float64(r.Int64())) ctx.Stroke() } c.Image = ctx.Image() return &c.Image } func (c *DwellingCaptcha) GetImage() *image.Image { if c.Image == nil { return c.GenerateImage() } return &c.Image } func (c *DwellingCaptcha) Solve(answer Answer) bool { c.Solved = c.Answer == answer return c.Solved } func (c *DwellingCaptcha) GetAnswer() Answer { return c.Answer } func (c *DwellingCaptcha) IsSolved() bool { return c.Solved } func (c *DwellingCaptcha) Expire() time.Time { return c.ExpireIn }