Java图片验证码

作者: 雪飘千里 | 来源:发表于2019-08-12 18:36 被阅读0次

    采用验证码很重要的原因就是为了防止系统被攻击,比如机器重复注册,短信重复发送;
    下面介绍常用的两种验证码:数字验证码和算法验证码

    基本原理分为两步:
    1)验证码生成:先生成随机数,把结果存在session中,然后生成图片,并把图片返回前端,当然,也可以存储到redis中
    2)验证码验证:前端输入验证码后,后端使用session中存的验证码和前端传参验证码做校验
    注:如果是短信发送需要验证码的话,需要注意一点,在发送短信时,参数除了要有手机号以外,还需要有验证码,后端接收到以后,还需要验证一次,验证成功以后,要把session中的验证码删除,防止,恶意攻击

    1、随机数验证码

    public void getImageCode1(HttpServletRequest request, HttpServletResponse response){
             try {
                 // 设置响应的类型格式为图片格式
                 response.setContentType("image/jpeg");
                 // 禁止图像缓存。
                 response.setHeader("Pragma","no-cache");
                 response.setHeader("Cache-Control","no-cache");
                 response.setDateHeader("Expires",0);
    
                 // 生成随机字串
                 String verifyCode = VerifyCodeUtils.generateVerifyCode(4);
    
                 HttpSession session = request.getSession(true);
                 // 删除以前的
                 session.removeAttribute("verifyCode");
                 // 存入会话session
                 session.setAttribute("verifyCode", verifyCode.toLowerCase());
                 request.getSession().setAttribute("codeTime",new Date().getTime());
                 // 生成图片
                 int w = 150, h = 30;
                 VerifyCodeUtils.outputImage(w, h, response.getOutputStream(), verifyCode);
             } catch (IOException e) {
                 logger.error("生成图片验证码失败,{}",e);
             }
    
         }
    

    2、算法验证码

    public void test(HttpServletRequest request, HttpServletResponse response){
            try {
                // 设置响应的类型格式为图片格式
                response.setContentType("image/jpeg");
                // 禁止图像缓存。
                response.setHeader("Pragma","no-cache");
                response.setHeader("Cache-Control","no-cache");
                response.setDateHeader("Expires",0);
                // 生成图片
                int width = 140, height = 40;
    
                String baseStr = generateCheckCode(request);
                logger.info("生成验证码{}",baseStr);
                BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
                OutputStream os = response.getOutputStream();
                Graphics g = image.getGraphics();
    
                Random random = new Random();
    
                g.setColor(getRandColor(random, 200, 250));
                g.fillRect(0, 0, width, height);
    
                String[] fontTypes = { "\u5b8b\u4f53", "\u65b0\u5b8b\u4f53", "\u9ed1\u4f53", "\u6977\u4f53", "\u96b6\u4e66" };
                int fontTypesLength = fontTypes.length;
    
                g.setColor(getRandColor(random, 160, 200));
                g.setFont(new Font("Times New Roman", Font.PLAIN, 14 + random.nextInt(6)));
    
                for (int i = 0; i < 255; i++) {
                    int x = random.nextInt(width);
                    int y = random.nextInt(height);
                    int xl = random.nextInt(12);
                    int yl = random.nextInt(12);
                    g.drawLine(x, y, x + xl, y + yl);
                }
    
                String [] baseChar = baseStr.split(" ");
                for (int i = 0; i < baseChar.length; i++) {
                    g.setColor(getRandColor(random, 30, 150));
                    g.setFont(new Font(fontTypes[random.nextInt(fontTypesLength)], Font.BOLD, 22 + random.nextInt(6)));
                    g.drawString(baseChar[i], 24 * i + 10, 24);
                }
    
                g.dispose();
    
                //发送图片
                ImageIO.write(image, "JPEG", os);
                os.flush();
                os.close();
                os = null;
                response.flushBuffer();
    
            } catch (Exception e) {
                logger.error("获取验证码出错{}",e);
    
            }
    
     private static Color getRandColor(Random random, int fc, int bc){
            if (fc > 255)
                fc = 255;
            if (bc > 255)
                bc = 255;
            int r = fc + random.nextInt(bc - fc);
            int g = fc + random.nextInt(bc - fc);
            int b = fc + random.nextInt(bc - fc);
            return new Color(r, g, b);
        }
    
    private static String generateCheckCode(HttpServletRequest request) {
            Random random = new Random();
            int intTemp;
            int intFirst = random.nextInt(100);
            int intSec = random.nextInt(100);
            String checkCode = "";
            int result = 0;
            switch (random.nextInt(6)) {
                case 0:
                    if (intFirst < intSec) {
                        intTemp = intFirst;
                        intFirst = intSec;
                        intSec = intTemp;
                    }
                    checkCode = intFirst + " - " + intSec + " = ?";
                    result = intFirst-intSec;
                    break;
                case 1:
                    if (intFirst < intSec) {
                        intTemp = intFirst;
                        intFirst = intSec;
                        intSec = intTemp;
                    }
                    checkCode = intFirst + " - ? = "+(intFirst-intSec);
                    result = intSec;
                    break;
                case 2:
                    if (intFirst < intSec) {
                        intTemp = intFirst;
                        intFirst = intSec;
                        intSec = intTemp;
                    }
                    checkCode = "? - "+intSec+" = "+(intFirst-intSec);
                    result = intFirst;
                    break;
                case 3:
                    checkCode = intFirst + " + " + intSec + " = ?";
                    result = intFirst + intSec;
                    break;
                case 4:
                    checkCode = intFirst + " + ? ="+(intFirst+intSec);
                    result = intSec;
                    break;
                case 5:
                    checkCode = "? + " + intSec + " ="+(intFirst+intSec);
                    result = intFirst;
                    break;
            }
            request.getSession().setAttribute("VERIFY_CODE", result);
            request.getSession().setAttribute("codeTime",new Date().getTime());
            return checkCode;
        }
    

    校验

    public Result verifyImageCode2(HttpServletRequest request, HttpSession session, String checkCode){
            Result result = new Result();
    
            //获得session中验证码
            Object verifyCode = session.getAttribute("VERIFY_CODE");
            if(verifyCode == null){
                result.setCode(Result.STATUS_ERROR);
                result.setMsg("验证码已过期,请重新获取验证码!");
                return  result;
            }
            logger.info("校验验证码{}={}",checkCode,verifyCode);
            // 验证码有效时长为1分钟
            Long codeTime = Long.valueOf(session.getAttribute("codeTime") + "");
            Date now = new Date();
            if ((now.getTime() - codeTime) / 1000 / 60 > 1){
                result.setCode(Result.STATUS_ERROR);
                result.setMsg("验证码已失效,请重新输入!");
                return  result;
            }
    
    
            if(StringUtil.isEmpty(checkCode) || StringUtil.isEmpty(verifyCode.toString()) ||
                    !verifyCode.toString().equalsIgnoreCase(checkCode)){
                result.setCode(Result.STATUS_ERROR);
                result.setMsg("验证码错误,请重新输入!");
                return  result;
            }
    
            result.setCode(Result.STATUS_OK);
            result.setMsg("验证通过!");
            return  result;
        }
    

    3、滑动图片验证码

    public Result getImageCode(HttpSession session, HttpServletResponse response,String userId,String phone) {
            Result result = new Result();
            logger.info("获取滑动图片,userId={},phone={}",userId,phone);
            //生成图片验证码
            int L = new Random().nextInt(180)+56;
            int W = new Random().nextInt(100);
            Map<String, Object> resultMap = new HashMap<>();
            String url = "https://picsum.photos/300/150/?image=" + new Random().nextInt(100);
            int type = 1;
            this.createImage(url, L, W, resultMap);
    
            int resultImageLength = L*280/300;
            int resultImageWidth= W*200/150;
            resultMap.put("w",resultImageWidth);
    
            //存储验证码
            //把移动距离存储起来
            String sessionId = session.getId();
            String key = StringUtil.join("_",userId,sessionId,phone,"YOUZAN");
            RedisKit.setCache(key,resultImageLength,60L);
    
            result.OK(resultMap);
            return result;
        }
    
    public static Map<String,Object> createImage(String urlStr, int L, Integer W, Map<String,Object> resultMap){
            try {
                 int targetLength=56;//小图长
                 int targetWidth=40;//小图宽
                //new 一个URL对象
                URL url = new URL(urlStr);
                //打开链接
                HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                //设置请求方式为"GET"
                conn.setRequestMethod("GET");
                //超时响应时间为5秒
                conn.setConnectTimeout(5 * 1000);
                //通过输入流获取图片数据
                if(conn.getResponseCode()==200) {
                    InputStream inStream = conn.getInputStream();
    
                    BufferedImage bufferedImage = ImageIO.read(new BufferedInputStream(inStream));
                    BufferedImage target= new BufferedImage(targetLength, targetWidth, BufferedImage.TYPE_4BYTE_ABGR);
    
                    cutByTemplate(bufferedImage,target,getBlockData(targetLength,targetWidth),targetLength, targetWidth,L,W);
    
                    //OutputStream os = response.getOutputStream();
    
                    //原始 大图
    //                if(type == 1) {
    //                    //ImageIO.write(bufferedImage, "jpg", os);
    //                }
    
                    BufferedImage srcImage = simpleBlur(bufferedImage, null);
                    //模糊处理 大图
    //                if(type ==2) {
    //                    //ImageIO.write(srcImage, "jpg", os);
    //                }
    //
    //                //压缩  大图
    //                if(type == 3) {
    //                    //fromBufferedImage2(srcImage, "jpg", response);
    //                }
                    byte[] bigImages = fromBufferedImage2(srcImage, "jpg");
                    //小图
    //                if(type == 4) {
    //                    //ImageIO.write(target, "jpg", os);
    //                }
                    resultMap.put("b",bigImages);//大图
                    //resultMap.put("b", getImageBytes(srcImage));//大图
                    resultMap.put("s", getImageBytes(target));//小图
                }else {
                    createImage(urlStr, L, W, resultMap);
                }
            } catch (Throwable e) {
                e.printStackTrace();
            }finally{
                return resultMap;
            }
        }
    
    private static void cutByTemplate(BufferedImage oriImage,BufferedImage targetImage, int[][] templateImage,int targetLength,int targetWidth, int x,int y) {
            for (int i = 0; i < targetLength; i++) {
                for (int j = 0; j < targetWidth; j++) {
                    int rgb = templateImage[i][j];
                    // 原图中对应位置变色处理
                    int rgb_ori = oriImage.getRGB(x + i, y + j);
    
                    if (rgb == 1) {
                        //抠图上复制对应颜色值
                        targetImage.setRGB(i, j, rgb_ori);
                        String hexStr = randomHexString(6);
                        //原图对应位置颜色变化
    
                        //int r = (0xff & rgb_ori);
                        //int g = (0xff & (rgb_ori >> 8));
                        //int b = (0xff & (rgb_ori >> 16));
                        //rgb_ori = r + (g << 8) + (b << 16) + (200 << 22);
                        //oriImage.setRGB(x + i, y + j, rgb_ori );
                        oriImage.setRGB(x + i, y + j, rgb_ori + Integer.parseInt(hexStr, 16));
                        //oriImage.setRGB(x + i, y + j,rgb_ori & 0x363636);
                    } else{
                        //这里把背景设为透明
                        targetImage.setRGB(i, j, rgb_ori & 0x00ffffff);
                        //oriImage.setRGB(x + i, y + j, rgb_ori & 0x363636 );
                    }
                }
            }
        }
    
    private static int[][] getBlockData( int targetLength, int targetWidth) {
    
             int circleR=6;//半径
             int r1=3;//距离点
            int[][] data = new int[targetLength][targetWidth];
            double x2 = targetLength - circleR;
    
            //随机生成圆的位置
            double h1 = circleR + Math.random() * (targetWidth - 3 * circleR - r1);
            double po = circleR * circleR;
    
            double xbegin = targetLength - circleR - r1;
            double ybegin = targetWidth - circleR - r1;
    
            for (int i = 0; i < targetLength; i++) {
                for (int j = 0; j < targetWidth; j++) {
                    double d3 = Math.pow(i - x2, 2) + Math.pow(j - h1, 2);
                    double d2 = Math.pow(j - 2, 2) + Math.pow(i - h1, 2);
                    if ((j <= ybegin && d2 <= po) || (i >= xbegin && d3 >= po)) {
                        data[i][j] = 0;
                    } else {
                        data[i][j] = 1;
                    }
    
                }
            }
            return data;
        }
    
    public static String randomHexString(int len)  {
            try {
                StringBuffer result = new StringBuffer();
                for(int i=0;i<len;i++) {
                    result.append(Integer.toHexString(new Random().nextInt(5)+1));
                }
                return result.toString().toUpperCase();
    
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
    
            }
            return null;
        }
    
    public static byte[] fromBufferedImage2(BufferedImage img,String imageType) throws IOException {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            bos.reset();
            // 得到指定Format图片的writer
            Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName(imageType);
            ImageWriter writer = (ImageWriter) iter.next();
    
            // 得到指定writer的输出参数设置(ImageWriteParam )
            ImageWriteParam iwp = writer.getDefaultWriteParam();
            iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); // 设置可否压缩
            iwp.setCompressionQuality(1f); // 设置压缩质量参数
            iwp.setProgressiveMode(ImageWriteParam.MODE_DISABLED);
    
            ColorModel colorModel = ColorModel.getRGBdefault();
            // 指定压缩时使用的色彩模式
            iwp.setDestinationType(new javax.imageio.ImageTypeSpecifier(colorModel,
                    colorModel.createCompatibleSampleModel(16, 16)));
    
            writer.setOutput(ImageIO.createImageOutputStream(bos));
            IIOImage iImage = new IIOImage(img, null, null);
            writer.write(null, iImage, iwp);
    
            byte[] d = bos.toByteArray();
    
            //ByteArrayInputStream in = new ByteArrayInputStream(d);    //将b作为输入流;
    
            //BufferedImage image = ImageIO.read(in);
    
            //OutputStream os = response.getOutputStream();
            //大图
            //ImageIO.write(image, "jpg", os);
    
            return d;
        }
    
    public static BufferedImage simpleBlur(BufferedImage src,BufferedImage dest) {
            BufferedImageOp op = getGaussianBlurFilter(2,false);
            dest = op.filter(src, dest);
            return dest;
        }
    
    public static ConvolveOp getGaussianBlurFilter(int radius,
                                                       boolean horizontal) {
            if (radius < 1) {
                throw new IllegalArgumentException("Radius must be >= 1");
            }
    
            int size = radius * 2 + 1;
            float[] data = new float[size];
    
            float sigma = radius / 3.0f;
            float twoSigmaSquare = 2.0f * sigma * sigma;
            float sigmaRoot = (float) Math.sqrt(twoSigmaSquare * Math.PI);
            float total = 0.0f;
    
            for (int i = -radius; i <= radius; i++) {
                float distance = i * i;
                int index = i + radius;
                data[index] = (float) Math.exp(-distance / twoSigmaSquare) / sigmaRoot;
                total += data[index];
            }
    
            for (int i = 0; i < data.length; i++) {
                data[i] /= total;
            }
    
            Kernel kernel = null;
            if (horizontal) {
                kernel = new Kernel(size, 1, data);
            } else {
                kernel = new Kernel(1, size, data);
            }
            return new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
        }
    
    public static byte[] getImageBytes(BufferedImage image) throws IOException {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ImageIO.write(image,"png",out);
            byte[] b = out.toByteArray();//转成byte数组
           // BASE64Encoder encoder = new BASE64Encoder();
            return b;//生成base64编码
        }
    

    校验

    //校验 滑动图片 验证码, 校验成功以后  发送短信
        @RequestMapping(value = "/verifyImageCode.json", method = RequestMethod.POST)
        @ResponseBody
        public Result verifyImageCode(HttpSession session,String userId,Long orgId,String phone,String index){
            Result result = new Result();
            try {
                //校验验证码
                String sessionId = session.getId();
    
                logger.info("校验滑动图片,sessionId={},userId={},phone={},index={}",sessionId,userId,phone,index);
    
                String key = StringUtil.join("_",userId,sessionId,phone,"YOUZAN");
                Integer value = RedisKit.getCache(key);
    
                if(null == value){
                    result.setCode(Result.STATUS_ERROR);
                    result.setMsg("验证失败!!!");
                    return  result;
                }
    
                //删除key
                RedisKit.deleteCache(key);
                //误差范围为+-2
                //不在误差范围内
                if(Math.abs(Double.valueOf(value)-Double.valueOf(index))>2){
                    result.setCode(Result.STATUS_ERROR);
                    result.setMsg("验证失败!!!");
                    return  result;
                }
    
                result.OK("验证通过,短信验证码已发送");
                // 校验成功以后,发送短信
                smsService.sendSmsCode(orgId,"YOUZAN",phone);
    
            } catch (Exception e) {
                logger.error("发送短信验证码失败,{}",e);
            }
            return  result;
        }
    

    4、工具类

    package com.vendor.util.msg;
    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.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.util.Arrays;
    import java.util.Random;
    import javax.imageio.ImageIO;
    
    
    /**
     * Created by zhangkai on 2019/2/16.
     */
    public class VerifyCodeUtils {
        // 使用到Algerian字体,系统里没有的话需要安装字体,字体只显示大写,去掉了1,0,i,o几个容易混淆的字符
        public static final String VERIFY_CODES = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
        private static Random random = new Random();
    
        /**
         * 使用系统默认字符源生成验证码
         *
         * @param verifySize
         *            验证码长度
         * @return
         */
        public static String generateVerifyCode(int verifySize) {
            return generateVerifyCode(verifySize, VERIFY_CODES);
        }
    
        /**
         * 使用指定源生成验证码
         *
         * @param verifySize
         *            验证码长度
         * @param sources
         *            验证码字符源
         * @return
         */
        public static String generateVerifyCode(int verifySize, String sources) {
            if (sources == null || sources.length() == 0) {
                sources = VERIFY_CODES;
            }
            int codesLen = sources.length();
            Random rand = new Random(System.currentTimeMillis());
            StringBuilder verifyCode = new StringBuilder(verifySize);
            for (int i = 0; i < verifySize; i++) {
                verifyCode.append(sources.charAt(rand.nextInt(codesLen - 1)));
            }
            return verifyCode.toString();
        }
    
        /**
         * 生成随机验证码文件,并返回验证码值
         *
         * @param w
         * @param h
         * @param outputFile
         * @param verifySize
         * @return
         * @throws IOException
         */
        public static String outputVerifyImage(int w, int h, File outputFile, int verifySize) throws IOException {
            String verifyCode = generateVerifyCode(verifySize);
            outputImage(w, h, outputFile, verifyCode);
            return verifyCode;
        }
    
        /**
         * 输出随机验证码图片流,并返回验证码值
         *
         * @param w
         * @param h
         * @param os
         * @param verifySize
         * @return
         * @throws IOException
         */
        public static String outputVerifyImage(int w, int h, OutputStream os, int verifySize) throws IOException {
            String verifyCode = generateVerifyCode(verifySize);
            outputImage(w, h, os, verifyCode);
            return verifyCode;
        }
    
        /**
         * 生成指定验证码图像文件
         *
         * @param w
         * @param h
         * @param outputFile
         * @param code
         * @throws IOException
         */
        public static void outputImage(int w, int h, File outputFile, String code) throws IOException {
            if (outputFile == null) {
                return;
            }
            File dir = outputFile.getParentFile();
            if (!dir.exists()) {
                dir.mkdirs();
            }
            try {
                outputFile.createNewFile();
                FileOutputStream fos = new FileOutputStream(outputFile);
                outputImage(w, h, fos, code);
                fos.close();
            } catch (IOException e) {
                throw e;
            }
        }
    
        /**
         * 输出指定验证码图片流
         *
         * @param w
         * @param h
         * @param os
         * @param code
         * @throws IOException
         */
        public static void outputImage(int w, int h, OutputStream os, String code) throws IOException {
            int verifySize = code.length();
            BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
            Random rand = new Random();
            Graphics2D g2 = image.createGraphics();
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            Color[] colors = new Color[5];
            Color[] colorSpaces = new Color[] { Color.WHITE, Color.CYAN, Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE, Color.PINK, Color.YELLOW };
            float[] fractions = new float[colors.length];
            for (int i = 0; i < colors.length; i++) {
                colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)];
                fractions[i] = rand.nextFloat();
            }
            Arrays.sort(fractions);
    
            g2.setColor(Color.GRAY);// 设置边框色
            g2.fillRect(0, 0, w, h);
    
            Color c = getRandColor(200, 250);
            g2.setColor(c);// 设置背景色
            g2.fillRect(0, 2, w, h - 4);
    
            // 绘制干扰线
            Random random = new Random();
            g2.setColor(getRandColor(160, 200));// 设置线条的颜色
            for (int i = 0; i < 20; i++) {
                int x = random.nextInt(w - 1);
                int y = random.nextInt(h - 1);
                int xl = random.nextInt(6) + 1;
                int yl = random.nextInt(12) + 1;
                g2.drawLine(x, y, x + xl + 40, y + yl + 20);
            }
    
            // 添加噪点
            float yawpRate = 0.05f;// 噪声率
            int area = (int) (yawpRate * w * h);
            for (int i = 0; i < area; i++) {
                int x = random.nextInt(w);
                int y = random.nextInt(h);
                int rgb = getRandomIntColor();
                image.setRGB(x, y, rgb);
            }
    
            shear(g2, w, h, c);// 使图片扭曲
    
            g2.setColor(getRandColor(100, 160));
            int fontSize = h - 4;
            Font font = new Font("Algerian", Font.ITALIC, fontSize);
            g2.setFont(font);
            char[] chars = code.toCharArray();
            for (int i = 0; i < verifySize; i++) {
                AffineTransform affine = new AffineTransform();
                affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1), (w / verifySize) * i + fontSize / 2, h / 2);
                g2.setTransform(affine);
                g2.drawChars(chars, i, 1, ((w - 10) / verifySize) * i + 5, h / 2 + fontSize / 2 - 10);
            }
    
            g2.dispose();
            ImageIO.write(image, "jpg", os);
        }
    
        private static Color getRandColor(int fc, int bc) {
            if (fc > 255)
                fc = 255;
            if (bc > 255)
                bc = 255;
            int r = fc + random.nextInt(bc - fc);
            int g = fc + random.nextInt(bc - fc);
            int b = fc + random.nextInt(bc - fc);
            return new Color(r, g, b);
        }
    
        private static int getRandomIntColor() {
            int[] rgb = getRandomRgb();
            int color = 0;
            for (int c : rgb) {
                color = color << 8;
                color = color | c;
            }
            return color;
        }
    
        private static int[] getRandomRgb() {
            int[] rgb = new int[3];
            for (int i = 0; i < 3; i++) {
                rgb[i] = random.nextInt(255);
            }
            return rgb;
        }
    
        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; // 50;
    
            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);
                }
    
            }
    
        }
    
        /*
         * public static void main(String[] args) throws IOException { File dir =
         * new File("F:/verifies"); int w = 200, h = 80; for (int i = 0; i < 50;
         * i++) { String verifyCode = generateVerifyCode(4); File file = new
         * File(dir, verifyCode + ".jpg"); outputImage(w, h, file, verifyCode); } }
         */
    }
    
    
    

    相关文章

      网友评论

        本文标题:Java图片验证码

        本文链接:https://www.haomeiwen.com/subject/opyrwqtx.html