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

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

add the backward compatibility with Python 2.4

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