version 0.2.4
[fms.git] / src / freenet / captcha / simplecaptcha.cpp
1 #include "../../../include/freenet/captcha/simplecaptcha.h"\r
2 #include "../../../include/freenet/captcha/easybmp/EasyBMP.h"\r
3 #include "../../../include/freenet/captcha/easybmp/EasyBMP_Font.h"\r
4 #include "../../../include/freenet/captcha/easybmp/EasyBMP_Geometry.h"\r
5 \r
6 #ifdef XMEM\r
7         #include <xmem.h>\r
8 #endif\r
9 \r
10 void SimpleCaptcha::Generate()\r
11 {\r
12         BMP bmp;\r
13         int bmpwidth=110;\r
14         int bmpheight=50;\r
15         RGBApixel lettercols[5];\r
16         std::string puzzlestring;\r
17         std::string tempfilename=GenerateRandomString(10);\r
18         tempfilename+=".bmp";\r
19 \r
20         puzzlestring=GenerateRandomString(5);\r
21         m_solution.clear();\r
22         m_solution.insert(m_solution.begin(),puzzlestring.begin(),puzzlestring.end());\r
23 \r
24         bmp.SetSize(bmpwidth,bmpheight);\r
25 \r
26         // first draw some random lines around the bitmap\r
27         int numlines=(rand()%10)+10;\r
28         for(int i=0; i<numlines; i++)\r
29         {\r
30                 RGBApixel pixel;\r
31                 int x1=rand()%bmpwidth;\r
32                 int y1=rand()%bmpheight;\r
33                 int x2=rand()%bmpwidth;\r
34                 int y2=rand()%bmpwidth;\r
35                 // keep the colors light\r
36                 pixel.Red=100+(rand()%150);\r
37                 pixel.Green=100+(rand()%150);\r
38                 pixel.Blue=100+(rand()%150);\r
39                 DrawAALine(bmp,x1,y1,x2,y2,pixel);\r
40         }\r
41 \r
42         // draw some random arcs\r
43         int numarcs=(rand()%10)+10;\r
44         for(int i=0; i<numarcs; i++)\r
45         {\r
46                 RGBApixel pixel;\r
47                 int x1=rand()%bmpwidth;\r
48                 int y1=rand()%bmpwidth;\r
49                 int radius=rand()%(bmpheight/2);\r
50                 double startangle=(double)(rand()%360)*(3.14159/180);\r
51                 double endangle=(double)(rand()%360)*(3.14159/180);\r
52                 pixel.Red=100+(rand()%150);\r
53                 pixel.Green=100+(rand()%150);\r
54                 DrawArc(bmp,x1,y1,radius,startangle,endangle,pixel);\r
55         }\r
56 \r
57         for(int i=0; i<5; i++)\r
58         {\r
59                 // keep the colors dark\r
60                 lettercols[i].Red=(rand()%200);\r
61                 lettercols[i].Green=(rand()%200);\r
62                 lettercols[i].Blue=(rand()%200);\r
63                 // draw a line with the letter col\r
64                 DrawAALine(bmp,rand()%bmpwidth,rand()%bmpheight,rand()%bmpwidth,rand()%bmpheight,lettercols[i]);\r
65         }\r
66 \r
67         // print puzzle onto bitmap\r
68         for(int i=0; i<5; i++)\r
69         {\r
70                 PrintLetter(bmp,puzzlestring[i],5+(i*20)+(rand()%11)-5,10+(rand()%10),20,lettercols[i]);\r
71         }\r
72 \r
73         /* TOO dificult to solve with this\r
74         // skew image left/right\r
75         double skew=0;\r
76         for(int yy=0; yy<bmpheight; yy++)\r
77         {\r
78                 RGBApixel pixel;\r
79                 skew=skew+(double)((rand()%11)-5)/20.0;\r
80                 int xx;\r
81                 for(xx=0; xx<skew; xx++)\r
82                 {\r
83                         pixel.Red=255;\r
84                         pixel.Green=255;\r
85                         pixel.Blue=255;\r
86                         bmp.SetPixel(xx,yy,pixel);\r
87                 }\r
88                 if(skew<0)\r
89                 {\r
90                         for(xx=0; xx<bmpwidth+skew; xx++)\r
91                         {\r
92                                 pixel=bmp.GetPixel(xx-skew,yy);\r
93                                 bmp.SetPixel(xx,yy,pixel);\r
94                         }\r
95                 }\r
96                 else\r
97                 {\r
98                         for(xx=bmpwidth-1; xx>skew; xx--)\r
99                         {\r
100                                 pixel=bmp.GetPixel(xx-skew,yy);\r
101                                 bmp.SetPixel(xx,yy,pixel);\r
102                         }\r
103                 }\r
104                 for(xx=bmpwidth+skew; xx<bmpwidth; xx++)\r
105                 {\r
106                         pixel.Red=255;\r
107                         pixel.Green=255;\r
108                         pixel.Blue=255;\r
109                         bmp.SetPixel(xx,yy,pixel);\r
110                 }\r
111         }\r
112         */\r
113 \r
114         // generate noise for each pixel\r
115         for(int yy=0; yy<bmpheight; yy++)\r
116         {\r
117                 for(int xx=0; xx<bmpwidth; xx++)\r
118                 {\r
119                         RGBApixel pixel=bmp.GetPixel(xx,yy);\r
120                         int tempred=pixel.Red+(rand()%21)-10;\r
121                         int tempgreen=pixel.Green+(rand()%21)-10;\r
122                         int tempblue=pixel.Blue+(rand()%21)-10;\r
123 \r
124                         tempred < 0 ? tempred=0 : false;\r
125                         tempred > 255 ? tempred=255 : false;\r
126                         tempgreen < 0 ? tempgreen=0 : false;\r
127                         tempgreen > 255 ? tempgreen=255 : false;\r
128                         tempblue < 0 ? tempblue=0 : false;\r
129                         tempblue > 255 ? tempblue=255 : false;\r
130 \r
131                         pixel.Red=tempred;\r
132                         pixel.Green=tempgreen;\r
133                         pixel.Blue=tempblue;\r
134 \r
135                         bmp.SetPixel(xx,yy,pixel);\r
136                 }\r
137         }\r
138 \r
139         bmp.WriteToFile(tempfilename.c_str());\r
140         ReadPuzzleData(tempfilename);\r
141         unlink(tempfilename.c_str());\r
142 }\r
143 \r
144 const std::string SimpleCaptcha::GenerateRandomString(const int len)\r
145 {\r
146         // no l,1 O,0 because they look too much alike\r
147         static std::string chars="abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ23456789";\r
148         std::string temp="";\r
149         for(int i=0; i<len; i++)\r
150         {\r
151                 temp+=chars[rand()%chars.size()];\r
152         }\r
153         return temp;\r
154 }\r
155 \r
156 const bool SimpleCaptcha::GetPuzzle(std::vector<unsigned char> &puzzle)\r
157 {\r
158         puzzle=m_puzzle;\r
159         return true;\r
160 }\r
161 \r
162 const bool SimpleCaptcha::GetSolution(std::vector<unsigned char> &solution)\r
163 {\r
164         solution=m_solution;\r
165         return true;\r
166 }\r
167 \r
168 void SimpleCaptcha::ReadPuzzleData(const std::string &filename)\r
169 {\r
170         long filelen;\r
171         FILE *infile=fopen(filename.c_str(),"rb");\r
172         if(infile)\r
173         {\r
174                 fseek(infile,0,SEEK_END);\r
175                 filelen=ftell(infile);\r
176                 fseek(infile,0,SEEK_SET);\r
177                 m_puzzle.resize(filelen);\r
178                 fread(&m_puzzle[0],1,filelen,infile);\r
179                 fclose(infile);\r
180         }\r
181 }\r