Backend Development 12 min read

Generating and Parsing QR Code Images in Java with ZXing

This article demonstrates how to use Google's ZXing Core library in a Java Maven project to generate QR code images, create random verification codes, and decode QR codes from files, providing complete code examples and step-by-step instructions.

Java Captain
Java Captain
Java Captain
Generating and Parsing QR Code Images in Java with ZXing

Today we need to generate QR code images using Java, so we summarize the process.

Goal: Use Google's ZXing Core library to generate and decode QR codes in Java.

Step 1: Add the ZXing Core dependency to the Maven pom.xml:

com.google.zxing
core
3.3.0

Step 2: Import the core classes. The MatrixToImageWriter class provides methods to convert a BitMatrix to a BufferedImage and write it to a file or stream.

import com.google.zxing.common.BitMatrix;

import javax.imageio.ImageIO;
import java.io.File;
import java.io.OutputStream;
import java.io.IOException;
import java.awt.image.BufferedImage;

/**
 *  用于二维码的生成,由Google提供。
 *
 * Created by Eric on 2017/2/15.
 */
public final class MatrixToImageWriter {

    private static final int BLACK = 0xFF000000;
    private static final int WHITE = 0xFFFFFFFF;

    private MatrixToImageWriter() {}

    public static BufferedImage toBufferedImage(BitMatrix matrix) {
        int width = matrix.getWidth();
        int height = matrix.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, matrix.get(x, y) ? BLACK : WHITE);
            }
        }
        return image;
    }

    public static void writeToFile(BitMatrix matrix, String format, File file)
            throws IOException {
        BufferedImage image = toBufferedImage(matrix);
        if (!ImageIO.write(image, format, file)) {
            throw new IOException("Could not write an image of format " + format + " to " + file);
        }
    }

    public static void writeToStream(BitMatrix matrix, String format, OutputStream stream)
            throws IOException {
        BufferedImage image = toBufferedImage(matrix);
        if (!ImageIO.write(image, format, stream)) {
            throw new IOException("Could not write an image of format " + format);
        }
    }
}

Step 3: The BufferedImageLuminanceSource class implements LuminanceSource for decoding QR code images.

import com.google.zxing.LuminanceSource;

import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;

/**
 * 用于二维码的解析,由Google提供。
 *
 * Created by Eric on 2017/2/15.
 */
public final class BufferedImageLuminanceSource extends LuminanceSource {

    private final BufferedImage image;
    private final int left;
    private final int top;

    public BufferedImageLuminanceSource(BufferedImage image) {
        this(image, 0, 0, image.getWidth(), image.getHeight());
    }

    public BufferedImageLuminanceSource(BufferedImage image, int left, int top, int width, int height) {
        super(width, height);

        int sourceWidth = image.getWidth();
        int sourceHeight = image.getHeight();
        if (left + width > sourceWidth || top + height > sourceHeight) {
            throw new IllegalArgumentException("Crop rectangle does not fit within image data.");
        }

        for (int y = top; y < top + height; y++) {
            for (int x = left; x < left + width; x++) {
                if ((image.getRGB(x, y) & 0xFF000000) == 0) {
                    image.setRGB(x, y, 0xFFFFFFFF); // = white
                }
            }
        }

        this.image = new BufferedImage(sourceWidth, sourceHeight, BufferedImage.TYPE_BYTE_GRAY);
        this.image.getGraphics().drawImage(image, 0, 0, null);
        this.left = left;
        this.top = top;
    }

    @Override
    public byte[] getRow(int y, byte[] row) {
        if (y < 0 || y >= getHeight()) {
            throw new IllegalArgumentException("Requested row is outside the image: " + y);
        }
        int width = getWidth();
        if (row == null || row.length < width) {
            row = new byte[width];
        }
        image.getRaster().getDataElements(left, top + y, width, 1, row);
        return row;
    }

    @Override
    public byte[] getMatrix() {
        int width = getWidth();
        int height = getHeight();
        int area = width * height;
        byte[] matrix = new byte[area];
        image.getRaster().getDataElements(left, top, width, height, matrix);
        return matrix;
    }

    @Override
    public boolean isCropSupported() {
        return true;
    }

    @Override
    public LuminanceSource crop(int left, int top, int width, int height) {
        return new BufferedImageLuminanceSource(image, this.left + left, this.top + top, width, height);
    }

