Generate a QR code with logo

effect

 

ready:

<dependency>
     <groupId>com.google.zxing</groupId>
     <artifactId>javase</artifactId>
     <version>3.4.0</version>
</dependency>

 

 

package com.muzhongyun.sannong.common.utils;

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 org.springframework.util.StringUtils;

import javax.imageio.ImageIO;
import javax.swing.filechooser.FileSystemView;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;


public class CodeUtils {
    /**
     * CODE_WIDTH:二维码宽度,单位像素
     * CODE_HEIGHT:二维码高度,单位像素
     * FRONT_COLOR:二维码前景色,0x000000 表示黑色
     * BACKGROUND_COLOR:二维码背景色,0xFFFFFF 表示白色
     * 演示用 16 进制表示,和前端页面 CSS 的取色是一样的,注意前后景颜色应该对比明显,如常见的黑白
     */
    private static final int CODE_WIDTH = 400;
    private static final int CODE_HEIGHT = 400;
    private static final int FRONT_COLOR = 0x000000;
    private static final int BACKGROUND_COLOR = 0xFFFFFF;

    public static void main(String[] args) {
        String codeContent1 = "www.baidu.com";
        File file = new File("D:/codes");
        String fileName = "z" + System.currentTimeMillis() + ".png";
        createCodeToFile(codeContent1, file, fileName, "只要我们可以好好学习java,我们一定可以成为大神!");

    }


