GcaptchaZ

GcaptchaZ Git Source Tree

Root/gcaptchaz.c

1#include <sys/time.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <string.h>
5#include <gd.h>
6#include <gdfontl.h>
7
8/*
9 This code is only a C implementation (with some minor modifications) of this captcha generator :
10 http://logz.org/captchaz/
11
12 Copyright November 2012 Grégory Soutadé
13 Copyright July 2007 Loz
14
15 LICENCE : Copyleft, Licence Art Libre (http://artlibre.org/licence/lal)
16
17 Modifications :
18 * Group letters
19 * Add another layer for letter rendering (more confusing)
20 * Change start, not appropriate for big fonts
21 * Change min/max font size
22
23 You need libgd2-xpm-dev package
24
25 It's recommanded the included font "scrawl.ttf"
26 */
27
28#define MAX(a, b) (((a) >= (b)) ? (a) : (b))
29
30// If not defined
31/* int overflow2(int a, int b) */
32/* { */
33/* if(a < 0 || b < 0) { */
34/* fprintf(stderr, "gd warning: one parameter to a memory allocation multiplication is negative, failing operation gracefully\n"); */
35/* return 1; */
36/* } */
37/* if(b == 0) */
38/* return 0; */
39/* if(a > 0xFFFFFFFF / b) { */
40/* fprintf(stderr, "gd warning: product of memory allocation multiplication would exceed INT_MAX, failing operation gracefully\n"); */
41/* return 1; */
42/* } */
43/* return 0; */
44/* } */
45
46static int my_rand(int min, int max)
47{
48 int val;
49 struct timeval tv;
50 static unsigned int seed = 0;
51 int interval;
52
53 if (seed == 0)
54 {
55 gettimeofday(&tv, NULL);
56 seed = tv.tv_usec;
57 }
58
59 val = rand_r(&seed);
60
61 if (min < 0)
62 {
63 if (max < 0)
64 interval = -(min-max);
65 else
66 interval = max-min;
67 }
68 else
69 interval = max-min;
70
71 val = (int)(((double)val/(double)RAND_MAX)*(double)(interval));
72
73 val += min;
74
75 /* printf("rand [%d..%d] %d\n", min, max, val); */
76
77 return val;
78}
79
80static inline int random_color(gdImagePtr im, int a, int b) {
81 return gdImageColorAllocate(im, my_rand(a,b), my_rand(a,b), my_rand(a,b));
82}
83
84static int generate_captcha(int width, int height, int inverse, char* font, char* phrase, char* out)
85{
86 gdImagePtr im;
87 int R, c1, c2;
88 int wd, x, y, w1, w2, limit, n, p, r, g, b;
89 int size, half, len;
90 double rotation;
91 char letter[2] = {0, 0};
92 int brect[8];
93 char* error;
94 const double rad = 3.14/(double)180;
95
96// initialize in-memory image with gd library
97 im = gdImageCreateTrueColor(width, height);
98
99 R = (inverse) ? 0xFF : 0x00;
100
101 gdImageFilledRectangle(im, 0, 0, width, height, random_color(im, 222^R, 255^R));
102
103 c1 = my_rand(150^R, 185^R);
104 c2 = my_rand(195^R, 230^R);
105
106// encolour bg
107 wd=20; x=0;
108 while (x < width)
109 {
110 gdImageFilledRectangle(im, x, 0, x+wd, height, random_color(im, 222^R, 255^R));
111 x += wd;
112 wd += MAX(10, my_rand(0, 20) - 10);
113 }
114
115 // make interesting background I, lines
116 wd=4; w1=0; w2=0;
117 for(x=0; x<width; x+=wd)
118 {
119 if (x < width)
120 gdImageLine(im, x+w1, 0, x+w2, height-1, random_color(im, c1, c2));
121
122 if (x < height)
123 gdImageLine(im, 0, x-w2, width-1, x-w1, random_color(im, c1, c2));
124
125 wd += my_rand(0, 8)-4;
126 if (wd < 1) wd = 2;
127 w1 += my_rand(0, 8)-4;
128 w2 += my_rand(0, 8)-4;
129
130 if ((x > height) && (x > height)) // ???
131 break;
132 }
133
134 // more disturbing II, random letters
135 limit = my_rand(30, 90);
136 for(n=0; n<limit; n++)
137 {
138 letter[0] = my_rand(31, 125); // only one letter
139 size = my_rand(5, height/2);
140 half = size / 2;
141 x = my_rand(-half, width+half);
142 y = my_rand(half, height);
143 rotation = my_rand(60, 300);
144 c1 = random_color(im, 130^R, 240^R);
145 error = gdImageStringFT(im, brect, c1, font, size, rotation, x, y, letter);
146 if (error)
147 {
148 fprintf(stderr, "%s, font is %s\n", error, font);
149 return 1;
150 }
151 }
152
153 // add the real text to it
154 len = strlen(phrase);
155 w1 = 10;
156 w2 = width / (height/4); // Change start, not appropriate for big fonts
157 x = w2;
158
159 for(p=0; p<len; p++)
160 {
161 letter[0] = phrase[p];
162 size = my_rand(height/4, height/3); // Change min/max font size
163 half = size / 2;
164 rotation = (double)my_rand(-33, 33)*rad;
165 y = my_rand(size+3, height-3);
166 /* x = w1 + w2*p; */
167 w1 += my_rand(-width/90, width/40);
168 r = my_rand(30, 99) ; g = my_rand(30, 99) ; b = my_rand(30, 99);
169 c1 = gdImageColorAllocate(im, r*1^R, g*1^R, b*1^R);
170 c2 = gdImageColorAllocate(im, r*2^R, g*2^R, b*2^R);
171 gdImageStringFT(im, brect, c2, font, size, rotation, x+1, y, letter);
172 gdImageStringFT(im, brect, c1, font, size, rotation, x, y-1, letter);
173 // Add another layer
174 gdImageStringFT(im, brect, c1, font, size, rotation, x+2, y+2, letter);
175 // Group letters
176 x += size;
177 }
178
179 FILE* f= fopen(out, "wb");
180
181 if (!f)
182 {
183 fprintf(stderr, "Error opening %s\n", out);
184 return 1;
185 }
186
187 gdImagePng(im, f);
188 fclose(f);
189
190 gdImageDestroy(im);
191
192 return 0;
193}
194
195static void usage()
196{
197 printf("gcpatchaz is a command line captcha generator\n\n");
198 printf("usage : gcpatchaz [options]\n");
199 printf("\t-w WIDTH\n");
200 printf("\t-h HEIGHT\n");
201 printf("\t-o OUT.PNG\n");
202 printf("\t-f FONT\n");
203 printf("\t-s STRING\n");
204 printf("\t-i : inverse\n");
205 printf("\t-h : help\n");
206 printf("\nLICENCE : Copyleft, Licence Art Libre (http://artlibre.org/licence/lal)\n");
207 printf("Copyright Grégory Soutadé (2012)\n");
208 printf("Copyright Loz (2007)\n");
209}
210
211int main(int argc, char** argv)
212{
213 int opt;
214 int width=180, height=40;
215 char* out = "captcha.png", *font = "ttf-japanese-gothic.ttf", *string = NULL;
216 int inverse= 0;
217 int i, res;
218
219 while ((opt = getopt(argc, argv, "w:H:o:f:s:ih")) != -1)
220 {
221 switch(opt)
222 {
223 case 'w': width = atoi(optarg); break;
224 case 'H': height = atoi(optarg); break;
225 case 'o': out = optarg; break;
226 case 'f': font = optarg; break;
227 case 's': string = strdup(optarg); break;
228 case 'i': inverse = 1; break;
229 case 'h':
230 usage();
231 return 0;
232 default:
233 usage();
234 return 1;
235 }
236 }
237
238 if (string == NULL)
239 {
240 string = malloc(6);
241 for(i=0; i<5; i++)
242 {
243 string[i] = my_rand(65, 90);
244 }
245 string[i] = 0;
246 }
247
248 res = generate_captcha(width, height, inverse, font, string, out);
249
250 if (res == 0)
251 printf("Captcha generated for text \"%s\"\n", string);
252
253 free(string);
254
255 return 0;
256}

Archive Download this file

Branches