import java.awt.Color;
//import java.awt.Graphics;
import java.awt.image.BufferedImage;
//import java.awt.image.RenderedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
//import java .util.Arrays;
//import java.util.Collections;
import javax.imageio.ImageIO;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import sun.awt.image.ImageFormatException;
public class AntiCaptcha {
static int []Position = {0,0}; // array of click coordinates
int xpos, ypos; // x and y coordinate for click
static int []captcha; // array of the captcha image
static boolean captcha_cracked;
static boolean [][]bCaptcha; // array of parsed captcha
static int [][]number; //
static int [][][][]pattern; // pattern array containing all pattern values
static String []numbers={"2.gif","4.gif","5.gif","6.gif","7.gif","8.gif","9.gif"};
static int threshold_black = 110; // pixels below this threshold of grey will be handled black
static int pattern_degree_max = 30; // max. degree for pattern rotation (-x� ... +x�)
static int pattern_degree_step = 5; // stepsize for pattern rotation
static int captcha_min_hitratio = 90; // min percentage of detected captcha pixel
static int trial;
AntiCaptcha() throws IOException {
xpos = 0;
ypos = 0;
trial = 0;
pattern = new int[7][4][1024][2];
load_pattern();
}
private void load_pattern() throws IOException {
int i;
//load and parse all pattern files
for(i=0; i<numbers.length; i++) {
pattern[i] = parse_pattern("gfx"+File.separator+"pattern_"+numbers[i]);
}
}
public static int[][][] parse_pattern(String sImg) throws IOException {
int[][][] singlePattern = new int[4][1024][2];
int x,y;
int argb=0; // alpha red green blue
int red, green, blue;
int cRed=0;
int cBlue=0;
int cBlack=0;
BufferedImage img = ImageIO.read(new File(sImg));
//scan trough the whole pattern image, first width (x) then Height (y)
for(y=0; y<img.getHeight(); y++) {
for(x=0; x<img.getWidth(); x++) {
// split into each color
argb = img.getRGB(x,y);
red = (argb >> 16) & 0xff;
green = (argb >> 8) & 0xff;
blue = (argb) & 0xff;
// green pixel is the origin
if (red<=10 && green>=245 && blue<=10) {
singlePattern[0][0][0]=x;
singlePattern[0][0][1]=y;
} else // add blue pixel to pattern[1]
if (red<=10 && green<=10 && blue>=245) {
singlePattern[1][cBlue][0]=x;
singlePattern[1][cBlue][1]=y;
cBlue++;
} else // add red pixel to pattern[2]
if (red>=245 && green<=10 && blue<=10) {
singlePattern[2][cRed][0]=x;
singlePattern[2][cRed][1]=y;
cRed++;
} else // add black pixel to pattern[3]
if (red<=10 && green<=10 && blue<=10) {
singlePattern[3][cBlack][0]=x;
singlePattern[3][cBlack][1]=y;
cBlack++;
}
//all other pixel will be ignored
}
}
singlePattern[0][1][0]=-999;
singlePattern[1][cBlue][0]=-999;
singlePattern[2][cRed][0]=-999;
singlePattern[3][cBlack][0]=-999;
return singlePattern;
}
public static boolean[][] parse_captcha(String sImg) throws IOException {
BufferedImage img = ImageIO.read(new File(sImg));
boolean[][] captcha_boolean = new boolean[img.getWidth()][img.getHeight()];
int x,y,x1,x2,y1,y2;
int neighbours=0;
int maxneighbours=0;
int argb=0; // alpha red green blue
int red, green, blue;
//scan trough the whole captcha image, first width (x) then Height (y)
for(y=0; y<img.getHeight(); y++) {
for(x=0; x<img.getWidth(); x++) {
argb = img.getRGB(x,y);
red = (argb >> 16) & 0xff;
green = (argb >> 8) & 0xff;
blue = (argb) & 0xff;
// check for black pixel
captcha_boolean[x][y] = ((red+green+blue)/3)<=threshold_black;
}
}
for(y=0; y<captcha_boolean[0].length; y++) {
for(x=0; x<captcha_boolean.length; x++) {
x1=x-1;
x2=x+1;
y1=y-1;
y2=y+1;
neighbours = 0;
maxneighbours = 0;
if (captcha_boolean[x][y]) {
if (x1>=0) {
if (captcha_boolean[x1][y]) {
neighbours=neighbours++;
}
maxneighbours++;
}
if (x2<captcha_boolean.length) {
if (captcha_boolean[x2][y]) {
neighbours=neighbours++;
}
maxneighbours++;
}
if (y1>=0) {
if (captcha_boolean[x][y1]) {
neighbours=neighbours++;
}
maxneighbours++;
}
if (y2<captcha_boolean[0].length) {
if (captcha_boolean[x][y2]) {
neighbours=neighbours++;
}
maxneighbours++;
}
// captcha_boolean[x][y]=(neighbours/maxneighbours)>0;
// captcha_boolean[x][y]=(maxneighbours>3);
}
}
}
captcha_cracked = false;
return captcha_boolean;
}
public static int[][][] copyPattern(int[][][] source) throws IOException {
int[][][] destination = new int[7][1024][2];
// create ObjectOutputStream
ByteArrayOutputStream bufOutStream = new ByteArrayOutputStream();
ObjectOutputStream outStream = new ObjectOutputStream(bufOutStream);
// write object to byte-Array
outStream.writeObject(source);
outStream.close();
// get buffer
byte[] buffer = bufOutStream.toByteArray();
// create ObjectInputStream
ByteArrayInputStream bufInStream = new ByteArrayInputStream(buffer);
ObjectInputStream inStream = new ObjectInputStream(bufInStream);
// read object to destination
try {
destination = (int[][][])inStream.readObject();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return destination;
}
public static int[] rotate(int[] xy, int deg) {
int[] r= new int[2];
double rad, rad_cos, rad_sin;
System.arraycopy(xy,0,r,0,2);
if((xy[0]==0 && xy[1]==0) || deg == 0) {
return r;
}
rad = Math.toRadians(deg*-1);
rad_cos = Math.cos(rad);
rad_sin = Math.sin(rad);
r[0] = (int) Math.round(xy[0]*rad_cos + xy[1]*rad_sin);
r[1] = (int) Math.round(-xy[0]*rad_sin + xy[1]*rad_cos);
// System.out.println("deg : "+deg+" => x: "+xy[0]+"->"+r[0]+" | y: "+xy[1]+"->"+r[1]);
return r;
}
public static int[] check_pattern(boolean[][] captcha) throws IOException {
int[] pos={(int)Math.floor((Math.random() * captcha.length) + 1),(int)Math.floor((Math.random() * captcha[0].length) + 1)};
int xd;
int yd;
int i;
int pl=pattern.length;
int blue, red, black;
int[][][] wPattern = null;
//check every loaded pattern
for (i=0; i<pl; i++) {
//copy pattern
int[][][] oPattern = AntiCaptcha.pattern[i];
wPattern = copyPattern(oPattern);
if (!captcha_cracked) {
// check every rotated pattern
for (int d=-1*pattern_degree_max ; d<=pattern_degree_max; d=d+pattern_degree_step) {
if (!captcha_cracked) {
// if (d!=0) {
// rotate every color pattern
for (int ci=0; ci<wPattern.length; ci++) {
// rotate every pixel of color pattern
for (int cc=0; cc<wPattern[ci].length; cc++) {
if (wPattern[ci][cc][0]!=-999) {
wPattern[ci][cc] = rotate(oPattern[ci][cc],d);
} else {
cc=wPattern[ci].length;
}
}
}
// }
//scan trough the whole captcha image, first width (x) then Height (y)
for(int y=0; y<captcha[0].length; y++) {
if (!captcha_cracked) {
for(int x=0; x<captcha.length; x++) {
blue=0;
red=0;
black=0;
boolean hit = true;
int hitratio = 100;
// check for ALL blue pixel
int cc = 0;
while (hit && (wPattern[1][cc][0]!=-999)) {
xd = x+wPattern[1][cc][0];
yd = y+wPattern[1][cc][1];
if (xd>=0 & xd<captcha.length & yd>=0 & yd<captcha[0].length) {
hit = captcha[xd][yd];
if (hit) {
blue++;
}
} else {
hit = false;
}
cc++;
}
// check for ALL red pixel
cc = 0;
while (hit && (wPattern[2][cc][0]!=-999)) {
xd = x+wPattern[2][cc][0];
yd = y+wPattern[2][cc][1];
if (xd>=0 & xd<captcha.length & yd>=0 & yd<captcha[0].length) {
hit = captcha[xd][yd];
if (hit) {
red++;
}
} else {
hit = false;
}
cc++;
}
// check for black pixel
cc = 0;
while (hit && hitratio>captcha_min_hitratio && (wPattern[3][cc][0]!=-999)) {
xd = x+wPattern[3][cc][0];
yd = y+wPattern[3][cc][1];
if (xd>=0 & xd<captcha.length & yd>=0 & yd<captcha[0].length) {
if (captcha[xd][yd]) {
black++;
}
} else {
hit = false;
}
cc++;
hitratio = (int) Math.floor(black*100/cc);
}
// hitratio = (int) Math.floor(ch*100/cc);
captcha_cracked = (hit & hitratio>=captcha_min_hitratio);
if (captcha_cracked) {
// int argb = Color.RED.getRGB();
// cc=0;
// while (wPattern[2][cc][0]!=-999) {
// xd = x+wPattern[2][cc][0];
// yd = y+wPattern[2][cc][1];
// bimage.setRGB(xd , yd , argb);
// cc++;
// }
// File outfile = new File("gfx/captcha_pattern_"+i+"_"+d+"_"+x+"_"+y+".bmp");
// ImageIO.write(bimage, "bmp", outfile);
pos[0]=x+wPattern[0][0][0];
pos[1]=y+wPattern[0][0][1];
// System.out.println("cracked => "+numbers[i]+" deg: "+d+" blue: "+blue+" red: "+red+" black: "+black+" hitratio: "+hitratio);
x=captcha.length;
} else {
if (hitratio <100) {
// System.out.println("NOT cracked => number: "+i+" deg: "+d+" blue: "+blue+" red: "+red+" black: "+black+" hitratio: "+hitratio);
}
}
}
}
}
}
}
}
}
return pos;
}
public static byte[] ImageToByteArray(String sImg) throws ImageFormatException, IOException {
BufferedImage img = ImageIO.read(new File(sImg));
ByteArrayOutputStream os = new ByteArrayOutputStream();
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(os);
encoder.encode(img);
return os.toByteArray();
}
public static int[] ImageToArray(String sImg) throws IOException {
BufferedImage img = ImageIO.read(new File(sImg));
int[][] pixel = new int[img.getHeight()][img.getWidth()];
int[] serialData = new int[img.getHeight()*img.getWidth()];
int y = 0;
for(int[] line: pixel) {
img.getRGB(0, y, img.getWidth(), 1, line, 0, 0);
int x;
for (x=0; x<img.getWidth(); x++) {
serialData[y*img.getHeight()+x]=255-(pixel[y][x] & 255);
}
y++;
// System.out.println("Number "+y+" => "+line+" <= Length "+line.length);
}
return serialData;
}
public void bwCaptcha(boolean[][] captcha) {
int argb;
BufferedImage bimage = new BufferedImage(captcha.length, captcha[0].length, BufferedImage.TYPE_INT_RGB);
for(int y=0; y<captcha[0].length; y++) {
for(int x=0; x<captcha.length; x++) {
if (captcha[x][y]) {
argb = Color.BLACK.getRGB();
} else {
argb = Color.WHITE.getRGB();
}
bimage.setRGB(x,y,argb);
}
}
File outfile = new File("gfx"+File.separator+"captcha_parsed.jpg");
try {
ImageIO.write(bimage, "jpg", outfile);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public int[] GetNumberPosition(Connection pennerConn, String sCaptchaImage) throws IOException, ImageFormatException {
// pennerConn.getCaptchaImage(sCaptchaImage);
// trial++;
// bCaptcha=parse_captcha("gfx"+File.separator+"captcha.jpg");
// Position=check_pattern(bCaptcha);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return Position;
}
}