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; } }