66 return two strings (text random, path of image).
77
88
9+ see help(module) for use
10+
11+ changes on versions:
12+ - from 0.1 to 0.2
13+ Added kw args, rotate arg change the angle of rotates
14+ Added retro-compatibility with python 2.7 (compatibility with py3 and py2)
15+
916---------------------------------------------------------------------------------
1017
1118MIT License
3845
3946
4047
41- version = 0.1 ;
48+ version = 0.2 ;
4249
4350_textRandom = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ;
44- _textRandom = _textRandom .upper ();
4551_textRandom += "0123456789" ;
4652
4753
4854def _invertColor (rgb ):
4955 return tuple ([255 - color for color in rgb ]);
5056
57+ def _getTextLength (font_pillow , text ):
58+ #calculate the width of char or text
59+ if hasattr (font_pillow , "getlength" ):
60+ #python3x
61+ return int (font_pillow .getlength (text ));
62+ else :
63+ #python2x (will be deprecated method on python3)
64+ return int (font_pillow .getsize (text )[0 ]);
65+
66+ def _getRandomContrastColor (background ):
67+ #select a random color with a contrast:
68+ color = background ;
69+ while abs (sum (background ) - sum (color )) < 300 :
70+ color = tuple ([randint (0 , 255 ) for i in range (3 )]);
71+ return color ;
5172
5273
74+ _validOptions = ("rotate" ,);
5375def CreateImageCaptcha (fontnames , fontsize , filename_out = None ,
54- length = 5 , valid = _textRandom , background = (200 , 200 , 200 ), addgarbage = True ):
76+ length = 5 , valid = _textRandom , background = (200 , 200 , 200 ), addgarbage = True , ** kw ):
5577
5678 """
5779 Generate a random image for captcha and save the image on a file.
@@ -90,8 +112,32 @@ def CreateImageCaptcha(fontnames, fontsize, filename_out=None,
90112 addgarbage: use a True or False boolean, this flag controls additional drawing of line shapes,
91113 default: True
92114
115+ **kw extras:
116+ rotate: the range of random rotations of a char,
117+ can be a pair of angles from -360 to 360 each.
118+ Can set this param to None value (no rotations, simple)
119+ default: (-60, 60)
120+
93121 """
94122
123+ for opt in kw :
124+ if not opt in _validOptions :
125+ raise Exception ("option %s not in (%s)" % (opt , str (_validOptions )));
126+
127+
128+ rotate = kw .get ("rotate" , (- 60 , 60 ));
129+ try :
130+ #need validate the rotate param
131+ if rotate != None :
132+ minAngle , maxAngle = rotate ;
133+ assert minAngle >= - 360 and minAngle <= 360 ;
134+ assert maxAngle >= - 360 and maxAngle <= 360 ;
135+
136+ except :
137+ raise Exception (
138+ """param -rotate can be a pair of angles from -360 to 360 each,
139+ example: (-100, 100) or (10, 60) or None (do not rotate, no angle).""" );
140+
95141 assert length > 0 ;
96142
97143 #creating text random:
@@ -116,32 +162,44 @@ def CreateImageCaptcha(fontnames, fontsize, filename_out=None,
116162 heightFont = sum (font .getmetrics ());
117163
118164 #drawing images of chars:
119- #draw = ImageDraw.Draw(image);
120- rotatedImagesChar = [];
121- for char in text :
122- widthChar = int (font .getlength (char ));
123-
124- #select a random color with a contrast:
125- color = background ;
126- while abs (sum (background ) - sum (color )) < 300 :
127- color = tuple ([randint (0 , 255 ) for i in range (3 )]);
128-
129- #new image char rotated:
130- imgChar = Image .new ("RGB" , (widthChar , heightFont ), background );
131- ImageDraw .Draw (imgChar ).text ((0 , 0 ), char , color , font = font );
132- imgChar = imgChar .rotate (randint (- 60 , 60 ), expand = True , fillcolor = background );
133-
134- rotatedImagesChar .append (imgChar )
165+
166+ if rotate != None :
167+ rotatedImagesChar = [];
168+ for char in text :
169+ #calculate the width of char:
170+ widthChar = _getTextLength (font , char );
135171
136- #create image main container:
137- tatalWidth = pad + sum ([img .width + pad for img in rotatedImagesChar ]);
138- lastx = pad ;
139- imgCaptcha = Image .new ("RGB" , (tatalWidth , heightFont + pad * 2 ), background );
172+ #select a random color with a contrast:
173+ color = _getRandomContrastColor (background );
174+
175+ #new image char rotated:
176+ imgChar = Image .new ("RGB" , (widthChar , heightFont ), background );
177+ ImageDraw .Draw (imgChar ).text ((0 , 0 ), char , color , font = font );
178+ imgChar = imgChar .rotate (randint (minAngle , maxAngle ),
179+ expand = True , fillcolor = background );
180+
181+ rotatedImagesChar .append (imgChar )
182+
183+ tatalWidth = pad + sum ([img .width + pad for img in rotatedImagesChar ]);
140184
141- #add images into container:
142- for imgChar in rotatedImagesChar :
143- imgCaptcha .paste (imgChar , (lastx , pad ));
144- lastx += imgChar .width + pad ;
185+ #create image main container:
186+ imgCaptcha = Image .new ("RGB" , (tatalWidth , heightFont + pad * 2 ), background );
187+
188+ lastx = pad ;
189+ #add images into container:
190+ for imgChar in rotatedImagesChar :
191+ imgCaptcha .paste (imgChar , (lastx , pad ));
192+ lastx += imgChar .width + pad ;
193+ else :
194+ #no-rotated chars:
195+ tatalWidth = _getTextLength (font , text ) + (pad * (len (text )+ 1 ));
196+ imgCaptcha = Image .new ("RGB" , (tatalWidth , heightFont + pad * 2 ), background );
197+ draw = ImageDraw .Draw (imgCaptcha );
198+ lastx = pad ;
199+ for char in text :
200+ color = _getRandomContrastColor (background );
201+ draw .text ((lastx , pad ), char , color , font = font );
202+ lastx += _getTextLength (font , char ) + pad ;
145203
146204 #add garbage ? :
147205 if addgarbage :
@@ -173,10 +231,21 @@ def CreateImageCaptcha(fontnames, fontsize, filename_out=None,
173231
174232if __name__ == "__main__" :
175233
176- text , fname = CreateImageCaptcha (["impact" , "arial" ], 25 , filename_out = "micaptcha.jpg" , background = (20 , 20 , 20 ));
234+ from time import time as timer ;
235+
236+ t1 = timer ();
237+ text , fname = CreateImageCaptcha (["impact" , "arial" ], 25 ,
238+ filename_out = "micaptcha.jpg" , background = (20 , 20 , 20 ));
239+
240+ t1 = timer ()- t1 ;
177241
178242 print (text , fname );
243+ print ("%f seconds transcurred" % t1 );
179244
180245 #windows:
181246 from os import startfile ;
182- startfile (fname )
247+ startfile (fname );
248+
249+ input ("Pause - press enter to exit..." );
250+
251+
0 commit comments