常用Utils系列之-二维码Utils

常用Utils系列之-二维码Utils

2.二维码生成及结合FastDFS文件服务器储存Utils

这个系列是我总结自己工作中常用的工具类 共享给大家 同时自己也做一个云备份
使用该类的不同组合可以选择进行单独二维码生成.,彩色二维码生成,嵌入logo,二维码嵌入背景图,生成临时文件上传文件服务器以及生成本地文件上传文件服务器等二维码生成功能.

package com.ytkj.teammanager.common.utils;

import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.util.Date;
import java.util.Hashtable;
import java.util.Random;

import javax.imageio.ImageIO;

import com.alibaba.fastjson.JSONObject;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.Result;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.ning.http.util.Base64;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

@Slf4j
public class QRCodeUtils {
    private static final String CHARSET = "utf-8";
    private static final String FORMAT_NAME = "JPG";
    // 二维码尺寸    
    private static final int QRCODE_SIZE = 300;
    // LOGO宽度    
    private static final int WIDTH = 60;
    // LOGO高度    
    private static final int HEIGHT = 60;

    private static RestTemplate restTemplate = new RestTemplate();


    private static BufferedImage createImage(String content, File logoFile,
                                             boolean needCompress) throws Exception {
        Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content,
                BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints);
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        BufferedImage image = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000
                        : 0xFFFFFFFF);
            }
        }
        if (CmUtil.isEmpty(logoFile)) {
            return image;
        }
        // 插入图片    
        QRCodeUtils.insertImage(image, logoFile, needCompress);
        return image;
    }


    private static BufferedImage createColorImage(String content, File logoFile,
                                                  boolean needCompress) throws Exception {
        Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content,
                BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints);
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        BufferedImage image = new BufferedImage(QRCODE_SIZE, QRCODE_SIZE,
                BufferedImage.TYPE_INT_RGB);
        // 给二维码上色
        int[] pixels = new int[width * height];
        boolean flag1 = true;
        int stopx = 0;
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                if (bitMatrix.get(x, y)) {
                    if (flag1) {
                        flag1 = false;
                    }
                } else {
                    if (!flag1) {
                        stopx = x;
                        break;
                    }
                }
            }
            if (!flag1) {

                break;
            }
        }

        for (int y = 0; y < width; y++) {
            for (int x = 0; x < width; x++) {
                if (bitMatrix.get(x, y)) {
                    if ((x < stopx) && (y < stopx)) {
                        Color color = new Color(231, 144, 56);
                        int colorInt = color.getRGB();
                        pixels[y * QRCODE_SIZE + x] = colorInt;
                    } else {
                        int num1 = (int) (50 - (50.0 - 13.0) / bitMatrix.getHeight() * (y + 1));
                        int num2 = (int) (165 - (165.0 - 72.0) / bitMatrix.getHeight() * (y + 1));
                        int num3 = (int) (162 - (162.0 - 107.0) / bitMatrix.getHeight() * (y + 1));
                        Color color = new Color(num1, num2, num3);
                        int colorInt = color.getRGB();
                        pixels[y * width + x] = colorInt;
                    }
                } else {
                    pixels[y * width + x] = -1;//白色
                }
            }
        }
        if (CmUtil.isEmpty(logoFile)) {
            return image;
        }
        image.getRaster().setDataElements(0, 0, QRCODE_SIZE, QRCODE_SIZE, pixels);
        // 插入图片
        QRCodeUtils.insertImage(image, logoFile, needCompress);
        return image;
    }

    /**
     * 插入LOGO
     *
     * @param source       二维码图片
     * @param logoFile     LOGO图片文件
     * @param needCompress 是否压缩
     * @throws Exception
     */
    private static void insertImage(BufferedImage source, File logoFile,
                                    boolean needCompress) throws Exception {

        if (!logoFile.exists()) {
            System.err.println("" + logoFile + "   该文件不存在!");
            return;
        }
        Image src = ImageIO.read(logoFile);
        int width = src.getWidth(null);
        int height = src.getHeight(null);
        // 压缩LOGO
        if (needCompress) {
            if (width > WIDTH) {
                width = WIDTH;
            }
            if (height > HEIGHT) {
                height = HEIGHT;
            }
            Image image = src.getScaledInstance(width, height,
                    Image.SCALE_SMOOTH);
            BufferedImage tag = new BufferedImage(width, height,
                    BufferedImage.TYPE_INT_RGB);
            Graphics g = tag.getGraphics();
            // 绘制缩小后的图
            g.drawImage(image, 0, 0, null);
            g.dispose();
            src = image;
        }
        // 插入LOGO    
        Graphics2D graph = source.createGraphics();
        int x = (QRCODE_SIZE - width) / 2;
        int y = (QRCODE_SIZE - height) / 2;
        graph.drawImage(src, x, y, width, height, null);
        Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
        graph.setStroke(new BasicStroke(3f));
        graph.draw(shape);
        graph.dispose();
    }

    /**
     * 生成二维码(内嵌LOGO)
     *
     * @param content      内容
     * @param logoFile     LOGO文件
     * @param destPath     存放目录
     * @param needCompress 是否压缩LOGO
     * @throws Exception
     */
    public static String encode(String content, File logoFile, String destPath,
                                boolean needCompress) throws Exception {
        BufferedImage image = QRCodeUtils.createImage(content, logoFile,
                needCompress);
        mkdirs(destPath);
        String file = new Random().nextInt(99999999) + ".jpg";
        ImageIO.write(image, FORMAT_NAME, new File(destPath + "/" + file));
        return file;
    }

    /**
     * 当文件夹不存在时,mkdirs会自动创建多层目录,区别于mkdir.(mkdir如果父目录不存在则会抛出异常)
     *
     * @param destPath 存放目录
     * @date 2013-12-11 上午10:16:36
     */
    public static void mkdirs(String destPath) {
        File file = new File(destPath);
        //当文件夹不存在时,mkdirs会自动创建多层目录,区别于mkdir.(mkdir如果父目录不存在则会抛出异常)    
        if (!file.exists() && !file.isDirectory()) {
            file.mkdirs();
        }
    }

    /**
     * 生成二维码(内嵌LOGO)
     *
     * @param content  内容
     * @param logoFile LOGO文件
     * @param destPath 存储地址
     * @throws Exception
     */
    public static void encode(String content, File logoFile, String destPath)
            throws Exception {
        QRCodeUtils.encode(content, logoFile, destPath, false);
    }

    /**
     * 生成二维码
     *
     * @param content      内容
     * @param destPath     存储地址
     * @param needCompress 是否压缩LOGO
     * @throws Exception
     */
    public static void encode(String content, String destPath,
                              boolean needCompress) throws Exception {
        QRCodeUtils.encode(content, null, destPath, needCompress);
    }

    /**
     * 生成二维码
     *
     * @param content  内容
     * @param destPath 存储地址
     * @throws Exception
     */
    public static String encode(String content, String destPath) throws Exception {
        return QRCodeUtils.encode(content, null, destPath, false);
    }

    /**
     * 生成二维码(内嵌LOGO)
     *
     * @param content      内容
     * @param logoFile     LOGO文件
     * @param output       输出流
     * @param needCompress 是否压缩LOGO
     * @throws Exception
     */
    public static void encode(String content, File logoFile,
                              OutputStream output, boolean needCompress) throws Exception {
        BufferedImage image = QRCodeUtils.createImage(content, logoFile,
                needCompress);
        ImageIO.write(image, FORMAT_NAME, output);
    }

    /**
     * 生成二维码
     *
     * @param content 内容
     * @param output  输出流
     * @throws Exception
     */
    public static void encode(String content, OutputStream output)
            throws Exception {
        QRCodeUtils.encode(content, null, output, false);
    }

    /**
     * 解析二维码
     *
     * @param file 二维码图片
     * @return
     * @throws Exception
     */
    public static String decode(File file) throws Exception {
        BufferedImage image;
        image = ImageIO.read(file);
        if (image == null) {
            return null;
        }
        BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(
                image);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        Result result;
        Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>();
        hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
        result = new MultiFormatReader().decode(bitmap, hints);
        String resultStr = result.getText();
        return resultStr;
    }

    /**
     * 解析二维码
     *
     * @param path 二维码图片地址
     * @return
     * @throws Exception
     */
    public static String decode(String path) throws Exception {
        return QRCodeUtils.decode(new File(path));
    }

    public static void main(String[] args) throws Exception {
        String text = "http://www.baidu.com";  //这里设置自定义网站url
        String logoPath = "C:\\Users\\admin\\Desktop\\test\\test.jpg";
        String destPath = "C:\\Users\\admin\\Desktop\\test\\";
        System.out.println(QRCodeUtils.encode(text, null, destPath, true));
    }


    /**
     * 生成二维码(内嵌LOGO)  并上传到文件服务器(fastDFS服务器)
     * 备注:实际生成了图片后删除
     *
     * @param content        内容
     * @param logoPath       LOGO文件相对位置
     * @param needCompress   是否压缩LOGO
     * @param imageServerUrl 图片服务器上传url
     * @param imageServer    图片服务器ip地址 用于最后拼接URL
     * @param channel        通道 用于区分不同项目路
     * @throws Exception
     */
    public static String encodeAndUpload(String content, String logoPath, boolean needCompress,
                                         String imageServerUrl, String imageServer, String channel) throws Exception {
        log.info("创建BufferedImage图片缓存开始");
        ClassPathResource classPathResource = new ClassPathResource(logoPath);

        InputStream inputStream = classPathResource.getInputStream();
        //生成目标文件
        File logoFile = File.createTempFile("logo_png", "png");
        try {
            FileUtils.copyInputStreamToFile(inputStream, logoFile);
        } finally {
            IOUtils.closeQuietly(inputStream);
        }
        BufferedImage image = QRCodeUtils.createImage(content, logoFile,
                needCompress);
        log.info("创建BufferedImage图片缓存完成");
        log.info("图片上传准备工作开始");
        // 封装文件服务器所需参数

        // 获取创建时间  YY-MM-DD
        String format = GetTimeUtil.format(DateStyle.YYYY_MM_DD.getValue(), new Date());
        String file = new Random().nextInt(99999999) + ".png";
        String path = QRCodeUtils.class.getClassLoader().getResource(".").getPath();
        mkdirs(path);
        String truefile = path + "/" + file;
        File file1 = new File(path + "/" + file);
        ImageIO.write(image, FORMAT_NAME, file1);
        FileSystemResource resource = new FileSystemResource(truefile);
        //设置文件路径(时间戳)
        String savePath = channel + "/" + format + "/" + file + ".png";
        log.info("图片上传准备工作完成");
        log.info("图片上传开始");
        MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
        HttpHeaders headers = new HttpHeaders();
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
        param.add("file", resource);
        param.add("channel", channel);
        param.add("filePath", savePath);
        HttpEntity<MultiValueMap<String, Object>> formEntity = new HttpEntity<>(param, headers);
        Object[] objects = new Object[0];
        ResponseEntity<FileResponseData> result = restTemplate.postForEntity(imageServerUrl, formEntity, FileResponseData.class, objects);

        if (!file1.delete()) {
            log.error("真实图片删除失败,file1.getPath()={}", file1.getPath());
        }

        log.info("图片上传完成,文件服务器响应result={}", JSONObject.toJSONString(result));
        FileResponseData fileResponseData = result.getBody();
        String imgUrl = imageServer + fileResponseData.getFilePath();
        log.info("获取图片URL成功,imgUrl = {}", imgUrl);
        return imgUrl;
    }


    /**
     * 生成二维码(内嵌LOGO)  并上传到文件服务器(fastDFS服务器)
     * 备注:实际生成了临时文件后删除
     *
     * @param content        内容
     * @param logoPath       LOGO地址
     * @param needCompress   是否压缩LOGO
     * @param imageServerUrl 图片服务器上传url
     * @param imageServer    图片服务器ip地址 用于最后拼接URL
     * @param channel        通道 用于区分不同项目路
     * @throws Exception
     */
    public static String encodeTeamFileAndUpload(String content, String logoPath, boolean needCompress,
                                                 String imageServerUrl, String imageServer, String channel) throws Exception {
        log.info("创建BufferedImage图片缓存开始");
        File logoFile = getPngFile(logoPath);
        BufferedImage image = QRCodeUtils.createColorImage(content, logoFile,
                needCompress);
        String bannerPath = "QRcode/banner.png";
        File bannerFile = getPngFile(bannerPath);
        BufferedImage bannerImage = ImageIO.read(bannerFile);

        log.info("创建BufferedImage图片缓存完成");

        log.info("图片上传准备工作开始");
        ByteArrayOutputStream baos = null;
        //构建io 流
        baos = new ByteArrayOutputStream();


        Graphics2D g = bannerImage.createGraphics();


        g.drawImage(image, 150, 300, image.getWidth(), image.getHeight(), null);
        g.dispose();
        ImageIO.write(bannerImage, "png", baos);

        //转换成字节
        byte[] bytes = baos.toByteArray();

        ////转换成base64串
        String imgBase64 = Base64.encode(bytes);


        //删除 \r\n
        imgBase64 = imgBase64.replaceAll("\n", "").replaceAll("\r", "");

        //拼接前缀
        imgBase64 = "data:image/png;base64," + imgBase64;

        // 封装文件服务器所需参数

        // 获取创建时间  YY-MM-DD
        String format = GetTimeUtil.format(DateStyle.YYYY_MM_DD.getValue(), new Date());
        String file = new Random().nextInt(99999999) + ".png";
        //设置文件路径(时间戳)
        String savePath = channel + "/" + format + "/" + file + ".png";
        //base64字符串转化成multipartFile
        MultipartFile multipartFile = BASE64DecodedMultipartFile.base64ToMultipart(imgBase64);
        log.info("图片上传准备工作完成");
        log.info("图片上传开始");
        MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
        HttpHeaders headers = new HttpHeaders();
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());

        //生成临时文件
        File tempFile = null;
        if (multipartFile != null && !StringUtils.isBlank(multipartFile.getOriginalFilename())) {
            headers.setContentType(MediaType.parseMediaType("multipart/form-data;charset=UTF-8"));
            String tempFilePath = System.getProperty("java.io.tmpdir") + multipartFile.getOriginalFilename();
            tempFile = new File(tempFilePath);
            multipartFile.transferTo(tempFile);
            FileSystemResource resource = new FileSystemResource(tempFilePath);
            param.add("file", resource);
        } else {
            param.add("file", (Object) null);
            headers.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8"));
        }
        param.add("channel", channel);
        param.add("filePath", savePath);
        HttpEntity<MultiValueMap<String, Object>> formEntity = new HttpEntity<>(param, headers);
        Object[] objects = new Object[0];
        ResponseEntity<FileResponseData> result = restTemplate.postForEntity(imageServerUrl, formEntity, FileResponseData.class, objects);

        // 关闭流
        baos.close();
        //删除临时文件
        if (tempFile.exists()) {
            System.gc();
            if (!tempFile.delete()) {
                log.error("临时图片删除失败,tempFile.getPath()={}", tempFile.getPath());
            }
        }

        log.info("图片上传完成,文件服务器响应result={}", JSONObject.toJSONString(result));
        FileResponseData fileResponseData = result.getBody();
        String imgUrl = imageServer + fileResponseData.getFilePath();
        log.info("获取图片URL成功,imgUrl = {}", imgUrl);
        return imgUrl;
    }


    /***
     * 二维码嵌套背景图的方法
     *@param bigPath 背景图 - 可传网络地址
     *@param smallPath 二维码地址 - 可传网络地址
     *@param newFilePath 生成新图片的地址
     * @param  x 二维码x坐标
     * @param  y 二维码y坐标
     * */
    public static void mergeImage(String bigPath, String smallPath, String newFilePath, String x, String y) throws IOException {

        try {
            BufferedImage small;
            BufferedImage big;
            if (bigPath.contains("http://") || bigPath.contains("https://")) {
                URL url = new URL(bigPath);
                big = ImageIO.read(url);
            } else {
                big = ImageIO.read(new File(bigPath));
            }


            if (smallPath.contains("http://") || smallPath.contains("https://")) {

                URL url = new URL(smallPath);
                small = ImageIO.read(url);
            } else {
                small = ImageIO.read(new File(smallPath));
            }

            Graphics2D g = big.createGraphics();

            float fx = Float.parseFloat(x);
            float fy = Float.parseFloat(y);
            int x_i = (int) fx;
            int y_i = (int) fy;
            g.drawImage(small, x_i, y_i, small.getWidth(), small.getHeight(), null);
            g.dispose();
            ImageIO.write(big, "png", new File(newFilePath));

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

所用到的返回数据类型 FileResponseData

import lombok.Data;

/**
* ***********************************************************
* Copyright © 2019 远眺科技 Inc.All rights reserved.  *
* ***********************************************************
*

* @generator: IntelliJ IDEA
* @project: team_manager
* @package: com.ytkj.teammanager.common.fileservice
* @name: FileResponseData
* @author: DillonDong
* @email: [email protected]
* @date: 8:43 2020/3/9
* @description: 文件上传服务 回参
*/

@Data
public class FileResponseData {
  private String code;
  private String message;
  private boolean success = true;
  private String filePath;
  private String fileName;
  private String fileType;
  private String httpUrl;
  private String token;

  public FileResponseData() {
  }

  public FileResponseData(boolean success) {
      this.success = success;
  }

  public FileResponseData(boolean success, String code, String message) {
      this.code = code;
      this.message = message;
      this.success = success;
  }
 

时间格式工具类 DateStyle

    public enum DateStyle {

      MM_DD("MM-dd"),
      YYYY_MM("yyyy-MM"),
      YYYY_MM_DD("yyyy-MM-dd"),
      MM_DD_HH_MM("MM-dd HH:mm"),
      MM_DD_HH_MM_SS("MM-dd HH:mm:ss"),
      YYYY_MM_DD_HH_MM("yyyy-MM-dd HH:mm"),
      YYYY_MM_DD_HH_MM_SS("yyyy-MM-dd HH:mm:ss"),
      YYYY_MM_DD_HH_MM_SS_BACK_SANT("yyyy/MM/dd HH:mm:ss"),
      CURRENT_YYYY_MM_DD_TIME_START("yyyy-MM-dd 00:00:00"),
      CURRENT_YYYY_MM_DD_TIME_END("yyyy-MM-dd 23:59:59"),

      MM_DD_EN("MM/dd"),
      YYYY_MM_EN("yyyy/MM"),
      YYYY_MM_DD_EN("yyyy/MM/dd"),
      MM_DD_HH_MM_EN("MM/dd HH:mm"),
      MM_DD_HH_MM_SS_EN("MM/dd HH:mm:ss"),
      YYYY_MM_DD_HH_MM_EN("yyyy/MM/dd HH:mm"),
      YYYY_MM_DD_HH_MM_SS_EN("yyyy/MM/dd HH:mm:ss"),
      CURRENT_YYYY_MM_DD_TIME_START_EN("yyyy/MM/dd 00:00:00"),
      CURRENT_YYYY_MM_DD_TIME_END_EN("yyyy/MM/dd 23:59:59"),

      MM_DD_CN("MM月dd日"),
      YYYY_MM_CN("yyyy年MM月"),
      YYYY_MM_DD_CN("yyyy年MM月dd日"),
      MM_DD_HH_MM_CN("MM月dd日 HH:mm"),
      MM_DD_HH_MM_SS_CN("MM月dd日 HH:mm:ss"),
      YYYY_MM_DD_HH_MM_CN("yyyy年MM月dd日 HH:mm"),
      YYYY_MM_DD_HH_MM_SS_CN("yyyy年MM月dd日 HH:mm:ss"),
      CURRENT_YYYY_MM_DD_TIME_START_CN("yyyy年MM月dd日 00:00:00"),
      CURRENT_YYYY_MM_DD_TIME_END_CN("yyyy年MM月dd日 23:59:59"),

      YYYYMMDDHHMMSS("yyyyMMddHHmmss"),
      YYYYMMDDHHMMSSSSS("yyyyMMddHHmmssSSS"),
      YYYY_MM_DD_HH_MM_SS_SSS_Z("yyyy-MM-dd HH:mm:ss SSS Z"),
      YYYYMM("yyyyMM"),
      YYYYMMDD("yyyyMMdd"),
      CURRENT_YYYYMMDD_TIME_START("yyyyMMdd000000"),
      CURRENT_YYYYMMDD_TIME_END("yyyyMMdd235959"),

      HH_MM("HH:mm"),
      HH_MM_SS("HH:mm:ss");


      private String value;

      DateStyle(String value) {
          this.value = value;
      }

      public String getValue() {
          return value;
      }
  }
}

你可能感兴趣的:(工具类)