# Stolen from tgcaptcha/plugins # http://code.google.com/p/tgcaptcha/source/browse/trunk/tgcaptcha/plugins/image/vanasco_dowty/captcha.py import random from PIL import Image, ImageDraw, ImageFont, ImageFilter import StringIO import math from pyramid.view import view_config from .words import TabMots from pyramid.response import Response class Captcha_Img(object): def __init__( self, width, height): self.width = width self.height = height self._layers = [ _PyCaptcha_SineWarp(amplitudeRange = (4, 8) , periodRange=(0.65,0.73) ), ] def getImg(self): """Get a PIL image representing this CAPTCHA test, creating it if necessary""" if not self._image: self._image = self.render() return self._image def render(self): """Render this CAPTCHA, returning a PIL image""" size = (self.width,self.height) #img = Image.new("RGB", size ) img = self._image for layer in self._layers: img = layer.render( img ) or img self._image = img return self._image class _PyCaptcha_WarpBase(object): """Abstract base class for image warping. Subclasses define a function that maps points in the output image to points in the input image. This warping engine runs a grid of points through this transform and uses PIL's mesh transform to warp the image. """ filtering = Image.BILINEAR resolution = 40 def get_transform(self, image): """Return a transformation function, subclasses should override this""" return lambda x, y: (x, y) def render(self, image): r = self.resolution xPoints = image.size[0] / r + 2 yPoints = image.size[1] / r + 2 f = self.get_transform(image) # Create a list of arrays with transformed points xRows = [] yRows = [] for j in xrange(yPoints): xRow = [] yRow = [] for i in xrange(xPoints): x, y = f(i*r, j*r) # Clamp the edges so we don't get black undefined areas x = max(0, min(image.size[0]-1, x)) y = max(0, min(image.size[1]-1, y)) xRow.append(x) yRow.append(y) xRows.append(xRow) yRows.append(yRow) # Create the mesh list, with a transformation for # each square between points on the grid mesh = [] for j in xrange(yPoints-1): for i in xrange(xPoints-1): mesh.append(( # Destination rectangle (i*r, j*r, (i+1)*r, (j+1)*r), # Source quadrilateral (xRows[j ][i ], yRows[j ][i ], xRows[j+1][i ], yRows[j+1][i ], xRows[j+1][i+1], yRows[j+1][i+1], xRows[j ][i+1], yRows[j ][i+1]), )) return image.transform(image.size, Image.MESH, mesh, self.filtering) class _PyCaptcha_SineWarp(_PyCaptcha_WarpBase): """Warp the image using a random composition of sine waves""" def __init__(self, amplitudeRange = (1,1),#(2, 6), periodRange = (1,1)#(0.65, 0.73), ): self.amplitude = random.uniform(*amplitudeRange) self.period = random.uniform(*periodRange) self.offset = (random.uniform(0, math.pi * 2 / self.period), random.uniform(0, math.pi * 2 / self.period)) def get_transform(self, image): return (lambda x, y, a = self.amplitude, p = self.period, o = self.offset: (math.sin( (y+o[0])*p )*a + x, math.sin( (x+o[1])*p )*a + y)) @view_config(route_name='captcha') def DoCaptcha(request): ImgSize = (230,100) WorkImg = Image.new( 'RGBA', ImgSize, (255, 255, 255, 0) ) Xmax, Ymax = WorkImg.size # Write something on it draw = ImageDraw.Draw(WorkImg) # use a truetype font #font = ImageFont.truetype("/var/lib/defoma/gs.d/dirs/fonts/LiberationMono-Regular.ttf", 40) # use it font = ImageFont.truetype("jm2l/static/fonts/LiberationMono-Regular.ttf",40) # Re-position # Choose a word for captcha text = random.choice(TabMots) Xt, Yt = font.getsize(text) OrX, OrY = (ImgSize[0]-Xt)/2, (ImgSize[1]-Yt)/2 draw.text((OrX, OrY), text, font=font, fill="#000000") # Apply a Blur # WorkImg=WorkImg.filter(ImageFilter.BLUR) # Apply a DETAIL WorkImg=WorkImg.filter(ImageFilter.DETAIL) # randomize parameters for perspective ax, ay = (random.uniform(0.9,1.2) , random.uniform(0.9,1.2)) tx, ty = (random.uniform(0,0.0003),random.uniform(0,0.0003)) bx, by = (random.uniform(0.5,0.8),random.uniform(0,0.2)) # Apply perspective to Captcha WorkImg= WorkImg.transform(ImgSize, Image.PERSPECTIVE, (ax, bx, -25, by, ay, -10, tx, ty)) # Apply SinWarp to Captcha tr = Captcha_Img(Xmax, Ymax) tr._image = WorkImg WorkImg = tr.render() # Apply a Smooth on it WorkImg=WorkImg.filter(random.choice([ImageFilter.SMOOTH, ImageFilter.SMOOTH_MORE])) # Save Result request.session['Captcha'] = text #session.save() ImgHandle = StringIO.StringIO() WorkImg.save(ImgHandle,'png') ImgHandle.seek(0) return Response(app_iter=ImgHandle, content_type = 'image/png')