java生成二维码工具类

POM依赖

        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.5.3</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.13.3</version>
        </dependency>

工具类代码

package com.common.util;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.itextpdf.text.Document;
import com.itextpdf.text.pdf.PdfWriter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.net.URLDecoder;
import java.nio.file.Paths;
import java.util.*;
import java.util.List;

/**
 * @program: dict-uomp_git
 * @description: 二维码工具类
 * @author: huang wei
 * @create: 2025-12-11 17:11
 */
@Slf4j
public class QrCodeUtil {
    /**
     * 默认编码方式
     */
    private static final String DEFAULT_CHARSET = "UTF-8";
    /**
     * 默认二维码图片格式
     */
    private static final String DEFAULT_SUBFIX = "png";
    /**
     * 生成二维码默认宽度
     */
    private static final int DEFAULT_WIDTH = 260;
    /**
     * 生成二维码默认高度
     */
    private static final int DEFAULT_HEIGHT = 300;
    /**
     * 默认二维码中间log宽度
     */
    private static final int DEFAULT_LOG_WIDTH = 50;
    /**
     * 默认二维码中间log高度
     */
    private static final int DEFAULT_LOG_HEIGHT = 50;
    /**
     * log默认路径
     */
    private static final String DEFAULT_LOG_PATH = QrCodeUtil.class.getClassLoader().getResource("uomp-logo.png").getPath();


    /**
    * @Description: 获取base64格式简单二维码
    * @author: hw
    * @date: 2025/12/12 10:20
    */
    public static String getQRCode(String data) {
        BufferedImage bufferedImage = generateQRCode(data,DEFAULT_WIDTH,DEFAULT_HEIGHT);
        return trans2Base64(bufferedImage);
    }
    /**
     * @Description: 获取base64格式二维码,带LOGO图标
     * @author: hw
     * @date: 2025/12/12 10:20
     */
    public static String getQRCodeWithLogo(String data) {
        BufferedImage bufferedImage = generateQRCode(data,DEFAULT_WIDTH,DEFAULT_HEIGHT);
        generateQRCodeWithLogo(bufferedImage, DEFAULT_WIDTH, DEFAULT_HEIGHT);
        return trans2Base64(bufferedImage);
    }
    /**
     * @Description: 获取base64格式二维码,带底部文字
     * @author: hw
     * @date: 2025/12/12 10:20
     */
    public static String getQRCodeWithText(String data, String text) {
        BufferedImage bufferedImage = generateQRCode(data,DEFAULT_WIDTH,DEFAULT_HEIGHT);
        generateQRCodeWithText(bufferedImage, DEFAULT_WIDTH, DEFAULT_HEIGHT, text);
        return trans2Base64(bufferedImage);
    }
    /**
     * @Description: 获取base64格式二维码,带LOGO图标+底部文字
     * @author: hw
     * @date: 2025/12/12 10:21
     */
    public static String getQRCodeWithLogoAndText(String data, String text) {
        BufferedImage bufferedImage = generateQRCode(data,DEFAULT_WIDTH,DEFAULT_HEIGHT);
        generateQRCodeWithLogo(bufferedImage, DEFAULT_WIDTH, DEFAULT_HEIGHT);
        generateQRCodeWithText(bufferedImage, DEFAULT_WIDTH, DEFAULT_HEIGHT, text);
        return trans2Base64(bufferedImage);
    }


