source: pwntcha/trunk/src/linuxfr/decoder.c @ 2317

Last change on this file since 2317 was 2317, checked in by Sam Hocevar, 12 years ago
  • Preparing a huge PWNtcha reorganisation. First step: put each decoder in its own subdirectory.
  • Property svn:keywords set to Id
File size: 4.3 KB
Line 
1/*
2 * linuxfr.c: decode linuxfr.org captchas
3 * $Id: decoder.c 2317 2008-04-26 08:41:35Z sam $
4 *
5 * Copyright: (c) 2005 Sam Hocevar <sam@zoy.org>
6 *  This program is free software. It comes without any warranty, to
7 *  the extent permitted by applicable law. You can redistribute it
8 *  and/or modify it under the terms of the Do What The Fuck You Want
9 *  To Public License, Version 2, as published by Sam Hocevar. See
10 *  http://sam.zoy.org/wtfpl/COPYING for more details.
11 */
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <limits.h>
17
18#include "config.h"
19#include "common.h"
20
21/* Main function */
22char *decode_linuxfr(struct image *img)
23{
24    static struct font *font = NULL;
25    char *result;
26    struct image *tmp;
27    int x, y, r, g, b, i, j, c;
28    int *stats;
29
30    if(!font)
31    {
32        font = font_load_fixed("font_linuxfr.png",
33                               "abcdefghijklmnopqrstuvwxyz"
34                               "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
35                               "0123456789");
36        if(!font)
37            exit(-1);
38    }
39
40    /* linuxfr captchas have 7 characters */
41    result = malloc(8 * sizeof(char));
42    memset(result, '\0', 8);
43
44    stats = malloc(img->height * sizeof(int));
45
46    tmp = image_dup(img);
47    filter_threshold(tmp, 150);
48
49    for(y = 0; y < tmp->height; y++)
50    {
51        int count = 0;
52        for(x = 0; x < tmp->width; x++)
53        {
54            getpixel(tmp, x, y, &r, &g, &b);
55            if(r == 0)
56                count++;
57        }
58        stats[y] = count;
59    }
60
61    /* Find 7 consecutive lines that have at least 14 pixels; they're
62     * baseline candidates */
63    for(y = 0; y < tmp->height - 11; y++)
64    {
65        int ycan = 1;
66        for(j = 3; j < 10; j++)
67        {
68            if(stats[y + j] < 14)
69            {
70                ycan = 0;
71                y = y + j - 3;
72                break;
73            }
74        }
75        if(!ycan)
76            continue;
77
78        /* Find 7 consecutive cells that have at least 2 pixels on
79         * each line; they're base column candidates */
80        for(x = 0; x < tmp->width - 9 * 7 + 1; x++)
81        {
82            int goodx = 1;
83            for(c = 0; c < 7 && goodx; c++)
84            {
85                for(j = 3; j < 10; j++)
86                {
87                    int count = 0;
88                    for(i = 0; i < 8; i++)
89                    {
90                        getpixel(tmp, x + c * 9 + i, y + j, &r, &g, &b);
91                        if(r == 0)
92                        {
93                            count++;
94                            if(count == 2)
95                                break;
96                        }
97                    }
98                    if(count < 2)
99                    {
100                        goodx = 0;
101                        break;
102                    }
103                }
104            }
105            if(!goodx)
106                continue;
107
108            /* Now we have an (x,y) candidate - try to fit 7 characters */
109            for(c = 0; c < 7 && goodx; c++)
110            {
111                int r2, g2, b2, ch;
112                int minerror = INT_MAX;
113                for(ch = 0; ch < font->size; ch++)
114                {
115                    int error = 0, goodch = 1;
116                    for(j = 0; j < 12 && goodch; j++)
117                        for(i = 0; i < 8; i++)
118                        {
119                            getpixel(tmp, x + c * 9 + i, y + j, &r, &g, &b);
120                            getpixel(font->img, ch * 9 + i, j, &r2, &g2, &b2);
121                            /* Only die if font is black and image is white */
122                            if(r > r2)
123                            {
124                                goodch = 0;
125                                break;
126                            }
127                            else if(r < r2)
128                                error++;
129                        }
130                    if(goodch && error < minerror)
131                    {
132                        minerror = error;
133                        result[c] = font->glyphs[ch].c;
134                        result[c+1] = '\0';
135                    }
136                }
137                if(minerror == INT_MAX)
138                    goodx = 0;
139            }
140            /* Wow, that was a good guess! Exit this loop */
141            if(goodx)
142                break;
143        }
144    }
145
146    image_free(tmp);
147    free(stats);
148
149    if(strlen(result) != 7)
150    {
151        free(result);
152        return NULL;
153    }
154
155    return result;
156}
157
Note: See TracBrowser for help on using the repository browser.