* 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_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? | |||
| ac_cv_my_have_imlib2="no" | |||
| save_CPPFLAGS="${CPPFLAGS}" | |||
| @@ -31,19 +44,6 @@ AC_CHECK_HEADERS(Imlib2.h, | |||
| 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 | |||
| @@ -3,16 +3,16 @@ NULL = | |||
| bin_PROGRAMS = pwntcha | |||
| pwntcha_CFLAGS = $(ADDITIONAL_CFLAGS) -Wall -O6 | |||
| 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 | |||
| ADDITIONAL_CFLAGS = `opencv-config --cflags` | |||
| ADDITIONAL_LDFLAGS = `opencv-config --libs opencv highgui` | |||
| else | |||
| if USE_IMLIB2 | |||
| ADDITIONAL_CFLAGS = `imlib2-config --cflags` -DX_DISPLAY_MISSING=1 | |||
| ADDITIONAL_LDFLAGS = `imlib2-config --libs` | |||
| else | |||
| ADDITIONAL_CFLAGS = | |||
| ADDITIONAL_LDFLAGS = | |||
| endif | |||
| @@ -18,11 +18,15 @@ struct image | |||
| }; | |||
| /* 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 */ | |||
| 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 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); | |||
| @@ -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); | |||
| struct image *filter_fill_holes(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_smooth(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; | |||
| } | |||
| struct image *filter_equalize(struct image *img) | |||
| struct image *filter_equalize(struct image *img, int threshold) | |||
| { | |||
| struct image *dst; | |||
| int x, y; | |||
| @@ -154,7 +154,7 @@ struct image *filter_equalize(struct image *img) | |||
| for(x = 0; x < img->width; x++) | |||
| { | |||
| 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); | |||
| } | |||
| @@ -240,7 +240,7 @@ struct image *filter_smooth(struct image *img) | |||
| struct image *filter_median(struct image *img) | |||
| { | |||
| #define MSIZE 4 | |||
| #define MSIZE 3 | |||
| struct image *dst; | |||
| int x, y, i, j, val[MSIZE*MSIZE]; | |||
| int r, g, b; | |||
| @@ -278,3 +278,36 @@ struct image *filter_median(struct image *img) | |||
| 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 "common.h" | |||
| #if defined(HAVE_IMLIB2_H) | |||
| # include <Imlib2.h> | |||
| #elif defined(HAVE_CV_H) | |||
| #if defined(HAVE_CV_H) | |||
| # include <cv.h> | |||
| # include <highgui.h> | |||
| #elif defined(HAVE_IMLIB2_H) | |||
| # include <Imlib2.h> | |||
| #else | |||
| # error "No imaging library" | |||
| #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); | |||
| #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) | |||
| #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); | |||
| 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 * 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); | |||
| #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) | |||
| #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); | |||
| 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; | |||
| } | |||
| 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) | |||
| { | |||
| 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) | |||
| { | |||
| #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]; | |||
| //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) | |||
| 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 | |||
| } | |||
| @@ -11,6 +11,7 @@ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <getopt.h> | |||
| #include "config.h" | |||
| @@ -87,7 +88,29 @@ int main(int argc, char *argv[]) | |||
| 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) | |||
| { | |||
| 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 */ | |||
| struct { int xmin, ymin, xmax, ymax; } objlist[100]; | |||
| int objects = 0, first = -1, last = -1; | |||
| int objects, first, last; | |||
| char *result; | |||
| /* Main function */ | |||
| 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 */ | |||
| result = malloc(8 * sizeof(char)); | |||
| /* 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 */ | |||
| 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 */ | |||
| 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; | |||
| } | |||
| @@ -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; | |||
| } | |||