87
|
1 """ Captcha.Visual.BAse
|
|
2
|
|
3 Base classes for visual CAPTCHAs. We use the Python Imaging Library
|
|
4 to manipulate these images.
|
|
5 """
|
|
6 #
|
|
7 # PyCAPTCHA Package
|
|
8 # Copyright (C) 2004 Micah Dowty <micah@navi.cx>
|
|
9 #
|
|
10
|
|
11 import Captcha
|
|
12 import Image
|
|
13
|
|
14 __all__ = ['ImageCaptcha', 'Layer']
|
|
15
|
|
16
|
|
17 class ImageCaptcha(Captcha.BaseCaptcha):
|
|
18 """Base class for image-based CAPTCHA tests.
|
|
19 The render() function generates the CAPTCHA image at the given size by
|
|
20 combining Layer instances from self.layers, which should be created by
|
|
21 the subclass-defined getLayers().
|
|
22 """
|
|
23 defaultSize = (32,32)
|
|
24 # anciennement a defaultSize(256,96)
|
|
25 def __init__(self, *args, **kwargs):
|
|
26 Captcha.BaseCaptcha.__init__(self)
|
|
27 self._layers = self.getLayers(*args, **kwargs)
|
|
28
|
|
29 def getImage(self):
|
|
30 """Get a PIL image representing this CAPTCHA test, creating it if necessary"""
|
|
31 if not self._image:
|
|
32 self._image = self.render()
|
|
33 return self._image
|
|
34
|
|
35 def getLayers(self):
|
|
36 """Subclasses must override this to return a list of Layer instances to render.
|
|
37 Lists within the list of layers are recursively rendered.
|
|
38 """
|
|
39 return []
|
|
40
|
|
41 def render(self, size=None):
|
|
42 """Render this CAPTCHA, returning a PIL image"""
|
|
43 if size is None:
|
|
44 size = self.defaultSize
|
|
45 img = Image.new("L", size)
|
|
46 # img = Image.new("RGB", size)
|
|
47 return self._renderList(self._layers, Image.new("L", size))
|
|
48
|
|
49 def _renderList(self, l, img):
|
|
50 for i in l:
|
|
51 if type(i) == tuple or type(i) == list:
|
|
52 img = self._renderList(i, img)
|
|
53 else:
|
|
54 img = i.render(img) or img
|
|
55 return img
|
|
56
|
|
57
|
|
58 class Layer(object):
|
|
59 """A renderable object representing part of a CAPTCHA.
|
|
60 The render() function should return approximately the same result, regardless
|
|
61 of the image size. This means any randomization must occur in the constructor.
|
|
62
|
|
63 If the render() function returns something non-None, it is taken as an image to
|
|
64 replace the current image with. This can be used to implement transformations
|
|
65 that result in a separate image without having to copy the results back to the first.
|
|
66 """
|
|
67 def render(self, img):
|
|
68 pass
|
|
69
|
|
70 ### The End ###
|