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

win.hupubao.common.utils.Captcha Maven / Gradle / Ivy

Go to download

简单封装公共工具,二维码工具,驼峰转换工具,des加解密工具,http访问工具,字符串工具,日期工具

There is a newer version: 2.0.4
Show newest version
/*
 * Copyright 2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package win.hupubao.common.utils;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.RandomStringUtils;
import win.hupubao.common.utils.rsa.RSA;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Arrays;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.imageio.ImageIO;

/**
 * 传统验证码生成器
 *
 * @author feihong
 * @date 2018-07-12
 */
public class Captcha {

    private static final Random random = new Random();
    private static final Pattern PATTERN_COLOR = Pattern.compile("^#([0-9a-fA-F]{6})$");
    private static final String CHARACTERS = "23456789abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";

    /**
     * Base64 image prefix.
     */
    private static String BASE64_IMAGE_PREFIX = "data:image/jpg;base64,";
    /**
     * Need base64 image prefix or not.
     */
    private static boolean NEED_PREFIX = true;
    /**
     * Character length of captcha.
     */
    private static int CAPTCHA_LENGTH = 4;
    /**
     * Image width of captcha.
     */
    private static int WIDTH = 64;
    /**
     * Image height of captcha.
     */
    private static int HEIGHT = 30;

    /**
     * Noise rate of captcha background.
     */
    private static float NOISE_RATE = 0.06f;
    /**
     * Bounds of captcha image noise line color.
     */
    private ColorBounds NOISE_LINE_COLOR_BOUNDS = new ColorBounds("#666633", "#997744");
    /**
     * Bounds of captcha image background color.
     */
    private ColorBounds BACKGROUND_COLOR_BOUNDS = new ColorBounds("#BBBBBB", "#CCCCCC");
    /**
     * Bounds of captcha character color.
     */
    private static ColorBounds CAPTCHA_CHARACTER_COLOR_BOUNDS = new ColorBounds("#554444", "#886677");
    /**
     * Noise line numbers.
     */
    private static int NOISE_LINE_NUM = 20;
    /**
     * Exclude similer character or not.
     */
    private static boolean EXCLUDE_SIMILER_CHARACTER = true;

    private CaptchaImage captchaImage;


    public Captcha() {
    }

    public static Captcha getInstance() {
        Captcha instance = Captcha.CaptchaInstance.INSTANCE.singleton;
        return instance;
    }

    private enum CaptchaInstance {
        INSTANCE;

        CaptchaInstance() {
            singleton = new Captcha();
        }

        private Captcha singleton;
    }


    public Captcha width(int width) {
        WIDTH = width;
        return this;
    }

    public Captcha height(int height) {
        HEIGHT = height;
        return this;
    }

    public Captcha needPrefix(boolean needPrefix) {
        NEED_PREFIX = needPrefix;
        return this;
    }

    public Captcha captchaLength(int captchaLength) {
        CAPTCHA_LENGTH = captchaLength;
        return this;
    }

    public Captcha noiseRate(float noiseRate) {
        NOISE_RATE = noiseRate;
        return this;
    }

    public Captcha base64ImagePrefix(String base64ImagePrefix) {
        BASE64_IMAGE_PREFIX = base64ImagePrefix;
        return this;
    }

    public Captcha noiseLineColorBounds(ColorBounds noiseLineColorBounds) {
        NOISE_LINE_COLOR_BOUNDS = noiseLineColorBounds;
        return this;
    }

    public Captcha backgroundColorBounds(ColorBounds backgroundColorBounds) {
        BACKGROUND_COLOR_BOUNDS = backgroundColorBounds;
        return this;
    }

    public Captcha captchaCharacterColorBounds(ColorBounds captchaCharacterColorBounds) {
        CAPTCHA_CHARACTER_COLOR_BOUNDS = captchaCharacterColorBounds;
        return this;
    }

    public Captcha noiseLineNum(int noiseLineNum) {
        NOISE_LINE_NUM = noiseLineNum;
        return this;
    }

    public Captcha isExcludeSimilerCharacter(boolean excludeSimilerCharacter) {
        EXCLUDE_SIMILER_CHARACTER = excludeSimilerCharacter;
        return this;
    }


    public static class CaptchaImage implements Serializable{
        private static final long serialVersionUID = 1L;
        private String captchaCode;
        private String base64Image;
        private BufferedImage bufferedImage;

        public String getCaptchaCode() {
            return captchaCode;
        }

        public void setCaptchaCode(String captchaCode) {
            this.captchaCode = captchaCode;
        }

        public String getBase64Image() {
            return base64Image;
        }

        public void setBase64Image(String base64Image) {
            this.base64Image = base64Image;
        }

        public BufferedImage getBufferedImage() {
            return bufferedImage;
        }

        public void setBufferedImage(BufferedImage bufferedImage) {
            this.bufferedImage = bufferedImage;
        }
    }
    public static class ColorBounds {
        private String start = "#999999";
        private String end = "#EEEEEE";

        public ColorBounds(String start, String end) {
            this.start = start;
            this.end = end;
        }

        public String getStart() {
            return start;
        }

        public void setStart(String start) {
            this.start = start;
        }

        public String getEnd() {
            return end;
        }

        public void setEnd(String end) {
            this.end = end;
        }
    }

    public CaptchaImage generate() {
        CaptchaImage captchaImage = new CaptchaImage();
        String captchaCode;
        if (EXCLUDE_SIMILER_CHARACTER) {
            captchaCode = generateChapterCodeWithoutSimilerCharacters();
        } else {
            captchaCode = RandomStringUtils.randomAlphanumeric(CAPTCHA_LENGTH);
        }

        captchaImage.setCaptchaCode(captchaCode);
        captchaImage.setBufferedImage(generateCaptchaImage(captchaCode));
        captchaImage.setBase64Image(generateCaptchaImageBase64(captchaCode));

        return captchaImage;
    }