    @Override
    public boolean isRotateSupported() {
        return true;
    }

    @Override
    public LuminanceSource rotateCounterClockwise() {
        int sourceWidth = image.getWidth();
        int sourceHeight = image.getHeight();

        AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, sourceWidth);

        BufferedImage rotatedImage = new BufferedImage(sourceHeight, sourceWidth, BufferedImage.TYPE_BYTE_GRAY);

        Graphics2D g = rotatedImage.createGraphics();
        g.drawImage(image, transform, null);
        g.dispose();

        int width = getWidth();
        return new BufferedImageLuminanceSource(rotatedImage, top, sourceWidth - (left + width), getHeight(), width);
    }
}

Step 4: Implement a method to generate a QR code image with given text, size, and format.

/**
 *  根据内容,生成指定宽高、指定格式的二维码图片
 *
 * @param text   内容
 * @param width  宽
 * @param height 高
 * @param format 图片格式
 * @return 生成的二维码图片路径
 * @throws Exception
 */
private static String generateQRCode(String text, int width, int height, String format) throws Exception {
    Hashtable
hints = new Hashtable<>();
    hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
    BitMatrix bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, hints);
    String pathName = "F:/new.png";
    File outputFile = new File(pathName);
    MatrixToImageWriter.writeToFile(bitMatrix, format, outputFile);
    return pathName;
}

Step 5: Provide a helper method to generate a random alphanumeric verification code of a specified length.

/**
 * 随机生成指定长度的验证码
 *
 * @param length 验证码长度
 * @return 生成的验证码
 */
private static String generateNumCode(int length) {
    String val = "";
    String charStr = "char";
    String numStr = "num";
    Random random = new Random();

    //参数length,表示生成几位随机数
    for (int i = 0; i < length; i++) {
        String charOrNum = random.nextInt(2) % 2 == 0 ? charStr : numStr;
        //输出字母还是数字
        if (charStr.equalsIgnoreCase(charOrNum)) {
            //输出是大写字母还是小写字母
            int temp = random.nextInt(2) % 2 == 0 ? 65 : 97;
            val += (char) (random.nextInt(26) + temp);
        } else if (numStr.equalsIgnoreCase(charOrNum)) {
            val += String.valueOf(random.nextInt(10));
        }
    }
    return val;
}

Step 6: Implement a method to parse a QR code image from a file path and return its content.

/**
 * 解析指定路径下的二维码图片
 *
 * @param filePath 二维码图片路径
 * @return
 */
private static String parseQRCode(String filePath) {
    String content = "";
    try {
        File file = new File(filePath);
        BufferedImage image = ImageIO.read(file);
        LuminanceSource source = new BufferedImageLuminanceSource(image);
        Binarizer binarizer = new HybridBinarizer(source);
        BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);
        Map
hints = new HashMap<>();
        hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
        MultiFormatReader formatReader = new MultiFormatReader();
        Result result = formatReader.decode(binaryBitmap, hints);

        System.out.println("result 为:" + result.toString());
        System.out.println("resultFormat 为:" + result.getBarcodeFormat());
        System.out.println("resultText 为:" + result.getText());
        //设置返回值
        content = result.getText();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return content;
}

Step 7: Test the generation and parsing in a main class.

import com.google.zxing.*;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Random;

/**
 * 利用Google的ZXing工具包,生成和解析二维码图片
 *
* Created by Eric on 2017/2/15.
 */
public class QRCodeEvents {

    public static void main(String[] args) {

        String text = generateNumCode(12);  //随机生成的12位验证码
        System.out.println("随机生成的12位验证码为: " + text);
        int width = 100;    //二维码图片的宽
        int height = 100;   //二维码图片的高
        String format = "png";  //二维码图片的格式

        try {
            //生成二维码图片,并返回图片路径
            String pathName = generateQRCode(text, width, height, format);
            System.out.println("生成二维码的图片路径: " + pathName);

            String content = parseQRCode(pathName);
            System.out.println("解析出二维码的图片的内容为: " + content);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Note: The example classes omit package statements; add appropriate packages as needed.

Reference: Original article https://www.cnblogs.com/xz-luckydog/p/6402568.html and a promotional note about joining a Java learning QQ group.

Javacode generationimage-processingMavenQR CodeZXing
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.