/* * scode.c: decode scode captchas * $Id: scode.c 409 2005-01-04 12:11:05Z sam $ * * Copyright: (c) 2004 Sam Hocevar * This program is free software; you can redistribute it and/or * modify it under the terms of the Do What The Fuck You Want To * Public License as published by Banlu Kemiyatorn. See * http://sam.zoy.org/projects/COPYING.WTFPL for more details. */ #include #include #include #include "config.h" #include "common.h" static char find_glyph(struct image *img, int xmin, int xmax); /* Main function */ char *decode_scode(struct image *img) { char *result; int stats[256]; int x, y, i, incell = 0, cur = 0, xmin = 0; int r, g, b; struct image *tmp1; /* allocate enough place */ result = malloc(1024 * sizeof(char)); /* Detect background: first and last 3 lines */ for(i = 0; i < 256; i++) stats[i] = 0; for(y = 0; y < 3; y++) for(x = 0; x < img->width; x++) { getpixel(img, x, y, &r, &g, &b); stats[r]++; getpixel(img, x, img->width - 1 - y, &r, &g, &b); stats[r]++; } /* Set non-background colours to 0 */ tmp1 = image_new(img->width, img->height); for(y = 0; y < img->height; y++) for(x = 0; x < img->width; x++) { getpixel(img, x, y, &r, &g, &b); if(stats[r]) setpixel(tmp1, x, y, 255, 255, 255); else setpixel(tmp1, x, y, 0, 0, 0); } /* Decode glyphs */ for(x = 0; x < img->width; x++) { int found = 0; for(y = 0; y < img->height; y++) { getpixel(tmp1, x, y, &r, &g, &b); if(!r) { found = 1; break; } } if(found && !incell) { incell = 1; xmin = x; } else if(!found && incell) { incell = 0; /* Find glyph */ result[cur++] = find_glyph(tmp1, xmin, x); } } image_free(tmp1); result[cur] = '\0'; return result; } static char find_glyph(struct image *img, int xmin, int xmax) { int ymin = -1, ymax = -1; int x, y, count = 0; int r, g, b; /* Compute vertical bounds of glyph */ for(y = 0; y < img->height; y++) { int found = 0; for(x = xmin; x < xmax; x++) { getpixel(img, x, y, &r, &g, &b); if(!r) { found = 1; break; } } if(found) { if(ymin == -1) ymin = y; else ymax = y + 1; } } for(x = xmin; x < xmax; x++) { for(y = ymin; y < ymax; y++) { getpixel(img, x, y, &r, &g, &b); if(!r) count += 5 * (y - ymin) ^ 3 * (x - xmin); //count += y - ymin; } } switch(count) { /* Scode font */ case 778: return '0'; case 621: return '1'; case 854: return '2'; case 784: return '3'; case 766: return '4'; case 771: return '5'; case 976: return '6'; case 585: return '7'; case 980: return '8'; case 896: return '9'; /* Small font */ case 584: return '0'; case 454: return '1'; case 517: return '2'; case 447: return '3'; case 469: return '4'; case 472: return '5'; case 564: return '6'; case 298: return '7'; case 560: return '8'; case 536: return '9'; /* Thin font */ case 438: return '0'; case 405: return '1'; case 485: return '2'; case 486: return '3'; case 413: return '4'; case 509: return '5'; case 582: return '6'; case 242: return '7'; case 579: return '8'; case 440: return '9'; #if 0 case 162: return '0'; case 131: return '1'; case 150: return '2'; case 139: return '3'; case 155: return '4'; case 159: return '5'; case 181: return '6'; case 90: return '7'; case 180: return '8'; case 170: return '9'; #endif default: dprintf("don't know about checksum %i\n", count); return '?'; } }