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
RevLine 
[797]1import os
2import re
3import math
[3685]4import inspect
5import operator
[2180]6try:
7    import hashlib as md5
[3144]8    md5.md5
[2180]9except ImportError:
10    import md5
[797]11from string import atoi
12from random import randint
13
14from DateTime import DateTime
15
[3685]16from plone.memoize import forever
17
[1954]18from quintagroup.captcha.core.data import basic_english
[3132]19#import quintagroup.captcha.core configuration values
[3600]20from quintagroup.captcha.core.config import (
21    DEFAULT_IMAGE_SIZE, DEFAULT_BG, DEFAULT_FONT_COLOR, DEFAULT_DISTORTION,
22    CAPTCHAS_COUNT)
[797]23
24try:
25    import Crypto.Cipher.DES as Crypto
[3144]26    Crypto
[3132]27except ImportError:
[797]28    import Crypto
29
[3128]30
[3685]31@forever.memoize
32def get_source_file_path(obj):
33    return inspect.getsourcefile(obj)
34
35
[3689]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
[3685]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
[1874]51def encrypt1(s):
[2180]52    return md5.md5(s).hexdigest().upper()
[1874]53
[3128]54
[797]55def getTransform(x, y, a, p, o):
[3128]56    return (math.sin((y + o[0]) * p) * a + x, math.sin((x + o[1]) * p) * a + y)
[797]57
[3128]58
[797]59def gen_captcha(**kwargs):
60    """Generate a captcha image"""
[3097]61    try:
62        from App import ImageFile
[3144]63        ImageFile
[3097]64    except ImportError:
65        import ImageFile
66    from PIL import Image
67    from PIL import ImageFont
68    from PIL import ImageDraw
[797]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
[3128]91    ALL_FONTS = ('Bd', 'It', 'MoBI', 'Mono', 'Se',
92                 'BI', 'MoBd', 'MoIt', 'SeBd', '')
[797]93    rand_font = random.choice(ALL_FONTS)
[3128]94    rand_font_path = FONT_PATH + '/vera/Vera%s.ttf' % rand_font
95    font = ImageFont.truetype(rand_font_path, fnt_sz)
[797]96    textSize = font.getsize(text)
97
98#------------------------------render   background1 -----------------------
[3128]99    image = Image.new('RGB', (textSize[0] + 7, textSize[1] + 7), bkground)
[797]100    image.paste(bkground)
101#------------------------------render       Text2 ------------------------
102    draw = ImageDraw.Draw(image)
[3128]103    alignment = (random.uniform(0, 1), random.uniform(0, 1))
[797]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
[3128]107    draw.text((x, y), text, font=font, fill=font_color)
[797]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):
[3128]121            x, y = getTransform(i * r, j * r, amplitude, period, offset)
[797]122
123            # Clamp the edges so we don't get black undefined areas
[3128]124            x = max(0, min(image.size[0] - 1, x))
125            y = max(0, min(image.size[1] - 1, y))
[797]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 = []
[3128]135    for j in xrange(yPoints - 1):
136        for i in xrange(xPoints - 1):
[797]137            mesh.append((
138                # Destination rectangle
[3128]139                (i * r, j * r,
140                 (i + 1) * r, (j + 1) * r),
[797]141                # Source quadrilateral
[3217]142                (xRows[j][i], yRows[j][i],
143                 xRows[j + 1][i], yRows[j + 1][i],
[3128]144                 xRows[j + 1][i + 1], yRows[j + 1][i + 1],
[3217]145                 xRows[j][i + 1], yRows[j][i + 1]),
[3600]146            ))
[797]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
[3128]156    return {'src': src, 'size': size}
[797]157
158
159def getWord(index):
160    words = basic_english.words.split()
161    return words[index]
162
[3128]163
[797]164def getIndex(word):
165    words = basic_english.words.split()
166    try:
167        res = words.index(word)
168    except ValueError:
[3144]169        res = len(words) + 1
[797]170    return res
171
[3128]172
[853]173def getCaptchasCount(dynamic):
174    if dynamic:
[797]175        return len(basic_english.words.split())
[853]176    else:
177        return CAPTCHAS_COUNT
[797]178
[3128]179
[797]180def formKey(num):
181    def normalize(s):
[3128]182        return (not len(s) % 8 and s) or normalize(s + str(randint(0, 9)))
[797]183
[3128]184    return normalize('%s_%i_' % (str(DateTime().timeTime()), num))
[797]185
[3128]186
[797]187def encrypt(key, s):
188    return toHex(Crypto.new(key).encrypt(s))
189
[3128]190
[797]191def decrypt(key, s):
192    return Crypto.new(key).decrypt(toStr(s))
193
[3128]194
[797]195def parseKey(s):
196    ps = re.match('^(.+?)_(.+?)_', s)
197    if ps is None:
198        return {'date': '', 'key': ''}
[3128]199    return {'date': ps.group(1), 'key': ps.group(2)}
[797]200
[3128]201
[797]202def toHex(s):
203    lst = []
204    for ch in s:
205        hv = hex(ord(ch)).replace('0x', '')
206        if len(hv) == 1:
[3128]207            hv = '0' + hv
[797]208        lst.append(hv)
209
[3128]210    return reduce(lambda x, y: x + y, lst)
[797]211
[3128]212
[797]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.