Java實現建立和解析帶圖示的二維碼
阿新 • • 發佈:2021-12-09
二維碼工具類
用到的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); } }