二維碼技術不是什麼新技術了,可是這幾天工做用到,而後才現學習現使用,使用的是Google的ZXing,使用起來很簡單,java
我練習的兩種方式,一種的簡單的javase工程,一種是Android客戶端生成解析二維碼的demo,線面逐個介紹。android
1、JavaSE生成解析二維碼,就是創建一個JavaProject,而後導入jar包,我用的是maven,因此創建了一個簡單的maven工程。git
一、第一種形式,生成一箇中間沒有logo的二維碼,並解析,寫好以後,直接說哪一個junit測試,就能生成解析二維碼了github
package com.wang.qr.code; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.nio.file.FileSystems; import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import javax.imageio.ImageIO; import org.junit.Test; import com.alibaba.fastjson.JSONObject; import com.google.zxing.BarcodeFormat; import com.google.zxing.Binarizer; import com.google.zxing.BinaryBitmap; import com.google.zxing.DecodeHintType; import com.google.zxing.EncodeHintType; import com.google.zxing.LuminanceSource; import com.google.zxing.MultiFormatReader; import com.google.zxing.MultiFormatWriter; import com.google.zxing.NotFoundException; import com.google.zxing.Result; import com.google.zxing.WriterException; import com.google.zxing.client.j2se.BufferedImageLuminanceSource; import com.google.zxing.client.j2se.MatrixToImageWriter; import com.google.zxing.common.BitMatrix; import com.google.zxing.common.HybridBinarizer; /** * 生成沒有logo的二維碼</br> 有多個信息json * * @author wang * */ public class QRCodeTest1 { /** * 生成二維碼</br> * * 二維碼中的內容是json數據 * * @throws WriterException * @throws IOException */ @Test public void testEncode() throws WriterException, IOException { /* * 把生成的二維碼放到此目錄下 */ String filePath = "E://"; /* * 生成的二維碼名稱 */ String fileName = "zxing.png"; JSONObject json = new JSONObject(); json.put("zxing", "https://github.com/zxing/zxing/tree/zxing-3.0.0/javase/src/main/java/com/google/zxing"); json.put("author", "shihy"); /* * 二維碼中的內容 */ String content = json.toJSONString();// 內容 int width = 200; // 圖像寬度 int height = 200; // 圖像高度 String format = "png";// 圖像類型 Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>(); hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);// 生成矩陣 Path path = FileSystems.getDefault().getPath(filePath, fileName); MatrixToImageWriter.writeToPath(bitMatrix, format, path);// 輸出圖像 System.out.println("輸出成功."); } /** * 解析二維碼</br> 二維碼中的內容是json數據 */ @Test public void testDecode() { /* * 要解析的二維碼 */ String filePath = "E://zxing.png"; BufferedImage image; try { image = ImageIO.read(new File(filePath)); LuminanceSource source = new BufferedImageLuminanceSource(image); Binarizer binarizer = new HybridBinarizer(source); BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer); Map<DecodeHintType, Object> hints = new HashMap<DecodeHintType, Object>(); hints.put(DecodeHintType.CHARACTER_SET, "UTF-8"); Result result = new MultiFormatReader().decode(binaryBitmap, hints);// 對圖像進行解碼 /* * 獲得二維碼中的字符串內容 */ //String context = result.getText(); JSONObject content = JSONObject.parseObject(result.getText()); System.out.println("圖片中內容: "); System.out.println("author: " + content.getString("author")); System.out.println("zxing: " + content.getString("zxing")); System.out.println("圖片中格式: "); System.out.println("encode: " + result.getBarcodeFormat()); } catch (IOException e) { e.printStackTrace(); } catch (NotFoundException e) { e.printStackTrace(); } } }
二、第二種形式,生成有logo的二維碼,工具類以下apache
package com.wang.qr.code.utils; import java.awt.Graphics2D; import java.awt.Image; import java.awt.image.BufferedImage; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Hashtable; import javax.imageio.ImageIO; import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.MultiFormatWriter; import com.google.zxing.client.j2se.MatrixToImageWriter; import com.google.zxing.common.BitMatrix; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; /** * 生成普通二維碼和生成帶logo的二維碼 * * @author wang * */ public class QRCodeTestUtil3 { private static final int BLACK = 0xFF000000; private static final int WHITE = 0xFFFFFFFF; /** * 生成普通沒有logo的二維碼 * * @param filePath * 文本文件路徑,該文件中的內容是生成二維碼圖片中的內容(文本需以UTF-8) * @param imgFormate * 指定生成的二維碼圖片的後綴名 * @param width * 指定生成的二維碼圖片的寬度 * @param height * 指定生成的二維碼圖片的高度 */ public static void createTwoDimensionalCode(String filePath, String imgFormate, int width, int height) { File file = new File(filePath); StringBuffer contents = new StringBuffer(""); // 讀取文本文件內容到 contents try { InputStream is = new FileInputStream(file); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); try { String temp = br.readLine(); while (temp != null) { contents.append(temp + "\r\n"); temp = br.readLine(); } } catch (IOException e) { e.printStackTrace(); } } catch (FileNotFoundException e) { e.printStackTrace(); } // 獲得圖片該存放路徑 String imgPath = file.getParent(); // 獲得文件該設置的名字 String imgName = file.getName(); int endIndex = imgName.lastIndexOf("."); imgName = imgName.substring(0, endIndex); File imageFile = new File(imgPath, imgName + "." + imgFormate); Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>(); // 指定糾錯等級 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L); // 指定編碼格式 hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); try { BitMatrix bitMatrix = new MultiFormatWriter().encode(contents.toString(), BarcodeFormat.QR_CODE, width, height, hints); MatrixToImageWriter.writeToPath(bitMatrix, imgFormate, imageFile.toPath()); } catch (Exception e) { e.printStackTrace(); } } /** * 生成帶logo的二維碼圖片 * * @param url * 要生成二維碼的url * @param imgPath * 二維碼生成的絕對路徑 * @param logoPath * 二維碼中間logo絕對地址 * @throws Exception */ public static void get2CodeImage(String url, String imgPath, String logoPath) throws Exception { String format = "png"; Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>(); hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, 300, 300, hints); File qrcodeFile = new File(imgPath); writeToFile(bitMatrix, format, qrcodeFile, logoPath); } /** * * @param matrix * 二維碼矩陣相關 * @param format * 二維碼圖片格式 * @param file * 二維碼圖片文件 * @param logoPath * logo路徑 * @throws IOException */ private static void writeToFile(BitMatrix matrix, String format, File file, String logoPath) throws IOException { BufferedImage image = toBufferedImage(matrix); Graphics2D gs = image.createGraphics(); // 載入logo Image img = ImageIO.read(new File(logoPath)); gs.drawImage(img, 125, 125, null); gs.dispose(); img.flush(); if (!ImageIO.write(image, format, file)) { throw new IOException("Could not write an image of format " + format + " to " + file); } } private 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; } }
測試類:json
package com.wang.qr.code; import org.junit.Test; import com.wang.qr.code.utils.QRCodeTestUtil3; /** * @author wang * */ public class QRCodeTest3 { @Test public void createNoLogoQRCode() { QRCodeTestUtil3.createTwoDimensionalCode("E://test.txt", "png", 200, 200); } @Test public void createHaveLogoQRCode() { try { QRCodeTestUtil3.get2CodeImage("https://shop100133013.taobao.com/shop/view_shop.htm?spm=a1z0k.7386009.1997989141.d4915209.abFEJh&shop_id=100133013", "E://havalogoQRCode.png", "E://logo.png"); } catch (Exception e) { e.printStackTrace(); } } }
效果圖:(一張有用的二維碼,不信能夠用微信掃掃哦。。。)canvas
在聯繫的時候,我是用的maven工程,附上maven工程的pom文件:微信
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>QRCodeTest</groupId> <artifactId>QRCodeTest</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>QRCodeTest</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> <scope>test</scope> </dependency> <dependency> <groupId>com.google.zxing</groupId> <artifactId>core</artifactId> <version>3.2.1</version> </dependency> <dependency> <groupId>com.google.zxing</groupId> <artifactId>javase</artifactId> <version>3.2.1</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.7</version> </dependency> </dependencies> </project>
2、第二個練習的是寫了一個Android的應用程序,可以根據填寫內容,和是否選擇二維碼logo,生成一個二維碼;可以像微信同樣掃描二維碼(在網上找到的demo代碼直接用的),app
Android上生成二維碼與javase生成二維碼的核心代碼原理同樣,都是zxing,可是有不同的地方,javase生成二維碼後,可以直 接在本地保存二維碼文件。Android應用程序這樣的話就不要友好了,咱們應該先將二維碼生成bitmap的形式,而後顯示在imageView上面, 由使用者選擇是否保存二維碼,就像下面的界面同樣,maven
這樣的話,生成二維碼的代碼就不同了。下面是在Android中生成二維碼bitmap的代碼:
package com.wang.qrcodecreateandscantool.util; import android.graphics.Bitmap; import android.graphics.Canvas; import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.MultiFormatWriter; import com.google.zxing.common.BitMatrix; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import java.util.Hashtable; /** * 生成二維碼的工具類 * <p/> * Created by wang on 2015/11/12. */ public class QRCodeCreateUtil { /** * 生成沒有logo的二維碼Bitmap * * @param context 二維碼內容 * @param widthPix 二維碼寬度 * @param heightPix 二維碼高度 * @return Bitmap */ public static Bitmap createNoLogoQRCode(String context, int widthPix, int heightPix) { Bitmap bitmap = null; try { Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>(); hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L); hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); BitMatrix bitMatrix = new MultiFormatWriter().encode(context, BarcodeFormat.QR_CODE, widthPix, heightPix, hints); int[] pixels = new int[widthPix * heightPix]; for (int y = 0; y < heightPix; y++) { for (int x = 0; x < widthPix; x++) { if (bitMatrix.get(x, y)) { pixels[y * widthPix + x] = 0xff000000; } else { pixels[y * widthPix + x] = 0xffffffff; } } } bitmap = Bitmap.createBitmap(widthPix, heightPix, Bitmap.Config.ARGB_8888); bitmap.setPixels(pixels, 0, widthPix, 0, 0, widthPix, heightPix); } catch (Exception e) { e.printStackTrace(); } return bitmap; } /** * 生成有logo的二維碼Bitmap * * @param context 二維碼內容 * @param widthPix 二維碼寬度 * @param heightPix 二維碼高度 * @param logo 二維碼logo的bitmap * @return Bitmap */ public static Bitmap createHaveLogoQRCode(String context, int widthPix, int heightPix, Bitmap logo) { Bitmap haveLogoQRCodeBitmap = null; Bitmap noLogoQRCodeBitmap = createNoLogoQRCode(context, widthPix, heightPix); haveLogoQRCodeBitmap = addLogo(noLogoQRCodeBitmap, logo); return haveLogoQRCodeBitmap; } /** * 向原來的bitmap上面添加一個bitmap * * @param src 原始Bitmap * @param logo 添加的Bitmap * @return Bitmap */ private static Bitmap addLogo(Bitmap src, Bitmap logo) { if (src == null) { return null; } if (logo == null) { return src; } int srcWidth = src.getWidth(); int srcHeight = src.getHeight(); int logoWidth = logo.getWidth(); int logoHeight = logo.getHeight(); if (srcWidth == 0 || srcHeight == 0) { return null; } if (logoWidth == 0 || logoHeight == 0) { return src; } float scaleFactor = srcWidth * 1.0f / 8 / logoWidth; Bitmap bitmap = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888); try { Canvas canvas = new Canvas(bitmap); canvas.drawBitmap(src, 0, 0, null); canvas.scale(scaleFactor, scaleFactor, srcWidth / 2, srcHeight / 2); canvas.drawBitmap(logo, (srcWidth - logoWidth) / 2, (srcHeight - logoHeight) / 2, null); canvas.save(Canvas.ALL_SAVE_FLAG); canvas.restore(); } catch (Exception e) { bitmap = null; e.getStackTrace(); } return bitmap; } }
相信有點Android基礎的猿們都會使用上面的代碼了,就不給使用代碼了。
這個Android應用程序還可以像微信同樣掃描二維碼,就行下面同樣:
這個功能是抄的,在網上找的示例代碼,一點沒改直接用了。。。掃描以後,可以對二維碼的內容進行解析,顯示在一個界面上。
這個Android應用程序是用Android studio建立的。