使用Zxing生成带Logo且底部带文字的二维码

1、引入依赖


<dependency>
    <groupId>com.google.zxinggroupId>
    <artifactId>coreartifactId>
    <version>3.4.1version>
dependency>

2、生成二维码

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
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.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class QRCodeGenerator {

    // 二维码尺寸
    private static final int QRCODE_SIZE = 512;
    // logo尺寸
    private static final int LOGO_SIZE = 200;
    // logo圆角
    private static final int LOGO_BORDER_RADIUS = 25;
    // 背景色
    private static final Color BACKGROUND_COLOR = new Color(230, 132, 72);
    // 字体颜色
    private static final Color TEXT_COLOR = Color.BLACK;
    // 图片padding
    private static final int PADDING = 20;
    // 底部文字大小
    private static int FONT_SIZE = 22;

    /**
     * 生成带底部文字的二维码
     *
     * @param content    二维码内容
     * @param text       底部文字
     * @param outputFile 输出文件
     */
    public static void generateQRCodeWithText(String content, String text, String logo, File outputFile) throws WriterException, IOException {
        // 创建二维码
        BufferedImage qrImage = createQRCode(content);

        // 计算最终图片高度(二维码高度 + 文字区域高度)
        int height = PADDING + qrImage.getHeight() + FONT_SIZE + PADDING;
        int width = PADDING + qrImage.getWidth() + PADDING;

        // 创建新的BufferedImage,包含二维码和文字区域
        BufferedImage combinedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = combinedImage.createGraphics();

        // 设置背景为白色
        g.setColor(BACKGROUND_COLOR);
        // 填充整个图片区域
        g.fillRect(0, 0, width, height);

        // 绘制二维码到新图片的上部
        g.drawImage(qrImage, PADDING, PADDING, null);

        // 绘制logo
        if (StringUtils.isNotBlank(logo)) {
            BufferedImage logoImg = ImageIO.read(new File(logo));
            // 设置logo宽高
            logoImg = resizeImageHighQuality(logoImg, LOGO_SIZE, LOGO_SIZE);
            // 设置logo圆角
            logoImg = createRoundedCornerImage(logoImg, LOGO_BORDER_RADIUS);
            g.drawImage(logoImg, PADDING + qrImage.getWidth() / 2 - LOGO_SIZE / 2, PADDING + qrImage.getHeight() / 2 - LOGO_SIZE / 2, null);
        }

        // 设置文字样式
        String fontName = "Microsoft YaHei";
        // 尝试加载字体,如果找不到则使用默认字体
        Font font;
        try {
            font = new Font(fontName, Font.PLAIN, FONT_SIZE);
        } catch (Exception e) {
            font = new Font("Arial", Font.PLAIN, FONT_SIZE);
            System.err.println("警告: 无法加载中文字体 " + fontName + ", 使用默认字体");
        }
        g.setColor(TEXT_COLOR);
        g.setFont(new Font(fontName, Font.BOLD, FONT_SIZE));

        // 计算文字位置(居中)
        FontMetrics fontMetrics = g.getFontMetrics();
        int textWidth = fontMetrics.stringWidth(text);
        // 如果文字太长,自动缩小字体,左右各留10像素边距
        int maxTextWidth = width - PADDING * 2;
        while (textWidth > maxTextWidth && FONT_SIZE > 8) {
            FONT_SIZE--;
            font = new Font(fontName, Font.PLAIN, FONT_SIZE);
            g.setFont(font);
            fontMetrics = g.getFontMetrics();
            textWidth = fontMetrics.stringWidth(text);
        }
        int x = (width - textWidth) / 2;
        int y = PADDING + qrImage.getHeight() + (height - PADDING - qrImage.getHeight()) / 2 + fontMetrics.getAscent() / 4;

        // 绘制文字
        g.drawString(text, x, y);
        g.dispose();

        // 保存图片
        ImageIO.write(combinedImage, "png", outputFile);
    }

    /**
     * 创建基本二维码图片
     *
     * @param content 二维码内容
     * @return BufferedImage
     * @throws WriterException
     */
    private static BufferedImage createQRCode(String content) throws WriterException {
        Map<EncodeHintType, Object> hints = new HashMap<>();
        // 高容错率
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        // 二维码边距
        hints.put(EncodeHintType.MARGIN, 0);

        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        BitMatrix bitMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints);

        BufferedImage image = new BufferedImage(QRCODE_SIZE, QRCODE_SIZE, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < QRCODE_SIZE; x++) {
            for (int y = 0; y < QRCODE_SIZE; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? TEXT_COLOR.getRGB() : BACKGROUND_COLOR.getRGB());
            }
        }

        return image;
    }

    /**
     * 设置图像宽高
     */
    private static BufferedImage resizeImageHighQuality(BufferedImage original, int targetWidth, int targetHeight) {
        BufferedImage resized = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = resized.createGraphics();

        // 设置抗锯齿和高质量渲染
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        g.drawImage(original, 0, 0, targetWidth, targetHeight, null);
        g.dispose();

        return resized;
    }

    /**
     * 创建圆角图像
     */
    private static BufferedImage createRoundedCornerImage(BufferedImage original, int arcSize) {
        int width = original.getWidth();
        int height = original.getHeight();

        // 创建新的空白图像,支持透明度
        BufferedImage rounded = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);

        // 启用抗锯齿
        Graphics2D g2d = rounded.createGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // 绘制圆角矩形路径并裁剪
        RoundRectangle2D roundRect = new RoundRectangle2D.Float(0, 0, width, height, arcSize, arcSize);
        g2d.setClip(roundRect);

        // 绘制原始图像
        g2d.drawImage(original, 0, 0, null);
        g2d.dispose();

        return rounded;
    }

    public static void main(String[] args) throws IOException, WriterException {
        String content = "https://www.baidu.com";
        String text = "百度一下,你就知道";
        File outputFile = new File("E:\\DeskTop\\baidu.png");

        generateQRCodeWithText(content, text, "E:\\DeskTop\\logo.png", outputFile);
        System.out.println("二维码已生成到: " + outputFile.getAbsolutePath());
    }
}

3、效果预览

使用Zxing生成带Logo且底部带文字的二维码_第1张图片

如您在阅读中发现不足,欢迎留言!!!

你可能感兴趣的:(使用Zxing生成带Logo且底部带文字的二维码)