#!/usr/bin/env python #-*- encoding: utf-8 -*- # # captcha.py # Library to simply use captchas. # # Copyright (c) 2008 Pierre "delroth" Bourdon # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # Original PHP code from coucou747, translated into Python. import math import random import sys import cgitb from PIL import Image, ImageDraw cgitb.enable() class Captcha(object): """ A captcha object is used to encapsulate a text and render the image with this text, which will generally be randomized. """ def randomString(self): """ Returns a random string to use in the captcha, with the most readable characters. """ out = '' for i in xrange(self.len): out += random.choice(self.charset) return out def getMatrix(self): """ Returns the deformation matrix. """ lim_x = 16 * (len(self.text) + 1) array = [] for k in xrange(20): array.append([]) for i in xrange(lim_x): array[k].append(math.cos((i * self.cy + k * self.cx * math.pi) * self.cangle + self.phy) * math.sin((i * self.cy + k * self.cx * math.pi) * self.cangle + self.phy) * self.h2 * 7) def e(x, y): array[x][y] -= 2 * self.h for k in xrange(1, len(self.text) + 1): for i in xrange(8): for j in xrange(7, -1, -1): if ord(self.alphabet[i + 4 + ord(self.text[k - 1]) * 8]) & (1 << j): e(i * 2 + 2, k * 16 + 9 - j * 2) e(i * 2 + 3, k * 16 + 9 - j * 2) e(i * 2 + 2, k * 16 + 10 - j * 2) e(i * 2 + 3, k * 16 + 10 - j * 2) return array def getColor(self, matrix, color): return color * (10 - matrix / 3) / 10 def drawMatrix(self, matrix, image): """ Draws the matrix on the image. """ drawer = ImageDraw.Draw(image) s, c = math.sin(self.angle), math.cos(self.angle) lx, ly = len(matrix[0]) - 1, len(matrix) - 1 dx, dy, by = self.dx, self.dy, self.by a = matrix for y in xrange(ly): for x in xrange(lx): drawer.polygon([((x + y * c) * dx, by + a[y][x] + (y + x * s) * dy), ((x + 1 + y * c) * dx, by + a[y + 1][x] + (y + 1 + x * s) * dy), ((x + 1 + (y + 1) * c) * dx, by + a[y + 1][x + 1] + (y + 1 + (x + 1) * s) * dy), ((x + (1 + y) * c) * dx, by + a[y][x + 1] + (y + (x + 1) * s) * dy)], outline=self.color, fill=self.background) del drawer def getImage(self): sizex = self.width sizey = self.height img = Image.new("RGBA", (sizex, sizey), self.background) self.drawMatrix(self.matrix, img) return img def loadAlphabet(self): return file(self.alphaf).read() def __init__(self, alphaf, charset="bcdefghijklmnopqrstuvwxyz", len=5, width=450, height=160, color=(0, 0, 0, 255), background=(255, 255, 255, 0), angle=-5*3.1415/200, dx=4, dy=6, by=40, h=5, h2=0, cangle=0.055, cx=0.5, cy=1, phy=0): l = locals() for k in l: if k == 'self': continue setattr(self, k, l[k]) self.alphabet = self.loadAlphabet() self.text = self.randomString() self.matrix = self.getMatrix() print 'Content-Type: image/png' print if __name__ == '__main__': c = Captcha('alt-8x8.psf', color=(0, 0, 255, 255), background=(255, 255, 255, 255)) c.getImage().save(sys.stdout, 'png')