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

Last change on this file since 3685 was 3685, checked in by vmaksymiv, 11 years ago

added inline validation derector

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