Android生成自定義二維碼
前面說過兩種二維碼掃描方式,現在說如何生成自定義酷炫二維碼。二維碼生成需要使用Google開源庫Zxing,Zxing的專案地址: ofollow,noindex" target="_blank">https://github.com/ZBar/ZBar ,我們只需要裡面的jar包:core:x.x.x.jar,建議用core:3.3.0。
劃重點:
- 一般二維碼
- 彩色二維碼
- 帶logo二維碼或帶logo的彩色二維碼
- 黑色色塊用圖片代替的二維碼
1.引入jar包
- app build.gradle中加入依賴
dependencies { ... implementation 'com.google.zxing:core:3.3.0' }
- 如果依賴同步失敗,下載jar包匯入libs下,並在app build.gradle中加入如下程式碼並
Sync Now
implementation fileTree(dir: 'libs', include: ['*.jar'])
2.How ?
先看簡單的二維碼生成
/** * 生成簡單二維碼 * * @param content字串內容 * @param width二維碼寬度 * @param height二維碼高度 * @param character_set編碼方式(一般使用UTF-8) * @param error_correction_level 容錯率 L:7% M:15% Q:25% H:35% * @param margin空白邊距(二維碼與邊框的空白區域) * @param color_black黑色色塊 * @param color_white白色色塊 * @return BitMap */ public static Bitmap createQRCodeBitmap(String content, int width,int height, String character_set,String error_correction_level, String margin,int color_black, int color_white) { // 字串內容判空 if (TextUtils.isEmpty(content)) { return null; } // 寬和高>=0 if (width < 0 || height < 0) { return null; } try { /** 1.設定二維碼相關配置 */ Hashtable<EncodeHintType, String> hints = new Hashtable<>(); // 字元轉碼格式設定 if (!TextUtils.isEmpty(character_set)) { hints.put(EncodeHintType.CHARACTER_SET, character_set); } // 容錯率設定 if (!TextUtils.isEmpty(error_correction_level)) { hints.put(EncodeHintType.ERROR_CORRECTION, error_correction_level); } // 空白邊距設定 if (!TextUtils.isEmpty(margin)) { hints.put(EncodeHintType.MARGIN, margin); } /** 2.將配置引數傳入到QRCodeWriter的encode方法生成BitMatrix(位矩陣)物件 */ BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints); /** 3.建立畫素陣列,並根據BitMatrix(位矩陣)物件為陣列元素賦顏色值 */ int[] pixels = new int[width * height]; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { //bitMatrix.get(x,y)方法返回true是黑色色塊,false是白色色塊 if (bitMatrix.get(x, y)) { pixels[y * width + x] = color_black;//黑色色塊畫素設定 } else { pixels[y * width + x] = color_white;// 白色色塊畫素設定 } } } /** 4.建立Bitmap物件,根據畫素陣列設定Bitmap每個畫素點的顏色值,並返回Bitmap物件 */ Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); bitmap.setPixels(pixels, 0, width, 0, 0, width, height); return bitmap; } catch (WriterException e) { e.printStackTrace(); return null; } }
主要步驟:
- 設定二維碼相關配置,包括傳入的二維碼長寬、容錯率和空白邊距大小。
- 將配置引數傳入到QRCodeWriter的encode方法並生成BitMatrix(位矩陣)物件。
- 位矩陣物件中bitMatrix.get(x, y)方法可判斷是黑色色塊還是白色色塊,根據不同色塊給陣列元素賦我們傳入的顏色值
- 根據畫素陣列每個畫素點的顏色值建立Bitmap物件並返回,即二維碼
主要引數介紹:
-
character_set
字符集/字元轉碼格式,通常使用UTF-8,格式不對可能導致亂碼。傳null時,預設使用 “ISO-8859-1”
-
error_correction_level
容錯率,也就是糾錯水平,二維碼破損一部分也能掃碼就歸功於容錯率,容錯率可分為L、 M、 Q、 H四個等級,其分別佔比為:L:7% M:15% Q:25% H:35%。傳null時,預設使用 “L”
當然容錯率越高,二維碼能儲存的內容也隨之變小。
-
margin
二維碼和邊框的空白區域寬度
-
color_black、color_white
黑色色塊和白素色塊,我們常見的二維碼一般是黑白兩色的,也就是這兩個色塊,可以自己傳入兩個顏色,so,彩色二維碼不就實現了。
呼叫生成:
createQRCodeBitmap(content, 800, 800,"UTF-8","H", "1", Color.BLACK, Color.WHITE);
黑色色塊用綠色(Color.GREEN)、藍色(Color.BLUE)、黃色(Color.YELLOW)…:
createQRCodeBitmap(content, 800, 800,"UTF-8","H", "1", Color.GREEN, Color.WHITE); ...
3.新增logo
二維碼生成當然少不了新增logo了,新增logo就是圖片合成,將logo圖片以一定比例合成在原二維碼圖片上。
直接看程式碼
/** * 向二維碼中間新增logo圖片(圖片合成) * * @param srcBitmap 原圖片(生成的簡單二維碼圖片) * @param logoBitmap logo圖片 * @param logoPercent 百分比 (用於調整logo圖片在原圖片中的顯示大小, 取值範圍[0,1] ) * @return */ private static Bitmap addLogo(Bitmap srcBitmap,Bitmap logoBitmap, float logoPercent){ if(srcBitmap == null){ return null; } if(logoBitmap == null){ return srcBitmap; } //傳值不合法時使用0.2F if(logoPercent < 0F || logoPercent > 1F){ logoPercent = 0.2F; } /** 1. 獲取原圖片和Logo圖片各自的寬、高值 */ int srcWidth = srcBitmap.getWidth(); int srcHeight = srcBitmap.getHeight(); int logoWidth = logoBitmap.getWidth(); int logoHeight = logoBitmap.getHeight(); /** 2. 計算畫布縮放的寬高比 */ float scaleWidth = srcWidth * logoPercent / logoWidth; float scaleHeight = srcHeight * logoPercent / logoHeight; /** 3. 使用Canvas繪製,合成圖片 */ Bitmap bitmap = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); canvas.drawBitmap(srcBitmap, 0, 0, null); canvas.scale(scaleWidth, scaleHeight, srcWidth/2, srcHeight/2); canvas.drawBitmap(logoBitmap, srcWidth/2 - logoWidth/2, srcHeight/2 - logoHeight/2, null); return bitmap; }
引數說明:
- srcBitmap:之前生成的簡單二維碼圖片
- logoBitmap:logo圖片
- logoPercent :logo圖片所佔的百分比,建議使用0.2F,百分比過大可能導致二維碼掃描失敗。
這裡就是一個簡單的圖片合成,首先獲取原圖片和logo圖片各自的寬高,通過我們傳入的百分比計算畫布縮放的寬高比,然後使用Canvas繪製,合成最終帶logo的二維碼。
為了方便,我們在最開始生成簡單二維碼的方法中傳入logo圖片和百分比,在生成Bitmap時新增logo,如下:
/** * * @param content字串內容 * @param width二維碼寬度 * @param height二維碼高度 * @param character_set編碼方式(一般使用UTF-8) * @param error_correction_level 容錯率 L:7% M:15% Q:25% H:35% * @param margin空白邊距(二維碼與邊框的空白區域) * @param color_black黑色色塊 * @param color_white白色色塊 * @param logoBitmaplogo圖片 * @param logoPercentlogo所佔百分比 * @return */ public static Bitmap createQRCodeBitmap(String content, int width, int height, String character_set, String error_correction_level,String margin, int color_black, int color_white,Bitmap logoBitmap, float logoPercent) { // 字串內容判空 if (TextUtils.isEmpty(content)) { return null; } // 寬和高>=0 if (width < 0 || height < 0) { return null; } try { /** 1.設定二維碼相關配置,生成BitMatrix(位矩陣)物件 */ Hashtable<EncodeHintType, String> hints = new Hashtable<>(); // 字元轉碼格式設定 if (!TextUtils.isEmpty(character_set)) { hints.put(EncodeHintType.CHARACTER_SET, character_set); } // 容錯率設定 if (!TextUtils.isEmpty(error_correction_level)) { hints.put(EncodeHintType.ERROR_CORRECTION, error_correction_level); } // 空白邊距設定 if (!TextUtils.isEmpty(margin)) { hints.put(EncodeHintType.MARGIN, margin); } /** 2.將配置引數傳入到QRCodeWriter的encode方法生成BitMatrix(位矩陣)物件 */ BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints); /** 3.建立畫素陣列,並根據BitMatrix(位矩陣)物件為陣列元素賦顏色值 */ int[] pixels = new int[width * height]; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { //bitMatrix.get(x,y)方法返回true是黑色色塊,false是白色色塊 if (bitMatrix.get(x, y)) { pixels[y * width + x] = color_black;//黑色色塊畫素設定 } else { pixels[y * width + x] = color_white;// 白色色塊畫素設定 } } } /** 4.建立Bitmap物件,根據畫素陣列設定Bitmap每個畫素點的顏色值,並返回Bitmap物件 */ Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); bitmap.setPixels(pixels, 0, width, 0, 0, width, height); /** 5.為二維碼新增logo圖示 */ if(logoBitmap != null){ return addLogo(bitmap, logoBitmap, logoPercent); } return bitmap; } catch (WriterException e) { e.printStackTrace(); return null; } }
呼叫:
createQRCodeBitmap(content, 800, 800,"UTF-8","H", "1", Color.BLACK, Color.WHITE,logoBitmap,0.2F);
logo圖片需要轉為Bitmap格式傳入,將專案資源下的圖片轉為Bitmap可使用如下方法
Resources res = getResources(); Bitmap logoBitmap= BitmapFactory.decodeResource(res,R.mipmap.logo);
效果圖:
4.使用圖片代替黑色色塊
什麼意思呢,看圖
就是將二維碼的黑色色塊使用圖片代替,視覺效果就是你的圖片在黑色色塊部分被顯示。
實現方法:
首先通過Bitmap的createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)方法從當前點陣圖,按一定的比例建立一個新的點陣圖,該方法需要傳入四個引數,第一個引數就是當前圖片,第二個和第三個引數是新點陣圖長寬(這裡傳入二維碼的長寬,保證圖的大小一樣),最後一個引數直接傳false。
Bitmap bitmap_black = Bitmap.createScaledBitmap(bitmap_black, width, height, false);
建立好新點陣圖後,在根據BitMatrix(位矩陣)物件為陣列元素賦顏色值時,將黑色色塊換為新點陣圖的畫素。
if (bitMatrix.get(x, y)) {// 黑色色塊畫素設定 if(bitmap_black != null) {//圖片不為null,則將黑色色塊換為新點陣圖的畫素。 pixels[y * width + x] = bitmap_black.getPixel(x, y); } else { pixels[y * width + x] = color_black; } } else { pixels[y * width + x] = color_white;// 白色色塊畫素設定 }
注:儘量選用深色圖片,否則影響掃描精度。
程式碼如下:
/** *生成自定義二維碼 * * @param content字串內容 * @param width二維碼寬度 * @param height二維碼高度 * @param character_set編碼方式(一般使用UTF-8) * @param error_correction_level 容錯率 L:7% M:15% Q:25% H:35% * @param margin空白邊距(二維碼與邊框的空白區域) * @param color_black黑色色塊 * @param color_white白色色塊 * @param logoBitmaplogo圖片(傳null時不新增logo) * @param logoPercentlogo所佔百分比 * @param bitmap_black用來代替黑色色塊的圖片(傳null時不代替) * @return */ public static Bitmap createQRCodeBitmap(String content, int width, int height, String character_set, String error_correction_level, String margin, int color_black, int color_white, Bitmap logoBitmap, float logoPercent, Bitmap bitmap_black) { // 字串內容判空 if (TextUtils.isEmpty(content)) { return null; } // 寬和高>=0 if (width < 0 || height < 0) { return null; } try { /** 1.設定二維碼相關配置,生成BitMatrix(位矩陣)物件 */ Hashtable<EncodeHintType, String> hints = new Hashtable<>(); // 字元轉碼格式設定 if (!TextUtils.isEmpty(character_set)) { hints.put(EncodeHintType.CHARACTER_SET, character_set); } // 容錯率設定 if (!TextUtils.isEmpty(error_correction_level)) { hints.put(EncodeHintType.ERROR_CORRECTION, error_correction_level); } // 空白邊距設定 if (!TextUtils.isEmpty(margin)) { hints.put(EncodeHintType.MARGIN, margin); } /** 2.將配置引數傳入到QRCodeWriter的encode方法生成BitMatrix(位矩陣)物件 */ BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints); /** 3.建立畫素陣列,並根據BitMatrix(位矩陣)物件為陣列元素賦顏色值 */ if (bitmap_black != null) { //從當前點陣圖按一定的比例建立一個新的點陣圖 bitmap_black = Bitmap.createScaledBitmap(bitmap_black, width, height, false); } int[] pixels = new int[width * height]; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { //bitMatrix.get(x,y)方法返回true是黑色色塊,false是白色色塊 if (bitMatrix.get(x, y)) {// 黑色色塊畫素設定 if (bitmap_black != null) {//圖片不為null,則將黑色色塊換為新點陣圖的畫素。 pixels[y * width + x] = bitmap_black.getPixel(x, y); } else { pixels[y * width + x] = color_black; } } else { pixels[y * width + x] = color_white;// 白色色塊畫素設定 } } } /** 4.建立Bitmap物件,根據畫素陣列設定Bitmap每個畫素點的顏色值,並返回Bitmap物件 */ Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); bitmap.setPixels(pixels, 0, width, 0, 0, width, height); /** 5.為二維碼新增logo圖示 */ if (logoBitmap != null) { return addLogo(bitmap, logoBitmap, logoPercent); } return bitmap; } catch (WriterException e) { e.printStackTrace(); return null; } }
原始碼已上傳至GitHub: https://github.com/yangxch/GenerateQRCode
生成二維碼方法我放到了一個工具類,呼叫時如果不需要logo或不需要用圖片代替黑色色塊,傳nulll 即可。
當然圖片不能直接寫死,可以拍照或相簿選擇,生成二維碼還可儲存至手機或分享給他人,實現方式後續更新,敬請關注。
更多技術乾貨,歡迎關注我的公眾號:ChaoYoung