rendered paste body/*
RS.com CA(P)TCHA Pre-Processor
21.04.2008 von Kugelfisch
BSD-artige Lizenz
Alternative Heuristik, um die Vorzeichen der Transformation zu erkennen.
EXPERIMENTELLER CODE!
Optionales Glätten des Outputs.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <jpeglib.h>
#include <math.h>
#define CATCHA_W 456
#define CATCHA_H 71
typedef struct {
int w,h;
unsigned char image[CATCHA_W][CATCHA_H];
} catcha;
typedef struct {
int x,y,w,h;
} rect;
void load_catcha(catcha* cat, char* filename) {
JSAMPARRAY buffer;
struct jpeg_error_mgr jerr;
struct jpeg_decompress_struct cinfo;
int x,y;
FILE* f = fopen(filename,"rb");
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, f);
jpeg_read_header(&cinfo, TRUE);
jpeg_start_decompress(&cinfo);
if(cinfo.output_width != CATCHA_W || cinfo.output_height != CATCHA_H) {
fprintf(stderr,"Invalid CAPTCHA size!");
exit(-1);
}
if(cinfo.output_components != 1) {
fprintf(stderr,"Invalid CAPTCHA! Too colorful.");
exit(-1);
}
buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, cinfo.output_width * cinfo.output_components, 1);
while ((y = cinfo.output_scanline) < cinfo.output_height) {
jpeg_read_scanlines(&cinfo, buffer, 1);
for(x=0; x<cinfo.output_width; x++)
cat->image[x][y] = buffer[0][x];
}
cat->w = CATCHA_W;
cat->h = CATCHA_H;
jpeg_finish_decompress(&cinfo);
fclose(f);
jpeg_destroy_decompress(&cinfo);
}
void save_catcha(catcha* cat, char* filename) {
JSAMPARRAY buffer;
struct jpeg_error_mgr jerr;
struct jpeg_compress_struct cinfo;
int x,y;
FILE* f = fopen(filename,"wb");
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
cinfo.image_width = cat->w;
cinfo.image_height = cat->h;
cinfo.input_components = 1;
cinfo.in_color_space = JCS_GRAYSCALE;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo,100,TRUE);
jpeg_stdio_dest(&cinfo, f);
jpeg_start_compress(&cinfo, FALSE);
buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, cat->w, 1);
for(y=0; y<cat->h; y++) {
for(x=0; x<cat->w; x++)
if(cat->image[x][y] < 200)
buffer[0][x] = cat->image[x][y];
else
buffer[0][x] = 0xFF;
jpeg_write_scanlines(&cinfo, buffer, 1);
}
jpeg_finish_compress(&cinfo);
fclose(f);
jpeg_destroy_compress(&cinfo);
}
#define WHITE_THRESHOLD (100)
rect image_get_clip_rect(unsigned char image[CATCHA_W][CATCHA_H]) {
rect r;
int x,y,top = -1,left = -1,right = -1,bottom = -1;
for(y=0; y<CATCHA_H && top < 0; y++)
for(x=0; x<CATCHA_W && top < 0; x++)
if(image[x][y] < WHITE_THRESHOLD)
top = y;
for(x=0; x<CATCHA_W && left < 0; x++)
for(y=0; y<CATCHA_H && left < 0; y++)
if(image[x][y] < WHITE_THRESHOLD)
left = x;
for(x=CATCHA_W-1; x>left && right < 0; x--)
for(y=0; y<CATCHA_H && right < 0; y++)
if(image[x][y] < WHITE_THRESHOLD)
right = x;
for(y=CATCHA_H-1; y>top && bottom < 0; y--)
for(x=0; x<CATCHA_W && bottom < 0; x++)
if(image[x][y] < WHITE_THRESHOLD)
bottom = y;
r.x = left;
r.y = top;
r.w = right-left;
r.h = bottom-top;
return r;
}
void image_enhance(unsigned char image[CATCHA_W][CATCHA_H]) {
int x,y;
double pixval;
unsigned char p;
unsigned char t_image[CATCHA_W][CATCHA_H];
for(y=0; y<CATCHA_H; y++)
for(x=0; x<CATCHA_W; x++) {
p = image[x][y];
if(p > 170)
t_image[x][y] = 0xFF;
else if(p < 75)
t_image[x][y] = 0x00;
else
t_image[x][y] = p;
}
for(y=1; y<CATCHA_H-1; y++)
for(x=1; x<CATCHA_W-1; x++) {
pixval = (t_image[x][y]*1.0+
t_image[x-1][y]*0.5+t_image[x+1][y]*0.5+
t_image[x][y-1]*0.5+t_image[x][y+1]*0.5)/3.0;
pixval /= 255.0;
pixval = pow(pixval,1.66);
pixval *= 255.0;
if(pixval < 0.0)
pixval = 0.0;
if(pixval > 255.0)
pixval = 255.0;
image[x][y] = 0xFF & ((int)round(pixval));
}
}
#define SINE_MAX_X (-3)
#define SINE_OMEGA_X (0.1386)
#define SINE_PHI_X (0)
#define SINE_MAX_Y (-3)
#define SINE_OMEGA_Y (0.1248)
#define SINE_PHI_Y (0)
void catcha_reverse_sine_transform(catcha* cat, int all_export, int do_enhance) {
int x,y,shift,run,best_run_A,best_run,A;
unsigned char img[4][CATCHA_W][CATCHA_H];
rect r;
char name[16];
best_run_A = CATCHA_W*CATCHA_H;
best_run = -1;
for(run=0; run<4; run++) {
memcpy(img[run],cat->image,CATCHA_W*CATCHA_H);
// transform in x-direction
for(y=0; y<CATCHA_H; y++) {
shift = (run>1?1:-1)*(int)round(SINE_MAX_X*sin(SINE_OMEGA_X*y+SINE_PHI_X));
if(shift > 0) {
for(x=0; x<CATCHA_W; x++)
img[run][x][y] = (x+shift<CATCHA_W)?img[run][x+shift][y]:0xFF;
} else {
for(x=CATCHA_W-1; x>=0; x--)
img[run][x][y] = (x+shift>=0)?img[run][x+shift][y]:0xFF;
}
}
// transform in y-direction
for(x=0; x<CATCHA_W; x++) {
shift = ((run%2)>0?1:-1)*(int)round(SINE_MAX_Y*sin(SINE_OMEGA_Y*x+SINE_PHI_Y));
if(shift > 0) {
for(y=0; y<CATCHA_H; y++)
img[run][x][y] = (y+shift<CATCHA_H)?img[run][x][y+shift]:0xFF;
} else {
for(y=CATCHA_H-1; y>=0; y--)
img[run][x][y] = (y+shift>=0)?img[run][x][y+shift]:0xFF;
}
}
r = image_get_clip_rect(img[run]);
A = r.h+r.w;
if(A < best_run_A) {
best_run_A = A;
best_run = run;
}
printf("rect on (%d %d) transform: x:%d y:%d w:%d h:%d; A=%d\n",(run>1?1:-1),((run%2)>0?1:-1),r.x,r.y,r.w,r.h,A);
}
if(all_export) {
for(run = 0; run<4; run++) {
if(run == best_run)
continue;
memcpy(cat->image,img[run],CATCHA_W*CATCHA_H);
snprintf(name,15,"transform%d.jpg",run);
if(do_enhance)
image_enhance(cat->image);
save_catcha(cat,name);
}
}
if(best_run != -1)
memcpy(cat->image,img[best_run],CATCHA_W*CATCHA_H);
if(do_enhance)
image_enhance(cat->image);
}
int main(int argc, char** argv) {
catcha cat;
int all_export = 0;
int do_enhance = 0;
char* arg;
if(argc < 3)
return -1;
while(argc > 3) {
arg = argv[--argc];
if(strcmp(arg,"all") == 0)
all_export = 1;
if(strcmp(arg,"enhance") == 0)
do_enhance = 1;
}
printf("enhance %d - export %d\n",do_enhance,all_export);
load_catcha(&cat,argv[1]);
catcha_reverse_sine_transform(&cat,all_export,do_enhance);
save_catcha(&cat,argv[2]);
return 0;
}