31from optparse
import OptionParser
40 from PIL
import ImageFont
41 from PIL
import ImageDraw
42 from PIL
import ImageEnhance
43 from PIL
import ImageOps
45 sys.exit(
"This script requires the Python Imaging Library - http://www.pythonware.com/products/pil/")
64 for i
in range(t, b+1):
76 """Generate a captcha image"""
85 edge = max(dim[0], dim[1]) + 2*min(dim[0], dim[1])
86 im =
Image.new(
'RGB', (edge, edge), bgcolor)
90 d.text((x/2-dim[0]/2, y/2-dim[1]/2), text, font=font, fill=fgcolor)
105 bord = min(dim[0], dim[1])/4
106 im =
im.crop((bbox[0]-bord, bbox[1]-bord, bbox[2]+bord, bbox[3]+bord))
114 """Generate a subdirectory path out of the first _levels_
115 characters of _hash_, and ensure the directories exist
118 for i
in range(0, levels):
129def try_pick_word(words, blacklist, verbose, nwords, min_length, max_length):
130 if words
is not None:
138 max_length = max_length
if max_length > 0
else 10
143 print(
"word is %s" % word)
145 if len(word) < min_length:
147 print(
"skipping word pair '%s' because it has fewer than %d characters" % (word, min_length))
150 if max_length > 0
and len(word) > max_length:
152 print(
"skipping word pair '%s' because it has more than %d characters" % (word, max_length))
157 print(
"skipping word pair '%s' because it contains non-alphabetic characters" % word)
160 for naughty
in blacklist:
163 print(
"skipping word pair '%s' because it contains blacklisted word '%s'" % (word, naughty))
167def pick_word(words, blacklist, verbose, nwords, min_length, max_length):
168 for x
in range(1000):
169 word =
try_pick_word(words, blacklist, verbose, nwords, min_length, max_length)
172 sys.exit(
"Unable to find valid word combinations")
183 blacklist = object[2]
188 for i
in range(count):
192 md5hash =
hashlib.md5((key+salt+word+key+salt).encode(
'utf-8')).hexdigest()[:16]
193 filename =
"image_%s_%s.png" % (salt, md5hash)
201if __name__ ==
'__main__':
202 """This grabs random words from the dictionary 'words' (one
203 word per line) and generates a captcha image for each one,
204 with a keyed salted hash of the correct answer in the filename.
206 To check a reply, hash it in the same way with the same salt and
207 secret key, then compare with the hash value given.
210 parser = OptionParser()
212 parser.add_option(
"--random", help=
"Use random charcters instead of a wordlist", action=
"store_true")
213 parser.add_option(
"--key", help=
"The passphrase set as $wgCaptchaSecret (required)", metavar=
"KEY")
214 parser.add_option(
"--output", help=
"The directory to put the images in - $wgCaptchaDirectory (required)", metavar=
"DIR")
215 parser.add_option(
"--font", help=
"The font to use (required)", metavar=
"FONT.ttf")
216 parser.add_option(
"--font-size", help=
"The font size (default 40)", metavar=
"N", type=
'int', default=40)
217 parser.add_option(
"--count", help=
"The maximum number of images to make (default 20)", metavar=
"N", type=
'int', default=20)
218 parser.add_option(
"--blacklist", help=
"A blacklist of words that should not be used", metavar=
"FILE", default=
os.path.join(script_dir,
"blacklist"))
219 parser.add_option(
"--fill", help=
"Fill the output directory to contain N files, overrides count, cannot be used with --dirs", metavar=
"N", type=
'int')
220 parser.add_option(
"--dirs", help=
"Put the images into subdirectories N levels deep - $wgCaptchaDirectoryLevels", metavar=
"N", type=
'int')
221 parser.add_option(
"--verbose",
"-v", help=
"Show debugging information", action=
'store_true')
222 parser.add_option(
"--number-words", help=
"Number of words from the wordlist which make a captcha challenge (default 2)", type=
'int', default=2)
223 parser.add_option(
"--min-length", help=
"Minimum length for a captcha challenge", type=
'int', default=1)
224 parser.add_option(
"--max-length", help=
"Maximum length for a captcha challenge", type=
'int', default=-1)
225 parser.add_option(
"--threads", help=
"Maximum number of threads to be used to generate captchas.", type=
'int', default=1)
234 sys.exit(
"Need to specify a wordlist")
242 sys.exit(
"Need to specify an output directory")
246 sys.exit(
"Need to specify the location of a font")
257 count = max(0, fill - len(
os.listdir(output)))
262 words = [x
for x
in words
263 if len(x)
in (4,5)
and x[0] !=
"f"
264 and x[0] != x[1]
and x[-1] != x[-2]]
267 sys.exit(
"No need to generate CAPTCHA images.")
273 chunks = int(count / threads)
277 print(
"Generating %s CAPTCHA images separated in %s image(s) per chunk run by %s threads..." % (count, chunks, threads))
278 for i
in range(0, threads):
279 data.append([chunks, words, blacklist, opts, font, fontsize])
281 p.map(run_in_thread, data)
and that you know you can do these things To protect your we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights These restrictions translate to certain responsibilities for you if you distribute copies of the or if you modify it For if you distribute copies of such a whether gratis or for a you must give the recipients all the rights that you have You must make sure that receive or can get the source code And you must show them these terms so they know their rights We protect your rights with two and(2) offer you this license which gives you legal permission to copy
while(( $__line=Maintenance::readconsole()) !==false) print
pick_word(words, blacklist, verbose, nwords, min_length, max_length)
try_pick_word(words, blacklist, verbose, nwords, min_length, max_length)
gen_subdir(basedir, md5hash, levels)
gen_captcha(text, fontname, fontsize, file_name)
wobbly_copy(src, wob, col, scale, ang)