Java生成、解析二维码

今天研究了一下二维码生成和解析,不过这个解析的方法不好,解析会出现错误。

使用QRCode.jar:

package com.test;
 
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
 
import javax.imageio.ImageIO;
 
import jp.sourceforge.qrcode.QRCodeDecoder;
import jp.sourceforge.qrcode.data.QRCodeImage;
 
import com.swetake.util.Qrcode;
 
public class Code {
	
    public static void main(String[] args) {
        encode("http://www.acgist.com", "D:\\code.png", "E:\\workspace\\acgist\\WebRoot\\img\\logo\\logo.png");
        System.out.println(decode("D:\\code.png"));
    }
 
    private final static int PADDING = 10; // 设置边框
    private final static int LINE_WIDTH = 4; // 二维码线条宽度
    private final static int CODE_WH = 184; // 图片高宽,公式:(21 + 4 * (CODE_VERSION - 1)) * LINE_WIDTH + 2 * PADDING
    private final static int LOGO_MAX_WH = 30; // LOGO最大高宽
    private final static int CODE_VERSION = 6; // 数值越大,容纳的信息越多,但是注意适合就好,太大加上LOGO后容易这里的解析方法抛错误,但是其他的二维码软件可以识别
    private final static int CODE_VERSION_MAX_BYTES = 108; // 最大字节大小
 
    /**
     * 生成二维码
     * 
     * @param msg 二维码图片的内容
     * @param codePath 生成二维码图片完整的路径
     * @param logoPath 二维码图片中间的logo路径
     */
    public static void encode(String msg, String codePath, String logoPath) {
        Graphics2D graphics2d = null;
        BufferedImage logoImage = null;
        BufferedImage codeImage = null;
        try {
            Qrcode qrcode = new Qrcode();
            qrcode.setQrcodeEncodeMode('B'); // 编码方式
            qrcode.setQrcodeErrorCorrect('M'); // 容错级别
            qrcode.setQrcodeVersion(CODE_VERSION);
            byte[] msgBytes = msg.getBytes("UTF-8");
            codeImage = new BufferedImage(CODE_WH, CODE_WH, BufferedImage.TYPE_INT_RGB);
            graphics2d = codeImage.createGraphics();
            graphics2d.setBackground(Color.WHITE);
            graphics2d.clearRect(0, 0, CODE_WH, CODE_WH);
            graphics2d.setColor(Color.BLACK);
            if (msgBytes.length > 0 && msgBytes.length < CODE_VERSION_MAX_BYTES) {
                boolean[][] codeOut = qrcode.calQrcode(msgBytes);
                for (int i = 0; i < codeOut.length; i++) {
                    for (int j = 0; j < codeOut.length; j++) {
                        if (codeOut[j][i]) {
                            graphics2d.fillRect(j * LINE_WIDTH + PADDING, i * LINE_WIDTH + PADDING, LINE_WIDTH, LINE_WIDTH);
                        }
                    }
                }
            } else {
                throw new RuntimeException("内容太长:" + msg);
            }
            if (logoPath != null) {
                logoImage = ImageIO.read(new File(logoPath));// 实例化一个Image对象。
                int w = logoImage.getWidth() > LOGO_MAX_WH ? LOGO_MAX_WH : logoImage.getWidth();
                int h = logoImage.getHeight() > LOGO_MAX_WH ? LOGO_MAX_WH : logoImage.getHeight();
                int pw = (CODE_WH - w) / 2;
                int ph = (CODE_WH - h) / 2;
                graphics2d.drawImage(logoImage.getScaledInstance(w, h, Image.SCALE_SMOOTH), pw, ph, null);
            }
            codeImage.flush();
            ImageIO.write(codeImage, "png", new File(codePath));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (graphics2d != null)
                graphics2d.dispose();
        }
    }
 
    /**
     * 解析二维码
     * 
     * @param codePath 解析二维码文件路径
     * @return 内容
     */
    public static String decode(String codePath) {
        File codeFile = new File(codePath);
        String msg = null;
        try {
            final BufferedImage codeImage = ImageIO.read(codeFile);
            QRCodeDecoder decoder = new QRCodeDecoder();
            msg = new String(decoder.decode(new QRCodeImage() {
                @Override
                public int getWidth() {
                    return codeImage.getWidth();
                }
                @Override
                public int getHeight() {
                    return codeImage.getHeight();
                }
                @Override
                public int getPixel(int x, int y) {
                    return codeImage.getRGB(x, y);
                }
            }));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return msg;
    }
 
}

效果:

ACGIST二维码

注意:一定要注意设置CODE_VERSION这个参数,如果设置不恰当很容易导致上面的解析方法抛出异常或者解析乱码。

Exception in thread "main" java.lang.IllegalStateException: This method must be called after QRCodeImageReader.getQRCodeSymbol() called
    at jp.sourceforge.qrcode.reader.QRCodeImageReader.getQRCodeSymbolWithAdjustedGrid(QRCodeImageReader.java:239)
    at jp.sourceforge.qrcode.QRCodeDecoder.decode(QRCodeDecoder.java:140)
    at jp.sourceforge.qrcode.QRCodeDecoder.decode(QRCodeDecoder.java:68)

参考文章:http://blog.csdn.net/wangpeng047/article/details/7181217