Android工具类: 基于Zxing的二维码生成和展示
2017-07-29 18:01
211 查看
前言
Android日常开发中,不可避免遇到二维码开发的需求,本文抛开扫描解析二维码,提供一下生成二维码的思路,和封装好的工具类,很简单实现二维码生成和展示。注意:本文二维码生成基于著名的二维码库:Zxing v3.2.1
所以你需要先添加Zxing的Jar包 在Gradle中添加对Zxing的依赖如果你觉得看一篇文章太麻烦,请直接跳到文章末尾,按说明,轻松实现二维码解析&生成
需求基本上有这几种:生成二维码
生成带图标的二维码
生成二维码放入ImageView中展示(提供给其他设备扫描)
生成二维码保存到本地(以供文件导出,或者保存备用)
接口设计
根据需求设计两种方法:createQrCode() –> 生成二维码(可以带图标)
createQrCode2ImageView() –> 生成二维码放入ImageView中展示(可以带图标)
简单设计2种接口,大部分都是重载方法:
interface IQrCodeEncoder { //最基本的方法 Bitmap createQrCode(String content, int widthAndHeight); void createQrCode2ImageView(String content, ImageView imageView); //带图标(通过传入R资源/Drawable对象/Bitmap对象的图标) Bitmap createQrCode(String content, int width, int iconRes); Bitmap createQrCode(String content, int width, Drawable iconDrawable); Bitmap createQrCode(String content, int width, Bitmap iconBitmap); void createQrCode2ImageView(String content, ImageView imageView, int iconRes); void createQrCode2ImageView(String content, ImageView imageView, Drawable iconDrawable); void createQrCode2ImageView(String content, ImageView imageView, Bitmap iconBitmap); //手动设定是否带图标 Bitmap createQrCode(String content, int width, int iconRes, boolean hasIcon); Bitmap createQrCode(String content, int width, Drawable iconDrawable, boolean hasIcon); Bitmap createQrCode(String content, int width, Bitmap iconBitmap, boolean hasIcon); void createQrCode2ImageView(String content, ImageView imageView, int iconRes, boolean hasIcon); void createQrCode2ImageView(String content, ImageView imageView, Drawable iconDrawable, boolean hasIcon); void createQrCode2ImageView(String content, ImageView imageView, Bitmap iconBitmap, boolean hasIcon); //将R资源转为Bitmap对象 Bitmap getBitmapByRes(int resId); //将Drawable转为Bitmap对象 Bitmap getBitmapByDrawable(Drawable drawable); //将Icon覆盖到二维码上并返回 带Icon的二维码 Bitmap addIcon2QrCode(Bitmap icon, Bitmap qrCode); }
实现接口
实现思路很简单,基本上就是:1.根据提供的内容生成对应的二维码
2.判断是否需要在二维码上添加Icon,若不需要,直接生成Bitmap
2.1 若需要添加Icon,先获取Icon,将不同的资源类型(R资源,Drawable)统统转换为Bitmap,然后通过
addIcon2QrCode(Bitmap icon, Bitmap qrCode)接口获取到带Icon的二维码Bitmap,
2.2 若不需要添加Icon,判断是否需要直接展示在ImageView上,若需要,展示在ImageView上,否则返回Bitmap
3 获得返回的Bitmap后,判断是否需要直接展示在ImageView上,若需要,展示在ImageView上,否则返回Bitmap
看一下代码实现:
public class QRCodeEncoder implements IQrCodeEncoder { private static final int NO_ICON_RES = 0; private Activity activity; private BitmapCompressor bmpConpressor; public QRCodeEncoder(Activity activity) { setActivity(activity); bmpConpressor = new BitmapCompressor(); } public void setActivity(Activity activity) { this.activity = activity; } @Override public Bitmap createQrCode(String content, int width) { return createQrCode(content, width, NO_ICON_RES); } @Override public Bitmap createQrCode(String content, int width, int iconRes) { return createQrCode(content, width, iconRes, true); } @Override public Bitmap createQrCode(String content, int width, Drawable iconDrawable) { return createQrCode(content, width, iconDrawable, true); } @Override public Bitmap createQrCode(String content, int width, Bitmap iconBitmap) { return createQrCode(content, width, iconBitmap, true); } @Override public void createQrCode2ImageView(String content, ImageView imageView) { this.createQrCode2ImageView(content, imageView, NO_ICON_RES, false); } @Override public void createQrCode2ImageView(String content, ImageView imageView, int iconRes) { this.createQrCode2ImageView(content, imageView, iconRes, true); } @Override public void createQrCode2ImageView(String content, ImageView imageView, Drawable iconDrawable) { this.createQrCode2ImageView(content, imageView, iconDrawable, true); } @Override public void createQrCode2ImageView(String content, ImageView imageView, Bitmap iconBitmap) { this.createQrCode2ImageView(content, imageView, iconBitmap, true); } @Override public void createQrCode2ImageView(String content, ImageView imageView, int iconRes, boolean hasIcon) { Bitmap iconBitmap = null; if (iconRes != NO_ICON_RES) iconBitmap = getBitmapByRes(iconRes); this.createQrCode2ImageView(content, imageView, iconBitmap, hasIcon); } @Override public void createQrCode2ImageView(String content, ImageView imageView, Drawable iconDrawable, boolean hasIcon) { Bitmap iconBitmap = null; if (iconDrawable != null) iconBitmap = getBitmapByDrawable(iconDrawable); this.createQrCode2ImageView(content, imageView, iconBitmap, hasIcon); } @Override public void createQrCode2ImageView(String content, ImageView imageView, Bitmap iconBitmap, boolean hasIcon) { DisplayMetrics dm = new DisplayMetrics(); activity.getWindowManager().getDefaultDisplay().getMetrics(dm); int mScreenWidth = dm.widthPixels; Bitmap qrCode = createQrCode(content, mScreenWidth, iconBitmap, hasIcon); if (qrCode != null) { imageView.setImageBitmap(qrCode); } } @Override public Bitmap createQrCode(String content, int width, int iconRes, boolean hasIcon) { Bitmap iconBitmap = null; if (iconRes != NO_ICON_RES) iconBitmap = getBitmapByRes(iconRes); return createQrCode(content, width, iconBitmap, hasIcon); } @Override public Bitmap createQrCode(String content, int width, Drawable iconDrawable, boolean hasIcon) { Bitmap iconBitmap = null; if (iconDrawable != null) iconBitmap = getBitmapByDrawable(iconDrawable); return createQrCode(content, width, iconBitmap, hasIcon); } /** * Create QrCode with text content. * We suggest that developer adjusts the content length, more content text means more difficult for scanning result on the device. * * @param content QrCode content * @param width QrCode width&Height * @param iconBitmap center icon if you want add icon in Bitmap * @param hasIcon if false,iconBitmap will not show on QrCode bitmap * @return QrCode bitmap */ @Override public Bitmap createQrCode(String content, int width, Bitmap iconBitmap, boolean hasIcon) { try { //配置参数 Map<EncodeHintType, Object> hints = new HashMap<>(); hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); //容错级别 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // TODO set blank width, default is 4 // hints.put(EncodeHintType.MARGIN, 2); BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, width, width, hints); int[] pixels = new int[width * width]; // 下面这里按照二维码的算法,逐个生成二维码的图片, // 两个for循环是图片横列扫描的结果 for (int y = 0; y < width; y++) { for (int x = 0; x < width; x++) { if (bitMatrix.get(x, y)) { pixels[y * width + x] = 0xff000000; //black } else { pixels[y * width + x] = 0xffffffff; //white } } } Bitmap bitmap = Bitmap.createBitmap(width, width, Bitmap.Config.ARGB_8888); bitmap.setPixels(pixels, 0, width, 0, 0, width, width); //Add the Icon to the QrCode bitmap center if (iconBitmap != null && hasIcon) { bitmap = addIcon2QrCode(iconBitmap, bitmap); } //compress bitmap return bmpConpressor.compressBitmap(bitmap); } catch (WriterException e) { e.printStackTrace(); } return null; } @Override public Bitmap getBitmapByRes(int resId) { return BitmapFactory.decodeResource(activity.getResources(), resId); } @Override public Bitmap getBitmapByDrawable(Drawable drawable) { return Bitmap.createBitmap( drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565); } /** * Add the Icon to the QrCode bitmap center * * @param icon the icon * @param qrCode the qrCode * @return QrCode Bitmap with icon */ @Override public Bitmap addIcon2QrCode(Bitmap icon, Bitmap qrCode) { if (qrCode == null) { return null; } if (icon == null) { return qrCode; } int srcWidth = qrCode.getWidth(); int srcHeight = qrCode.getHeight(); int iconWidth = icon.getWidth(); int iconHeight = icon.getHeight(); if (srcWidth == 0 || srcHeight == 0) { return null; } if (iconWidth == 0 || iconHeight == 0) { return qrCode; } //Icon size/ QrCode size = 1:5 float scaleFactor = srcWidth * 1.0f / 5 / iconWidth; Bitmap bitmap = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888); try { Canvas canvas = new Canvas(bitmap); canvas.drawBitmap(qrCode, 0, 0, null); canvas.scale(scaleFactor, scaleFactor, srcWidth / 2, srcHeight / 2); canvas.drawBitmap(icon, (srcWidth - iconWidth) / 2, (srcHeight - iconHeight) / 2, null); canvas.save(Canvas.ALL_SAVE_FLAG); canvas.restore(); } catch (Exception e) { bitmap = null; e.getStackTrace(); } return bitmap; } }
图片压缩
事实上,Bitmap是很吃资源的,所以我们在生成二维码的同时,简单对Bitmap进行压缩再返回:接口
public interface IBitmapCompressor { Bitmap compressBitmap(Bitmap bmp); }
实现
public class BitmapCompressor implements IBitmapCompressor { private int bmpQuality = 64 * 1024; //compress bitmap size -> 64k /** * set compress bitmap size,with unit KB,default value is 64KB * @param bmpQuality */ public void setBmpQuality(int bmpQuality) { this.bmpQuality = bmpQuality * 1024; } @Override public Bitmap compressBitmap(Bitmap bmp) { byte[] bytes = compressBitmap2ByteArray(bmp); ByteArrayInputStream inputs = new ByteArrayInputStream(bytes); return BitmapFactory.decodeStream(inputs, null, null); } private byte[] compressBitmap2ByteArray(Bitmap bmp) { ByteArrayOutputStream output = new ByteArrayOutputStream(); bmp.compress(Bitmap.CompressFormat.JPEG, 100, output); float zoom = (float) Math.sqrt(32 * 1024 / (float) output.toByteArray().length); //获取缩放比例 // set Rect datas Matrix matrix = new Matrix(); matrix.setScale(zoom, zoom); // create new bitmap with Rect datas Bitmap resultBitmap = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true); output.reset(); resultBitmap.compress(Bitmap.CompressFormat.JPEG, 100, output); // if result still > bmpQuality,compress bitmap continue. while (output.toByteArray().length > bmpQuality) { matrix.setScale(0.9f, 0.9f);//scale 0.1 every time resultBitmap = Bitmap.createBitmap( resultBitmap, 0, 0, resultBitmap.getWidth(), resultBitmap.getHeight(), matrix, true); output.reset(); resultBitmap.compress(Bitmap.CompressFormat.JPEG, 100, output); } return output.toByteArray(); } }
这里的bmpQuality 就是要压缩到的大小,一般来说,64K的二维码都足以让绝大多数设备轻松扫描解析了。
当然我也提供了一个接口方便去设置bmpQuality的值:
/** * set compress bitmap size,with unit KB,default value is 64KB * @param bmpQuality */ public void setBmpQuality(int bmpQuality) { this.bmpQuality = bmpQuality * 1024; }
如何使用:
我们只需要在Activity中初始化://初始化 qrCodeEncoder = new QRCodeEncoder(this); //根据内容生成二维码并展示在ImageView上 String textContent = "https://github.com/qingmei2"; qrCodeEncoder.createQrCode2ImageView(textContent, iamgeView); //或者带Icon的二维码 qrCodeEncoder.createQrCode2ImageView(textContent, iamgeView, R.mipmap.ic_launcher);
结果如下:
内容:”https://github.com/qingmei2”
一般二维码:
带Icon的二维码:
更简单的方式
是不是觉得还是有点麻烦,没关系,笔者花了点时间将二维码的生成&解析封装成了library,只需要按照上面的使用文档使用就可以了:简单易上手的 Android 扫描二维码控件
如果只是需要用到二维码的生成,只需要添加对应的依赖,然后直接按照QrCodeScannerView-Android中文说明文档或者文章上方的「如何使用」方式直接使用即可。
相关文章推荐
- Android基于Google Zxing实现二维码/条形码扫描、生成二维码/条形码
- Android基于Zxing实现扫描和生成二维码
- Android基于google Zxing实现二维码的生成
- 基于ZXing Android实现生成二维码图片和相机扫描二维码图片即时解码的功能
- Android基于Zxing实现二维码,条形码扫描和生成二维码
- Android 基于google Zxing实现二维码的生成,识别和长按识别的效果
- Android基于Google Zxing生成二维码
- Android平台利用ZXING生成二维码图片
- Android 基于google Zxing实现二维码、条形码扫描,仿微信二维码扫描效果
- 基于zxing的彩色二维码生成与解析
- Android:基于google Zxing实现二维码、条形码扫描,仿微信二维码扫描效果
- Android二维码开发(基于Zxing)
- Android 基于google Zxing实现二维码、条形码扫描
- Android平台利用ZXING生成二维码图片
- Android 基于google Zxing实现二维码、条形码扫描,仿微信二维码扫描效果
- ZXing二维码生成工具类
- Android 基于google Zxing实现二维码、条形码扫描,仿微信二维码扫描效果
- Android zxing生成二维码
- Android 基于google Zxing实现二维码、条形码扫描,仿微信二维码扫描效果
- ZXing 二维码解析生成工具类