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
RevLine 
[382]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 */
[381]11
12#include <stdio.h>
13#include <stdlib.h>
[383]14#include <string.h>
[411]15#include <limits.h>
[382]16#include <math.h>
[381]17
18#include "config.h"
19#include "common.h"
20
[445]21static void count_objects(struct image *img);
22static void rotate(struct image *img);
23static void find_glyphs(struct image *img);
[421]24
[381]25/* Global stuff */
[386]26struct { int xmin, ymin, xmax, ymax; } objlist[100];
[389]27int objects, first, last;
[381]28char *result;
29
[386]30/* Main function */
[400]31char *decode_slashdot(struct image *img)
[381]32{
[445]33    struct image *tmp1, *tmp2;
[386]34
[389]35    /* Initialise local data */
36    objects = 0;
37    first = -1;
38    last = -1;
39
[386]40    /* Slashdot captchas have 7 characters */
41    result = malloc(8 * sizeof(char));
[408]42    strcpy(result, "       ");
[386]43
44    /* Clean image a bit */
[445]45    tmp1 = image_dup(img);
46    filter_detect_lines(tmp1);
47    filter_fill_holes(tmp1);
[386]48
49    /* Detect small objects to guess image orientation */
[445]50    tmp2 = image_dup(tmp1);
51    filter_median(tmp2);
52    filter_equalize(tmp2, 200);
53    count_objects(tmp2);
[386]54
55    /* Invert rotation and find glyphs */
[445]56    rotate(tmp1);
57    filter_median(tmp1);
58    find_glyphs(tmp1);
[386]59
[389]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
[386]68    return result;
[381]69}
70
[386]71/* The following functions are local */
[381]72
[445]73static void count_objects(struct image *img)
[381]74{
[445]75    struct image *tmp;
[381]76    int gotblack = 1;
77    int x, y, i;
78    int r, g, b;
79
[445]80    tmp = image_new(img->width, img->height);
[381]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);
[445]86            setpixel(tmp, x, y, r, g, b);
[381]87        }
88
89    while(gotblack)
90    {
91        gotblack = 0;
[445]92        for(y = 0; y < tmp->height; y++)
93            for(x = 0; x < tmp->width; x++)
[381]94            {
[445]95                getpixel(tmp, x, y, &r, &g, &b);
[395]96                if(r == 0 && g == 0 && b == 0)
[381]97                {
98                    gotblack = 1;
[445]99                    filter_flood_fill(tmp, x, y, 254 - objects, 0, 0);
[381]100                    objects++;
101                }
102            }
103    }
104
105    //printf("%i objects\n", objects);
106
107    for(i = 0; i < objects; i++)
108    {
[445]109        objlist[i].ymin = tmp->height;
[381]110        objlist[i].ymax = 0;
111
[445]112        for(y = 0; y < tmp->height; y++)
113            for(x = 0; x < tmp->width; x++)
[381]114            {
[445]115                getpixel(tmp, x, y, &r, &g, &b);
[381]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;
[445]128            filter_flood_fill(tmp, objlist[i].xmin, objlist[i].ymin, 0, 0, 255);
[381]129        }
130    }
131
[445]132    image_swap(img, tmp);
133    image_free(tmp);
[381]134}
135
[445]136static void rotate(struct image *img)
[381]137{
[445]138    struct image *tmp;
[381]139    int x, y, xdest, ydest;
[386]140    int r, g, b;
141    //int R, G, B;
[381]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
[446]153    tmp = image_new(img->width, img->height);
[381]154
[446]155    for(y = 0; y < img->height; y++)
156        for(x = 0; x < img->width; x++)
[381]157        {
[446]158            xtmp = 1.0 * (x - img->width / 2);
159            ytmp = 1.0 * (y - img->height / 2);
[381]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;
[445]174            setpixel(tmp, x, y, r, g, b);
[381]175        }
176
[445]177    image_swap(img, tmp);
178    image_free(tmp);
[381]179}
180
[445]181static void find_glyphs(struct image *img)
[381]182{
[448]183    static struct font *font = NULL;
[445]184    struct image *tmp;
[381]185    int x, y, i = 0;
[386]186    int r, g, b;
[448]187    int xmin, xmax, ymin, ymax, startx = 0, cur = 0;
[381]188    int distmin, distx, disty, distch;
189
[448]190    if(!font)
[381]191    {
[448]192        font = font_load_variable("font_slashdot.png", "abcdefgijkmnpqrstvwxyz");
193        if(!font)
194            exit(1);
[381]195    }
196
[445]197    tmp = image_new(img->width, img->height);
[381]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);
[445]203            setpixel(tmp, x, y, 255, g, 255);
[381]204        }
205
[386]206    while(cur < 7)
[381]207    {
[386]208        /* Try to find 1st letter */
[411]209        distmin = INT_MAX;
[448]210        for(i = 0; i < font->size; i++)
[386]211        {
[411]212            int localmin = INT_MAX, localx, localy;
[448]213            xmin = font->glyphs[i].xmin;
214            ymin = font->glyphs[i].ymin;
215            xmax = font->glyphs[i].xmax;
216            ymax = font->glyphs[i].ymax;
[446]217            for(y = -5; y < 5; y++)
218                for(x = startx - 5; x < startx + 5; x++)
[386]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;
[448]226                            getgray(font->img, xmin + z, ymin + t, &r);
[386]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);
[448]232                    dist = dist * 128 / font->glyphs[i].count;
[386]233                    if(dist < localmin)
[381]234                    {
[386]235                        localmin = dist;
236                        localx = x;
237                        localy = y;
[381]238                    }
239                }
[386]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;
[381]247            }
248        }
249
[448]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;
[386]255        for(y = 0; y < ymax - ymin; y++)
256            for(x = 0; x < xmax - xmin; x++)
257            {
[448]258                getpixel(font->img, xmin + x, ymin + y, &r, &g, &b);
[386]259                if(r > 128) continue;
[445]260                setpixel(tmp, distx + x, disty + y, r, g, b);
[386]261            }
[381]262
[386]263        startx = distx + xmax - xmin;
[448]264        result[cur++] = font->glyphs[distch].c;
[386]265    }
[381]266
[445]267    image_swap(img, tmp);
268    image_free(tmp);
[381]269}
270
Note: See TracBrowser for help on using the repository browser.