|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- # 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')
|