All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.panxiaochao.captcha.draw.CharacterCaptcha Maven / Gradle / Ivy

The newest version!
package io.github.panxiaochao.captcha.draw;

import io.github.panxiaochao.captcha.enums.CaptchaType;
import io.github.panxiaochao.captcha.enums.ImageType;
import io.github.panxiaochao.captcha.generator.CharacterCaptchaGenerator;
import io.github.panxiaochao.captcha.generator.ICaptchaGenerator;
import io.github.panxiaochao.captcha.utils.Graphics2DUtil;
import io.github.panxiaochao.core.utils.ObjectUtil;
import io.github.panxiaochao.core.utils.RandomUtil;
import io.github.panxiaochao.core.utils.StringPools;
import io.github.panxiaochao.crypto.utils.Base64Util;
import org.apache.commons.io.IOUtils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 

* 字符串验证码,默认PNG格式, Builder模式. *

* * @author Lypxc * @since 2024-08-12 * @version 1.0 */ public class CharacterCaptcha implements IDrawCaptcha { private static final long serialVersionUID = 1L; private static final Builder INSTANCE = new Builder(); /** * 验证码 */ private String captchaCode; /** * 验证码字节数组 */ private byte[] imageBytes; /** * 验证码生成器 */ private final ICaptchaGenerator generator; /** * 图片生成格式 */ private final ImageType imageType; /** * 图片的宽度 - width */ private final int width; /** * 图片的高度- height */ private final int height; /** * 验证码干扰元素个数 */ private final int interfereCount; /** * 背景色 */ private final Color background; /** * 字体 */ private final Font font; /** * 干扰类型,圈圈 - 干扰线 */ private final int interfereType; /** * 构造方法 */ public CharacterCaptcha(Builder builder) { this.generator = new CharacterCaptchaGenerator(builder.codeLength, builder.captchaType); this.imageType = builder.imageType; this.width = builder.width; this.height = builder.height; this.interfereCount = builder.interfereCount; this.background = builder.background; this.font = builder.font; this.interfereType = builder.interfereCount; } /** * 获取实例 * @return CharacterCaptcha */ public static Builder builder() { return INSTANCE; } public static class Builder { /** * 图片的宽度 - width */ private int width; /** * 图片的高度- height */ private int height; /** * 验证码干扰元素个数 */ private int interfereCount; /** * 字体 */ private Font font; /** * 验证码生成器 */ private ICaptchaGenerator generator; /** * 验证码字符个数 */ private int codeLength; /** * 验证码字符类型 */ private CaptchaType captchaType; /** * 背景色 */ private Color background; /** * 验证码生成格式 */ private ImageType imageType; /** * 干扰类型,圈圈 - 干扰线 */ private int interfereType; /** * Instantiates a new Builder. */ public Builder() { // Default value this.width = 100; this.height = 40; this.interfereCount = 50; this.codeLength = 4; this.font = new Font(Font.SANS_SERIF, Font.PLAIN, (int) (this.height * 0.8)); this.captchaType = CaptchaType.CHAR_NUMBER; this.background = Color.WHITE; this.imageType = ImageType.PNG; this.interfereType = 0; } /** * 图片的宽度,默认100px */ public Builder width(int width) { this.width = width; return this; } /** * 图片的高度,默认40px */ public Builder height(int height) { this.height = height; return this; } /** * 验证码干扰元素个数,默认50个 */ public Builder interfereCount(int interfereCount) { this.interfereCount = interfereCount; return this; } /** * 字体,默认Font.SANS_SERIF */ public Builder font(Font font) { this.font = font; return this; } /** * 验证码字符个数,默认4个 */ public Builder codeLength(int codeLength) { this.codeLength = codeLength; return this; } /** * 验证码字符类型,默认字符数字混合 */ public Builder captchaType(CaptchaType captchaType) { this.captchaType = captchaType; return this; } /** * 背景色,默认白色 */ public Builder background(Color background) { this.background = background; return this; } /** * 验证码生成格式,默认输出PNG格式 */ public Builder imageType(ImageType imageType) { this.imageType = imageType; return this; } /** * 干扰类型,圈圈 - 干扰线,默认圈圈 * *

* 圈圈:0,干扰线:1 *

*/ public Builder interfereType(int interfereType) { this.interfereType = interfereType; return this; } public CharacterCaptcha build() { return new CharacterCaptcha(this); } } /** * 图片输出媒体类型 */ public String getContentType() { return this.imageType.getContentType(); } /** * 获取验证码的内容 */ @Override public String getCaptchaCode() { if (ObjectUtil.isEmpty(this.captchaCode)) { this.captchaCode = generator.generateCode(); } return this.captchaCode; } /** * 将验证码写出入到目标流中 * @param out 目标流 */ @Override public void writeTo(OutputStream out) { try { IOUtils.write(getImageBytes(), out); } catch (IOException e) { // skip } } /** * 获取图形验证码图片bytes */ @Override public byte[] getImageBytes() { if (ObjectUtil.isEmpty(this.imageBytes)) { try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { ImageIO.write(drawImage(), this.imageType.getSuffix(), out); this.imageBytes = out.toByteArray(); } catch (IOException e) { // skip } } return this.imageBytes; } /** * 获得图片的Base64形式 */ @Override public String getImageBase64() { return Base64Util.encodeToString(getImageBytes()); } /** * 获取图片的Base64Data格式 */ @Override public String getImageBase64Data() { return String.join(StringPools.COMMA, imageType.getImageData(), Base64Util.encodeToString(getImageBytes())); } /** * 绘制图片 * *
    *
  • TYPE_INT_RGB: 包含 8 位 RGB 像素的图像,其中每个像素由 32 位整数表示
  • *
  • TYPE_4BYTE_ABGR: 包含 8 位 ABGR 像素的图像,其中每个像素由 32 位整数表示,支持alpha通道的rgb图像
  • *
*/ private BufferedImage drawImage() { final BufferedImage image = new BufferedImage(this.width, this.height, ObjectUtil.isEmpty(this.background) ? BufferedImage.TYPE_4BYTE_ABGR : BufferedImage.TYPE_INT_RGB); final Graphics2D graphics = Graphics2DUtil.createGraphics(image, this.background); try { // 随机画干扰元素 if (this.interfereType == 0) { // 干扰圈圈 drawInterfereCircle(graphics); } else { // 干扰线 drawInterfereLine(graphics); } // 画字符串 Graphics2DUtil.drawString(graphics, getCaptchaCode(), this.font, this.width, this.height); } catch (Exception e) { throw new RuntimeException("Draw Graphics2D is error!", e); } finally { // 释放资源 graphics.dispose(); } return image; } /** * 绘制干扰圈圈 * @param graphics {@link Graphics2D}画笔 */ private void drawInterfereCircle(Graphics2D graphics) { final ThreadLocalRandom random = RandomUtil.threadLocalRandom(); for (int i = 0; i < this.interfereCount; i++) { graphics.setColor(Graphics2DUtil.randomColor()); graphics.drawOval(random.nextInt(width), random.nextInt(height), random.nextInt(height >> 2), random.nextInt(height >> 2)); } } /** * 绘制干扰线 * @param graphics {@link Graphics2D}画笔 */ private void drawInterfereLine(Graphics2D graphics) { final ThreadLocalRandom random = RandomUtil.threadLocalRandom(); for (int i = 0; i < this.interfereCount; i++) { int xs = random.nextInt(width); int ys = random.nextInt(height); int xe = xs + random.nextInt(width / 5); int ye = ys + random.nextInt(height / 5); graphics.setColor(Graphics2DUtil.randomColor()); graphics.drawLine(xs, ys, xe, ye); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy