Le repo des sources pour le site web des JM2L
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 
 

152 Zeilen
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')