aboutsummaryrefslogtreecommitdiffstats
path: root/jm2l/captcha.py
diff options
context:
space:
mode:
authortr4ck3ur <tr4ck3ur@style-python.fr>2015-02-13 02:29:37 +0100
committertr4ck3ur <tr4ck3ur@style-python.fr>2015-02-13 02:29:37 +0100
commitfa4a9859c57de6b7894ff4b84b75d242f2b796f5 (patch)
treec6ec352fdd634ca3e645cb2db897a127fcff299b /jm2l/captcha.py
downloadjm2l-fa4a9859c57de6b7894ff4b84b75d242f2b796f5.tar.gz
jm2l-fa4a9859c57de6b7894ff4b84b75d242f2b796f5.tar.bz2
jm2l-fa4a9859c57de6b7894ff4b84b75d242f2b796f5.tar.xz
jm2l-fa4a9859c57de6b7894ff4b84b75d242f2b796f5.zip
first drop
Diffstat (limited to 'jm2l/captcha.py')
-rw-r--r--jm2l/captcha.py151
1 files changed, 151 insertions, 0 deletions
diff --git a/jm2l/captcha.py b/jm2l/captcha.py
new file mode 100644
index 0000000..1069d98
--- /dev/null
+++ b/jm2l/captcha.py
@@ -0,0 +1,151 @@
+# 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/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')