    /**
     * 生成二维码 并 保存为图片
     */
    /**
     * @param codeContent :二维码参数内容,如果是一个网页地址,如 https://www.baidu.com/ 则 微信扫一扫会直接进入此地址
     *                    如果是一些参数,如 1541656080837,则微信扫一扫会直接回显这些参数值
     * @param codeSaveUrl :二维码图片保存的目录,如 D:/codes
     * @param fileName    :二维码图片文件名称,带格式,如 123.png
     */
    public static void createCodeToFile(String codeContent, File codeSaveUrl, String fileName, String note) {
        try {
            //判断内容是否为空
            if (!StringUtils.isEmpty(codeContent)) {
                System.out.println("二维码内容为空,请输入内容.....");
                return;
            }
            codeContent = codeContent.trim();//去除内容空格
            //如果地址为空,那么就保存到桌面
            if (codeSaveUrl == null || codeSaveUrl.isFile()) {
                codeSaveUrl = FileSystemView.getFileSystemView().getHomeDirectory();
            }
            if (!codeSaveUrl.exists()) {
                codeSaveUrl.mkdirs();
                System.out.println("二维码图片目录不存在,开始创建...");
            }
            if (StringUtils.isEmpty(fileName)) {
                fileName = new Date().getTime() + ".png";
                System.out.println("二维码图片文件名为空,随机生成 png 格式图片...");
            }

            Map<EncodeHintType, Object> hints = new HashMap();
            //设置字符编码类型
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            /**设置误差校正
             * L = ~7% correction、M = ~15% correction、Q = ~25% correction、H = ~30%
             * 等级不一样,生成的图片也会不一样
             */
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
            //设置二维码边距,单位像素,值越小,二维码距离四周越近
            hints.put(EncodeHintType.MARGIN, 1);

            /**
             * MultiFormatWriter:多格式写入,这是一个工厂类,里面重载了两个 encode 方法,用于写入条形码或二维码
             *      encode(String contents,BarcodeFormat format,int width, int height,Map<EncodeHintType,?> hints)
             *      contents:条形码/二维码内容
             *      format:编码类型,如 条形码,二维码 等
             *      width:码的宽度
             *      height:码的高度
             *      hints:码内容的编码类型
             * BarcodeFormat:枚举该程序包已知的条形码格式,即创建何种码,如 1 维的条形码,2 维的二维码 等
             * BitMatrix:位(比特)矩阵或叫2D矩阵,也就是需要的二维码
             */
            MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
            BitMatrix bitMatrix = multiFormatWriter.encode(codeContent, BarcodeFormat.QR_CODE, CODE_WIDTH, CODE_HEIGHT, hints);
            //BufferedImage  x 横坐标 y纵坐标
            BufferedImage bufferedImage = new BufferedImage(CODE_WIDTH, CODE_HEIGHT, BufferedImage.TYPE_INT_BGR);
            for (int x = 0; x < CODE_WIDTH; x++) {
                for (int y = 0; y < CODE_HEIGHT; y++) {
                    //bufferedImage中的x是横坐标 y是纵坐标
                    //BitMatrix的get(int x, int y) 获取比特矩阵内容,指定位置有值,则返回true,将其设置为前景色,否则设置为背景色
                    bufferedImage.setRGB(x, y, bitMatrix.get(x, y) ? FRONT_COLOR : BACKGROUND_COLOR);
                }
            }

            /**给二维码添加logo*/
            LogoMatrix(bufferedImage, "D:/codes/22.png");
            /**保存二维码图片文件*/
            File codeImgFile = new File(codeSaveUrl, fileName);
            ImageIO.write(bufferedImage, "png", codeImgFile);

            System.out.println("二维码图片生成成功:" + codeImgFile.getPath());


            // 自定义文本描述
            if (!StringUtils.isEmpty(note)) {
                // 新的图片,把带logo的二维码下面加上文字
                BufferedImage outImage = new BufferedImage(400, 445, BufferedImage.TYPE_4BYTE_ABGR);
                Graphics2D outg = outImage.createGraphics();
                // 画二维码到新的面板
                outg.drawImage(bufferedImage, 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight(), null);
                // 画文字到新的面板
                outg.setColor(Color.BLACK);
                outg.setFont(new Font("楷体", Font.BOLD, 30)); // 字体、字型、字号
                int strWidth = outg.getFontMetrics().stringWidth(note);
                Integer height = 400;
                if (strWidth > 399) {
                    //长度过长就截取前面部分
                    // 长度过长就换行
                    String note1 = note.substring(0, note.length() / 2);
                    String note2 = note.substring(note.length() / 2, note.length());
                    int strWidth1 = outg.getFontMetrics().stringWidth(note1);
                    int strWidth2 = outg.getFontMetrics().stringWidth(note2);

                    outg.drawString(note1, 200 - strWidth1 / 2, height + (outImage.getHeight() - height) / 2 + 12);
                    BufferedImage outImage2 = new BufferedImage(400, 485, BufferedImage.TYPE_4BYTE_ABGR);
                    Graphics2D outg2 = outImage2.createGraphics();
                    outg2.drawImage(outImage, 0, 0, outImage.getWidth(), outImage.getHeight(), null);
                    outg2.setColor(Color.BLACK);
                    outg2.setFont(new Font("宋体", Font.BOLD, 30)); // 字体、字型、字号

                    outg2.drawString(note2, 200 - strWidth2 / 2, outImage.getHeight() + (outImage2.getHeight() - outImage.getHeight()) / 2 + 5);
                    outg2.dispose();
                    outImage2.flush();
                    outImage = outImage2;
                } else {
                    outg.drawString(note, 200 - strWidth / 2, height + (outImage.getHeight() - height) / 2 + 12); // 画文字
                }
                outg.dispose();
                outImage.flush();
                bufferedImage = outImage;
            }

            bufferedImage.flush();
            /**
             * 区别就是以一句,输出到输出流中,如果第三个参数是 File,则输出到文件中
             */
            ImageIO.write(bufferedImage, "png", codeImgFile);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static BufferedImage LogoMatrix(BufferedImage matrixImage, String logoUrl) throws IOException {
        /**
         * 读取二维码图片,并构建绘图对象
         */
        Graphics2D g2 = matrixImage.createGraphics();

        int matrixWidth = matrixImage.getWidth();
        int matrixHeigh = matrixImage.getHeight();

        /**
         * 读取Logo图片
         */
        if (StringUtils.isEmpty(logoUrl)){
            throw new IOException("logoUrl地址不能为空.....");
        }
        BufferedImage logo = ImageIO.read(new File(logoUrl));

        //开始绘制图片
        g2.drawImage(logo, matrixWidth / 5 * 2, matrixHeigh / 5 * 2, matrixWidth / 5, matrixHeigh / 5, null);//绘制
        BasicStroke stroke = new BasicStroke(5, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
        g2.setStroke(stroke);// 设置笔画对象
        //指定弧度的圆角矩形
        RoundRectangle2D.Float round = new RoundRectangle2D.Float(matrixWidth / 5 * 2, matrixHeigh / 5 * 2, matrixWidth / 5, matrixHeigh / 5, 20, 20);
        g2.setColor(Color.white);
        g2.draw(round);// 绘制圆弧矩形

        //设置logo 有一道灰色边框
        BasicStroke stroke2 = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
        g2.setStroke(stroke2);// 设置笔画对象
        RoundRectangle2D.Float round2 = new RoundRectangle2D.Float(matrixWidth / 5 * 2 + 2, matrixHeigh / 5 * 2 + 2, matrixWidth / 5 - 4, matrixHeigh / 5 - 4, 20, 20);
        g2.setColor(new Color(128, 128, 128));
        g2.draw(round2);// 绘制圆弧矩形

        g2.dispose();
        matrixImage.flush();
        return matrixImage;
    }

}

 

Guess you like

Origin blog.csdn.net/qq_36138652/article/details/114986021