A self hosted chat application with end-to-end encrypted messaging.
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.

191 lines
4.8 KiB

  1. package org.ros.chatto.captcha;
  2. import javax.imageio.ImageIO;
  3. import java.awt.Color;
  4. import java.awt.Graphics2D;
  5. import java.awt.RenderingHints;
  6. import java.awt.image.BufferedImage;
  7. import java.io.IOException;
  8. import java.util.Random;
  9. /**
  10. * This class represents a simple captcha consisting of an image {@code png} and
  11. * its text value. Comic Neue Bold Font. Capital english letters {@code ONLY}.
  12. *
  13. * @since 1.3
  14. * @author Gennadiy Golovin
  15. */
  16. public final class SimpleCaptcha {
  17. private BufferedImage imagePng;
  18. private char[] text;
  19. /**
  20. * Initializes a newly created default object consisting of 8 capital
  21. * english letters.
  22. */
  23. public SimpleCaptcha() {
  24. this.text = getRandomChars();
  25. try {
  26. generateCaptcha();
  27. } catch (IOException e) {
  28. e.printStackTrace();
  29. }
  30. }
  31. /**
  32. * Initializes a newly created object, which length depends on the passed
  33. * {@code int} parameter, which {@code MUST} be greater than 0. If the
  34. * condition is not met, initializes a newly created default object
  35. * consisting of 8 symbols.
  36. *
  37. * @param length
  38. * the quantity of symbols, that the captcha consists of, greater
  39. * than 0.
  40. */
  41. public SimpleCaptcha(int length) {
  42. if (length < 1) {
  43. this.text = getRandomChars();
  44. } else {
  45. this.text = getRandomChars(length);
  46. }
  47. try {
  48. generateCaptcha();
  49. } catch (IOException e) {
  50. e.printStackTrace();
  51. }
  52. }
  53. /**
  54. * Initializes a newly created object based on the passed {@link String}
  55. * parameter, consisting of capital english letters. If the condition is not
  56. * met, initializes a newly created default object consisting of 8 capital
  57. * english letters.
  58. *
  59. * @param text
  60. * the text string with the value of the captcha, length greater
  61. * than 0.
  62. */
  63. public SimpleCaptcha(String text) {
  64. if (text == null || text.equals("")) {
  65. this.text = getRandomChars();
  66. } else {
  67. this.text = text.toCharArray();
  68. }
  69. try {
  70. generateCaptcha();
  71. } catch (IOException e) {
  72. this.text = getRandomChars();
  73. try {
  74. generateCaptcha();
  75. } catch (IOException ex) {
  76. ex.printStackTrace();
  77. }
  78. }
  79. }
  80. /**
  81. * Returns the picture with captcha
  82. *
  83. * @return {@link BufferedImage}
  84. */
  85. public BufferedImage getImagePng() {
  86. return imagePng;
  87. }
  88. /**
  89. * Returns the text value of the captcha
  90. *
  91. * @return {@link String}
  92. */
  93. public String getText() {
  94. return String.valueOf(text);
  95. }
  96. //////// //////// //////// //////// //////// //////// //////// ////////
  97. private char[] getRandomChars() {
  98. return getRandomChars(8);
  99. }
  100. private char[] getRandomChars(int quantity) {
  101. char[] randomString = new char[quantity];
  102. Random random = new Random();
  103. int capitalLetter;
  104. for (int i = 0; i < quantity; i++) {
  105. capitalLetter = 65 + random.nextInt(26);
  106. randomString[i] = (char) capitalLetter;
  107. }
  108. return randomString;
  109. }
  110. private void generateCaptcha() throws IOException {
  111. int charsQuantity = this.text.length;
  112. BufferedImage[] images = new BufferedImage[charsQuantity];
  113. for (int i = 0; i < charsQuantity; i++) {
  114. images[i] = ImageIO.read(SimpleCaptcha.class
  115. .getResourceAsStream("/pictures/" + this.text[i] + ".png"));
  116. if (i % 2 == 0) {
  117. images[i] = rotateImage(images[i], 25);
  118. } else {
  119. images[i] = rotateImage(images[i], -20);
  120. }
  121. }
  122. int imageSize = 30;
  123. int rotatedImageSize = (int) Math.sqrt(imageSize * imageSize * 2);
  124. BufferedImage captchaImg = new BufferedImage(
  125. rotatedImageSize * (charsQuantity - 1) / 10 * 6
  126. + rotatedImageSize,
  127. rotatedImageSize, BufferedImage.TYPE_INT_ARGB);
  128. Graphics2D graphics2d = captchaImg.createGraphics();
  129. graphics2d.setBackground(Color.WHITE);
  130. graphics2d.clearRect(0, 0, captchaImg.getWidth(),
  131. captchaImg.getHeight());
  132. for (int i = 0; i < charsQuantity; i++) {
  133. captchaImg.getGraphics().drawImage(images[i],
  134. rotatedImageSize * i / 10 * 6, 0, null);
  135. }
  136. graphics2d.dispose();
  137. this.imagePng = captchaImg;
  138. }
  139. private BufferedImage rotateImage(BufferedImage buffImage, double angle) {
  140. double radian = Math.toRadians(angle);
  141. double sin = Math.abs(Math.sin(radian));
  142. double cos = Math.abs(Math.cos(radian));
  143. int width = buffImage.getWidth();
  144. int height = buffImage.getHeight();
  145. int nWidth = (int) Math
  146. .floor((double) width * cos + (double) height * sin);
  147. int nHeight = (int) Math
  148. .floor((double) height * cos + (double) width * sin);
  149. BufferedImage rotatedImage = new BufferedImage(nWidth, nHeight,
  150. BufferedImage.TYPE_INT_ARGB);
  151. Graphics2D graphics = rotatedImage.createGraphics();
  152. graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
  153. RenderingHints.VALUE_INTERPOLATION_BICUBIC);
  154. graphics.translate((nWidth - width) / 2, (nHeight - height) / 2);
  155. graphics.rotate(radian, (double) (width / 2), (double) (height / 2));
  156. graphics.drawImage(buffImage, 0, 0, null);
  157. graphics.dispose();
  158. return rotatedImage;
  159. }
  160. }