суббота, 31 января 2009 г.

pyCaptcha

Intro

Python - язык программирования.
pyCaptcha - библиотка для него, позволяющая без труда делать капчи.
Её код отлично коментирован, но, к сожалению, на этом документация и кончается. Ниже краткий обзор

Примеры сгенерированных картинок

pyCaptcha example pyCaptcha example pyCaptcha example pyCaptcha example pyCaptcha example pyCaptcha example pyCaptcha example pyCaptcha example pyCaptcha example

Сущности

Основными сущностями являются слой и капча
Layer (Captcha.Visual.Base.Layer)
Слой - это нечто, что можно наложить на картинку и получить другую картинку.
Реализованны следующию виды слоёв (в скобках указаны аргументы конструктора):
  • Фоновые (Captcha.Visual.Backgounds.*): SolidColor(color="white"), Grid(size=16, foreground="black"), TiledImage(imageFactory=Pictures.abstract), CroppedImage(imageFactory=Pictures.nature), RandomDots(colors=("white", "black"), dotSize=4, numDots=400)
  • Текстовые (Captcha.Visual.Text.*): TextLayer(text, alignment=None, font=None, fontFactory=None, textColor="black", borderSize=0, borderColor="white")
  • Искажения (Captcha.Visual.Distortions.*): WigglyBlocks(blockSize=16, sigma=0.01, iterations=300) сдвигает случайные блоки, SineWarp(amplitudeRange=(3, 6.5), periodRange=(0.04,0.1))
Captcha
Пакет предоставляет чистую абстракцию капчи - класс Captcha.Base.BaseCaptcha, умеющий исключительно сравнивать решение против правильных ответов. Причём и то, и другое может быть списком и ошибки первого и второго родов можно задать при наследовании (по умолчанию, требуется единственный, правильный ответ).
От него наследует класс Captcha.Visual.Base.ImageCaptcha. Практический интерес представляют методы getLayers, возвращающий список объектов-слоёв, и render, возвращающий PIL-изображение.
Также имеется несколько вспомагательных классов
Captcha.Visual.Base.ImageFactory
Предоставляют случайную картинку из указанной директории. В комплект входят два объекта этого класса: abstract и nature. Передаются в конструкторы слоёв TiledImage и CroppedImage
Captcha.Base.WordList
Читает файл со словами и по методу pick выдаёт случайное. Удобно использовать при генерации вопроса-ответа. Предопределены словари basic_english и basic_english_restricted - второй есть ограничение первого на слова от пяти до восьми символов включительно.
Captcha.Visaul.Text.FontFactory
Принимает список шрифтов, и диапазон допустимых размеров. По методу pick возвращает пару (fileName, size), которую можно передать ImageFont.truetype(). Предопределен объект defaultFontFactory - шрифт vera и размеры от 30 до 40.
Captcha.Base.Factory, Captcha.Base.PersistentFactory
Предоставляют базовые возможности по хранению капч, следят за соблюдением таймаутов

Получение пакета. Пример создания капчи

Последнюю версию можно получить с svn.

$ svn co http://svn.navi.cx/misc/trunk/pycaptcha/
$ find -name .snv -delete
Ниже приведён файл, генерирующий капчи выше, класть в папку pycaptcha

#!/usr/bin/env python

from Captcha.Visual import Text, Backgrounds, Distortions, ImageCaptcha


class PseudoBackGimpy(ImageCaptcha):
    def __init__(self, word, *args, **kwargs):
        self.word = word
        super(PseudoBackGimpy, self).__init__(*args, **kwargs)
    def getLayers(self):
        word = self.word
        return [
            Backgrounds.CroppedImage(),
            Text.TextLayer(word, borderSize=1),
            Distortions.SineWarp(),
            ]


class AngryBackGimpy(ImageCaptcha):
    def __init__(self, word, *args, **kwargs):
        self.word = word
        super(AngryBackGimpy, self).__init__(*args, **kwargs)
    def getLayers(self):
        word = self.word
        return [
            Backgrounds.TiledImage(),
            Backgrounds.RandomDots(),
            Text.TextLayer(word, borderSize=2),
            Distortions.WigglyBlocks(),
            ]
        
class Smoothy(ImageCaptcha):
    def __init__(self, word, *args, **kwargs):
        self.word = word
        super(Smoothy, self).__init__(*args, **kwargs)
    def getLayers(self):
        word = self.word
        return [
            Backgrounds.SolidColor(),
            Backgrounds.Grid(),
            Backgrounds.RandomDots(),
            Text.TextLayer(word, borderSize=3),
            Backgrounds.RandomDots(),
            Distortions.SineWarp(),
            ]

word = 'pyCaptcha'
examples_count = 3
size = (300,100)
klasses = [PseudoBackGimpy, AngryBackGimpy, Smoothy, ]
for klass in klasses:
    for current in range(examples_count):
        captcha = klass(word)
        img = captcha.render(size)
        img.save('_'.join(['out', word, str(klass.__name__), str(current)+".png"]))