前言
ZXing,一個支持在圖像中解碼和生成條形碼(如二維碼、PDF 417、EAN、UPC、Aztec、Data Matrix、Codabar)的庫。ZXing(“zebra crossing”)是一個開源的、多格式的、用Java實現的一維/二維條碼圖像處理庫,具有到其他語言的端口。
GitHub地址,猛戳:https://github.com/zxing/zxing
API文檔,猛戳:https://zxing.github.io/zxing/apidocs/index.html
介紹文檔,猛戳:https://zxing.github.io/zxing/
代碼編寫
部分代碼參考:https://blog.csdn.net/weixin_39494923/article/details/79058799
maven
我們是java端,所以需要引這兩個
<!-- ZXing --> <dependency> <groupId>com.google.zxing</groupId> <artifactId>core</artifactId> <version>3.3.3</version> </dependency> <dependency> <groupId>com.google.zxing</groupId> <artifactId>javase</artifactId> <version>3.3.3</version> </dependency>
Test.java
public class Test{ public static void main(String[] args) { try { QREncode(); QRReader(new File("D:\\zxing1.gif")); } catch (WriterException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (NotFoundException e) { e.printStackTrace(); } } /** * 生成二維碼 */ public static void QREncode() throws WriterException, IOException { String content = "個人博客:https://www.cnblogs.com/huanzi-qch/";//二維碼內容 int width = 200; // 圖像寬度 int height = 200; // 圖像高度 String format = "gif";// 圖像類型 Map<EncodeHintType, Object> hints = new HashMap<>(); //內容編碼格式 hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // 指定糾錯等級 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); //設置二維碼邊的空度,非負數 hints.put(EncodeHintType.MARGIN, 1); BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints); MatrixToImageWriter.writeToPath(bitMatrix, format, new File("D:\\zxing.gif").toPath());// 輸出原圖片 MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(0xFF000001, 0xFFFFFFFF); /* 問題:生成二維碼正常,生成帶logo的二維碼logo變成黑白 原因:MatrixToImageConfig默認黑白,需要設置BLACK、WHITE 解決:https://ququjioulai.iteye.com/blog/2254382 */ BufferedImage bufferedImage = LogoMatrix(MatrixToImageWriter.toBufferedImage(bitMatrix,matrixToImageConfig), new File("D:\\logo.png")); // BufferedImage bufferedImage = LogoMatrix(toBufferedImage(bitMatrix), new File("D:\\logo.png")); ImageIO.write(bufferedImage, "gif", new File("D:\\zxing1.gif"));//輸出帶logo圖片 System.out.println("輸出成功."); } /** * 識別二維碼 */ public static void QRReader(File file) throws IOException, NotFoundException { MultiFormatReader formatReader = new MultiFormatReader(); //讀取指定的二維碼文件 BufferedImage bufferedImage =ImageIO.read(file); BinaryBitmap binaryBitmap= new BinaryBitmap(new HybridBinarizer(new BufferedImageLuminanceSource(bufferedImage))); //定義二維碼參數 Map hints= new HashMap<>(); hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); com.google.zxing.Result result = formatReader.decode(binaryBitmap, hints); //輸出相關的二維碼信息 System.out.println("解析結果:"+result.toString()); System.out.println("二維碼格式類型:"+result.getBarcodeFormat()); System.out.println("二維碼文本內容:"+result.getText()); bufferedImage.flush(); } /** * 二維碼添加logo * @param matrixImage 源二維碼圖片 * @param logoFile logo圖片 * @return 返回帶有logo的二維碼圖片 * 參考:https://blog.csdn.net/weixin_39494923/article/details/79058799 */ public static BufferedImage LogoMatrix(BufferedImage matrixImage, File logoFile) throws IOException{ /** * 讀取二維碼圖片,並構建繪圖對象 */ Graphics2D g2 = matrixImage.createGraphics(); int matrixWidth = matrixImage.getWidth(); int matrixHeigh = matrixImage.getHeight(); /** * 讀取Logo圖片 */ BufferedImage logo = ImageIO.read(logoFile); //開始繪制圖片 g2.drawImage(logo,matrixWidth/5*2,matrixHeigh/5*2, matrixWidth/5, matrixHeigh/5, null);//繪制 BasicStroke stroke = new BasicStroke(5,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND); g2.setStroke(stroke);// 設置筆畫對象 //指定弧度的圓角矩形 RoundRectangle2D.Float round = new RoundRectangle2D.Float(matrixWidth/5*2, matrixHeigh/5*2, matrixWidth/5, matrixHeigh/5,20,20); g2.setColor(Color.white); g2.draw(round);// 繪制圓弧矩形 //設置logo 有一道灰色邊框 BasicStroke stroke2 = new BasicStroke(1,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND); g2.setStroke(stroke2);// 設置筆畫對象 RoundRectangle2D.Float round2 = new RoundRectangle2D.Float(matrixWidth/5*2+2, matrixHeigh/5*2+2, matrixWidth/5-4, matrixHeigh/5-4,20,20); g2.setColor(new Color(128,128,128)); g2.draw(round2);// 繪制圓弧矩形 g2.dispose(); matrixImage.flush() ; return matrixImage ; } }
效果演示
D盤文件
查看圖片
后台識別、微信掃描結果
后記
后端生成我們可以用ZXing框架,那么前端js又應該如何生成、識別二維碼呢?QRCode.js,QRCode.js 是一個用於生成二維碼的 JavaScript 庫。主要是通過獲取 DOM 的標簽,再通過 HTML5 Canvas 繪制而成,不依賴任何庫。菜鳥教程,猛戳:http://www.runoob.com/w3cnote/javascript-qrcodejs-library.html
但是qrcode默認不支持自定義logo,怎么辦呢?兩種方法:
1、創建一個img標簽,調整樣式,讓logo在二維碼區域上居中顯示
2、創建一個canvas畫布,將二維碼跟logo重新繪制,讓logo在二維碼區域上居中顯示
補充
2020-02-25補充:實現二維碼輸出到瀏覽器功能
1、生成二維碼時,不是直接保存成圖片,而是返回BufferedImage
/** * 生成二維碼 */ public static BufferedImage QREncode(String content){ int width = 250; // 圖像寬度 int height = 250; // 圖像高度 Map<EncodeHintType, Object> hints = new HashMap<>(); //內容編碼格式 hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // 指定糾錯等級 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); //設置二維碼邊的空度,非負數 hints.put(EncodeHintType.MARGIN, 1); BitMatrix bitMatrix = null; BufferedImage bufferedImage = null; try { bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints); MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(0xFF000001, 0xFFFFFFFF); bufferedImage = MatrixToImageWriter.toBufferedImage(bitMatrix,matrixToImageConfig); } catch (WriterException e) { e.printStackTrace(); } //無logo //return bufferedImage; //帶logo,System.getProperty("user.dir")是項目工程根路徑 assert bufferedImage != null; return LogoMatrix(bufferedImage,new File(System.getProperty("user.dir") + "\\src\\main\\resources\\static\\img\\logo.png")); }
2、新增controller,供web調用
//獲取二維碼圖片 @GetMapping("getBarCodeImage/{id}") public void getBarCodeImage(@PathVariable("id") String id) throws IOException { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getResponse(); //設置頁面不緩存 assert response != null; response.setHeader("Pragma", "no-cache"); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0); response.getOutputStream(); //設置輸出的內容的類型為JPEG圖像 response.setContentType("image/jpeg"); //通過id查詢數據設置二維碼內容 String text = "{\"id\":\""+ id +"\"}" BufferedImage bufferedImage = QREncode(text); //寫給瀏覽器 ImageIO.write(bufferedImage, "JPEG", response.getOutputStream()); }
3、web頁面調用,thymeleaf語法
<img id="barCodeImage" th:src="@{'/getBarCodeImage/' + ${id}}"/> <br/><br/> <button th:onclick="${'document.getElementById(''barCodeImage'').src = ctx + ''/getBarCodeImage/'+ id +'?time='' + new Date().getTime()'}">
刷新二維碼
</button>