Le repo des sources pour le site web des JM2L
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

152 lines
5.4 KiB

  1. # Stolen from tgcaptcha/plugins
  2. # http://code.google.com/p/tgcaptcha/source/browse/trunk/tgcaptcha/plugins/image/vanasco_dowty/captcha.py
  3. import random
  4. from PIL import Image, ImageDraw, ImageFont, ImageFilter
  5. import cStringIO as StringIO
  6. import math
  7. from pyramid.view import view_config
  8. from .words import TabMots
  9. from pyramid.response import Response
  10. class Captcha_Img(object):
  11. def __init__( self, width, height):
  12. self.width = width
  13. self.height = height
  14. self._layers = [
  15. _PyCaptcha_SineWarp(amplitudeRange = (4, 8) , periodRange=(0.65,0.73) ),
  16. ]
  17. def getImg(self):
  18. """Get a PIL image representing this CAPTCHA test, creating it if necessary"""
  19. if not self._image:
  20. self._image = self.render()
  21. return self._image
  22. def render(self):
  23. """Render this CAPTCHA, returning a PIL image"""
  24. size = (self.width,self.height)
  25. #img = Image.new("RGB", size )
  26. img = self._image
  27. for layer in self._layers:
  28. img = layer.render( img ) or img
  29. self._image = img
  30. return self._image
  31. class _PyCaptcha_WarpBase(object):
  32. """Abstract base class for image warping. Subclasses define a
  33. function that maps points in the output image to points in the input image.
  34. This warping engine runs a grid of points through this transform and uses
  35. PIL's mesh transform to warp the image.
  36. """
  37. filtering = Image.BILINEAR
  38. resolution = 40
  39. def get_transform(self, image):
  40. """Return a transformation function, subclasses should override this"""
  41. return lambda x, y: (x, y)
  42. def render(self, image):
  43. r = self.resolution
  44. xPoints = image.size[0] / r + 2
  45. yPoints = image.size[1] / r + 2
  46. f = self.get_transform(image)
  47. # Create a list of arrays with transformed points
  48. xRows = []
  49. yRows = []
  50. for j in xrange(yPoints):
  51. xRow = []
  52. yRow = []
  53. for i in xrange(xPoints):
  54. x, y = f(i*r, j*r)
  55. # Clamp the edges so we don't get black undefined areas
  56. x = max(0, min(image.size[0]-1, x))
  57. y = max(0, min(image.size[1]-1, y))
  58. xRow.append(x)
  59. yRow.append(y)
  60. xRows.append(xRow)
  61. yRows.append(yRow)
  62. # Create the mesh list, with a transformation for
  63. # each square between points on the grid
  64. mesh = []
  65. for j in xrange(yPoints-1):
  66. for i in xrange(xPoints-1):
  67. mesh.append((
  68. # Destination rectangle
  69. (i*r, j*r,
  70. (i+1)*r, (j+1)*r),
  71. # Source quadrilateral
  72. (xRows[j ][i ], yRows[j ][i ],
  73. xRows[j+1][i ], yRows[j+1][i ],
  74. xRows[j+1][i+1], yRows[j+1][i+1],
  75. xRows[j ][i+1], yRows[j ][i+1]),
  76. ))
  77. return image.transform(image.size, Image.MESH, mesh, self.filtering)
  78. class _PyCaptcha_SineWarp(_PyCaptcha_WarpBase):
  79. """Warp the image using a random composition of sine waves"""
  80. def __init__(self,
  81. amplitudeRange = (1,1),#(2, 6),
  82. periodRange = (1,1)#(0.65, 0.73),
  83. ):
  84. self.amplitude = random.uniform(*amplitudeRange)
  85. self.period = random.uniform(*periodRange)
  86. self.offset = (random.uniform(0, math.pi * 2 / self.period),
  87. random.uniform(0, math.pi * 2 / self.period))
  88. def get_transform(self, image):
  89. return (lambda x, y,
  90. a = self.amplitude,
  91. p = self.period,
  92. o = self.offset:
  93. (math.sin( (y+o[0])*p )*a + x,
  94. math.sin( (x+o[1])*p )*a + y))
  95. @view_config(route_name='captcha')
  96. def DoCaptcha(request):
  97. ImgSize = (230,100)
  98. WorkImg = Image.new( 'RGBA', ImgSize, (255, 255, 255, 0) )
  99. Xmax, Ymax = WorkImg.size
  100. # Write something on it
  101. draw = ImageDraw.Draw(WorkImg)
  102. # use a truetype font
  103. #font = ImageFont.truetype("/var/lib/defoma/gs.d/dirs/fonts/LiberationMono-Regular.ttf", 40)
  104. # use it
  105. font = ImageFont.truetype("jm2l/static/fonts/LiberationMono-Regular.ttf",40)
  106. # Re-position
  107. # Choose a word for captcha
  108. text = random.choice(TabMots)
  109. Xt, Yt = font.getsize(text)
  110. OrX, OrY = (ImgSize[0]-Xt)/2, (ImgSize[1]-Yt)/2
  111. draw.text((OrX, OrY), text, font=font, fill="#000000")
  112. # Apply a Blur
  113. # WorkImg=WorkImg.filter(ImageFilter.BLUR)
  114. # Apply a DETAIL
  115. WorkImg=WorkImg.filter(ImageFilter.DETAIL)
  116. # randomize parameters for perspective
  117. ax, ay = (random.uniform(0.9,1.2) , random.uniform(0.9,1.2))
  118. tx, ty = (random.uniform(0,0.0003),random.uniform(0,0.0003))
  119. bx, by = (random.uniform(0.5,0.8),random.uniform(0,0.2))
  120. # Apply perspective to Captcha
  121. WorkImg= WorkImg.transform(ImgSize, Image.PERSPECTIVE, (ax, bx, -25, by, ay, -10, tx, ty))
  122. # Apply SinWarp to Captcha
  123. tr = Captcha_Img(Xmax, Ymax)
  124. tr._image = WorkImg
  125. WorkImg = tr.render()
  126. # Apply a Smooth on it
  127. WorkImg=WorkImg.filter(random.choice([ImageFilter.SMOOTH, ImageFilter.SMOOTH_MORE]))
  128. # Save Result
  129. request.session['Captcha'] = text
  130. #session.save()
  131. ImgHandle = StringIO.StringIO()
  132. WorkImg.save(ImgHandle,'png')
  133. ImgHandle.seek(0)
  134. return Response(app_iter=ImgHandle, content_type = 'image/png')