Java generates and parses QR codes

Foreword: I have done a lot of projects on WeChat official accounts and mobile websites, and I know a little bit about QR codes. When I first received this task, I thought about using QR codes to save texts, so I had to study them first. Let’s take a look at how many things this little QR code can store.
Requirements: Use a QR code to store text (xml, json), and the mobile phone can scan the QR code to obtain the text information.

What is a QR code (network information):

Two-dimensional code is also called two-dimensional bar code. The common two-dimensional code is QR Code , and the full name of QR is Quick Response. It is a very popular encoding method on mobile devices in recent years . It can store more than traditional Bar Code. The information can also represent more data types.
Encoding a two-dimensional code is to convert some given characters and numbers into a specific processed picture, while parsing a two-dimensional code is the opposite, which is to parse an encoded picture into a number or text.
A two-dimensional code can hold up to 1850 capital letters≈ 2710 numbers≈ 1108 bytes≈ more than 500 Chinese characters, which is about tens of times higher than the information capacity of ordinary barcodes.

Development

zxing

The first framework found is google's zxing

<!-- 谷歌 1D/2D条形码图像处理库  -->
<dependency>
  <groupId>com.google.zxing</groupId>
  <artifactId>core</artifactId>
  <version>3.3.0</version>
</dependency>

Operated a wave and wrote a tool QRUtil

import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Shape;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Hashtable;
import javax.imageio.ImageIO;
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;

/**
 * QRCode生成工具类
 * @author: stone
 * @create: 2019-08-08 14:34
 **/
public class QRCodeUtil {

    private static final String CHARSET = "utf-8";
    private static final String FORMAT_NAME = "JPG";
    // 二维码尺寸
    private static final int QRCODE_SIZE = 600;
    // LOGO宽度
    private static final int WIDTH = 60;
    // LOGO高度
    private static final int HEIGHT = 60;

    private static BufferedImage createImage(String content, String imgPath, boolean needCompress) throws Exception {
        Hashtable hints = new Hashtable();
        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 (imgPath == null || "".equals(imgPath)) {
            return image;
        }
        // 插入图片
        QRCodeUtil.insertImage(image, imgPath, needCompress);
        return image;
    }

    private static void insertImage(BufferedImage source, String imgPath, boolean needCompress) throws Exception {
        File file = new File(imgPath);
        if (!file.exists()) {
            System.err.println("" + imgPath + "   该文件不存在!");
            return;
        }
        Image src = ImageIO.read(new File(imgPath));
        int width = src.getWidth(null);
        int height = src.getHeight(null);
        if (needCompress) { // 压缩LOGO
            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();
    }

    public static void encode(String content, String imgPath, String destPath, boolean needCompress) throws Exception {
        BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress);
        mkdirs(destPath);
        // String file = new Random().nextInt(99999999)+".jpg";
        // ImageIO.write(image, FORMAT_NAME, new File(destPath+"/"+file));
        ImageIO.write(image, FORMAT_NAME, new File(destPath));
    }

    public static BufferedImage encode(String content, String imgPath, boolean needCompress) throws Exception {
        BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress);
        return image;
    }

    public static void mkdirs(String destPath) {
        File file = new File(destPath);
        // 当文件夹不存在时,mkdirs会自动创建多层目录,区别于mkdir.(mkdir如果父目录不存在则会抛出异常)
        if (!file.exists() && !file.isDirectory()) {
            file.mkdirs();
        }
    }

    public static void encode(String content, String imgPath, String destPath) throws Exception {
        QRCodeUtil.encode(content, imgPath, destPath, false);
    }

    public static void encode(String content, String destPath) throws Exception {
        QRCodeUtil.encode(content, null, destPath, false);
    }

    public static void encode(String content, String imgPath, OutputStream output, boolean needCompress)
            throws Exception {
        BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress);
        ImageIO.write(image, FORMAT_NAME, output);
    }

    public static void encode(String content, OutputStream output) throws Exception {
        QRCodeUtil.encode(content, null, output, false);
    }

    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 hints = new Hashtable();
        hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
        result = new MultiFormatReader().decode(bitmap, hints);
        String resultStr = result.getText();
        return resultStr;
    }

    public static String decode(String path) throws Exception {
        return QRCodeUtil.decode(new File(path));
    }

    public static void main(String args[]){
        // 存放在二维码中的内容
        String aimTextPath = "E:\\QRCode导出文件夹\\《最长的电影》.txt";
        StringBuilder result = new StringBuilder();
        try{
            FileInputStream fis = new FileInputStream(aimTextPath);
            InputStreamReader isr = new InputStreamReader(fis, "GBK");
            BufferedReader br = new BufferedReader(isr);
            String line = null;
            while ((line = br.readLine()) != null) {
                result.append(line);
                result.append("\r\n"); // 补上换行符
            }

            br.close();
        }catch(Exception e){
            e.printStackTrace();
        }
        String text = result.toString();

        // 嵌入二维码的图片路径
        String imgPath = "E:\\QRCode导出文件夹\\logo.jpg";
        // 生成的二维码的路径及名称
        String destPath = "E:\\QRCode导出文件夹\\img.jpg";
        try {
            //生成二维码
            QRCodeUtil.encode(text, imgPath, destPath, true);
            // 解析二维码
            String str = QRCodeUtil.decode(destPath);
            // 打印出解析出的内容
            System.out.println(str);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

The code is very simple, you can understand it just by looking at it.
After testing, the code that I wrote to parse the QR code is not very efficient. If the content stored in the current QR code is full, this analysis method will report an error. Specifically, zxing cannot read the content. get to the bottom. For example, the following two-dimensional code:
The longest movie lyrics
The full lyrics of the song "The Longest Movie" is stored in it, including 314 characters of line breaks. Since the business is still not very clear, the 314 here are not known at what level, but I feel that they should be enough.
But I was not satisfied with this set of tools, so I found another tool library.

hutool

This is a treasure for Java engineers. There are a variety of utils encapsulated in it. When I first found this tool library, I just laughed... ahem. It also contains the packaging of com.google.zxing. I don’t know if I don’t try it. The packaging method in it is more efficient than what I wrote above... This package is also open source, you can see the specific content inside, but because of our company The project has imported the hutool package, so on this basis, using hutool directly will save the project volume more than I import zxing and package it.
After chattering so much, post the official api of hutool.

Hutool官网:https://hutool.cn/
QrCodeUtil api:https://apidoc.gitee.com/loolly/hutool/

maven quote:

<dependency>
  <groupId>cn.hutool</groupId>
  <artifactId>hutool-all</artifactId>
  <version>4.5.15</version>
</dependency>

Copyright statement: The content of the article is summarized on the Internet. If it violates the rights of the original author, please contact me for deletion or authorization

Guess you like

Origin blog.csdn.net/qq845484236/article/details/98876328