* cleaned up the slashdot code. * decode phpBB captchas. * added filter_contrast. git-svn-id: file:///srv/caca.zoy.org/var/lib/svn/pwntcha/trunk@389 92316355-f0b4-4df1-b90c-862c8a59935fmaster
@@ -18,6 +18,19 @@ AC_C_CONST | |||||
AC_C_INLINE | AC_C_INLINE | ||||
AC_TYPE_SIZE_T | AC_TYPE_SIZE_T | ||||
# Use OpenCV? | |||||
ac_cv_my_have_opencv="no" | |||||
save_CPPFLAGS="${CPPFLAGS}" | |||||
AC_PATH_PROG(OPENCV_CONFIG, opencv-config, no) | |||||
if test "${OPENCV_CONFIG}" != "no"; then | |||||
CPPFLAGS="${CPPFLAGS} `opencv-config --cflags`" | |||||
fi | |||||
AC_CHECK_HEADERS(cv.h, | |||||
[ac_cv_my_have_opencv="yes"], | |||||
[ac_cv_my_have_opencv="no"]) | |||||
CPPFLAGS="${save_CPPFLAGS}" | |||||
AM_CONDITIONAL(USE_OPENCV, test "${ac_cv_my_have_opencv}" = "yes") | |||||
# Use Imlib2? | # Use Imlib2? | ||||
ac_cv_my_have_imlib2="no" | ac_cv_my_have_imlib2="no" | ||||
save_CPPFLAGS="${CPPFLAGS}" | save_CPPFLAGS="${CPPFLAGS}" | ||||
@@ -31,19 +44,6 @@ AC_CHECK_HEADERS(Imlib2.h, | |||||
CPPFLAGS="${save_CPPFLAGS}" | CPPFLAGS="${save_CPPFLAGS}" | ||||
AM_CONDITIONAL(USE_IMLIB2, test "${ac_cv_my_have_imlib2}" = "yes") | AM_CONDITIONAL(USE_IMLIB2, test "${ac_cv_my_have_imlib2}" = "yes") | ||||
# Use Imlib2? | |||||
ac_cv_my_have_opencv="no" | |||||
save_CPPFLAGS="${CPPFLAGS}" | |||||
AC_PATH_PROG(OPENCV_CONFIG, opencv-config, no) | |||||
if test "${OPENCV_CONFIG}" != "no"; then | |||||
CPPFLAGS="${CPPFLAGS} `opencv-config --cflags`" | |||||
fi | |||||
AC_CHECK_HEADERS(cv.h, | |||||
[ac_cv_my_have_opencv="yes"], | |||||
[ac_cv_my_have_opencv="no"]) | |||||
CPPFLAGS="${save_CPPFLAGS}" | |||||
AM_CONDITIONAL(USE_OPENCV, test "${ac_cv_my_have_opencv}" = "yes") | |||||
if test "${ac_cv_my_have_imlib2}" = "no" -a "${ac_cv_my_have_opencv}" = "no"; then | if test "${ac_cv_my_have_imlib2}" = "no" -a "${ac_cv_my_have_opencv}" = "no"; then | ||||
AC_MSG_ERROR([[cannot find Imlib2 or OpenCV, please install one of them]]) | AC_MSG_ERROR([[cannot find Imlib2 or OpenCV, please install one of them]]) | ||||
fi | fi | ||||
@@ -3,16 +3,16 @@ NULL = | |||||
bin_PROGRAMS = pwntcha | bin_PROGRAMS = pwntcha | ||||
pwntcha_CFLAGS = $(ADDITIONAL_CFLAGS) -Wall -O6 | pwntcha_CFLAGS = $(ADDITIONAL_CFLAGS) -Wall -O6 | ||||
pwntcha_LDFLAGS = $(ADDITIONAL_LDFLAGS) | pwntcha_LDFLAGS = $(ADDITIONAL_LDFLAGS) | ||||
pwntcha_SOURCES = main.c image.c filters.c slashdot.c common.h | |||||
pwntcha_SOURCES = main.c image.c filters.c common.h slashdot.c phpbb.c test.c | |||||
if USE_IMLIB2 | |||||
ADDITIONAL_CFLAGS = `imlib2-config --cflags` -DX_DISPLAY_MISSING=1 | |||||
ADDITIONAL_LDFLAGS = `imlib2-config --libs` | |||||
else | |||||
if USE_OPENCV | if USE_OPENCV | ||||
ADDITIONAL_CFLAGS = `opencv-config --cflags` | ADDITIONAL_CFLAGS = `opencv-config --cflags` | ||||
ADDITIONAL_LDFLAGS = `opencv-config --libs opencv highgui` | ADDITIONAL_LDFLAGS = `opencv-config --libs opencv highgui` | ||||
else | else | ||||
if USE_IMLIB2 | |||||
ADDITIONAL_CFLAGS = `imlib2-config --cflags` -DX_DISPLAY_MISSING=1 | |||||
ADDITIONAL_LDFLAGS = `imlib2-config --libs` | |||||
else | |||||
ADDITIONAL_CFLAGS = | ADDITIONAL_CFLAGS = | ||||
ADDITIONAL_LDFLAGS = | ADDITIONAL_LDFLAGS = | ||||
endif | endif | ||||
@@ -18,11 +18,15 @@ struct image | |||||
}; | }; | ||||
/* available CAPTCHA decoders */ | /* available CAPTCHA decoders */ | ||||
char * decode_slashdot(struct image *img); | |||||
char *decode_phpbb(struct image *img); | |||||
char *decode_slashdot(struct image *img); | |||||
char *decode_test(struct image *img); | |||||
/* image operations */ | /* image operations */ | ||||
struct image * image_load(char *name); | |||||
struct image * image_new(int width, int height); | |||||
struct image *image_load(char *name); | |||||
struct image *image_new(int width, int height); | |||||
void image_free(struct image *img); | |||||
void image_display(struct image *img); | |||||
int getgray(struct image *img, int x, int y, int *g); | int getgray(struct image *img, int x, int y, int *g); | ||||
int getpixel(struct image *img, int x, int y, int *r, int *g, int *b); | int getpixel(struct image *img, int x, int y, int *r, int *g, int *b); | ||||
int setpixel(struct image *img, int x, int y, int r, int g, int b); | int setpixel(struct image *img, int x, int y, int r, int g, int b); | ||||
@@ -31,8 +35,9 @@ int setpixel(struct image *img, int x, int y, int r, int g, int b); | |||||
void filter_flood_fill(struct image *img, int x, int y, int r, int g, int b); | void filter_flood_fill(struct image *img, int x, int y, int r, int g, int b); | ||||
struct image *filter_fill_holes(struct image *img); | struct image *filter_fill_holes(struct image *img); | ||||
struct image *filter_detect_lines(struct image *img); | struct image *filter_detect_lines(struct image *img); | ||||
struct image *filter_equalize(struct image *img); | |||||
struct image *filter_equalize(struct image *img, int threshold); | |||||
struct image *filter_trick(struct image *img); | struct image *filter_trick(struct image *img); | ||||
struct image *filter_smooth(struct image *img); | struct image *filter_smooth(struct image *img); | ||||
struct image *filter_median(struct image *img); | struct image *filter_median(struct image *img); | ||||
struct image *filter_contrast(struct image *img); | |||||
@@ -142,7 +142,7 @@ struct image *filter_detect_lines(struct image *img) | |||||
return dst; | return dst; | ||||
} | } | ||||
struct image *filter_equalize(struct image *img) | |||||
struct image *filter_equalize(struct image *img, int threshold) | |||||
{ | { | ||||
struct image *dst; | struct image *dst; | ||||
int x, y; | int x, y; | ||||
@@ -154,7 +154,7 @@ struct image *filter_equalize(struct image *img) | |||||
for(x = 0; x < img->width; x++) | for(x = 0; x < img->width; x++) | ||||
{ | { | ||||
getpixel(img, x, y, &r, &g, &b); | getpixel(img, x, y, &r, &g, &b); | ||||
if(r < 200) r = 50; else r = 200; | |||||
if(r < threshold) r = 0; else r = 255; | |||||
setpixel(dst, x, y, r, r, r); | setpixel(dst, x, y, r, r, r); | ||||
} | } | ||||
@@ -240,7 +240,7 @@ struct image *filter_smooth(struct image *img) | |||||
struct image *filter_median(struct image *img) | struct image *filter_median(struct image *img) | ||||
{ | { | ||||
#define MSIZE 4 | |||||
#define MSIZE 3 | |||||
struct image *dst; | struct image *dst; | ||||
int x, y, i, j, val[MSIZE*MSIZE]; | int x, y, i, j, val[MSIZE*MSIZE]; | ||||
int r, g, b; | int r, g, b; | ||||
@@ -278,3 +278,36 @@ struct image *filter_median(struct image *img) | |||||
return dst; | return dst; | ||||
} | } | ||||
struct image *filter_contrast(struct image *img) | |||||
{ | |||||
struct image *dst; | |||||
int histo[256]; | |||||
int x, y, i, min = 255, max = 0; | |||||
int r, g, b; | |||||
dst = image_new(img->width, img->height); | |||||
for(y = 0; y < img->height; y++) | |||||
for(x = 0; x < img->width; x++) | |||||
{ | |||||
getgray(img, x, y, &r); | |||||
if(r < min) min = r; | |||||
if(r > max) max = r; | |||||
} | |||||
if(min == max) | |||||
histo[min] = 127; | |||||
else | |||||
for(i = min; i < max; i++) | |||||
histo[i] = (i - min) * 255 / (max - min); | |||||
for(y = 0; y < img->height; y++) | |||||
for(x = 0; x < img->width; x++) | |||||
{ | |||||
getgray(img, x, y, &r); | |||||
setpixel(dst, x, y, histo[r], histo[r], histo[r]); | |||||
} | |||||
return dst; | |||||
} | |||||
@@ -15,79 +15,93 @@ | |||||
#include "config.h" | #include "config.h" | ||||
#include "common.h" | #include "common.h" | ||||
#if defined(HAVE_IMLIB2_H) | |||||
# include <Imlib2.h> | |||||
#elif defined(HAVE_CV_H) | |||||
#if defined(HAVE_CV_H) | |||||
# include <cv.h> | # include <cv.h> | ||||
# include <highgui.h> | # include <highgui.h> | ||||
#elif defined(HAVE_IMLIB2_H) | |||||
# include <Imlib2.h> | |||||
#else | #else | ||||
# error "No imaging library" | # error "No imaging library" | ||||
#endif | #endif | ||||
struct image * image_load(char *name) | |||||
struct image *image_load(char *name) | |||||
{ | { | ||||
struct image * img; | |||||
#if defined(HAVE_IMLIB2_H) | |||||
struct image *img; | |||||
#if defined(HAVE_CV_H) | |||||
IplImage *priv = cvLoadImage(name, -1); | |||||
#elif defined(HAVE_IMLIB2_H) | |||||
Imlib_Image priv = imlib_load_image(name); | Imlib_Image priv = imlib_load_image(name); | ||||
#elif defined(HAVE_CV_H) | |||||
IplImage * priv = cvLoadImage(name, -1); | |||||
#endif | #endif | ||||
if(!priv) | if(!priv) | ||||
return NULL; | return NULL; | ||||
img = malloc(sizeof(struct image)); | img = malloc(sizeof(struct image)); | ||||
#if defined(HAVE_IMLIB2_H) | |||||
#if defined(HAVE_CV_H) | |||||
img->width = priv->width; | |||||
img->height = priv->height; | |||||
img->pitch = priv->widthStep; | |||||
img->channels = priv->nChannels; | |||||
img->pixels = priv->imageData; | |||||
#elif defined(HAVE_IMLIB2_H) | |||||
imlib_context_set_image(priv); | imlib_context_set_image(priv); | ||||
img->width = imlib_image_get_width(); | img->width = imlib_image_get_width(); | ||||
img->height = imlib_image_get_height(); | img->height = imlib_image_get_height(); | ||||
img->pitch = 4 * imlib_image_get_width(); | img->pitch = 4 * imlib_image_get_width(); | ||||
img->channels = 4; | img->channels = 4; | ||||
img->pixels = (char *)imlib_image_get_data(); | img->pixels = (char *)imlib_image_get_data(); | ||||
#elif defined(HAVE_CV_H) | |||||
img->width = priv->width; | |||||
img->height = priv->height; | |||||
img->pitch = priv->widthStep; | |||||
img->channels = priv->nChannels; | |||||
img->pixels = priv->imageData; | |||||
#endif | #endif | ||||
img->priv = (void *)priv; | img->priv = (void *)priv; | ||||
return img; | return img; | ||||
} | } | ||||
struct image * image_new(int width, int height) | |||||
struct image *image_new(int width, int height) | |||||
{ | { | ||||
struct image * img; | |||||
#if defined(HAVE_IMLIB2_H) | |||||
struct image *img; | |||||
#if defined(HAVE_CV_H) | |||||
IplImage *priv = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3); | |||||
#elif defined(HAVE_IMLIB2_H) | |||||
Imlib_Image priv = imlib_create_image(width, height); | Imlib_Image priv = imlib_create_image(width, height); | ||||
#elif defined(HAVE_CV_H) | |||||
IplImage * priv = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3); | |||||
#endif | #endif | ||||
if(!priv) | if(!priv) | ||||
return NULL; | return NULL; | ||||
img = malloc(sizeof(struct image)); | img = malloc(sizeof(struct image)); | ||||
#if defined(HAVE_IMLIB2_H) | |||||
#if defined(HAVE_CV_H) | |||||
img->width = priv->width; | |||||
img->height = priv->height; | |||||
img->pitch = priv->widthStep; | |||||
img->channels = priv->nChannels; | |||||
img->pixels = priv->imageData; | |||||
#elif defined(HAVE_IMLIB2_H) | |||||
imlib_context_set_image(priv); | imlib_context_set_image(priv); | ||||
img->width = imlib_image_get_width(); | img->width = imlib_image_get_width(); | ||||
img->height = imlib_image_get_height(); | img->height = imlib_image_get_height(); | ||||
img->pitch = 4 * imlib_image_get_width(); | img->pitch = 4 * imlib_image_get_width(); | ||||
img->channels = 4; | img->channels = 4; | ||||
img->pixels = (char *)imlib_image_get_data(); | img->pixels = (char *)imlib_image_get_data(); | ||||
#elif defined(HAVE_CV_H) | |||||
img->width = priv->width; | |||||
img->height = priv->height; | |||||
img->pitch = priv->widthStep; | |||||
img->channels = priv->nChannels; | |||||
img->pixels = priv->imageData; | |||||
#endif | #endif | ||||
img->priv = (void *)priv; | img->priv = (void *)priv; | ||||
return img; | return img; | ||||
} | } | ||||
void image_free(struct image *img) | |||||
{ | |||||
#if defined(HAVE_CV_H) | |||||
IplImage *iplimg; | |||||
iplimg = (IplImage *)img->priv; | |||||
cvReleaseImage(&iplimg); | |||||
#elif defined(HAVE_IMLIB2_H) | |||||
imlib_context_set_image(img->priv); | |||||
imlib_free_image(); | |||||
#endif | |||||
free(img); | |||||
} | |||||
int getgray(struct image *img, int x, int y, int *g) | int getgray(struct image *img, int x, int y, int *g) | ||||
{ | { | ||||
if(x < 0 || y < 0 || x >= img->width || y >= img->height) | if(x < 0 || y < 0 || x >= img->width || y >= img->height) | ||||
@@ -132,19 +146,21 @@ int setpixel(struct image *img, int x, int y, int r, int g, int b) | |||||
void image_display(struct image *img) | void image_display(struct image *img) | ||||
{ | { | ||||
#if defined(HAVE_IMLIB2_H) | |||||
#if defined(HAVE_CV_H) | |||||
char name[BUFSIZ]; | |||||
sprintf(name, "Image %p (%i x %i)", img, img->width, img->height); | |||||
cvNamedWindow(name, 0); | |||||
cvShowImage(name, img->priv); | |||||
cvResizeWindow(name, img->width * 2, img->height * 2 + 50); | |||||
while((unsigned char)cvWaitKey(0) != 0x1b) | |||||
; | |||||
#elif defined(HAVE_IMLIB2_H) | |||||
//char name[BUFSIZ]; | //char name[BUFSIZ]; | ||||
//static int i = 0; | //static int i = 0; | ||||
//sprintf(name, "image%i-%ix%i.png", i++, img->width, img->height); | //sprintf(name, "image%i-%ix%i.png", i++, img->width, img->height); | ||||
//imlib_context_set_image(img->priv); | //imlib_context_set_image(img->priv); | ||||
//imlib_save_image(name); | //imlib_save_image(name); | ||||
//fprintf(stderr, "saved to %s\n", name); | //fprintf(stderr, "saved to %s\n", name); | ||||
#elif defined(HAVE_CV_H) | |||||
char name[BUFSIZ]; | |||||
sprintf(name, "Image %p (%i x %i)", img, img->width, img->height); | |||||
cvNamedWindow(name, 0); | |||||
cvShowImage(name, img->priv); | |||||
cvResizeWindow(name, 320, 120); | |||||
#endif | #endif | ||||
} | } | ||||
@@ -11,6 +11,7 @@ | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | |||||
#include <getopt.h> | #include <getopt.h> | ||||
#include "config.h" | #include "config.h" | ||||
@@ -87,7 +88,29 @@ int main(int argc, char *argv[]) | |||||
continue; | continue; | ||||
} | } | ||||
result = decode_slashdot(img); | |||||
if(!strcmp(mode, "test")) | |||||
result = decode_test(img); | |||||
else if(!strcmp(mode, "phpbb")) | |||||
result = decode_phpbb(img); | |||||
else if(!strcmp(mode, "slashdot")) | |||||
result = decode_slashdot(img); | |||||
else | |||||
{ | |||||
if(img->width == 320 && img->height == 50) | |||||
result = decode_phpbb(img); | |||||
else if(img->height == 69) | |||||
result = decode_slashdot(img); | |||||
else | |||||
{ | |||||
fprintf(stderr, "%s: could not guess CAPTCHA type\n", argv[0]); | |||||
printf("\n"); | |||||
image_free(img); | |||||
continue; | |||||
} | |||||
} | |||||
image_free(img); | |||||
if(!result) | if(!result) | ||||
{ | { | ||||
fprintf(stderr, "%s: sorry, decoding failed\n", argv[0]); | fprintf(stderr, "%s: sorry, decoding failed\n", argv[0]); | ||||
@@ -0,0 +1,136 @@ | |||||
/* | |||||
* phpbb.c: decode phpBB captchas | |||||
* $Id$ | |||||
* | |||||
* Copyright: (c) 2005 Sam Hocevar <sam@zoy.org> | |||||
* 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 <stdio.h> | |||||
#include <stdlib.h> | |||||
#include <string.h> | |||||
#include "config.h" | |||||
#include "common.h" | |||||
/* Our macros */ | |||||
#define FONTNAME "share/font_phpbb.png" | |||||
static struct image *find_glyphs(struct image *img); | |||||
/* Global stuff */ | |||||
char *result; | |||||
/* Main function */ | |||||
char *decode_phpbb(struct image *img) | |||||
{ | |||||
char all[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789"; | |||||
struct image *tmp1, *tmp2, *tmp3; | |||||
struct image *font = image_load(FONTNAME); | |||||
int x, y, i = 0; | |||||
int r, g, b; | |||||
int xmin, xmax, ymin, ymax, cur, offset = -1; | |||||
int distmin, distx, disty, distch; | |||||
/* phpBB captchas have 6 characters */ | |||||
result = malloc(7 * sizeof(char)); | |||||
if(!font) | |||||
{ | |||||
fprintf(stderr, "cannot load font %s\n", FONTNAME); | |||||
exit(-1); | |||||
} | |||||
tmp1 = filter_smooth(img); | |||||
tmp2 = filter_equalize(tmp1, 128); | |||||
tmp3 = image_new(img->width, img->height); | |||||
for(x = 0; x < img->width; x++) | |||||
for(y = 0; y < img->height; y++) | |||||
{ | |||||
getpixel(tmp2, x, y, &r, &g, &b); | |||||
if(r == 0 && offset == -1) | |||||
offset = x; | |||||
getpixel(img, x, y, &r, &g, &b); | |||||
setpixel(tmp3, x, y, 255, g, 255); | |||||
} | |||||
strcpy(result, " "); | |||||
for(cur = 0; cur < 6; cur++) | |||||
{ | |||||
/* Try to find 1st letter */ | |||||
distmin = 999999999; | |||||
for(i = 0; i < 35; i++) | |||||
{ | |||||
int localmin = 99999999, localx, localy; | |||||
xmin = i * 40; | |||||
ymin = 0; | |||||
xmax = i * 40 + 40; | |||||
ymax = 40; | |||||
for(y = 0; y < img->height - 40; y++) | |||||
{ | |||||
x = offset - 3; | |||||
if(cur == 0) | |||||
x -= 10; | |||||
if(x < 0) | |||||
x = 0; | |||||
for(; x < offset + 3; x++) | |||||
{ | |||||
int z, t, dist; | |||||
dist = 0; | |||||
for(t = 0; t < ymax - ymin; t++) | |||||
for(z = 0; z < xmax - xmin; z++) | |||||
{ | |||||
int r2; | |||||
getgray(font, xmin + z, ymin + t, &r); | |||||
getgray(tmp2, x + z, y + t, &r2); | |||||
dist += (r - r2) * (r - r2); | |||||
} | |||||
if(dist < localmin) | |||||
{ | |||||
localmin = dist; | |||||
localx = x; | |||||
localy = y; | |||||
} | |||||
} | |||||
} | |||||
if(localmin < distmin) | |||||
{ | |||||
distmin = localmin; | |||||
distx = localx; | |||||
disty = localy; | |||||
distch = i; | |||||
} | |||||
} | |||||
/* Print min glyph (debug) */ | |||||
xmin = distch * 40; | |||||
ymin = 0; | |||||
xmax = distch * 40 + 40; | |||||
ymax = 40; | |||||
for(y = 0; y < ymax - ymin; y++) | |||||
for(x = 0; x < xmax - xmin; x++) | |||||
{ | |||||
int r2; | |||||
getpixel(font, xmin + x, ymin + y, &r2, &g, &b); | |||||
if(r2 > 128) continue; | |||||
getpixel(tmp3, distx + x, disty + y, &r, &g, &b); | |||||
setpixel(tmp3, distx + x, disty + y, r2, g, b); | |||||
} | |||||
offset = distx + xmax - xmin; | |||||
result[cur] = all[distch]; | |||||
} | |||||
image_free(tmp1); | |||||
image_free(tmp2); | |||||
image_free(tmp3); | |||||
image_free(font); | |||||
return result; | |||||
} | |||||
@@ -30,30 +30,48 @@ static struct image *find_glyphs(struct image *img); | |||||
/* Global stuff */ | /* Global stuff */ | ||||
struct { int xmin, ymin, xmax, ymax; } objlist[100]; | struct { int xmin, ymin, xmax, ymax; } objlist[100]; | ||||
int objects = 0, first = -1, last = -1; | |||||
int objects, first, last; | |||||
char *result; | char *result; | ||||
/* Main function */ | /* Main function */ | ||||
char * decode_slashdot(struct image *img) | char * decode_slashdot(struct image *img) | ||||
{ | { | ||||
struct image *tmp, *tmp2; | |||||
struct image *tmp1, *tmp2, *tmp3, *tmp4, *tmp5, *tmp6, *tmp7; | |||||
/* Initialise local data */ | |||||
objects = 0; | |||||
first = -1; | |||||
last = -1; | |||||
/* Slashdot captchas have 7 characters */ | /* Slashdot captchas have 7 characters */ | ||||
result = malloc(8 * sizeof(char)); | result = malloc(8 * sizeof(char)); | ||||
/* Clean image a bit */ | /* Clean image a bit */ | ||||
tmp = filter_detect_lines(img); | |||||
tmp = filter_fill_holes(tmp); | |||||
tmp1 = filter_detect_lines(img); | |||||
tmp2 = filter_fill_holes(tmp1); | |||||
/* Detect small objects to guess image orientation */ | /* Detect small objects to guess image orientation */ | ||||
tmp2 = filter_median(tmp); | |||||
tmp2 = filter_equalize(tmp2); | |||||
count_objects(tmp2); | |||||
tmp3 = filter_median(tmp2); | |||||
tmp4 = filter_equalize(tmp3, 200); | |||||
count_objects(tmp4); | |||||
/* Invert rotation and find glyphs */ | /* Invert rotation and find glyphs */ | ||||
tmp = rotate(tmp); | |||||
tmp = filter_median(tmp); | |||||
tmp = find_glyphs(tmp); | |||||
tmp5 = rotate(tmp2); | |||||
tmp6 = filter_median(tmp5); | |||||
tmp7 = find_glyphs(tmp6); | |||||
/* Clean up our mess */ | |||||
image_free(tmp1); | |||||
image_free(tmp2); | |||||
image_free(tmp3); | |||||
image_free(tmp4); | |||||
image_free(tmp5); | |||||
image_free(tmp6); | |||||
image_free(tmp7); | |||||
/* aaaaaaa means decoding failed */ | |||||
if(!strcmp(result, "aaaaaaa")) | |||||
result[0] = '\0'; | |||||
return result; | return result; | ||||
} | } | ||||
@@ -0,0 +1,155 @@ | |||||
/* | |||||
* test.c: test captchas | |||||
* $Id$ | |||||
* | |||||
* Copyright: (c) 2004 Sam Hocevar <sam@zoy.org> | |||||
* 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 <stdio.h> | |||||
#include <stdlib.h> | |||||
#include <string.h> | |||||
#include <math.h> | |||||
#include "config.h" | |||||
#include "common.h" | |||||
/* Our macros */ | |||||
#define FONTNAME "share/font_phpbb.png" | |||||
static struct image *find_glyphs(struct image *img); | |||||
/* Global stuff */ | |||||
struct { int xmin, ymin, xmax, ymax; } objlist[100]; | |||||
int objects, first, last; | |||||
char *result; | |||||
/* Main function */ | |||||
char * decode_test(struct image *img) | |||||
{ | |||||
struct image *tmp1, *tmp2, *tmp3, *tmp4, *tmp5, *tmp6, *tmp7; | |||||
/* Initialise local data */ | |||||
objects = 0; | |||||
first = -1; | |||||
last = -1; | |||||
/* phpBB captchas have 6 characters */ | |||||
result = malloc(7 * sizeof(char)); | |||||
tmp1 = filter_smooth(img); | |||||
tmp2 = filter_median(tmp1); | |||||
tmp3 = filter_equalize(tmp2, 130); | |||||
tmp4 = filter_median(tmp3); | |||||
tmp5 = find_glyphs(tmp3); | |||||
image_free(tmp1); | |||||
image_free(tmp2); | |||||
image_free(tmp3); | |||||
image_free(tmp4); | |||||
image_free(tmp5); | |||||
return result; | |||||
} | |||||
/* The following functions are local */ | |||||
static struct image *find_glyphs(struct image *img) | |||||
{ | |||||
char all[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789"; | |||||
struct image *dst; | |||||
struct image *font = image_load(FONTNAME); | |||||
int x, y, i = 0; | |||||
int r, g, b; | |||||
int xmin, xmax, ymin, ymax, incell = 0, count = 0, cur = 0, offset = -1; | |||||
int distmin, distx, disty, distch; | |||||
if(!font) | |||||
{ | |||||
fprintf(stderr, "cannot load font %s\n", FONTNAME); | |||||
exit(-1); | |||||
} | |||||
dst = image_new(img->width, img->height); | |||||
for(x = 0; x < img->width; x++) | |||||
for(y = 0; y < img->height; y++) | |||||
{ | |||||
getpixel(img, x, y, &r, &g, &b); | |||||
setpixel(dst, x, y, 255, g, 255); | |||||
if(r == 0 && offset == -1) | |||||
offset = x; | |||||
} | |||||
strcpy(result, " "); | |||||
while(cur < 6) | |||||
{ | |||||
/* Try to find 1st letter */ | |||||
distmin = 999999999; | |||||
for(i = 0; i < 35; i++) | |||||
{ | |||||
int localmin = 99999999, localx, localy; | |||||
xmin = i * 40; | |||||
ymin = 0; | |||||
xmax = i * 40 + 40; | |||||
ymax = 40; | |||||
for(y = 0; y < img->height - 40; y++) | |||||
{ | |||||
x = offset - 5; | |||||
if(cur == 0) | |||||
x -= 15; | |||||
if(x < 0) | |||||
x = 0; | |||||
for(; x < offset + 10; x++) | |||||
{ | |||||
int z, t, dist; | |||||
dist = 0; | |||||
for(t = 0; t < ymax - ymin; t++) | |||||
for(z = 0; z < xmax - xmin; z++) | |||||
{ | |||||
int r2; | |||||
getgray(font, xmin + z, ymin + t, &r); | |||||
getgray(img, x + z, y + t, &r2); | |||||
dist += abs(r - r2); | |||||
} | |||||
if(dist < localmin) | |||||
{ | |||||
localmin = dist; | |||||
localx = x; | |||||
localy = y; | |||||
} | |||||
} | |||||
} | |||||
if(localmin < distmin) | |||||
{ | |||||
distmin = localmin; | |||||
distx = localx; | |||||
disty = localy; | |||||
distch = i; | |||||
} | |||||
} | |||||
/* Print min glyph (debug) */ | |||||
xmin = distch * 40; | |||||
ymin = 0; | |||||
xmax = distch * 40 + 40; | |||||
ymax = 40; | |||||
for(y = 0; y < ymax - ymin; y++) | |||||
for(x = 0; x < xmax - xmin; x++) | |||||
{ | |||||
getpixel(font, xmin + x, ymin + y, &r, &g, &b); | |||||
if(r > 128) continue; | |||||
setpixel(dst, distx + x, disty + y, r, g, b); | |||||
} | |||||
offset = distx + xmax - xmin; | |||||
result[cur++] = all[distch]; | |||||
} | |||||
return dst; | |||||
} | |||||