    /**
     * @Description: 生成base64格式的二维码
     * @Param:
     * @return:
     * @author: hw
     * @date: 2025/12/12 10:06
     */
    private static String trans2Base64(BufferedImage bufferedImage) {
        if (bufferedImage == null) {
            return null;
        }
        try {
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            ImageIO.write(bufferedImage, DEFAULT_SUBFIX, stream);
            String base64 = new String(Base64.getEncoder().encode(stream.toByteArray()));
            stream.close();
            return "data:image/"+DEFAULT_SUBFIX+";base64," +  base64;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 生成简单二维码BufferedImage对象
     * @param data     二维码内容(文本/URL/WiFi配置等)
     * @param width    二维码宽度(像素)
     * @param height   二维码高度(像素)
     * @return
     */
    private static BufferedImage generateQRCode(String data, int width, int height) {
        if (StringUtils.isEmpty(data)) {
            return null;
        }
        try {
            //1.设置二维码生成参数
            Map<EncodeHintType, Object> hints = new HashMap<>();
            hints.put(EncodeHintType.CHARACTER_SET, DEFAULT_CHARSET);
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
            hints.put(EncodeHintType.MARGIN, 1);

            //2.生成二维码矩阵数据
            MultiFormatWriter writer = new MultiFormatWriter();
            BitMatrix bitMatrix = writer.encode(data, BarcodeFormat.QR_CODE, width, height, hints);

            //3.转换为图像对象
            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) ? Color.BLACK.getRGB() : Color.WHITE.getRGB());
                }
            }
            return image;
        } catch (Exception e) {
            log.error("生成简单二维码BufferedImage对象异常", e);
        }
        return null;
    }

    /**
    * @Description: 二维码BufferedImage添加logo图片
    * @Param:
    * @return:
    * @author: hw
    * @date: 2025/12/12 16:07
    */
    private static void generateQRCodeWithLogo(BufferedImage bufferedImage, Integer width, Integer height){
        try {
            // LOGO处理
            String logoPath = URLDecoder.decode(DEFAULT_LOG_PATH, "UTF-8");
            File file = new File(logoPath);
            if (file.exists()) {
                Image logoImage = ImageIO.read(file);
                Image image = logoImage.getScaledInstance(DEFAULT_LOG_WIDTH, DEFAULT_LOG_HEIGHT, Image.SCALE_SMOOTH);
                BufferedImage tag = new BufferedImage(DEFAULT_LOG_WIDTH, DEFAULT_LOG_HEIGHT, BufferedImage.TYPE_INT_RGB);
                Graphics g = tag.getGraphics();
                // 绘制缩小后的图
                g.drawImage(image, 0, 0, null);
                g.dispose();

                // 插入LOGO
                int x = (width - DEFAULT_LOG_WIDTH) / 2;
                int y = (height - DEFAULT_LOG_HEIGHT) / 2;
                Graphics2D graph = bufferedImage.createGraphics();
                graph.drawImage(image, x, y, DEFAULT_LOG_WIDTH, DEFAULT_LOG_HEIGHT, null);
                Shape shape = new RoundRectangle2D.Float(x, y, DEFAULT_LOG_WIDTH, DEFAULT_LOG_HEIGHT, 6, 6);
                graph.setStroke(new BasicStroke(3f));
                graph.draw(shape);
                graph.dispose();
            }
        } catch (Exception e) {
            log.error("二维码BufferedImage添加logo异常", e);
        }
    }

    /**
    * @Description: 二维码BufferedImage添加底部文字
    * @Param:
    * @return:
    * @author: hw
    * @date: 2025/12/12 16:10
    */
    private static void generateQRCodeWithText(BufferedImage bufferedImage, Integer width, Integer height, String text){
        try {
            // 插入底部文本
            if (!StringUtils.isEmpty(text)) {
                int fontStyle = 1;
                int fontSize = 14;
                // 计算文字开始的位置(居中显示)
                // x开始的位置:(图片宽度-字体大小*字的个数)/2
                int startX = (width - (fontSize * text.length())) / 2;
                // y开始的位置:图片高度-(图片高度-图片宽度)/2
//                int startY = height - (height - width)/2;
                int startY = height - fontSize;
                Graphics2D graph = bufferedImage.createGraphics();
                graph.setColor(Color.BLUE);
                // 字体风格与字体大小
                graph.setFont(new Font(null, fontStyle, fontSize));
                graph.drawString(text, startX, startY);
                graph.dispose();
            }
        } catch (Exception e) {
            log.error("二维码BufferedImage添加底部文字异常", e);
        }
    }


    /**
    * @Description: 批量生成二维码
    * @Param: batchData 底部文字(text):转成二维码的文本(data)
    * @return:
    * @author: hw
    * @date: 2025/12/11 17:18
    */
    private static List<BufferedImage> batchGenerateQRCodeWithLogoAndText(Map<String,String> batchData) {
        return batchGenerateQRCodeWithLogoAndText(batchData, DEFAULT_WIDTH, DEFAULT_HEIGHT);
    }
    private static List<BufferedImage> batchGenerateQRCodeWithLogoAndText(Map<String,String> batchData, int width, int height) {
        //1.设置二维码生成参数
        Map<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        hints.put(EncodeHintType.ERROR_CORRECTION, com.google.zxing.qrcode.decoder.ErrorCorrectionLevel.M);
        hints.put(EncodeHintType.MARGIN, 1);

        List<BufferedImage> bufferedImageList = new ArrayList<>();
        for (String text : batchData.keySet()){
            try {
                //2.生成二维码矩阵数据
                MultiFormatWriter writer = new MultiFormatWriter();
                BitMatrix bitMatrix = writer.encode(batchData.get(text), BarcodeFormat.QR_CODE, width, height, hints);

                //3.转换为图像对象
                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) ? Color.BLACK.getRGB() : Color.WHITE.getRGB());
                    }
                }

                // 4.写入logo
                generateQRCodeWithLogo(image, width, height);
                // 5.写入文本
                generateQRCodeWithText(image, width, height, text);

                bufferedImageList.add(image);
            } catch (Exception e) {
                log.error("生成二维码BufferedImage异常: {}", text, e);
            }
        }
        return bufferedImageList;
    }

    /**
    * @Description: 图片导出为PDF
    * @Param:
    * @return:
    * @author: hw
    * @date: 2025/12/15 9:00
    */
    public static void saveImagesToPDF(List<BufferedImage> bufferedImageList, String outputPath){
        Document document = new Document();
        try {
            PdfWriter.getInstance(document, new FileOutputStream(outputPath));
            document.open();
            for (BufferedImage bufferedImage : bufferedImageList) {
                // 创建PDF图片对象
                try {
                    com.itextpdf.text.Image pdfImage = com.itextpdf.text.Image.getInstance(bufferedImage, null);
                    pdfImage.setAlignment(com.itextpdf.text.Image.ALIGN_CENTER);
                    document.add(pdfImage);
                }catch (Exception e){
                    log.error("创建PDF图片对象失败", e);
                }
            }
        } catch (Exception e){
            log.error("图片导出为PDF异常", e);
        } finally {
            document.close();
        }
    }

    public static void main(String[] args) {
        // 生成二维码base64数据
//        String data = "{\"msg\": \"d7572de94b9debc5b4d605697669c4c9\",\"keyNum\": 1,\"algType\": \"SM4\"}";
//        String text = "校园安防-研发测试-大法师-003";
//        System.out.println(getQRCode(data));
//        System.out.println(getQRCodeWithLogo(data));
//        System.out.println(getQRCodeWithText(data, text));
//        System.out.println(getQRCodeWithLogoAndText(data, text));


        // 批量生成二维码并导出为pdf
        String path = Paths.get("").toAbsolutePath().toString();
        String outputPath = path+File.separator+"output.pdf"; // PDF文件的输出路径
        Map<String,String> map = new HashMap<>();
        map.put("校园安防-研发测试-大法师-001","{\"msg\": \"d7572de94b9debc5b4d605697669c4c9\",\"keyNum\": 1,\"algType\": \"SM4\"}");
        map.put("校园安防-研发测试-大法师-002","{\"msg\": \"d7572de94b9debc5b4d605697669c4c9\",\"keyNum\": 1,\"algType\": \"SM4\"}");
        map.put("校园安防-研发测试-大法师-003","{\"msg\": \"d7572de94b9debc5b4d605697669c4c9\",\"keyNum\": 1,\"algType\": \"SM4\"}");
        List<BufferedImage> images = batchGenerateQRCodeWithLogoAndText(map);
        saveImagesToPDF(images, outputPath);
        System.out.println("PDF文件已保存至:" + outputPath);
    }


}

posted @ 2025-12-15 09:22  逐梦寻欢  阅读(24)  评论(0)    收藏  举报