You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
192 lines
4.8 KiB
192 lines
4.8 KiB
package org.ros.chatto.captcha;
|
|
|
|
import javax.imageio.ImageIO;
|
|
|
|
import java.awt.Color;
|
|
import java.awt.Graphics2D;
|
|
import java.awt.RenderingHints;
|
|
import java.awt.image.BufferedImage;
|
|
import java.io.IOException;
|
|
import java.util.Random;
|
|
|
|
/**
|
|
* This class represents a simple captcha consisting of an image {@code png} and
|
|
* its text value. Comic Neue Bold Font. Capital english letters {@code ONLY}.
|
|
*
|
|
* @since 1.3
|
|
* @author Gennadiy Golovin
|
|
*/
|
|
public final class SimpleCaptcha {
|
|
|
|
private BufferedImage imagePng;
|
|
private char[] text;
|
|
|
|
/**
|
|
* Initializes a newly created default object consisting of 8 capital
|
|
* english letters.
|
|
*/
|
|
public SimpleCaptcha() {
|
|
this.text = getRandomChars();
|
|
|
|
try {
|
|
generateCaptcha();
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initializes a newly created object, which length depends on the passed
|
|
* {@code int} parameter, which {@code MUST} be greater than 0. If the
|
|
* condition is not met, initializes a newly created default object
|
|
* consisting of 8 symbols.
|
|
*
|
|
* @param length
|
|
* the quantity of symbols, that the captcha consists of, greater
|
|
* than 0.
|
|
*/
|
|
public SimpleCaptcha(int length) {
|
|
if (length < 1) {
|
|
this.text = getRandomChars();
|
|
} else {
|
|
this.text = getRandomChars(length);
|
|
}
|
|
|
|
try {
|
|
generateCaptcha();
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initializes a newly created object based on the passed {@link String}
|
|
* parameter, consisting of capital english letters. If the condition is not
|
|
* met, initializes a newly created default object consisting of 8 capital
|
|
* english letters.
|
|
*
|
|
* @param text
|
|
* the text string with the value of the captcha, length greater
|
|
* than 0.
|
|
*/
|
|
public SimpleCaptcha(String text) {
|
|
if (text == null || text.equals("")) {
|
|
this.text = getRandomChars();
|
|
} else {
|
|
this.text = text.toCharArray();
|
|
}
|
|
|
|
try {
|
|
generateCaptcha();
|
|
} catch (IOException e) {
|
|
this.text = getRandomChars();
|
|
try {
|
|
generateCaptcha();
|
|
} catch (IOException ex) {
|
|
ex.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the picture with captcha
|
|
*
|
|
* @return {@link BufferedImage}
|
|
*/
|
|
public BufferedImage getImagePng() {
|
|
return imagePng;
|
|
}
|
|
|
|
/**
|
|
* Returns the text value of the captcha
|
|
*
|
|
* @return {@link String}
|
|
*/
|
|
public String getText() {
|
|
return String.valueOf(text);
|
|
}
|
|
|
|
//////// //////// //////// //////// //////// //////// //////// ////////
|
|
|
|
private char[] getRandomChars() {
|
|
return getRandomChars(8);
|
|
}
|
|
|
|
private char[] getRandomChars(int quantity) {
|
|
|
|
char[] randomString = new char[quantity];
|
|
|
|
Random random = new Random();
|
|
|
|
int capitalLetter;
|
|
|
|
for (int i = 0; i < quantity; i++) {
|
|
capitalLetter = 65 + random.nextInt(26);
|
|
randomString[i] = (char) capitalLetter;
|
|
}
|
|
|
|
return randomString;
|
|
}
|
|
|
|
private void generateCaptcha() throws IOException {
|
|
int charsQuantity = this.text.length;
|
|
BufferedImage[] images = new BufferedImage[charsQuantity];
|
|
|
|
for (int i = 0; i < charsQuantity; i++) {
|
|
images[i] = ImageIO.read(SimpleCaptcha.class
|
|
.getResourceAsStream("/pictures/" + this.text[i] + ".png"));
|
|
if (i % 2 == 0) {
|
|
images[i] = rotateImage(images[i], 25);
|
|
} else {
|
|
images[i] = rotateImage(images[i], -20);
|
|
}
|
|
}
|
|
|
|
int imageSize = 30;
|
|
int rotatedImageSize = (int) Math.sqrt(imageSize * imageSize * 2);
|
|
|
|
BufferedImage captchaImg = new BufferedImage(
|
|
rotatedImageSize * (charsQuantity - 1) / 10 * 6
|
|
+ rotatedImageSize,
|
|
rotatedImageSize, BufferedImage.TYPE_INT_ARGB);
|
|
Graphics2D graphics2d = captchaImg.createGraphics();
|
|
graphics2d.setBackground(Color.WHITE);
|
|
graphics2d.clearRect(0, 0, captchaImg.getWidth(),
|
|
captchaImg.getHeight());
|
|
for (int i = 0; i < charsQuantity; i++) {
|
|
captchaImg.getGraphics().drawImage(images[i],
|
|
rotatedImageSize * i / 10 * 6, 0, null);
|
|
}
|
|
graphics2d.dispose();
|
|
this.imagePng = captchaImg;
|
|
}
|
|
|
|
private BufferedImage rotateImage(BufferedImage buffImage, double angle) {
|
|
|
|
double radian = Math.toRadians(angle);
|
|
double sin = Math.abs(Math.sin(radian));
|
|
double cos = Math.abs(Math.cos(radian));
|
|
|
|
int width = buffImage.getWidth();
|
|
int height = buffImage.getHeight();
|
|
|
|
int nWidth = (int) Math
|
|
.floor((double) width * cos + (double) height * sin);
|
|
int nHeight = (int) Math
|
|
.floor((double) height * cos + (double) width * sin);
|
|
|
|
BufferedImage rotatedImage = new BufferedImage(nWidth, nHeight,
|
|
BufferedImage.TYPE_INT_ARGB);
|
|
|
|
Graphics2D graphics = rotatedImage.createGraphics();
|
|
|
|
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
|
|
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
|
graphics.translate((nWidth - width) / 2, (nHeight - height) / 2);
|
|
graphics.rotate(radian, (double) (width / 2), (double) (height / 2));
|
|
graphics.drawImage(buffImage, 0, 0, null);
|
|
graphics.dispose();
|
|
|
|
return rotatedImage;
|
|
}
|
|
}
|