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.

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