關於二維碼是什麼,以及二維碼是如何生成的,我也沒有研究得很深刻,就很少說了,以避免誤導你們。請參看:java
下面是一個能夠生成和解析二維碼的工具類,該類用到了zxing工具包,我經過Maven去下載的:工具
<dependencies> <!-- JavaSE包依賴於Core包,所以Core包不須要直接依賴了 <dependency> <groupId>com.google.zxing</groupId> <artifactId>core</artifactId> <version>3.1.0</version> </dependency> --> <dependency> <groupId>com.google.zxing</groupId> <artifactId>javase</artifactId> <version>3.1.0</version> </dependency> </dependencies>
在網上搜索的時候我發現,有很多同窗在使用maven的時候都同時導入了這兩個包,可是我發現這個artifactId爲javase的包依賴於core包,所以咱們不須要再在pom.xml中聲明對core包的依賴了。測試
下面這個類是一個工具類,該類能夠生成一維碼和二維碼,也能夠解析二維碼:google
package com.abc.qrcode; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Image; import java.awt.geom.AffineTransform; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import com.google.zxing.BarcodeFormat; import com.google.zxing.Binarizer; import com.google.zxing.BinaryBitmap; import com.google.zxing.LuminanceSource; import com.google.zxing.MultiFormatReader; import com.google.zxing.MultiFormatWriter; import com.google.zxing.NotFoundException; import com.google.zxing.ReaderException; import com.google.zxing.Result; import com.google.zxing.WriterException; import com.google.zxing.client.j2se.BufferedImageLuminanceSource; import com.google.zxing.common.BitMatrix; import com.google.zxing.common.HybridBinarizer; public class QRCodeUtil { // 這幾項能夠由其餘調用的類設置,所以是public static的 public static int BARCODE_WIDTH = 80; public static int QRCODE_WIDTH = 200; public static String FORMAT = "jpg";// 生成的圖片格式 public static int BLACK = 0x000000;// 編碼的顏色 public static int WHITE = 0xFFFFFF;// 空白的顏色 // 二維碼中間的圖像配置。注意,因爲二維碼的容錯率有限,所以中間遮擋的面積不要太大,不然可能解析不出來。 private static int ICON_WIDTH = (int)(QRCODE_WIDTH / 6); private static int HALF_ICON_WIDTH = ICON_WIDTH / 2; private static int FRAME_WIDTH = 2;// Icon四周的邊框寬度 // 二維碼讀碼器和寫碼器 private static final MultiFormatWriter WRITER = new MultiFormatWriter(); private static final MultiFormatReader READER = new MultiFormatReader(); // 測試 public static void main(String[] args) throws Exception { /** * 二維碼測試。 */ String iconPath = "C:\\icon.jpg"; String content = "http://www.baidu.com"; File qrCode = new File("C:\\QRCode." + FORMAT); File qrCodeWithIcon = new File("C:\\QRCodeWithIcon." + FORMAT); // 生成二維碼 writeToFile(createQRCode(content), qrCode); // 生成帶圖標的二維碼 writeToFile(createQRCodeWithIcon(content, iconPath), qrCodeWithIcon); // 解析二維碼 System.out.println(parseImage(qrCode)); // 解析帶圖標的二維碼 System.out.println(parseImage(qrCodeWithIcon)); // 編碼成字節數組 byte[] data = createQRCodeToBytes(content); String result = parseQRFromBytes(data); System.out.println(result); /** * 一維碼測試。 */ String barCodeContent="6936983800013"; File barCode = new File("C:\\BarCode." + FORMAT); // 生成一維碼 writeToFile(createBarCode(barCodeContent), barCode); // 解析一維碼 System.out.println(parseImage(barCode)); } /** * 將String編碼成二維碼的圖片後,使用字節數組表示,便於傳輸。 * * @param content * @return * @throws WriterException * @throws IOException */ public static byte[] createQRCodeToBytes(String content) throws WriterException, IOException { BufferedImage image = createQRCode(content); ByteArrayOutputStream os = new ByteArrayOutputStream(); ImageIO.write(image, FORMAT, os); return os.toByteArray(); } /** * 把一個String編碼成二維碼的BufferedImage. * * @param content * @return * @throws WriterException */ public static final BufferedImage createQRCode(String content) throws WriterException { // 長和寬同樣,因此只須要定義一個SIZE便可 BitMatrix matrix = WRITER.encode( content, BarcodeFormat.QR_CODE, QRCODE_WIDTH, QRCODE_WIDTH); return toBufferedImage(matrix); } /** * 編碼字符串爲二維碼,並在該二維碼中央插入指定的圖標。 * @param content * @param iconPath * @return * @throws WriterException */ public static final BufferedImage createQRCodeWithIcon( String content, String iconPath) throws WriterException { BitMatrix matrix = WRITER.encode( content, BarcodeFormat.QR_CODE, QRCODE_WIDTH, QRCODE_WIDTH); // 讀取Icon圖像 BufferedImage scaleImage = null; try { scaleImage = scaleImage(iconPath, ICON_WIDTH, ICON_WIDTH, true); } catch (IOException e) { e.printStackTrace(); } int[][] iconPixels = new int[ICON_WIDTH][ICON_WIDTH]; for (int i = 0; i < scaleImage.getWidth(); i++) { for (int j = 0; j < scaleImage.getHeight(); j++) { iconPixels[i][j] = scaleImage.getRGB(i, j); } } // 二維碼的寬和高 int halfW = matrix.getWidth() / 2; int halfH = matrix.getHeight() / 2; // 計算圖標的邊界: int minX = halfW - HALF_ICON_WIDTH;//左 int maxX = halfW + HALF_ICON_WIDTH;//右 int minY = halfH - HALF_ICON_WIDTH;//上 int maxY = halfH + HALF_ICON_WIDTH;//下 int[] pixels = new int[QRCODE_WIDTH * QRCODE_WIDTH]; // 修改二維碼的字節信息,替換掉一部分爲圖標的內容。 for (int y = 0; y < matrix.getHeight(); y++) { for (int x = 0; x < matrix.getWidth(); x++) { // 若是點在圖標的位置,用圖標的內容替換掉二維碼的內容 if (x > minX && x < maxX && y > minY && y < maxY) { int indexX = x - halfW + HALF_ICON_WIDTH; int indexY = y - halfH + HALF_ICON_WIDTH; pixels[y * QRCODE_WIDTH + x] = iconPixels[indexX][indexY]; } // 在圖片四周造成邊框 else if ((x > minX - FRAME_WIDTH && x < minX + FRAME_WIDTH && y > minY - FRAME_WIDTH && y < maxY + FRAME_WIDTH) || (x > maxX - FRAME_WIDTH && x < maxX + FRAME_WIDTH && y > minY - FRAME_WIDTH && y < maxY + FRAME_WIDTH) || (x > minX - FRAME_WIDTH && x < maxX + FRAME_WIDTH && y > minY - FRAME_WIDTH && y < minY + FRAME_WIDTH) || (x > minX - FRAME_WIDTH && x < maxX + FRAME_WIDTH && y > maxY - FRAME_WIDTH && y < maxY + FRAME_WIDTH)) { pixels[y * QRCODE_WIDTH + x] = WHITE; } else { // 這裏是其餘不屬於圖標的內容。即爲二維碼沒有被圖標遮蓋的內容,用矩陣的值來顯示顏色。 pixels[y * QRCODE_WIDTH + x] = matrix.get(x, y) ? BLACK : WHITE; } } } // 用修改後的字節數組建立新的BufferedImage. BufferedImage image = new BufferedImage( QRCODE_WIDTH, QRCODE_WIDTH, BufferedImage.TYPE_INT_RGB); image.getRaster().setDataElements(0, 0, QRCODE_WIDTH, QRCODE_WIDTH, pixels); return image; } /** * 從一個二維碼圖片的字節信息解碼出二維碼中的內容。 * * @param data * @return * @throws ReaderException * @throws IOException */ public static String parseQRFromBytes(byte[] data) throws ReaderException, IOException { ByteArrayInputStream is = new ByteArrayInputStream(data); BufferedImage image = ImageIO.read(is); return parseImage(image); } /** * 從一個圖片文件中解碼出二維碼中的內容。 * * @param file * @return 解析後的內容。 * @throws IOException * @throws ReaderException */ public static final String parseImage(File file) throws IOException, ReaderException { BufferedImage image = ImageIO.read(file); return parseImage(image); } /** * 將字符串編碼成一維碼(條形碼)。 * @param content * @return * @throws WriterException * @throws IOException */ public static BufferedImage createBarCode(String content) throws WriterException, IOException { MultiFormatWriter writer = new MultiFormatWriter(); // 一維碼的寬>高。這裏我設置爲 寬:高=2:1 BitMatrix matrix = writer.encode(content, BarcodeFormat.EAN_13, BARCODE_WIDTH * 3, BARCODE_WIDTH); return toBufferedImage(matrix); } /** * 從圖片中解析出一維碼或者二維碼的內容。若是解析失敗,則拋出NotFoundException。 * @param image * @return * @throws NotFoundException */ public static final String parseImage(BufferedImage image) throws NotFoundException { LuminanceSource source = new BufferedImageLuminanceSource(image); Binarizer binarizer = new HybridBinarizer(source); BinaryBitmap bitmap = new BinaryBitmap(binarizer); Result result = READER.decode(bitmap); // 這裏丟掉了Result中其餘一些數據 return result.getText(); } /** * 將BufferedImage對象輸出到指定的文件中。 * * @param image * @param destFile * @throws IOException */ public static final void writeToFile(BufferedImage image, File destFile) throws IOException { ImageIO.write(image, FORMAT, destFile); } /** * 將一個BitMatrix對象轉換成BufferedImage對象 * * @param matrix * @return */ 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; } /** * 把傳入的原始圖像按高度和寬度進行縮放,生成符合要求的圖標。 * * @param srcImageFile 源文件地址 * @param height 目標高度 * @param width 目標寬度 * @param hasFiller 比例不對時是否須要補白:true爲補白; false爲不補白; * @throws IOException */ private static BufferedImage scaleImage(String srcImageFile, int height, int width, boolean hasFiller) throws IOException { double ratio = 0.0; // 縮放比例 File file = new File(srcImageFile); BufferedImage srcImage = ImageIO.read(file); Image destImage = srcImage.getScaledInstance( width, height, BufferedImage.SCALE_SMOOTH); // 計算比例 if ((srcImage.getHeight() > height) || (srcImage.getWidth() > width)) { if (srcImage.getHeight() > srcImage.getWidth()) { ratio = (new Integer(height)).doubleValue() / srcImage.getHeight(); } else { ratio = (new Integer(width)).doubleValue() / srcImage.getWidth(); } AffineTransformOp op = new AffineTransformOp( AffineTransform.getScaleInstance(ratio, ratio), null); destImage = op.filter(srcImage, null); } if (hasFiller) {// 補白 BufferedImage image = new BufferedImage( width, height, BufferedImage.TYPE_INT_RGB); Graphics2D graphic = image.createGraphics(); graphic.setColor(Color.white); graphic.fillRect(0, 0, width, height); if (width == destImage.getWidth(null)) { graphic.drawImage(destImage, 0, (height - destImage.getHeight(null)) / 2, destImage.getWidth(null), destImage.getHeight(null), Color.white, null); } else { graphic.drawImage(destImage, (width - destImage.getWidth(null)) / 2, 0, destImage.getWidth(null), destImage.getHeight(null), Color.white, null); } graphic.dispose(); destImage = image; } return (BufferedImage) destImage; } }
方法的做用和用法在文檔中都寫得很清楚啦,就不須要解釋了。下面是執行結果:編碼
下面是生成的二維碼:spa
下面是生成的一維碼:.net
你們能夠用手機掃描試試看。code