1. 程式人生 > 其它 >Java實現建立和解析帶圖示的二維碼

Java實現建立和解析帶圖示的二維碼

二維碼工具類

用到的jar包:

<dependency>
	<groupId>com.google.zxing</groupId>
	<artifactId>core</artifactId>
	<version>${zxingcore.version}</version>
</dependency>

<dependency>
	<groupId>com.google.zxing</groupId>
	<artifactId>javase</artifactId>
	<version>${zxingse.version}</version>
</dependency>

程式碼:

package com.util.qrcode;

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.NotFoundException;
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;

import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.OutputStream;
import java.util.Hashtable;
import javax.imageio.ImageIO;


/**
 * <p>Description: 二維碼工具類</p>
 * <p>Copyright: Copyright (c) 2020</p>
 * @author ZhangLang
 * Create Time: 2020年1月15日 上午11:18:34
 */
public class QRCodeUtil {
    private static final String CHARSET = "utf-8";
    private static final String FORMAT_NAME = "jpg";

    // 二維碼尺寸,畫素
    private int QRCODE_SIZE = 500;

    // LOGO尺寸,畫素
    private int LOGO_SIZE = 166;

    //背景色白色
    private int offColor = 0xFFFFFFFF;

    //前景色,預設黑色
    private int onColor = 0xFF000000;

    /**
     * 設定二維碼顏色
     * @param onColor        16進位制顏色,例如:0xFF000000,0xFF為字首,000000為16進位制顏色
     */
    public void setOnColor(int onColor) {
        this.onColor = onColor;
    }

    /**
     * 設定二維碼大小,預設500
     * @param qRCODE_SIZE 畫素
     */
    public void setQRCodeSize(int qRCODE_SIZE) {
        QRCODE_SIZE = qRCODE_SIZE;
    }

    /**
     * 設定二維碼logo大小, 預設166
     * @param lOGO_SIZE 畫素
     */
    public void setLogoSize(int lOGO_SIZE) {
        LOGO_SIZE = lOGO_SIZE;
    }

    /**
     * Description: 建立資料夾, 當資料夾不存在時,mkdirs會自動建立多層目錄,區別於mkdir.(mkdir如果父目錄不存在則會丟擲異常)
     * Create Time: 2020年1月15日 上午11:34:10
     * @author ZhangLang
     * @param destPath
     */
    private File mkdirs(String destPath) {
        File file = new File(destPath);

        if (!file.exists() && !file.isDirectory()) {
            file.mkdirs();
        }

        return file;
    }

    /**
     * Description: 生成二維碼圖片,並嵌入二維碼logo
     * @param content                二維碼內容
     * @param imgPath                嵌入logo圖片路徑
     * @return
     * @throws Exception
     */
    private BufferedImage createImage(String content, String imgPath)
        throws Exception {
        Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 0);

        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) ? onColor : offColor);
            }
        }
        if ((imgPath == null) || "".equals(imgPath)) {
            return image;
        }
        // 插入圖片
        this.insertImage(image, imgPath, true);
        
        return image;
    }

    /**
     * Description: 向二維碼中插入logo
     * @param source        二維碼圖片
     * @param imgPath        logo路徑
     * @param needCompress        是否需要壓縮logo
     * @throws Exception
     */
    private void insertImage(BufferedImage source, String imgPath,
        boolean needCompress) throws Exception {
        File file = new File(imgPath);

        if (!file.exists()) {
            return;
        }

        Image src = ImageIO.read(new File(imgPath));
        int width = src.getWidth(null);
        int height = src.getHeight(null);

        if (needCompress) { // 壓縮LOGO
           	// logo圖片不要超過二維碼尺寸的50%
            if ((QRCODE_SIZE / 2.5) < LOGO_SIZE) {
                LOGO_SIZE = (int) (QRCODE_SIZE / 2.5);
            }
            width = LOGO_SIZE;
            height = LOGO_SIZE;

            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();
        //給graph帶上反鋸齒屬性
        graph.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        graph.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        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();
    }

    /**
     * Description:        生成帶logo二維碼
     * @param content        內容
     * @param imgPath        logo圖片路徑
     * @param destPath        二維碼圖片儲存路徑
     * @throws Exception
     */
    public File encode(String content, String imgPath, String destPath) {
        File file = null;
        try {
            BufferedImage image = this.createImage(content, imgPath);
            file = mkdirs(destPath);
            ImageIO.write(image, FORMAT_NAME, file);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return file;
    }

    /**
     * Description: 生成普通二維碼
     * @param content        內容
     * @param destPath        二維碼圖片儲存路徑
     * @return
     * @throws Exception
     */
    public File encode(String content, String destPath) {
        return this.encode(content, null, destPath);
    }

    /**
     * Description: 生成帶logo二維碼並寫入output
     * @param content        內容
     * @param imgPath        logo圖片路徑
     * @param output
     * @throws Exception
     */
    public void encode(String content, String imgPath, OutputStream output) {
        try {
            BufferedImage image = this.createImage(content, imgPath);
            ImageIO.write(image, FORMAT_NAME, output);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Description:         生成普通二維碼並寫入output
     * @param content        內容
     * @param output
     * @throws Exception
     */
    public void encode(String content, OutputStream output) {
        this.encode(content, null, output);
    }

    /**
     * Description: 解析二維碼內容
     * @param file 二維碼圖片檔案
     * @return
     * @throws Exception
     */
    public String decode(File file) {
        String resultStr = "";

        try {
            BufferedImage image = ImageIO.read(file);
            if (image == null) {
                return resultStr;
            }

            BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));

            Hashtable<DecodeHintType, String> hints = new Hashtable<DecodeHintType, String>();
            hints.put(DecodeHintType.CHARACTER_SET, CHARSET);

            try {
                Result result = new MultiFormatReader().decode(bitmap, hints);
                resultStr = result.getText();
            } catch (NotFoundException e) {
                //沒有讀取到二維碼內容
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultStr;
    }

    /**
     * Description: 解析二維碼內容
     * @param path 二維碼圖片路徑
     * @return
     * @throws Exception
     */
    public String decode(String path) {
        File file = new File(path);
        if (!file.exists()) {
            return "";
        }
        return this.decode(file);
    }

    public static void main(String[] args) {
        String logoPath = "E:\\qrCode\\saif-icon.png";
        String content = "4004378093";
        QRCodeUtil qrCodeUtil = new QRCodeUtil();
        qrCodeUtil.setOnColor(0xFF333333);
        qrCodeUtil.setLogoSize(166);

        File file = qrCodeUtil.encode(content, logoPath,
                "E:\\qrCode\\qrcode\\qrcode3.png");
        String qrcodePath = file.getAbsolutePath();
        System.out.println("-->" + qrcodePath);

        String result = qrCodeUtil.decode(qrcodePath);
        System.out.println("--->" + result);
    }
}