001package io.jboot.web.render; 002 003import com.jfinal.captcha.CaptchaRender; 004import com.jfinal.kit.StrKit; 005 006import java.awt.*; 007import java.awt.geom.QuadCurve2D; 008import java.awt.image.BufferedImage; 009import java.util.concurrent.ThreadLocalRandom; 010 011public class JbootCaptchaRender extends CaptchaRender { 012 013 // 验证码随机字符数组 014 protected static char[] charArray = "1234567890ABCDEFGHJKMNPQRSTUVWXY".toCharArray(); 015 016 017 /** 018 * @param randomArrayString 019 */ 020 public static void setRandomArrayString(String randomArrayString) { 021 if (StrKit.isBlank(randomArrayString)) { 022 throw new IllegalArgumentException("randomArrayString can not be blank."); 023 } 024 charArray = randomArrayString.toCharArray(); 025 } 026 027 028 @Override 029 protected String getRandomString() { 030 char[] randomChars = new char[4]; 031 for (int i = 0; i < randomChars.length; i++) { 032 randomChars[i] = charArray[ThreadLocalRandom.current().nextInt(charArray.length)]; 033 } 034 return String.valueOf(randomChars); 035 } 036 037 038 @Override 039 protected void drawGraphic(String randomString, BufferedImage image) { 040 // 获取图形上下文 041 Graphics2D g = image.createGraphics(); 042 043 g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR); 044 // 图形抗锯齿 045 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 046 // 字体抗锯齿 047 g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 048 049 ThreadLocalRandom random = ThreadLocalRandom.current(); 050 051 // 设定背景色 052 g.setColor(getRandomColor(210, 250, random)); 053 g.fillRect(0, 0, WIDTH, HEIGHT); 054 055 //绘制小字符背景 056 Color color = null; 057 for (int i = 0; i < 20; i++) { 058 color = getRandomColor(120, 200, random); 059 g.setColor(color); 060 String rand = String.valueOf(charArray[random.nextInt(charArray.length)]); 061 g.drawString(rand, random.nextInt(WIDTH), random.nextInt(HEIGHT)); 062 color = null; 063 } 064 065 //设定字体 066 g.setFont(RANDOM_FONT[random.nextInt(RANDOM_FONT.length)]); 067 // 绘制验证码 068 for (int i = 0; i < randomString.length(); i++) { 069 //旋转度数 最好小于45度 070 int degree = random.nextInt(28); 071 if (i % 2 == 0) { 072 degree = degree * (-1); 073 } 074 //定义坐标 075 int x = 22 * i, y = 21; 076 //旋转区域 077 g.rotate(Math.toRadians(degree), x, y); 078 //设定字体颜色 079 color = getRandomColor(20, 130, random); 080 g.setColor(color); 081 //将认证码显示到图象中 082 g.drawString(String.valueOf(randomString.charAt(i)), x + 8, y + 10); 083 //旋转之后,必须旋转回来 084 g.rotate(-Math.toRadians(degree), x, y); 085 } 086 //图片中间曲线,使用上面缓存的color 087 g.setColor(color); 088 //width是线宽,float型 089 BasicStroke bs = new BasicStroke(3); 090 g.setStroke(bs); 091 //画出曲线 092 QuadCurve2D.Double curve = new QuadCurve2D.Double(0d, random.nextInt(HEIGHT - 8) + 4, WIDTH / 2, HEIGHT / 2, WIDTH, random.nextInt(HEIGHT - 8) + 4); 093 g.draw(curve); 094 // 销毁图像 095 g.dispose(); 096 } 097 098 099}