diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..f5bde17 --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Sam Hocevar diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..670a8d2 --- /dev/null +++ b/COPYING @@ -0,0 +1,12 @@ +do What The Fuck you want to Public License + +Version 1.0, March 2000 +Copyright (C) 2000 Banlu Kemiyatorn (]d). +136 Nives 7 Jangwattana 14 Laksi Bangkok +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + +Ok, the purpose of this license is simple +and you just + +DO WHAT THE FUCK YOU WANT TO. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/ChangeLog @@ -0,0 +1 @@ + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..12804f6 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,12 @@ +NULL = + +SUBDIRS = src +DIST_SUBDIRS = $(SUBDIRS) + +EXTRA_DIST = \ + bootstrap \ + ChangeLog \ + $(NULL) + +AUTOMAKE_OPTIONS = dist-bzip2 + diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/NEWS @@ -0,0 +1 @@ + diff --git a/README b/README new file mode 100644 index 0000000..6bd6ead --- /dev/null +++ b/README @@ -0,0 +1,4 @@ +PWNTCHA - Pretend We're Not a Turing Computer but a Human Antagonist + +This research software studies captchas. + diff --git a/bootstrap b/bootstrap new file mode 100755 index 0000000..63e324f --- /dev/null +++ b/bootstrap @@ -0,0 +1,51 @@ +#! /bin/sh + +## bootstrap file for Elk -- Sam Hocevar +## $Id: bootstrap 253 2004-08-09 20:08:52Z sam $ + +set -x +set -e + +# Get a sane environment, just in case +LANG=C +export LANG +CYGWIN=binmode +export CYGWIN + +# Check for automake +amvers="no" +if automake-1.9 --version >/dev/null 2>&1; then + amvers="-1.9" +elif automake-1.8 --version >/dev/null 2>&1; then + amvers="-1.8" +elif automake-1.7 --version >/dev/null 2>&1; then + amvers="-1.7" +elif automake-1.6 --version >/dev/null 2>&1; then + amvers="-1.6" +elif automake-1.5 --version >/dev/null 2>&1; then + amvers="-1.5" +elif automake --version > /dev/null 2>&1; then + amvers="`automake --version | sed -e '1s/[^0-9]*//' -e q`" + if expr "$amvers" "<" "1.5" > /dev/null 2>&1; then + amvers="no" + else + amvers="" + fi +fi + +if test "$amvers" = "no"; then + set +x + echo "$0: you need automake version 1.5 or later" + exit 1 +fi + +# Remove old cruft +rm -f aclocal.m4 configure config.guess config.log config.sub config.cache config.h.in config.h compile ltmain.sh libtool ltconfig missing mkinstalldirs depcomp install-sh INSTALL +rm -Rf autom4te.cache autotools +mkdir autotools + +aclocal${amvers} +autoconf +autoheader +automake${amvers} --add-missing --copy + diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..3b52bf4 --- /dev/null +++ b/configure.ac @@ -0,0 +1,55 @@ +# $Id: configure.ac 253 2004-08-09 20:08:52Z sam $ + +AC_INIT(src/main.c) + +AC_PREREQ(2.50) +AC_CONFIG_AUX_DIR(autotools) +AC_CANONICAL_SYSTEM + +AM_INIT_AUTOMAKE(pwntcha, 0.0) +AM_CONFIG_HEADER(config.h) + +AC_PROG_CC +AM_PROG_CC_C_O +AC_PROG_CXX +AC_STDC_HEADERS + +AC_C_CONST +AC_C_INLINE +AC_TYPE_SIZE_T + +# Use Imlib2? +ac_cv_my_have_imlib2="no" +save_CPPFLAGS="${CPPFLAGS}" +AC_PATH_PROG(IMLIB2_CONFIG, imlib2-config, no) +if test "${IMLIB2_CONFIG}" != "no"; then + CPPFLAGS="${CPPFLAGS} `imlib2-config --cflags` -DX_DISPLAY_MISSING=1" +fi +AC_CHECK_HEADERS(Imlib2.h, + [ac_cv_my_have_imlib2="yes"], + [ac_cv_my_have_imlib2="no"]) +CPPFLAGS="${save_CPPFLAGS}" +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 + AC_MSG_ERROR([[cannot find Imlib2 or OpenCV, please install one of them]]) +fi + +AC_OUTPUT([ + Makefile + src/Makefile +]) + diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..b931ead --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,20 @@ +NULL = + +bin_PROGRAMS = pwntcha +pwntcha_CFLAGS = $(ADDITIONAL_CFLAGS) -Wall +pwntcha_LDFLAGS = $(ADDITIONAL_LDFLAGS) +pwntcha_SOURCES = main.c image.c slashdot.c + +if USE_IMLIB2 +ADDITIONAL_CFLAGS = `imlib2-config --cflags` -DX_DISPLAY_MISSING=1 +ADDITIONAL_LDFLAGS = `imlib2-config --libs` +else +if USE_OPENCV +ADDITIONAL_CFLAGS = `opencv-config --cflags` +ADDITIONAL_LDFLAGS = `opencv-config --libs opencv highgui` +else +ADDITIONAL_CFLAGS = +ADDITIONAL_LDFLAGS = +endif +endif + diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..c00d016 --- /dev/null +++ b/src/common.h @@ -0,0 +1,19 @@ + +/* image structure */ +struct image +{ + int width, height, pitch, channels; + unsigned char *pixels; + void *priv; +}; + +/* available CAPTCHA decoders */ +char * slashdot_decode(char *image); + +/* image operations */ +struct image * load_image(char *name); +struct image * new_image(int width, int height); +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 setpixel(struct image *img, int x, int y, int r, int g, int b); + diff --git a/src/image.c b/src/image.c new file mode 100644 index 0000000..98419fc --- /dev/null +++ b/src/image.c @@ -0,0 +1,140 @@ + +#include +#include +#include + +#include "config.h" +#include "common.h" + +#if defined(HAVE_IMLIB2_H) +# include +#elif defined(HAVE_CV_H) +# include +# include +#else +# error "No imaging library" +#endif + +struct image * load_image(char *name) +{ + struct image * img; +#if defined(HAVE_IMLIB2_H) + Imlib_Image priv = imlib_load_image(name); +#elif defined(HAVE_CV_H) + IplImage * priv = cvLoadImage(name, -1); +#endif + + if(!priv) + return NULL; + + img = malloc(sizeof(struct image)); +#if defined(HAVE_IMLIB2_H) + imlib_context_set_image(priv); + img->width = imlib_image_get_width(); + img->height = imlib_image_get_height(); + img->pitch = 4 * imlib_image_get_width(); + img->channels = 4; + 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 + img->priv = (void *)priv; + + return img; +} + +struct image * new_image(int width, int height) +{ + struct image * img; +#if defined(HAVE_IMLIB2_H) + Imlib_Image priv = imlib_create_image(width, height); +#elif defined(HAVE_CV_H) + IplImage * priv = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3); +#endif + + if(!priv) + return NULL; + + img = malloc(sizeof(struct image)); +#if defined(HAVE_IMLIB2_H) + imlib_context_set_image(priv); + img->width = imlib_image_get_width(); + img->height = imlib_image_get_height(); + img->pitch = 4 * imlib_image_get_width(); + img->channels = 4; + 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 + img->priv = (void *)priv; + + return img; +} + +int getgray(struct image *img, int x, int y, int *g) +{ + if(x < 0 || y < 0 || x >= img->width || y >= img->height) + { + *g = 255; + return -1; + } + + *g = (unsigned char)img->pixels[y * img->pitch + x * img->channels + 1]; + + return 0; +} + +int getpixel(struct image *img, int x, int y, int *r, int *g, int *b) +{ + if(x < 0 || y < 0 || x >= img->width || y >= img->height) + { + *r = 255; + *g = 255; + *b = 255; + return -1; + } + + *b = (unsigned char)img->pixels[y * img->pitch + x * img->channels]; + *g = (unsigned char)img->pixels[y * img->pitch + x * img->channels + 1]; + *r = (unsigned char)img->pixels[y * img->pitch + x * img->channels + 2]; + + return 0; +} + +int setpixel(struct image *img, int x, int y, int r, int g, int b) +{ + if(x < 0 || y < 0 || x >= img->width || y >= img->height) + return -1; + + img->pixels[y * img->pitch + x * img->channels] = b; + img->pixels[y * img->pitch + x * img->channels + 1] = g; + img->pixels[y * img->pitch + x * img->channels + 2] = r; + + return 0; +} + +void display_image(struct image *img) +{ + char name[BUFSIZ]; +#if defined(HAVE_IMLIB2_H) + //static int i = 0; + //sprintf(name, "image%i-%ix%i.png", i++, img->width, img->height); + //imlib_context_set_image(img->priv); + //imlib_save_image(name); + //fprintf(stderr, "saved to %s\n", name); +#elif defined(HAVE_CV_H) + sprintf(name, "Image %p (%i x %i)", img, img->width, img->height); + cvNamedWindow(name, 0); + cvShowImage(name, img->priv); + cvResizeWindow(name, 320, 120); +#endif +} + diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..faaa239 --- /dev/null +++ b/src/main.c @@ -0,0 +1,27 @@ + +#include +#include +#include + +#include "config.h" +#include "common.h" + +int main(int argc, char *argv[]) +{ + char *result; + + if(argc != 2) + { + fprintf(stderr, "usage: %s \n", argv[0]); + return -1; + } + + result = slashdot_decode(argv[1]); + if(!result) + return -1; + + printf("%s\n", result); + + return 0; +} + diff --git a/src/slashdot.c b/src/slashdot.c new file mode 100644 index 0000000..7eaccfa --- /dev/null +++ b/src/slashdot.c @@ -0,0 +1,646 @@ + +#include +#include +#include + +#include "config.h" +#include "common.h" + +/* Our macros */ +#define FACTOR 1 +//#define FONTNAME "font.png" // use with FACTOR = 2 +//#define FONTNAME "font_dilated.png" // use with FACTOR = 2 +#define FONTNAME "font_dilated_half.png" // use with FACTOR = 1 + +/* Global stuff */ +char *result; + +struct +{ + int xmin, ymin, xmax, ymax; +} +objlist[100]; +int objects = 0, first = -1, last = -1; + +/* Functions */ + +void flood_fill(struct image *img, int x, int y, int r, int g, int b) +{ + int oldr, oldg, oldb; + int nextr, nextg, nextb; + + if(x < 0 || y < 0 || x >= img->width || y >= img->height) + return; + + getpixel(img, x, y, &oldr, &oldg, &oldb); + setpixel(img, x, y, r, g, b); + + getpixel(img, x + 1, y, &nextr, &nextg, &nextb); + if(nextr == oldr && nextg == oldg && nextb == oldb) + flood_fill(img, x + 1, y, r, g, b); + + getpixel(img, x - 1, y, &nextr, &nextg, &nextb); + if(nextr == oldr && nextg == oldg && nextb == oldb) + flood_fill(img, x - 1, y, r, g, b); + + getpixel(img, x, y + 1, &nextr, &nextg, &nextb); + if(nextr == oldr && nextg == oldg && nextb == oldb) + flood_fill(img, x, y + 1, r, g, b); + + getpixel(img, x, y - 1, &nextr, &nextg, &nextb); + if(nextr == oldr && nextg == oldg && nextb == oldb) + flood_fill(img, x, y - 1, r, g, b); +} + +struct image *count_objects(struct image *img) +{ + struct image *dst; + int gotblack = 1; + int x, y, i; + int r, g, b; + + dst = new_image(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); + setpixel(dst, x, y, r, g, b); + } + + while(gotblack) + { + gotblack = 0; + for(y = 0; y < dst->height; y++) + for(x = 0; x < dst->width; x++) + { + getpixel(dst, x, y, &r, &g, &b); + if(r == 50 && g == 50 && b == 50) + { + gotblack = 1; + flood_fill(dst, x, y, 255 - objects, 0, 0); + objects++; + } + } + } + + //printf("%i objects\n", objects); + + for(i = 0; i < objects; i++) + { + objlist[i].ymin = dst->height; + objlist[i].ymax = 0; + + for(y = 0; y < dst->height; y++) + for(x = 0; x < dst->width; x++) + { + getpixel(dst, x, y, &r, &g, &b); + if(r == 255 - i && g == 0 && b == 0) + { + if(y < objlist[i].ymin) { objlist[i].ymin = y; objlist[i].xmin = x; } + if(y > objlist[i].ymax) { objlist[i].ymax = y; objlist[i].xmax = x; } + } + } + //printf("y min-max: %i %i (size %i)\n", objlist[i].ymin, objlist[i].ymax, objlist[i].ymax - objlist[i].ymin + 1); + if(objlist[i].ymax - objlist[i].ymin > 18 && objlist[i].ymax - objlist[i].ymin < 27) + { + if(first == -1) + first = i; + last = i; + flood_fill(dst, objlist[i].xmin, objlist[i].ymin, 0, 0, 255); + } + } + +#if 0 + { CvPoint A, B; + A.x = (objlist[first].xmin + objlist[first].xmax) / 2; + A.y = (objlist[first].ymin + objlist[first].ymax) / 2; + B.x = (objlist[last].xmin + objlist[last].xmax) / 2; + B.y = (objlist[last].ymin + objlist[last].ymax) / 2; + cvLine(dst, A, B, 0, 2.0, 0); + } +#endif + + return dst; +} + +struct image *rotate(struct image *img) +{ + struct image *dst; + int x, y, xdest, ydest; + int r, g, b, R, G, B; + int X = objlist[first].xmin - objlist[last].xmin; + int Y = objlist[first].ymin - objlist[last].ymin; + float xtmp, ytmp; + float sina = (1.0 * Y) / sqrt(1.0 * X * X + Y * Y); + float cosa = (1.0 * X) / sqrt(1.0 * X * X + Y * Y); + if(sina * cosa > 0) + { + sina = -sina; + cosa = -cosa; + } + + dst = new_image(img->width * FACTOR, img->height * FACTOR); + + for(y = 0; y < img->height * FACTOR; y++) + for(x = 0; x < img->width * FACTOR; x++) + { + xtmp = 1.0 * (x - img->width * FACTOR / 2) / FACTOR; + ytmp = 1.0 * (y - img->height * FACTOR / 2) / FACTOR; + xdest = xtmp * cosa - ytmp * sina + 0.5 * img->width; + ydest = ytmp * cosa + xtmp * sina + 0.5 * img->height; + //R = G = B = 0; + getpixel(img, xdest, ydest, &r, &g, &b); + //R += r; G += g; B += b; + //getpixel(img, xdest+1, ydest, &r, &g, &b); + //R += r; G += g; B += b; + //getpixel(img, xdest, ydest+1, &r, &g, &b); + //R += r; G += g; B += b; + //getpixel(img, xdest+1, ydest+1, &r, &g, &b); + //R += r; G += g; B += b; + //r = R / 4; g = G / 4; b = B / 4; + if(r == 255 && g == 0 && b == 255) + g = 255; + setpixel(dst, x, y, r, g, b); + } + + return dst; +} + +struct image *fill_holes(struct image *img) +{ + struct image *dst; + int x, y; + int r, g, b; + + dst = new_image(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); + setpixel(dst, x, y, r, g, b); + } + + for(y = 0; y < dst->height; y++) + for(x = 2; x < dst->width - 2; x++) + { + int c1, c2, c3, c4, c5; + getpixel(img, x-2, y, &c1, &g, &b); + getpixel(img, x-1, y, &c2, &g, &b); + getpixel(img, x, y, &c3, &g, &b); + getpixel(img, x+1, y, &c4, &g, &b); + getpixel(img, x+2, y, &c5, &g, &b); + if(c1 < 127 && c2 < 127 && c3 > 128 && c4 < 127) + c3 = (c1 + c2 + c4) / 3; + else if(c2 < 127 && c3 > 128 && c4 < 127 && c5 < 127) + c3 = (c2 + c4 + c5) / 3; + setpixel(dst, x, y, c3, c3, c3); + } + + for(x = 0; x < dst->width; x++) + for(y = 2; y < dst->height - 2; y++) + { + int c1, c2, c3, c4, c5; + getpixel(img, x, y-2, &c1, &g, &b); + getpixel(img, x, y-1, &c2, &g, &b); + getpixel(img, x, y, &c3, &g, &b); + getpixel(img, x, y+1, &c4, &g, &b); + getpixel(img, x, y+2, &c5, &g, &b); + if(c1 < 127 && c2 < 127 && c3 > 128 && c4 < 127) + c3 = (c1 + c2 + c4) / 3; + else if(c2 < 127 && c3 > 128 && c4 < 127 && c5 < 127) + c3 = (c2 + c4 + c5) / 3; + setpixel(dst, x, y, c3, c3, c3); + } + + return dst; +} + +struct image *cut_cells(struct image *img) +{ + struct image *dst; + int x, y; + int r, g, b; + + dst = new_image(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); + setpixel(dst, x, y, r, g, b); + } + + for(x = 0; x < img->width; x++) + { + setpixel(dst, x, 0, 255, 255, 255); + setpixel(dst, x, img->height - 1, 255, 255, 255); + } + + for(y = 0; y < img->height; y++) + for(x = 0; x < 7; x++) + { + setpixel(dst, x * img->width / 7, y, 255, 255, 255); + setpixel(dst, (x + 1) * img->width / 7 - 1, y, 255, 255, 255); + } + + return dst; +} + +struct image *detect_lines(struct image *img) +{ + struct image *dst; + int x, y; + int r, ra, rb, g, b; + + dst = new_image(img->width, img->height); + + /* Remove white lines */ + for(y = 0; y < img->height; y++) + for(x = 0; x < img->width; x++) + { + getpixel(img, x, y, &r, &g, &b); + setpixel(dst, x, y, r, g, b); +#if 1 + if(y > 0 && y < img->height - 1) + { + getpixel(img, x, y - 1, &ra, &g, &b); + getpixel(img, x, y + 1, &rb, &g, &b); + if(r > ra && (r - ra) * (r - rb) > 5000) + setpixel(dst, x, y, ra, ra, ra); + } +#endif + } + + /* Remove black lines */ + for(y = 0; y < img->height; y++) + for(x = 0; x < img->width; x++) + { + getpixel(dst, x, y, &r, &g, &b); + if(y > 0 && y < img->height - 1) + { + getpixel(img, x, y - 1, &ra, &g, &b); + getpixel(img, x, y + 1, &rb, &g, &b); + if(r < ra && (r - ra) * (r - rb) > 500) + setpixel(dst, x, y, ra, ra, ra); + } + } + + return dst; +} + +struct image *equalize(struct image *img) +{ + struct image *dst; + int x, y; + int r, g, b; + + dst = new_image(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(r < 200) r = 50; else r = 200; + setpixel(dst, x, y, r, r, r); + } + + return dst; +} + +struct image *trick(struct image *img) +{ +#define TSIZE 3 + struct image *dst; + int x, y, i, j, val, m, more, l, less; + int r, g, b; + + dst = new_image(img->width, img->height); + + for(y = 0; y < img->height; y++) + for(x = 0; x < img->width; x++) + setpixel(dst, x, y, 255, 255, 255); + + for(y = TSIZE/2; y < img->height - TSIZE/2; y++) + for(x = TSIZE/2; x < img->width - TSIZE/2; x++) + { + getpixel(img, x + j - TSIZE/2, y + i - TSIZE/2, &val, &g, &b); + m = more = l = less = 0; + for(i = 0; i < TSIZE; i++) + for(j = 0; j < TSIZE; j++) + { + getpixel(img, x + j - TSIZE/2, y + i - TSIZE/2, &r, &g, &b); + if(r > val) + { + more += r; + m++; + } + else if(r < val) + { + less += r; + l++; + } + } + + if(l >= 6) + i = less / l; + else if(m >= 6) + i = more / m; + else + i = val; + setpixel(dst, x, y, i, i, i); + } + + return dst; +} + +struct image *smooth(struct image *img) +{ +#define SSIZE 3 + struct image *dst; + int x, y, i, j, val; + int r, g, b; + + dst = new_image(img->width, img->height); + + for(y = 0; y < img->height; y++) + for(x = 0; x < img->width; x++) + setpixel(dst, x, y, 255, 255, 255); +return dst; + + for(y = SSIZE/2; y < img->height - SSIZE/2; y++) + for(x = SSIZE/2; x < img->width - SSIZE/2; x++) + { + val = 0; + for(i = 0; i < SSIZE; i++) + for(j = 0; j < SSIZE; j++) + { + getpixel(img, x + j - SSIZE/2, y + i - SSIZE/2, &r, &g, &b); + val += r; + } + + i = val / (SSIZE * SSIZE); + setpixel(dst, x, y, i, i, i); + } + + return dst; +} + +struct image *median(struct image *img) +{ +#define MSIZE 4 + struct image *dst; + int x, y, i, j, val[MSIZE*MSIZE]; + int r, g, b; + + dst = new_image(img->width, img->height); + + for(y = 0; y < img->height; y++) + for(x = 0; x < img->width; x++) + setpixel(dst, x, y, 255, 255, 255); + + for(y = MSIZE/2; y < img->height - MSIZE/2; y++) + for(x = MSIZE/2; x < img->width - MSIZE/2; x++) + { + for(i = 0; i < MSIZE; i++) + for(j = 0; j < MSIZE; j++) + { + getpixel(img, x + j - SSIZE/2, y + i - SSIZE/2, &r, &g, &b); + val[i * MSIZE + j] = r; + } + + /* Bubble sort power! */ + for(i = 0; i < MSIZE * MSIZE / 2 + 1; i++) + for(j = i + 1; j < MSIZE * MSIZE; j++) + if(val[i] > val[j]) + { + register int k = val[i]; + val[i] = val[j]; + val[j] = k; + } + + i = val[MSIZE * MSIZE / 2]; + setpixel(dst, x, y, i, i, i); + } + + return dst; +} + +struct image * find_glyphs(struct image *img) +{ + char all[] = "abcdefgijkmnpqrstvwxyz"; + struct + { + int xmin, xmax, ymin, ymax; + int count; + } + glyphs[22]; + struct image *dst; + struct image *font = load_image(FONTNAME); + int x, y, i = 0; + int r, g, b, r2, g2, b2; + int xmin, xmax, ymin, ymax, incell = 0, count = 0, startx = 0, cur = 0; + int distmin, distx, disty, distch; + + if(!font) + { + fprintf(stderr, "cannot load font %s\n", FONTNAME); + exit(-1); + } + + dst = new_image(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); + setpixel(dst, x, y, 255, g, 255); + } + + strcpy(result, " "); + + for(x = 0; x < font->width; x++) + { + int found = 0; + for(y = 0; y < font->height; y++) + { + getpixel(font, x, y, &r, &g, &b); + if(r < 128) + { + found = 1; + count += (255 - r); + } + } + if(found && !incell) + { + incell = 1; + xmin = x; + } + else if(!found && incell) + { + incell = 0; + xmax = x; +#if 0 + ymin = font->height; + ymax = 0; + for(y = 0; y < font->height; y++) + { + int newx; + int gotit = 0; + for(newx = xmin; newx < xmax; newx++) + { + getpixel(font, newx, y, &r, &g, &b); + if(r < 128) + { + gotit = 1; + break; + } + } + if(gotit) + { + if(ymin > y) ymin = y; + if(ymax <= y) ymax = y + 1; + } + } +#else + ymin = 0; + ymax = font->height; +#endif + glyphs[i].xmin = xmin; + glyphs[i].xmax = xmax; + glyphs[i].ymin = ymin; + glyphs[i].ymax = ymax; + glyphs[i].count = count; + count = 0; + i++; + } + } + + if(i != 22) + { + printf("error: could not find 22 glyphs in font\n"); + exit(-1); + } + +while(cur < 7) +{ + /* Try to find 1st letter */ + distmin = 999999999; + for(i = 0; i < 22; i++) + { + int localmin = 99999999, localx, localy; +//if(all[i] == 'i') continue; + xmin = glyphs[i].xmin; + ymin = glyphs[i].ymin; + xmax = glyphs[i].xmax; + ymax = glyphs[i].ymax; + //printf("trying to find %c (%i×%i) - ", all[i], xmax - xmin, ymax - ymin); + for(y = -5 * FACTOR; y < 5 * FACTOR; y++) + for(x = startx - 5 * FACTOR; x < startx + 5 * FACTOR; x++) + { + int z, t, dist; + dist = 0; + for(t = 0; t < ymax - ymin; t++) + for(z = 0; z < xmax - xmin; z++) + { + getgray(font, xmin + z, ymin + t, &r); + getgray(img, x + z, y + t, &r2); + dist += abs(r - r2); + } +// printf("%i %i -> %i\n", x, y, dist); + //dist /= sqrt(xmax - xmin); + dist = dist * 128 / glyphs[i].count; + if(dist < localmin) + { + localmin = dist; + localx = x; + localy = y; + } + } + //fprintf(stderr, "%i (%i,%i)\n", localmin, localx - startx, localy); + if(localmin < distmin) + { + distmin = localmin; + distx = localx; + disty = localy; + distch = i; + } + } + + //fprintf(stderr, "%i (%i,%i)\n", distmin, distx - startx, disty); + //printf("min diff: %c - %i (%i, %i)\n", all[distch], distmin, distx, disty); + + /* Print min glyph */ + xmin = glyphs[distch].xmin; + ymin = glyphs[distch].ymin; + xmax = glyphs[distch].xmax; + ymax = glyphs[distch].ymax; + 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); + } + + startx = distx + xmax - xmin; + result[cur++] = all[distch]; +} + + return dst; +} + +char * slashdot_decode(char *image) +{ + struct image *img, *tmp, *tmp2, *dst; + + img = load_image(image); + if(img == NULL) + return NULL; + + result = malloc(8 * sizeof(char)); +// display(img); + +// tmp = equalize(img); +// display(tmp); +// tmp = fill_holes(tmp); +// display(tmp); + +// dst = median(tmp); +tmp = smooth(img); +tmp = fill_holes(img); +tmp = median(tmp); +//tmp = smooth(tmp); +//display(tmp); +//tmp = trick(tmp); +//display(tmp); +tmp = equalize(tmp); +//display(tmp); + +tmp = detect_lines(img); +tmp = fill_holes(tmp); +//tmp = cut_cells(tmp); +//display_image(tmp); + +tmp2 = median(tmp); +tmp2 = equalize(tmp2); +count_objects(tmp2); +//display_image(tmp2); + +//tmp = median(tmp); +tmp = rotate(tmp); +tmp = median(tmp); +//display_image(tmp); +//tmp = equalize(tmp); +//tmp = cut_cells(tmp); +// cvSaveImage(argv[2], tmp); + +tmp = find_glyphs(tmp); +//display_image(tmp); + +// cvSaveImage(argv[3], tmp); + + return result; +} +