/* * Copyright (C) 2018 Jenly Yu * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.king.zxing.util; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.support.annotation.ColorInt; import android.support.annotation.FloatRange; import android.support.annotation.NonNull; import android.text.TextPaint; import android.text.TextUtils; import android.util.Log; 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.RGBLuminanceSource; import com.google.zxing.Result; import com.google.zxing.WriterException; import com.google.zxing.common.BitMatrix; import com.google.zxing.common.GlobalHistogramBinarizer; import com.google.zxing.common.HybridBinarizer; import com.google.zxing.qrcode.QRCodeReader; import com.google.zxing.qrcode.QRCodeWriter; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import com.king.zxing.CaptureHelper; import com.king.zxing.DecodeFormatManager; import java.util.HashMap; import java.util.Map; import java.util.Vector; /** * @author Jenly Jenly */ public final class CodeUtils { private CodeUtils(){ throw new AssertionError(); } /** * 生成二维码 * @param content 二维码的内容 * @param heightPix 二维码的高 * @return */ public static Bitmap createQRCode(String content, int heightPix) { return createQRCode(content,heightPix,null); } /** * 生成二维码 * @param content 二维码的内容 * @param heightPix 二维码的高 * @param codeColor 二维码的颜色 * @return */ public static Bitmap createQRCode(String content, int heightPix,int codeColor) { return createQRCode(content,heightPix,null,codeColor); } /** * 生成我二维码 * @param content 二维码的内容 * @param heightPix 二维码的高 * @param logo logo大小默认占二维码的20% * @return */ public static Bitmap createQRCode(String content, int heightPix, Bitmap logo) { return createQRCode(content,heightPix,logo,Color.BLACK); } /** * 生成我二维码 * @param content 二维码的内容 * @param heightPix 二维码的高 * @param logo logo大小默认占二维码的20% * @param codeColor 二维码的颜色 * @return */ public static Bitmap createQRCode(String content, int heightPix, Bitmap logo,int codeColor) { return createQRCode(content,heightPix,logo,0.2f,codeColor); } /** * 生成二维码 * @param content 二维码的内容 * @param heightPix 二维码的高 * @param logo 二维码中间的logo * @param ratio logo所占比例 因为二维码的最大容错率为30%,所以建议ratio的范围小于0.3 * @return */ public static Bitmap createQRCode(String content, int heightPix, Bitmap logo,@FloatRange(from = 0.0f,to = 1.0f)float ratio) { //配置参数 Map hints = new HashMap<>(); hints.put( EncodeHintType.CHARACTER_SET, "utf-8"); //容错级别 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); //设置空白边距的宽度 hints.put(EncodeHintType.MARGIN, 1); //default is 4 return createQRCode(content,heightPix,logo,ratio,hints); } /** * 生成二维码 * @param content 二维码的内容 * @param heightPix 二维码的高 * @param logo 二维码中间的logo * @param ratio logo所占比例 因为二维码的最大容错率为30%,所以建议ratio的范围小于0.3 * @param codeColor 二维码的颜色 * @return */ public static Bitmap createQRCode(String content, int heightPix, Bitmap logo,@FloatRange(from = 0.0f,to = 1.0f)float ratio,int codeColor) { //配置参数 Map hints = new HashMap<>(); hints.put( EncodeHintType.CHARACTER_SET, "utf-8"); //容错级别 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); //设置空白边距的宽度 hints.put(EncodeHintType.MARGIN, 1); //default is 4 return createQRCode(content,heightPix,logo,ratio,hints,codeColor); } public static Bitmap createQRCode(String content, int heightPix, Bitmap logo,@FloatRange(from = 0.0f,to = 1.0f)float ratio,Map hints) { return createQRCode(content,heightPix,logo,ratio,hints,Color.BLACK); } /** * 生成二维码 * @param content 二维码的内容 * @param heightPix 二维码的高 * @param logo 二维码中间的logo * @param ratio logo所占比例 因为二维码的最大容错率为30%,所以建议ratio的范围小于0.3 * @param hints * @param codeColor 二维码的颜色 * @return */ public static Bitmap createQRCode(String content, int heightPix, Bitmap logo,@FloatRange(from = 0.0f,to = 1.0f)float ratio,Map hints,int codeColor) { try { // 图像数据转换,使用了矩阵转换 BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, heightPix, heightPix, hints); int[] pixels = new int[heightPix * heightPix]; // 下面这里按照二维码的算法,逐个生成二维码的图片, // 两个for循环是图片横列扫描的结果 for (int y = 0; y < heightPix; y++) { for (int x = 0; x < heightPix; x++) { if (bitMatrix.get(x, y)) { pixels[y * heightPix + x] = codeColor; } else { pixels[y * heightPix + x] = Color.WHITE; } } } // 生成二维码图片的格式 Bitmap bitmap = Bitmap.createBitmap(heightPix, heightPix, Bitmap.Config.ARGB_8888); bitmap.setPixels(pixels, 0, heightPix, 0, 0, heightPix, heightPix); if (logo != null) { bitmap = addLogo(bitmap, logo,ratio); } return bitmap; } catch (WriterException e) { Log.w(CaptureHelper.TAG,e.getMessage()); } return null; } /** * 在二维码中间添加Logo图案 * @param src * @param logo * @param ratio logo所占比例 因为二维码的最大容错率为30%,所以建议ratio的范围小于0.3 * @return */ private static Bitmap addLogo(Bitmap src, Bitmap logo,@FloatRange(from = 0.0f,to = 1.0f) float ratio) { 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; } //logo大小为二维码整体大小 float scaleFactor = srcWidth * ratio / 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.restore(); } catch (Exception e) { bitmap = null; Log.w(CaptureHelper.TAG,e.getMessage()); } return bitmap; } /** * 解析二维码图片 * @param bitmapPath * @return */ public static String parseQRCode(String bitmapPath) { Map hints = new HashMap<>(); hints.put(DecodeHintType.CHARACTER_SET, "utf-8"); hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE); return parseQRCode(bitmapPath,hints); } /** * 解析二维码图片 * @param bitmapPath * @param hints * @return */ public static String parseQRCode(String bitmapPath, Map hints){ Result result = parseQRCodeResult(bitmapPath,hints); if(result != null){ return result.getText(); } return null; } /** * 解析二维码图片 * @param bitmapPath * @param hints * @return */ public static Result parseQRCodeResult(String bitmapPath, Map hints){ Result result = null; try{ QRCodeReader reader = new QRCodeReader(); RGBLuminanceSource source = getRGBLuminanceSource(compressBitmap(bitmapPath)); if (source != null) { boolean isReDecode; try { BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); result = reader.decode(bitmap,hints); isReDecode = false; } catch (Exception e) { isReDecode = true; } if(isReDecode){ try { BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source.invert())); result = reader.decode(bitmap,hints); isReDecode = false; } catch (Exception e) { isReDecode = true; } } if(isReDecode){ try{ BinaryBitmap bitmap = new BinaryBitmap(new GlobalHistogramBinarizer(source)); result = reader.decode(bitmap,hints); isReDecode = false; }catch (Exception e){ isReDecode = true; } } if(isReDecode && source.isRotateSupported()){ try{ BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source.rotateCounterClockwise())); result = reader.decode(bitmap,hints); }catch (Exception e){ } } reader.reset(); } }catch (Exception e){ Log.w(CaptureHelper.TAG,e.getMessage()); } return result; } /** * 解析一维码/二维码图片 * @param bitmapPath * @return */ public static String parseCode(String bitmapPath){ Map hints = new HashMap<>(); //添加可以解析的编码类型 Vector decodeFormats = new Vector<>(); decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS); decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS); decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS); decodeFormats.addAll(DecodeFormatManager.AZTEC_FORMATS); decodeFormats.addAll(DecodeFormatManager.PDF417_FORMATS); hints.put(DecodeHintType.CHARACTER_SET, "utf-8"); hints.put(DecodeHintType.TRY_HARDER,Boolean.TRUE); hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats); return parseCode(bitmapPath,hints); } /** * 解析一维码/二维码图片 * @param bitmapPath * @param hints 解析编码类型 * @return */ public static String parseCode(String bitmapPath, Map hints){ Result result = parseCodeResult(bitmapPath,hints); if(result != null){ return result.getText(); } return null; } /** * 解析一维码/二维码图片 * @param bitmapPath * @param hints 解析编码类型 * @return */ public static Result parseCodeResult(String bitmapPath, Map hints){ Result result = null; try{ MultiFormatReader reader = new MultiFormatReader(); reader.setHints(hints); RGBLuminanceSource source = getRGBLuminanceSource(compressBitmap(bitmapPath)); if (source != null) { boolean isReDecode; try { BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); result = reader.decodeWithState(bitmap); isReDecode = false; } catch (Exception e) { isReDecode = true; } if(isReDecode){ try { BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source.invert())); result = reader.decodeWithState(bitmap); isReDecode = false; } catch (Exception e) { isReDecode = true; } } if(isReDecode){ try{ BinaryBitmap bitmap = new BinaryBitmap(new GlobalHistogramBinarizer(source)); result = reader.decodeWithState(bitmap); isReDecode = false; }catch (Exception e){ isReDecode = true; } } if(isReDecode && source.isRotateSupported()){ try{ BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source.rotateCounterClockwise())); result = reader.decodeWithState(bitmap); }catch (Exception e){ } } reader.reset(); } }catch (Exception e){ Log.w(CaptureHelper.TAG,e.getMessage()); } return result; } /** * 压缩图片 * @param path * @return */ private static Bitmap compressBitmap(String path){ BitmapFactory.Options newOpts = new BitmapFactory.Options(); // 开始读入图片,此时把options.inJustDecodeBounds 设回true了 newOpts.inJustDecodeBounds = true;//获取原始图片大小 BitmapFactory.decodeFile(path, newOpts);// 此时返回bm为空 int w = newOpts.outWidth; int h = newOpts.outHeight; float width = 800f; float height = 480f; // 缩放比,由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可 int be = 1;// be=1表示不缩放 if (w > h && w > width) {// 如果宽度大的话根据宽度固定大小缩放 be = (int) (newOpts.outWidth / width); } else if (w < h && h > height) {// 如果高度高的话根据宽度固定大小缩放 be = (int) (newOpts.outHeight / height); } if (be <= 0) be = 1; newOpts.inSampleSize = be;// 设置缩放比例 // 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了 newOpts.inJustDecodeBounds = false; return BitmapFactory.decodeFile(path, newOpts); } /** * 获取RGBLuminanceSource * @param bitmap * @return */ private static RGBLuminanceSource getRGBLuminanceSource(@NonNull Bitmap bitmap){ int width = bitmap.getWidth(); int height = bitmap.getHeight(); int[] pixels = new int[width * height]; bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight()); return new RGBLuminanceSource(width, height, pixels); } /** * 生成条形码 * @param content * @param desiredWidth * @param desiredHeight * @return */ public static Bitmap createBarCode(String content, int desiredWidth, int desiredHeight) { return createBarCode(content,BarcodeFormat.CODE_128,desiredWidth,desiredHeight,null); } /** * 生成条形码 * @param content * @param format * @param desiredWidth * @param desiredHeight * @return */ public static Bitmap createBarCode(String content,BarcodeFormat format, int desiredWidth, int desiredHeight) { return createBarCode(content,format,desiredWidth,desiredHeight,null); } public static Bitmap createBarCode(String content, int desiredWidth, int desiredHeight, boolean isShowText) { return createBarCode(content,BarcodeFormat.CODE_128,desiredWidth,desiredHeight,null,isShowText,40,Color.BLACK); } /** * 生成条形码 * @param content * @param desiredWidth * @param desiredHeight * @param isShowText * @param codeColor * @return */ public static Bitmap createBarCode(String content, int desiredWidth, int desiredHeight, boolean isShowText,@ColorInt int codeColor) { return createBarCode(content,BarcodeFormat.CODE_128,desiredWidth,desiredHeight,null,isShowText,40,codeColor); } /** * 生成条形码 * @param content * @param format * @param desiredWidth * @param desiredHeight * @param hints * @return */ public static Bitmap createBarCode(String content, BarcodeFormat format, int desiredWidth, int desiredHeight, Map hints) { return createBarCode(content,format,desiredWidth,desiredHeight,hints,false,40,Color.BLACK); } /** * 生成条形码 * @param content * @param format * @param desiredWidth * @param desiredHeight * @param hints * @param isShowText * @return */ public static Bitmap createBarCode(String content, BarcodeFormat format, int desiredWidth, int desiredHeight, Map hints, boolean isShowText) { return createBarCode(content,format,desiredWidth,desiredHeight,hints,isShowText,40,Color.BLACK); } /** * 生成条形码 * @param content * @param format * @param desiredWidth * @param desiredHeight * @param isShowText * @param codeColor * @return */ public static Bitmap createBarCode(String content, BarcodeFormat format, int desiredWidth, int desiredHeight, boolean isShowText,@ColorInt int codeColor) { return createBarCode(content,format,desiredWidth,desiredHeight,null,isShowText,40,codeColor); } /** * 生成条形码 * @param content * @param format * @param desiredWidth * @param desiredHeight * @param hints * @param isShowText * @return */ public static Bitmap createBarCode(String content, BarcodeFormat format, int desiredWidth, int desiredHeight, Map hints, boolean isShowText,@ColorInt int codeColor) { return createBarCode(content,format,desiredWidth,desiredHeight,hints,isShowText,40,codeColor); } /** * 生成条形码 * @param content * @param format * @param desiredWidth * @param desiredHeight * @param hints * @param isShowText * @param textSize * @param codeColor * @return */ public static Bitmap createBarCode(String content,BarcodeFormat format, int desiredWidth, int desiredHeight,Map hints,boolean isShowText,int textSize,@ColorInt int codeColor) { if(TextUtils.isEmpty(content)){ return null; } final int WHITE = Color.WHITE; final int BLACK = codeColor; MultiFormatWriter writer = new MultiFormatWriter(); try { BitMatrix result = writer.encode(content, format, desiredWidth, desiredHeight, hints); int width = result.getWidth(); int height = result.getHeight(); int[] pixels = new int[width * height]; // All are 0, or black, by default for (int y = 0; y < height; y++) { int offset = y * width; for (int x = 0; x < width; x++) { pixels[offset + x] = result.get(x, y) ? BLACK : WHITE; } } Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); bitmap.setPixels(pixels, 0, width, 0, 0, width, height); if(isShowText){ return addCode(bitmap,content,textSize,codeColor,textSize/2); } return bitmap; } catch (WriterException e) { Log.w(CaptureHelper.TAG,e.getMessage()); } return null; } /** * 条形码下面添加文本信息 * @param src * @param code * @param textSize * @param textColor * @return */ private static Bitmap addCode(Bitmap src,String code,int textSize,@ColorInt int textColor,int offset) { if (src == null) { return null; } if (TextUtils.isEmpty(code)) { return src; } //获取图片的宽高 int srcWidth = src.getWidth(); int srcHeight = src.getHeight(); if (srcWidth <= 0 || srcHeight <= 0) { return null; } Bitmap bitmap = Bitmap.createBitmap(srcWidth, srcHeight + textSize + offset * 2, Bitmap.Config.ARGB_8888); try { Canvas canvas = new Canvas(bitmap); canvas.drawBitmap(src, 0, 0, null); TextPaint paint = new TextPaint(); paint.setTextSize(textSize); paint.setColor(textColor); paint.setTextAlign(Paint.Align.CENTER); canvas.drawText(code,srcWidth/2,srcHeight + textSize /2 + offset,paint); canvas.save(); canvas.restore(); } catch (Exception e) { bitmap = null; Log.w(CaptureHelper.TAG,e.getMessage()); } return bitmap; } }