|
|
@ -0,0 +1,183 @@ |
|
|
|
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; |
|
|
|
} |
|
|
|
} |