    /**
     * Generate a base64 captcha image.
     *
     * @return
     * @throws IOException
     */
    private String generateCaptchaImageBase64(String captchaCode) {
        BufferedImage bufferedImage = generateCaptchaImage(captchaCode);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        try {
            ImageIO.write(bufferedImage, "jpg", outputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return (NEED_PREFIX ? BASE64_IMAGE_PREFIX : "") + Base64.encodeBase64String(outputStream.toByteArray());
    }


    /**
     * Generate a captcha image.
     *
     * @return
     * @throws IOException
     */
    private BufferedImage generateCaptchaImage(String captchaCode) {

        BufferedImage image = new BufferedImage(Captcha.WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics2D = image.createGraphics();
        graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        // Background color.
        Color bgColor = getRandomColor(BACKGROUND_COLOR_BOUNDS);
        graphics2D.setColor(bgColor);
        graphics2D.fillRect(0, 0, WIDTH, HEIGHT);

        //Draw noise line.
        if (NOISE_LINE_NUM > 0) {
            graphics2D.setColor(getRandomColor(NOISE_LINE_COLOR_BOUNDS));
            for (int i = 0; i < NOISE_LINE_NUM; i++) {
                int x = random.nextInt(WIDTH - 1);
                int y = random.nextInt(HEIGHT - 1);
                int xl = random.nextInt(6) + 1;
                int yl = random.nextInt(12) + 1;
                graphics2D.drawLine(x, y, x + xl + 40, y + yl + 20);
            }
        }

        //Noise point.
        int area = (int) (NOISE_RATE * WIDTH * HEIGHT);
        for (int i = 0; i < area; i++) {
            int xxx = random.nextInt(WIDTH);
            int yyy = random.nextInt(HEIGHT);
            int rgb = getRandomColor(NOISE_LINE_COLOR_BOUNDS).getRGB();
            image.setRGB(xxx, yyy, rgb);
        }

        //Shear image.
        shear(graphics2D, WIDTH, HEIGHT, bgColor);

        //Captcha characters.
        int fontSize = (int) (HEIGHT * 0.8);
        int fx = 0;
        int fy;
        graphics2D.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, fontSize));
        for (int i = 0; i < captchaCode.length(); i++) {
            fy = (int) ((Math.random() * 0.3 + 0.6) * HEIGHT);
            graphics2D.setColor(getRandomColor(CAPTCHA_CHARACTER_COLOR_BOUNDS));
            graphics2D.drawString(captchaCode.charAt(i) + "", fx, fy);
            fx += (WIDTH / captchaCode.length()) * (Math.random() * 0.3 + 0.8);
        }

        graphics2D.dispose();

        return image;
    }


    private static void shear(Graphics g, int w1, int h1, Color color) {
        shearX(g, w1, h1, color);
        shearY(g, w1, h1, color);
    }

    private static void shearX(Graphics g, int w1, int h1, Color color) {

        int period = random.nextInt(2);

        boolean borderGap = true;
        int frames = 1;
        int phase = random.nextInt(2);

        for (int i = 0; i < h1; i++) {
            double d = (double) (period >> 1)
                    * Math.sin((double) i / (double) period
                    + (6.2831853071795862D * (double) phase)
                    / (double) frames);
            g.copyArea(0, i, w1, 1, (int) d, 0);
            if (borderGap) {
                g.setColor(color);
                g.drawLine((int) d, i, 0, i);
                g.drawLine((int) d + w1, i, w1, i);
            }
        }

    }

    private static void shearY(Graphics g, int w1, int h1, Color color) {

        int period = random.nextInt(40) + 10;

        boolean borderGap = true;
        int frames = 20;
        int phase = 7;
        for (int i = 0; i < w1; i++) {
            double d = (double) (period >> 1)
                    * Math.sin((double) i / (double) period
                    + (6.2831853071795862D * (double) phase)
                    / (double) frames);
            g.copyArea(i, 0, 1, h1, 0, (int) d);
            if (borderGap) {
                g.setColor(color);
                g.drawLine(i, (int) d, i, 0);
                g.drawLine(i, (int) d + h1, i, h1);
            }

        }

    }

    private Color getRandomColor(ColorBounds colorBounds) {

        String start = colorBounds.getStart();
        String end = colorBounds.getEnd();

        if (!PATTERN_COLOR.matcher(start).matches()
                || !PATTERN_COLOR.matcher(end).matches()) {
            return Color.WHITE;
        }

        int startRInt = Integer.parseInt(start.substring(1, 3), 16);
        int startGInt = Integer.parseInt(start.substring(3, 5), 16);
        int startBInt = Integer.parseInt(start.substring(5, 7), 16);

        int endRInt = Integer.parseInt(end.substring(1, 3), 16);
        int endGInt = Integer.parseInt(end.substring(3, 5), 16);
        int endBInt = Integer.parseInt(end.substring(5, 7), 16);

        int r = startRInt + random.nextInt(endRInt - startRInt);
        int g = startGInt + random.nextInt(endGInt - startGInt);
        int b = startBInt + random.nextInt(endBInt - startBInt);
        return new Color(r, g, b);
    }

    private static String generateChapterCodeWithoutSimilerCharacters() {
        int codesLen = CHARACTERS.length();
        Random rand = new Random(System.currentTimeMillis());
        StringBuilder sb = new StringBuilder(CAPTCHA_LENGTH);
        for (int i = 0; i < CAPTCHA_LENGTH; i++) {
            sb.append(CHARACTERS.charAt(rand.nextInt(codesLen - 1)));
        }
        return sb.toString();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy