diff --git a/src/main/java/com/wf/captcha/ChineseCaptcha.java b/src/main/java/com/wf/captcha/ChineseCaptcha.java index 6d524a3..2c3af93 100644 --- a/src/main/java/com/wf/captcha/ChineseCaptcha.java +++ b/src/main/java/com/wf/captcha/ChineseCaptcha.java @@ -1,5 +1,7 @@ package com.wf.captcha; +import com.wf.captcha.base.ChineseCaptchaAbstract; + import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; @@ -58,6 +60,7 @@ public class ChineseCaptcha extends ChineseCaptchaAbstract { g.fillRect(0, 0, width, height); // 抗锯齿 g.setColor(color()); + Font font = getFont(); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); int hp = (height - font.getSize()) >> 1; int h = height - hp; diff --git a/src/main/java/com/wf/captcha/ChineseGifCaptcha.java b/src/main/java/com/wf/captcha/ChineseGifCaptcha.java index dc6e12c..4cea9fd 100644 --- a/src/main/java/com/wf/captcha/ChineseGifCaptcha.java +++ b/src/main/java/com/wf/captcha/ChineseGifCaptcha.java @@ -1,5 +1,8 @@ package com.wf.captcha; +import com.wf.captcha.base.ChineseCaptchaAbstract; +import com.wf.captcha.utils.GifEncoder; + import java.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; @@ -73,6 +76,7 @@ public class ChineseGifCaptcha extends ChineseCaptchaAbstract { g2d.setColor(fontcolor); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // 画验证码 + Font font = getFont(); int hp = (height - font.getSize()) >> 1; int h = height - hp; int w = width / strs.length; diff --git a/src/main/java/com/wf/captcha/GifCaptcha.java b/src/main/java/com/wf/captcha/GifCaptcha.java index e4f870d..6d80c7c 100644 --- a/src/main/java/com/wf/captcha/GifCaptcha.java +++ b/src/main/java/com/wf/captcha/GifCaptcha.java @@ -1,5 +1,8 @@ package com.wf.captcha; +import com.wf.captcha.base.Captcha; +import com.wf.captcha.utils.GifEncoder; + import java.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; @@ -84,6 +87,7 @@ public class GifCaptcha extends Captcha { // 随机画干扰线 drawLine(2, g2d); // 画验证码 + Font font = getFont(); int hp = (height - font.getSize()) >> 1; int h = height - hp; int w = width / strs.length; diff --git a/src/main/java/com/wf/captcha/SpecCaptcha.java b/src/main/java/com/wf/captcha/SpecCaptcha.java index 9a78684..74abf82 100644 --- a/src/main/java/com/wf/captcha/SpecCaptcha.java +++ b/src/main/java/com/wf/captcha/SpecCaptcha.java @@ -1,5 +1,7 @@ package com.wf.captcha; +import com.wf.captcha.base.Captcha; + import java.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; @@ -40,7 +42,6 @@ public class SpecCaptcha extends Captcha { */ @Override public boolean out(OutputStream out) { - checkAlpha(); return graphicsImage(textChar(), out); } @@ -52,51 +53,51 @@ public class SpecCaptcha extends Captcha { * @return boolean */ private boolean graphicsImage(char[] strs, OutputStream out) { - boolean ok; try { BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics2D g = (Graphics2D) bi.getGraphics(); + // 填充背景 g.setColor(Color.WHITE); g.fillRect(0, 0, width, height); // 抗锯齿 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setStroke(new BasicStroke(1.3f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL)); // 随机画干扰线 - drawLine(3, g); + // drawLine(3, g); // 随机画干扰圆 - drawOval(8, g); + // drawOval(8, g); + drawBesselLine(2, g); // 画字符串 - AlphaComposite ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f);// 指定透明度 - g.setComposite(ac3); - int hp = (height - font.getSize()) >> 1; - int h = height - hp; - int w = width / strs.length; - int sp = (w - font.getSize()) / 2; + // AlphaComposite ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f);// 指定透明度 + // g.setComposite(ac3); + g.setFont(getFont()); + int fontSize = getFont().getSize(); + int fY = height - ((height - fontSize) >> 1); // 文字的纵坐标 + int fW = width / strs.length; // 每一个字符所占的宽度 + int fSp = (fW - fontSize) / 2; // 字符的左右边距 for (int i = 0; i < strs.length; i++) { - g.setColor(new Color(20 + num(110), 20 + num(110), 20 + num(110))); + g.setColor(color()); // 计算坐标 - int x = i * w + sp + num(3); - int y = h - num(3, 6); - if (x < 8) { + int x = i * fW + fSp; + int y = fY/* - num(3, 6)*/; + /*if (x < 8) { x = 8; } - if (x + font.getSize() > width) { - x = width - font.getSize(); - } - if (y > height) { + if (x + fontSize > width) { + x = width - fontSize; + }*/ + /*if (y > height) { y = height; } - if (y - font.getSize() < 0) { - y = font.getSize(); - } - g.setFont(font.deriveFont(num(2) == 0 ? Font.PLAIN : Font.ITALIC)); + if (y - fontSize < 0) { + y = fontSize; + }*/ g.drawString(String.valueOf(strs[i]), x, y); } ImageIO.write(bi, "png", out); out.flush(); - ok = true; + return true; } catch (IOException e) { - ok = false; e.printStackTrace(); } finally { try { @@ -105,6 +106,6 @@ public class SpecCaptcha extends Captcha { e.printStackTrace(); } } - return ok; + return false; } } \ No newline at end of file diff --git a/src/main/java/com/wf/captcha/Captcha.java b/src/main/java/com/wf/captcha/base/Captcha.java similarity index 64% rename from src/main/java/com/wf/captcha/Captcha.java rename to src/main/java/com/wf/captcha/base/Captcha.java index 2fbb633..c70b009 100644 --- a/src/main/java/com/wf/captcha/Captcha.java +++ b/src/main/java/com/wf/captcha/base/Captcha.java @@ -1,6 +1,10 @@ -package com.wf.captcha; +package com.wf.captcha.base; import java.awt.*; +import java.awt.geom.CubicCurve2D; +import java.awt.geom.QuadCurve2D; +import java.io.File; +import java.io.IOException; import java.io.OutputStream; /** @@ -8,20 +12,33 @@ import java.io.OutputStream; * Created by 王帆 on 2018-07-27 上午 10:08. */ public abstract class Captcha extends Randoms { - protected Font font = new Font("Arial", Font.BOLD, 32); // 字体Verdana - protected int len = 4; // 验证码随机字符长度 - protected int width = 130; // 验证码显示宽度 - protected int height = 48; // 验证码显示高度 - protected String chars = null; // 当前验证码 - protected int charType = TYPE_DEFAULT; // 验证码类型,1字母数字混合,2纯数字,3纯字母 + // 常用颜色 + public static final int[][] COLOR = {{0, 135, 255}, {51, 153, 51}, {255, 102, 102}, {255, 153, 0}, {153, 102, 0}, {153, 102, 153}, {51, 153, 153}, {102, 102, 255}, {0, 102, 204}, {204, 51, 51}, {0, 153, 204}, {0, 51, 102}}; + // 验证码文本类型 public static final int TYPE_DEFAULT = 1; // 字母数字混合 public static final int TYPE_ONLY_NUMBER = 2; // 纯数字 public static final int TYPE_ONLY_CHAR = 3; // 纯字母 public static final int TYPE_ONLY_UPPER = 4; // 纯大写字母 public static final int TYPE_ONLY_LOWER = 5; // 纯小写字母 public static final int TYPE_NUM_AND_UPPER = 6; // 数字大写字母 - // 常用颜色 - public static final int[][] COLOR = {{0, 135, 255}, {51, 153, 51}, {255, 102, 102}, {255, 153, 0}, {153, 102, 0}, {153, 102, 153}, {51, 153, 153}, {102, 102, 255}, {0, 102, 204}, {204, 51, 51}, {0, 153, 204}, {0, 51, 102}}; + // 内置字体 + public static final int FONT_1 = 0; + public static final int FONT_2 = 1; + public static final int FONT_3 = 2; + public static final int FONT_4 = 3; + public static final int FONT_5 = 4; + public static final int FONT_6 = 5; + public static final int FONT_7 = 6; + public static final int FONT_8 = 7; + public static final int FONT_9 = 8; + public static final int FONT_10 = 9; + private static final String[] FONT_NAMES = new String[]{"actionj.ttf", "epilog.ttf", "fresnel.ttf", "headache.ttf", "lexo.ttf", "prefix.ttf", "progbot.ttf", "ransom.ttf", "robot.ttf", "scandal.ttf"}; + private Font font = null; // 验证码的字体 + protected int len = 5; // 验证码随机字符长度 + protected int width = 130; // 验证码显示宽度 + protected int height = 48; // 验证码显示高度 + protected int charType = TYPE_DEFAULT; // 验证码类型 + protected String chars = null; // 当前验证码 /** * 生成随机验证码 @@ -112,7 +129,7 @@ public abstract class Captcha extends Randoms { } /** - * 检查验证码是否生成,没有这立即生成 + * 检查验证码是否生成,没有则立即生成 */ public void checkAlpha() { if (chars == null) { @@ -175,7 +192,53 @@ public abstract class Captcha extends Randoms { } } + /** + * 随机画贝塞尔曲线 + * + * @param num 数量 + * @param g Graphics2D + */ + public void drawBesselLine(int num, Graphics2D g) { + drawBesselLine(num, null, g); + } + + /** + * 随机画贝塞尔曲线 + * + * @param num 数量 + * @param color 颜色 + * @param g Graphics2D + */ + public void drawBesselLine(int num, Color color, Graphics2D g) { + for (int i = 0; i < num; i++) { + g.setColor(color == null ? color() : color); + int x1 = 5; + int y1 = num(5, height - 5); + int x2 = width - 5; + int y2 = num(5, height - 5); + int ctrlx = num(5, width - 5); + int ctrly = num(5, height - 5); + if (num(2) == 0) { // 二阶贝塞尔曲线 + QuadCurve2D shape = new QuadCurve2D.Double(); + shape.setCurve(x1, y1, ctrlx, ctrly, x2, y2); + g.draw(shape); + } else { // 三阶贝塞尔曲线 + int ctrlx1 = num(5, width - 5); + int ctrly1 = num(5, height - 5); + CubicCurve2D shape = new CubicCurve2D.Double(x1, y1, ctrlx, ctrly, ctrlx1, ctrly1, x2, y2); + g.draw(shape); + } + } + } + public Font getFont() { + if (font == null) { + try { + setFont(FONT_1); + } catch (Exception e) { + setFont(new Font("Arial", Font.BOLD, 32)); + } + } return font; } @@ -183,6 +246,14 @@ public abstract class Captcha extends Randoms { this.font = font; } + public void setFont(int font) throws IOException, FontFormatException { + setFont(font, Font.BOLD, 32f); + } + + public void setFont(int font, int style, float size) throws IOException, FontFormatException { + this.font = Font.createFont(Font.TRUETYPE_FONT, new File(getClass().getResource("/" + FONT_NAMES[font]).getFile())).deriveFont(style, size); + } + public int getLen() { return len; } diff --git a/src/main/java/com/wf/captcha/ChineseCaptchaAbstract.java b/src/main/java/com/wf/captcha/base/ChineseCaptchaAbstract.java similarity index 98% rename from src/main/java/com/wf/captcha/ChineseCaptchaAbstract.java rename to src/main/java/com/wf/captcha/base/ChineseCaptchaAbstract.java index edc0e2d..bd3a11a 100644 --- a/src/main/java/com/wf/captcha/ChineseCaptchaAbstract.java +++ b/src/main/java/com/wf/captcha/base/ChineseCaptchaAbstract.java @@ -1,4 +1,6 @@ -package com.wf.captcha; +package com.wf.captcha.base; + +import com.wf.captcha.base.Captcha; import java.awt.*; diff --git a/src/main/java/com/wf/captcha/Randoms.java b/src/main/java/com/wf/captcha/base/Randoms.java similarity index 98% rename from src/main/java/com/wf/captcha/Randoms.java rename to src/main/java/com/wf/captcha/base/Randoms.java index 1771a48..f125a29 100644 --- a/src/main/java/com/wf/captcha/Randoms.java +++ b/src/main/java/com/wf/captcha/base/Randoms.java @@ -1,4 +1,4 @@ -package com.wf.captcha; +package com.wf.captcha.base; import java.util.Random; diff --git a/src/main/java/com/wf/captcha/utils/CaptchaUtil.java b/src/main/java/com/wf/captcha/utils/CaptchaUtil.java index 9a25298..0c3595e 100644 --- a/src/main/java/com/wf/captcha/utils/CaptchaUtil.java +++ b/src/main/java/com/wf/captcha/utils/CaptchaUtil.java @@ -6,7 +6,7 @@ import java.io.IOException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import com.wf.captcha.Captcha; +import com.wf.captcha.base.Captcha; import com.wf.captcha.GifCaptcha; import com.wf.captcha.SpecCaptcha; diff --git a/src/main/java/com/wf/captcha/Encoder.java b/src/main/java/com/wf/captcha/utils/Encoder.java similarity index 99% rename from src/main/java/com/wf/captcha/Encoder.java rename to src/main/java/com/wf/captcha/utils/Encoder.java index 177f167..1cd35f2 100644 --- a/src/main/java/com/wf/captcha/Encoder.java +++ b/src/main/java/com/wf/captcha/utils/Encoder.java @@ -1,4 +1,4 @@ -package com.wf.captcha; +package com.wf.captcha.utils; import java.io.IOException; import java.io.OutputStream; diff --git a/src/main/java/com/wf/captcha/GifEncoder.java b/src/main/java/com/wf/captcha/utils/GifEncoder.java similarity index 99% rename from src/main/java/com/wf/captcha/GifEncoder.java rename to src/main/java/com/wf/captcha/utils/GifEncoder.java index 5636e33..9ed2a91 100644 --- a/src/main/java/com/wf/captcha/GifEncoder.java +++ b/src/main/java/com/wf/captcha/utils/GifEncoder.java @@ -1,4 +1,4 @@ -package com.wf.captcha; +package com.wf.captcha.utils; import java.awt.*; import java.awt.image.BufferedImage; diff --git a/src/main/java/com/wf/captcha/Quant.java b/src/main/java/com/wf/captcha/utils/Quant.java similarity index 99% rename from src/main/java/com/wf/captcha/Quant.java rename to src/main/java/com/wf/captcha/utils/Quant.java index ed6cbf9..c0b2c2f 100644 --- a/src/main/java/com/wf/captcha/Quant.java +++ b/src/main/java/com/wf/captcha/utils/Quant.java @@ -1,4 +1,4 @@ -package com.wf.captcha; +package com.wf.captcha.utils; /** * diff --git a/src/main/resources/actionj.ttf b/src/main/resources/actionj.ttf new file mode 100644 index 0000000..8439247 Binary files /dev/null and b/src/main/resources/actionj.ttf differ diff --git a/src/main/resources/epilog.ttf b/src/main/resources/epilog.ttf new file mode 100644 index 0000000..bd9614a Binary files /dev/null and b/src/main/resources/epilog.ttf differ diff --git a/src/main/resources/fresnel.ttf b/src/main/resources/fresnel.ttf new file mode 100644 index 0000000..7e32a51 Binary files /dev/null and b/src/main/resources/fresnel.ttf differ diff --git a/src/main/resources/headache.ttf b/src/main/resources/headache.ttf new file mode 100644 index 0000000..26fa0af Binary files /dev/null and b/src/main/resources/headache.ttf differ diff --git a/src/main/resources/lexo.ttf b/src/main/resources/lexo.ttf new file mode 100644 index 0000000..411af54 Binary files /dev/null and b/src/main/resources/lexo.ttf differ diff --git a/src/main/resources/prefix.ttf b/src/main/resources/prefix.ttf new file mode 100644 index 0000000..a1aeed0 Binary files /dev/null and b/src/main/resources/prefix.ttf differ diff --git a/src/main/resources/progbot.ttf b/src/main/resources/progbot.ttf new file mode 100644 index 0000000..c98d122 Binary files /dev/null and b/src/main/resources/progbot.ttf differ diff --git a/src/main/resources/ransom.ttf b/src/main/resources/ransom.ttf new file mode 100644 index 0000000..779ab8e Binary files /dev/null and b/src/main/resources/ransom.ttf differ diff --git a/src/main/resources/robot.ttf b/src/main/resources/robot.ttf new file mode 100644 index 0000000..09e2de0 Binary files /dev/null and b/src/main/resources/robot.ttf differ diff --git a/src/main/resources/scandal.ttf b/src/main/resources/scandal.ttf new file mode 100644 index 0000000..22e3a7e Binary files /dev/null and b/src/main/resources/scandal.ttf differ diff --git a/src/test/java/com/wf/captcha/CaptchaTest.java b/src/test/java/com/wf/captcha/CaptchaTest.java index 3900b1f..bde5244 100644 --- a/src/test/java/com/wf/captcha/CaptchaTest.java +++ b/src/test/java/com/wf/captcha/CaptchaTest.java @@ -1,9 +1,15 @@ package com.wf.captcha; +import com.wf.captcha.base.Captcha; import org.junit.Test; +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.geom.QuadCurve2D; +import java.awt.image.BufferedImage; import java.io.File; import java.io.FileOutputStream; +import java.io.IOException; /** * 测试类 @@ -13,12 +19,13 @@ public class CaptchaTest { @Test public void test() throws Exception { - /*for (int i = 0; i < 5; i++) { + for (int i = 0; i < 5; i++) { SpecCaptcha specCaptcha = new SpecCaptcha(); - specCaptcha.setCharType(Captcha.TYPE_ONLY_UPPER); + // specCaptcha.setCharType(Captcha.TYPE_ONLY_UPPER); System.out.println(specCaptcha.text()); + // specCaptcha.setFont(Font.createFont(Font.TRUETYPE_FONT, new File(getClass().getResource("/actionj.ttf").getFile())).deriveFont(Font.BOLD, 32)); specCaptcha.out(new FileOutputStream(new File("D:/Java/aa" + i + ".png"))); - }*/ + } } @Test @@ -48,4 +55,62 @@ public class CaptchaTest { }*/ } + @Test + public void test2() throws Exception { + String[] colors = new String[]{"#8cc540", "#009f5d", "#019fa0", "#019fde", "#007cdc", "#887ddd", "#cd7bdd", "#ff5675", "#ff1244", "#ff8345", "#f8bd0b", "#d1d2d4"}; + String[] fonts = new String[]{"actionj.ttf", "epilog.ttf", "fresnel.ttf", "headache.ttf", "lexo.ttf", "prefix.ttf", "progbot.ttf", "ransom.ttf", "robot.ttf", "scandal.ttf"}; + int i = 0; + for (String f : fonts) { + i++; + FileOutputStream out = new FileOutputStream(new File("D:/Java/aa" + i + ".png")); + try { + int width = 130, height = 48; + BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + Graphics2D g = (Graphics2D) bi.getGraphics(); + g.setColor(Color.WHITE); + g.fillRect(0, 0, width, height); + // 抗锯齿 + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g.setStroke(new BasicStroke(1.3f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL)); + // 画字符串 + float fontSize = 32f; + Font font = Font.createFont(Font.TRUETYPE_FONT, new File(getClass().getResource("/" + f).getFile())).deriveFont(Font.BOLD, fontSize); + g.setFont(font); + char[] chars = "N4WbS".toCharArray(); + float sp = (width / chars.length - fontSize) / 2; + int j = 0; + for (char c : chars) { + j++; + g.setColor(Color.getColor(colors[j])); + float x = sp * j + fontSize * (j - 1); + float y = (height - fontSize) / 2 + fontSize; + System.out.println(x + "-" + y); + g.drawString(String.valueOf(c), x, y); + } + g.drawString("Hello", 8, 37); + // + QuadCurve2D shape = new QuadCurve2D.Double(); + shape.setCurve(8, 38, 38, 10, 120, 40); + g.draw(shape); + ImageIO.write(bi, "png", out); + out.flush(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + @Test + public void test3() throws Exception { + String filePath = getClass().getResource("/actionj.ttf").getFile(); + System.out.println(filePath); + } + + }