source: products/quintagroup.captcha.core/trunk/quintagroup/captcha/core/utils.py @ 3692

Last change on this file since 3692 was 3692, checked in by potar, 11 years ago

add Python 2.4 support

File size: 5.7 KB
Line 
1import os
2import re
3import math
4import inspect
5import operator
6try:
7    import hashlib as md5
8    md5.md5
9except ImportError:
10    import md5
11from string import atoi
12from random import randint
13
14from DateTime import DateTime
15
16from plone.memoize import forever
17
18from quintagroup.captcha.core.data import basic_english
19#import quintagroup.captcha.core configuration values
20from quintagroup.captcha.core.config import (
21    DEFAULT_IMAGE_SIZE, DEFAULT_BG, DEFAULT_FONT_COLOR, DEFAULT_DISTORTION,
22    CAPTCHAS_COUNT)
23
24try:
25    import Crypto.Cipher.DES as Crypto
26    Crypto
27except ImportError:
28    import Crypto
29
30
31@forever.memoize
32def get_source_file_path(obj):
33    return inspect.getsourcefile(obj)
34
35
36try:
37    # introduced in Python 2.5
38    from __builtin__ import any
39except ImportError:
40    # BBB: Python 2.4 support
41    def any(iterable):
42        for element in iterable:
43            if element:
44                return True
45        return False
46
47
48def detectInlineValidation(validation_module):
49    validation_module_path = get_source_file_path(validation_module)
50    path = operator.itemgetter(1)
51    return any(path(frame) == validation_module_path
52               for frame in inspect.stack())
53
54
55def encrypt1(s):
56    return md5.md5(s).hexdigest().upper()
57
58
59def getTransform(x, y, a, p, o):
60    return (math.sin((y + o[0]) * p) * a + x, math.sin((x + o[1]) * p) * a + y)
61
62
63def gen_captcha(**kwargs):
64    """Generate a captcha image"""
65    try:
66        from App import ImageFile
67        ImageFile
68    except ImportError:
69        import ImageFile
70    from PIL import Image
71    from PIL import ImageFont
72    from PIL import ImageDraw
73    import random
74    from PIL import ImageFile as pyImageFile
75    import sys
76    sys.modules['ImageFile'] = pyImageFile
77    from cStringIO import StringIO
78
79    text = kwargs.get('text', None)
80    fnt_sz = kwargs.get('size', DEFAULT_IMAGE_SIZE)
81    bkground = kwargs.get('bkground', DEFAULT_BG)
82    font_color = kwargs.get('font_color', DEFAULT_FONT_COLOR)
83    distortion = kwargs.get('distortion', DEFAULT_DISTORTION)
84
85    period = distortion[0]
86    amplitude = distortion[1]
87    offset = distortion[2]
88
89    outFile = StringIO()
90
91    DATA_PATH = os.path.abspath(os.path.dirname(__file__)) + '/data'
92    FONT_PATH = DATA_PATH + '/fonts'
93
94    #select font for captcha text
95    ALL_FONTS = ('Bd', 'It', 'MoBI', 'Mono', 'Se',
96                 'BI', 'MoBd', 'MoIt', 'SeBd', '')
97    rand_font = random.choice(ALL_FONTS)
98    rand_font_path = FONT_PATH + '/vera/Vera%s.ttf' % rand_font
99    font = ImageFont.truetype(rand_font_path, fnt_sz)
100    textSize = font.getsize(text)
101
102#------------------------------render   background1 -----------------------
103    image = Image.new('RGB', (textSize[0] + 7, textSize[1] + 7), bkground)
104    image.paste(bkground)
105#------------------------------render       Text2 ------------------------
106    draw = ImageDraw.Draw(image)
107    alignment = (random.uniform(0, 1), random.uniform(0, 1))
108    x = int((image.size[0] - textSize[0]) * alignment[0] + 0.5)
109    y = int((image.size[1] - textSize[1]) * alignment[1] + 0.5)
110
111    draw.text((x, y), text, font=font, fill=font_color)
112
113#------------------------------render       Distortion -----------------------
114    r = 1
115    xPoints = image.size[0] / r + 2
116    yPoints = image.size[1] / r + 2
117
118    # Create a list of arrays with transformed points
119    xRows = []
120    yRows = []
121    for j in xrange(yPoints):
122        xRow = []
123        yRow = []
124        for i in xrange(xPoints):
125            x, y = getTransform(i * r, j * r, amplitude, period, offset)
126
127            # Clamp the edges so we don't get black undefined areas
128            x = max(0, min(image.size[0] - 1, x))
129            y = max(0, min(image.size[1] - 1, y))
130
131            xRow.append(x)
132            yRow.append(y)
133        xRows.append(xRow)
134        yRows.append(yRow)
135
136    # Create the mesh list, with a transformation for
137    # each square between points on the grid
138    mesh = []
139    for j in xrange(yPoints - 1):
140        for i in xrange(xPoints - 1):
141            mesh.append((
142                # Destination rectangle
143                (i * r, j * r,
144                 (i + 1) * r, (j + 1) * r),
145                # Source quadrilateral
146                (xRows[j][i], yRows[j][i],
147                 xRows[j + 1][i], yRows[j + 1][i],
148                 xRows[j + 1][i + 1], yRows[j + 1][i + 1],
149                 xRows[j][i + 1], yRows[j][i + 1]),
150            ))
151
152    img = image.transform(image.size, Image.MESH, mesh, Image.BILINEAR)
153
154    # save the image to a file
155    img.save(outFile, format='jpeg')
156    outFile.seek(0)
157    src = outFile.read()
158    size = len(src)
159    sys.modules['ImageFile'] = ImageFile
160    return {'src': src, 'size': size}
161
162
163def getWord(index):
164    words = basic_english.words.split()
165    return words[index]
166
167
168def getIndex(word):
169    words = basic_english.words.split()
170    try:
171        res = words.index(word)
172    except ValueError:
173        res = len(words) + 1
174    return res
175
176
177def getCaptchasCount(dynamic):
178    if dynamic:
179        return len(basic_english.words.split())
180    else:
181        return CAPTCHAS_COUNT
182
183
184def formKey(num):
185    def normalize(s):
186        return (not len(s) % 8 and s) or normalize(s + str(randint(0, 9)))
187
188    return normalize('%s_%i_' % (str(DateTime().timeTime()), num))
189
190
191def encrypt(key, s):
192    return toHex(Crypto.new(key).encrypt(s))
193
194
195def decrypt(key, s):
196    return Crypto.new(key).decrypt(toStr(s))
197
198
199def parseKey(s):
200    ps = re.match('^(.+?)_(.+?)_', s)
201    if ps is None:
202        return {'date': '', 'key': ''}
203    return {'date': ps.group(1), 'key': ps.group(2)}
204
205
206def toHex(s):
207    lst = []
208    for ch in s:
209        hv = hex(ord(ch)).replace('0x', '')
210        if len(hv) == 1:
211            hv = '0' + hv
212        lst.append(hv)
213
214    return reduce(lambda x, y: x + y, lst)
215
216
217def toStr(s):
218    return s and chr(atoi(s[:2], base=16)) + toStr(s[2:]) or ''
Note: See TracBrowser for help on using the repository browser.