KickerBot/captchagen/captchagen.go

105 lines
3.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package captchagen
import (
"fmt"
"image"
"image/color"
"io/ioutil"
"log"
"math/rand"
"strings"
"time"
"github.com/fogleman/gg"
)
type Logo struct {
Image image.Image
IsCorrect bool
}
type Captcha struct {
Image image.Image
CorrectAnswer int
}
var Logos []Logo = []Logo{}
// Создаём пустое изображение с серым градиентом, грузим шрифт из /assets и возвращаем контекст вызвавшей функции
func initImage() *gg.Context {
dc := gg.NewContext(600, 400)
if err := dc.LoadFontFace("./assets/font.ttf", 24); err != nil {
panic(err)
}
grad := gg.NewLinearGradient(0, 0, 600, 400)
grad.AddColorStop(0, color.RGBA{71, 100, 106, 255})
grad.AddColorStop(1, color.RGBA{44, 43, 51, 255})
dc.SetFillStyle(grad)
dc.DrawRectangle(0, 0, 600, 400)
dc.Fill()
return dc
}
// Генерация капчи.
//
// На пустое изображение наносятся логотипы из списка, предварительно перемешанного.
// К изображениям также добавляются порядковые номера (начиная с 1 вместо 0),
// а правильный вариант возвращается вместе с итоговой картинкой
func GenCaptcha() Captcha {
dc := initImage()
rand.Seed(time.Now().UnixNano())
rand.Shuffle(len(Logos), func(i, j int) { Logos[i], Logos[j] = Logos[j], Logos[i] })
correct_answer := 0
count := len(Logos)
for i, logo := range Logos {
x := i*600/count + 50
y := rand.Intn(400 - logo.Image.Bounds().Dy())
dc.DrawImage(logo.Image, x, y)
if logo.IsCorrect {
correct_answer = i + 1
}
var tx float64 = float64(x) + 50.0
var ty float64 = float64(y) + 120.0
text := fmt.Sprintf("%d", i+1)
dc.SetRGB(1, 1, 1)
dc.DrawStringAnchored(text, tx, ty, 0.5, 0.5)
}
img := dc.Image()
captcha := Captcha{
Image: img,
CorrectAnswer: correct_answer,
}
return captcha
}
// Инициализация списка логотипов.
//
// Логотипы читаются из папки /assets рядом с исполняемым файлом.
// Принимается формат .png, логотип, представляющий правильный ответ называется godot.png
func Init() error {
files, err := ioutil.ReadDir("./assets")
if err != nil {
return err
}
for _, file := range files {
name := file.Name()
if !strings.HasSuffix(name, ".png") { // Грузим только .png
continue
}
log.Printf("%s", name) // Для отладки выводим имена файлов с логотипами
path := fmt.Sprintf("./assets/%s", name) // Составляем путь до файла
im, err := gg.LoadPNG(path) // Грузим png, возвращаем ошибку если что-то идёт не так
if err != nil {
log.Print(err)
return err
}
is_correct := strings.HasPrefix(name, "godot") // Если грузимый файл -- godot*.png - помечаем его как правильный
logo := Logo{Image: im, IsCorrect: is_correct} // Создаём в памяти структуру для капчи
Logos = append(Logos, logo) // Заносим логотип в общий список
}
return nil
}