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
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
[3692]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
[3689]46
47
[3685]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
[1874]55def encrypt1(s):
[2180]56    return md5.md5(s).hexdigest().upper()
[1874]57
[3128]58
[797]59def getTransform(x, y, a, p, o):
[3128]60    return (math.sin((y + o[0]) * p) * a + x, math.sin((x + o[1]) * p) * a + y)
[797]61
[3128]62
[797]63def gen_captcha(**kwargs):
64    """Generate a captcha image"""
[3097]65    try:
66        from App import ImageFile
[3144]67        ImageFile
[3097]68    except ImportError:
69        import ImageFile
70    from PIL import Image
71    from PIL import ImageFont
72    from PIL import ImageDraw
[797]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
[3128]95    ALL_FONTS = ('Bd', 'It', 'MoBI', 'Mono', 'Se',
96                 'BI', 'MoBd', 'MoIt', 'SeBd', '')
[797]97    rand_font = random.choice(ALL_FONTS)
[3128]98    rand_font_path = FONT_PATH + '/vera/Vera%s.ttf' % rand_font
99    font = ImageFont.truetype(rand_font_path, fnt_sz)
[797]100    textSize = font.getsize(text)
101
102#------------------------------render   background1 -----------------------
[3128]103    image = Image.new('RGB', (textSize[0] + 7, textSize[1] + 7), bkground)
[797]104    image.paste(bkground)
105#------------------------------render       Text2 ------------------------
106    draw = ImageDraw.Draw(image)
[3128]107    alignment = (random.uniform(0, 1), random.uniform(0, 1))
[797]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
[3128]111    draw.text((x, y), text, font=font, fill=font_color)
[797]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):
[3128]125            x, y = getTransform(i * r, j * r, amplitude, period, offset)
[797]126
127            # Clamp the edges so we don't get black undefined areas
[3128]128            x = max(0, min(image.size[0] - 1, x))
129            y = max(0, min(image.size[1] - 1, y))
[797]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 = []
[3128]139    for j in xrange(yPoints - 1):
140        for i in xrange(xPoints - 1):
[797]141            mesh.append((
142                # Destination rectangle
[3128]143                (i * r, j * r,
144                 (i + 1) * r, (j + 1) * r),
[797]145                # Source quadrilateral
[3217]146                (xRows[j][i], yRows[j][i],
147                 xRows[j + 1][i], yRows[j + 1][i],
[3128]148                 xRows[j + 1][i + 1], yRows[j + 1][i + 1],
[3217]149                 xRows[j][i + 1], yRows[j][i + 1]),
[3600]150            ))
[797]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
[3128]160    return {'src': src, 'size': size}
[797]161
162
163def getWord(index):
164    words = basic_english.words.split()
165    return words[index]
166
[3128]167
[797]168def getIndex(word):
169    words = basic_english.words.split()
170    try:
171        res = words.index(word)
172    except ValueError:
[3144]173        res = len(words) + 1
[797]174    return res
175
[3128]176
[853]177def getCaptchasCount(dynamic):
178    if dynamic:
[797]179        return len(basic_english.words.split())
[853]180    else:
181        return CAPTCHAS_COUNT
[797]182
[3128]183
[797]184def formKey(num):
185    def normalize(s):
[3128]186        return (not len(s) % 8 and s) or normalize(s + str(randint(0, 9)))
[797]187
[3128]188    return normalize('%s_%i_' % (str(DateTime().timeTime()), num))
[797]189
[3128]190
[797]191def encrypt(key, s):
192    return toHex(Crypto.new(key).encrypt(s))
193
[3128]194
[797]195def decrypt(key, s):
196    return Crypto.new(key).decrypt(toStr(s))
197
[3128]198
[797]199def parseKey(s):
200    ps = re.match('^(.+?)_(.+?)_', s)
201    if ps is None:
202        return {'date': '', 'key': ''}
[3128]203    return {'date': ps.group(1), 'key': ps.group(2)}
[797]204
[3128]205
[797]206def toHex(s):
207    lst = []
208    for ch in s:
209        hv = hex(ord(ch)).replace('0x', '')
210        if len(hv) == 1:
[3128]211            hv = '0' + hv
[797]212        lst.append(hv)
213
[3128]214    return reduce(lambda x, y: x + y, lst)
[797]215
[3128]216
[797]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.