|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- # 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 io
- # from io 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 range(int(yPoints)):
- xRow = []
- yRow = []
- for i in range(int(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 range(int(yPoints - 1)):
- for i in range(int(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):
- img_size = (230, 100)
- work_img = Image.new('RGBA', img_size, (255, 255, 255, 0))
- Xmax, Ymax = work_img.size
- # Write something on it
- draw = ImageDraw.Draw(work_img)
-
- # 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 = (img_size[0] - Xt) / 2, (img_size[1] - Yt) / 2
- draw.text((OrX, OrY), text, font=font, fill="#000000")
- # Apply a Blur
- # work_img=work_img.filter(ImageFilter.BLUR)
- # Apply a DETAIL
- work_img = work_img.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
- work_img = work_img.transform(img_size, Image.PERSPECTIVE, (ax, bx, -25, by, ay, -10, tx, ty))
- # Apply SinWarp to Captcha
- tr = Captcha_Img(Xmax, Ymax)
- tr._image = work_img
- work_img = tr.render()
- # Apply a Smooth on it
- work_img = work_img.filter(random.choice([ImageFilter.SMOOTH, ImageFilter.SMOOTH_MORE]))
- # Save Result
- request.session['Captcha'] = text
- # session.save()
- ImgHandle = io.BytesIO()
- work_img.save(ImgHandle, 'png')
- ImgHandle.seek(0)
- return Response(app_iter=ImgHandle, content_type='image/png')
|