/* * ticketmaster.c: decode ticketmaster captchas * $Id$ * * Copyright: (c) 2006 Sam Hocevar * This program is free software. It comes without any warranty, to * the extent permitted by applicable law. You can redistribute it * and/or modify it under the terms of the Do What The Fuck You Want * To Public License, Version 2, as published by Sam Hocevar. See * http://sam.zoy.org/wtfpl/COPYING for more details. */ #include #include #include #include #include "config.h" #include "common.h" #define WIDTH 290 #define HEIGHT 80 int grid_y[HEIGHT], grid_x[WIDTH]; int dx_top[WIDTH], dy_top[WIDTH]; int dx_bottom[WIDTH], dy_bottom[WIDTH]; int perturbation_color(struct image *img, int x, int y); int real_color(struct image *img, int x, int y); int detect_grid(struct image *img); int detect_lines(struct image *img, int top); static inline int fastgetgray(struct image *img, int x, int y) { int r, g, b; getpixel(img, x, y, &r, &g, &b); return (r + g + b + 1) / 3; } /* Main function */ char *decode_ticketmaster(struct image *img) { struct image *tmp; int x, y; if(detect_grid(img)) pwnprint("image has vertical grid\n"); detect_lines(img, 1); detect_lines(img, 0); tmp = image_dup(img); /* Remove perturbations */ for(y = 1; y < HEIGHT - 1; y++) { for(x = 1; x < WIDTH - 1; x++) { int i, j, ok = 1; if(perturbation_color(img, x, y) != 0) continue; for(j = -1; j <= 1; j++) { for(i = -1; i <= 1; i++) { if(i == 0 && j == 0) continue; if(real_color(img, x + i, y + j) != perturbation_color(img, x + i, y + j)) goto lol; } } if(!ok) continue; setpixel(tmp, x, y, 255, 255, 255); lol: continue; } } /* Lol, display lines */ for(x = 1; x < WIDTH - 1; x++) { if(dy_top[x]) for(y = 0; y < HEIGHT; y++) { int newx = (x * 1024 + dx_top[x] + (y * dy_top[x])) / 1024; setpixel(tmp, newx, y, 0, 255, 0); } if(dy_bottom[x]) for(y = 0; y < HEIGHT; y++) { int newx = (x * 1024 + dx_bottom[x] + (y * dy_bottom[x])) / 1024; setpixel(tmp, newx, (HEIGHT - y - 1), 0, 255, 0); } } image_save(tmp, "ticketmaster-output.bmp"); image_free(tmp); return strdup("lol"); } int real_color(struct image *img, int x, int y) { return fastgetgray(img, x, y) < 40 ? 0 : 255; } int perturbation_color(struct image *img, int x, int y) { if(grid_x[x]) return 0; if(grid_y[y]) return 0; return 255; } int detect_lines(struct image *img, int top) { int x, y, i, j; int dx, dy; int *mydx, *mydy; if(top) { mydx = dx_top; mydy = dy_top; } else { mydx = dx_bottom; mydy = dy_bottom; } /* Detect top-bottom line candidates */ for(x = 0; x < WIDTH; x++) { int candidate = 0, worstmissed; y = top ? 0 : HEIGHT - 3; for(j = 0; j < 3; j++) { for(i = -1; i <= 1; i++) { if(fastgetgray(img, x + i, y + j) < 40) { candidate++; break; } } } if(candidate < 3) continue; mydx[x] = mydy[x] = 0; worstmissed = 30; /* Refine slope, in 1/1024th of a pixel steps */ for(dx = -1024; dx < 1024; dx += 128) { for(dy = 700; dy < 1300; dy += 16) { int missed = 0; for(y = 0; y < HEIGHT; y++) { int newx = (x * 1024 + dx + (y * dy)) / 1024; int gray = fastgetgray(img, newx, top ? y : (HEIGHT - y - 1)); if(gray > 40) { missed++; if(missed >= worstmissed) break; } } if(missed < worstmissed) { worstmissed = missed; mydx[x] = dx; mydy[x] = dy; } } } if(worstmissed == 30) continue; pwnprint("found a line at %i (+ %i), slope %i/1024\n", x, mydx[x], mydy[x]); } return 1; } int detect_grid(struct image *img) { int x, y; int lines = 0, columns = 0; memset(grid_y, 0, sizeof(grid_y)); memset(grid_x, 0, sizeof(grid_x)); for(y = 0; y < HEIGHT; y++) { for(x = 0; x < WIDTH; x++) { if(fastgetgray(img, x, y) < 40) { grid_x[x]++; grid_y[y]++; } } } for(y = 0; y < HEIGHT; y++) if((grid_y[y] = (grid_y[y] > WIDTH * 90 / 100))) lines++; for(x = 0; x < WIDTH; x++) if((grid_x[x] = (grid_x[x] > HEIGHT * 90 / 100))) columns++; return lines * columns > 3 * 20; }