source: pwntcha/trunk/src/slashdot.c @ 448

Last change on this file since 448 was 448, checked in by Sam Hocevar, 16 years ago
  • Use font_load_* for all decoders.
  • Property svn:keywords set to Id
File size: 7.6 KB
Line 
1/*
2 * slashdot.c: decode Slashdot captchas
3 * $Id: slashdot.c 448 2005-01-10 15:31:33Z sam $
4 *
5 * Copyright: (c) 2004 Sam Hocevar <sam@zoy.org>
6 *   This program is free software; you can redistribute it and/or
7 *   modify it under the terms of the Do What The Fuck You Want To
8 *   Public License as published by Banlu Kemiyatorn. See
9 *   http://sam.zoy.org/projects/COPYING.WTFPL for more details.
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <limits.h>
16#include <math.h>
17
18#include "config.h"
19#include "common.h"
20
21static void count_objects(struct image *img);
22static void rotate(struct image *img);
23static void find_glyphs(struct image *img);
24
25/* Global stuff */
26struct { int xmin, ymin, xmax, ymax; } objlist[100];
27int objects, first, last;
28char *result;
29
30/* Main function */
31char *decode_slashdot(struct image *img)
32{
33    struct image *tmp1, *tmp2;
34
35    /* Initialise local data */
36    objects = 0;
37    first = -1;
38    last = -1;
39
40    /* Slashdot captchas have 7 characters */
41    result = malloc(8 * sizeof(char));
42    strcpy(result, "       ");
43
44    /* Clean image a bit */
45    tmp1 = image_dup(img);
46    filter_detect_lines(tmp1);
47    filter_fill_holes(tmp1);
48
49    /* Detect small objects to guess image orientation */
50    tmp2 = image_dup(tmp1);
51    filter_median(tmp2);
52    filter_equalize(tmp2, 200);
53    count_objects(tmp2);
54
55    /* Invert rotation and find glyphs */
56    rotate(tmp1);
57    filter_median(tmp1);
58    find_glyphs(tmp1);
59
60    /* Clean up our mess */
61    image_free(tmp1);
62    image_free(tmp2);
63
64    /* aaaaaaa means decoding failed */
65    if(!strcmp(result, "aaaaaaa"))
66        result[0] = '\0';
67
68    return result;
69}
70
71/* The following functions are local */
72
73static void count_objects(struct image *img)
74{
75    struct image *tmp;
76    int gotblack = 1;
77    int x, y, i;
78    int r, g, b;
79
80    tmp = image_new(img->width, img->height);
81
82    for(y = 0; y < img->height; y++)
83        for(x = 0; x < img->width; x++)
84        {
85            getpixel(img, x, y, &r, &g, &b);
86            setpixel(tmp, x, y, r, g, b);
87        }
88
89    while(gotblack)
90    {
91        gotblack = 0;
92        for(y = 0; y < tmp->height; y++)
93            for(x = 0; x < tmp->width; x++)
94            {
95                getpixel(tmp, x, y, &r, &g, &b);
96                if(r == 0 && g == 0 && b == 0)
97                {
98                    gotblack = 1;
99                    filter_flood_fill(tmp, x, y, 254 - objects, 0, 0);
100                    objects++;
101                }
102            }
103    }
104
105    //printf("%i objects\n", objects);
106
107    for(i = 0; i < objects; i++)
108    {
109        objlist[i].ymin = tmp->height;
110        objlist[i].ymax = 0;
111
112        for(y = 0; y < tmp->height; y++)
113            for(x = 0; x < tmp->width; x++)
114            {
115                getpixel(tmp, x, y, &r, &g, &b);
116                if(r == 255 - i && g == 0 && b == 0)
117                {
118                    if(y < objlist[i].ymin) { objlist[i].ymin = y; objlist[i].xmin = x; }
119                    if(y > objlist[i].ymax) { objlist[i].ymax = y; objlist[i].xmax = x; }
120                }
121            }
122        //printf("y min-max: %i %i (size %i)\n", objlist[i].ymin, objlist[i].ymax, objlist[i].ymax - objlist[i].ymin + 1);
123        if(objlist[i].ymax - objlist[i].ymin > 18 && objlist[i].ymax - objlist[i].ymin < 27)
124        {
125            if(first == -1)
126                first = i;
127            last = i;
128            filter_flood_fill(tmp, objlist[i].xmin, objlist[i].ymin, 0, 0, 255);
129        }
130    }
131
132    image_swap(img, tmp);
133    image_free(tmp);
134}
135
136static void rotate(struct image *img)
137{
138    struct image *tmp;
139    int x, y, xdest, ydest;
140    int r, g, b;
141    //int R, G, B;
142    int X = objlist[first].xmin - objlist[last].xmin;
143    int Y = objlist[first].ymin - objlist[last].ymin;
144    float xtmp, ytmp;
145    float sina = (1.0 * Y) / sqrt(1.0 * X * X + Y * Y);
146    float cosa = (1.0 * X) / sqrt(1.0 * X * X + Y * Y);
147    if(sina * cosa > 0)
148    {
149        sina = -sina;
150        cosa = -cosa;
151    }
152
153    tmp = image_new(img->width, img->height);
154
155    for(y = 0; y < img->height; y++)
156        for(x = 0; x < img->width; x++)
157        {
158            xtmp = 1.0 * (x - img->width / 2);
159            ytmp = 1.0 * (y - img->height / 2);
160            xdest = xtmp * cosa - ytmp * sina + 0.5 * img->width;
161            ydest = ytmp * cosa + xtmp * sina + 0.5 * img->height;
162            //R = G = B = 0;
163            getpixel(img, xdest, ydest, &r, &g, &b);
164            //R += r; G += g; B += b;
165            //getpixel(img, xdest+1, ydest, &r, &g, &b);
166            //R += r; G += g; B += b;
167            //getpixel(img, xdest, ydest+1, &r, &g, &b);
168            //R += r; G += g; B += b;
169            //getpixel(img, xdest+1, ydest+1, &r, &g, &b);
170            //R += r; G += g; B += b;
171            //r = R / 4; g = G / 4; b = B / 4;
172            if(r == 255 && g == 0 && b == 255)
173                g = 255;
174            setpixel(tmp, x, y, r, g, b);
175        }
176
177    image_swap(img, tmp);
178    image_free(tmp);
179}
180
181static void find_glyphs(struct image *img)
182{
183    static struct font *font = NULL;
184    struct image *tmp;
185    int x, y, i = 0;
186    int r, g, b;
187    int xmin, xmax, ymin, ymax, startx = 0, cur = 0;
188    int distmin, distx, disty, distch;
189
190    if(!font)
191    {
192        font = font_load_variable("font_slashdot.png", "abcdefgijkmnpqrstvwxyz");
193        if(!font)
194            exit(1);
195    }
196
197    tmp = image_new(img->width, img->height);
198
199    for(y = 0; y < img->height; y++)
200        for(x = 0; x < img->width; x++)
201        {
202            getpixel(img, x, y, &r, &g, &b);
203            setpixel(tmp, x, y, 255, g, 255);
204        }
205
206    while(cur < 7)
207    {
208        /* Try to find 1st letter */
209        distmin = INT_MAX;
210        for(i = 0; i < font->size; i++)
211        {
212            int localmin = INT_MAX, localx, localy;
213            xmin = font->glyphs[i].xmin;
214            ymin = font->glyphs[i].ymin;
215            xmax = font->glyphs[i].xmax;
216            ymax = font->glyphs[i].ymax;
217            for(y = -5; y < 5; y++)
218                for(x = startx - 5; x < startx + 5; x++)
219                {
220                    int z, t, dist;
221                    dist = 0;
222                    for(t = 0; t < ymax - ymin; t++)
223                        for(z = 0; z < xmax - xmin; z++)
224                        {
225                            int r2;
226                            getgray(font->img, xmin + z, ymin + t, &r);
227                            getgray(img, x + z, y + t, &r2);
228                            dist += abs(r - r2);
229                        }
230    //                printf("%i %i -> %i\n", x, y, dist);
231                    //dist /= sqrt(xmax - xmin);
232                    dist = dist * 128 / font->glyphs[i].count;
233                    if(dist < localmin)
234                    {
235                        localmin = dist;
236                        localx = x;
237                        localy = y;
238                    }
239                }
240            //fprintf(stderr, "%i (%i,%i)\n", localmin, localx - startx, localy);
241            if(localmin < distmin)
242            {
243                distmin = localmin;
244                distx = localx;
245                disty = localy;
246                distch = i;
247            }
248        }
249
250        /* Draw best glyph in picture (debugging purposes) */
251        xmin = font->glyphs[distch].xmin;
252        ymin = font->glyphs[distch].ymin;
253        xmax = font->glyphs[distch].xmax;
254        ymax = font->glyphs[distch].ymax;
255        for(y = 0; y < ymax - ymin; y++)
256            for(x = 0; x < xmax - xmin; x++)
257            {
258                getpixel(font->img, xmin + x, ymin + y, &r, &g, &b);
259                if(r > 128) continue;
260                setpixel(tmp, distx + x, disty + y, r, g, b);
261            }
262
263        startx = distx + xmax - xmin;
264        result[cur++] = font->glyphs[distch].c;
265    }
266
267    image_swap(img, tmp);
268    image_free(tmp);
269}
270
Note: See TracBrowser for help on using the repository browser.