咨询热线:15338715291 联系人:夏云松 地址:中国吉林前郭尔罗斯蒙古族自治县松原市经济技术开发区
zxing开源库的基本使用
来源:ebet白金会 发布时间:2019-11-07 点击量:444
如果你的项目中有模块跟二维码相关的话,那你一定听过或者用过大名鼎鼎的zxing开源库。
什么是zxing?
ZXing是一个开源的,用Java实现的多种格式的1D/2D条码图像处理库,它包含了联系到其他语言的端口。zxing可以实现使用手机的内置的摄像头完成条形码的扫描及解码。
本篇文章就来学习zxing的基本使用,学习了以下几个内容就能满足大部分项目中的二维码相关需求:
通过摄像头扫描二维码图片,读取图片内容从相册中选取二维码图片,读取图片内容自己输入字符串内容,生成二维码图片长按识别自己生成的二维码图片如何依赖zxing到项目中?
如果你还在使用zxing的jar包、或者你是把zxing的代码复制到项目中,使用这两种方式依赖的话那就out了,现在Android Studio可支持zxing在线依赖,目前最新版本是3.3.3。在线依赖的好处我就不多说了,相信大家都懂。
新建项目,在app/build.gradle文件中在线依赖:
implementation "com.google.zxing:core:3.3.3"
加入权限
因为扫描二维码需要摄像头权限,把图片保存到本地需要sdcard权限,所以需要在AndroidManifest.xml中加入相应的权限
<uses-permission android:name="android.permission.CAMERA" /><uses-permission android:name="android.permission.VIBRATE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-feature android:name="android.hardware.camera" /><uses-feature android:name="android.hardware.camera.autofocus" />
当然现在市面上的手机大部分都是6.0以上的操作系统了,所以还得在MainActivity的onCreate方法中动态申请以上这两个权限。
//6.0版本或以上需请求权限String[] permissions=new String[]{Manifest.permission. WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA};if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) { requestPermissions(permissions,PERMS_REQUEST_CODE);}
扫描二维码
项目依赖进来了,权限也有了,开始用代码实现第一个功能。点击扫描二维码按钮,开启一个ScanActivity,这个Activity是我之前封装好的,里面处理了扫描二维码的整个流程,扫描成功后会把扫描结果返回。ScanActivity类的代码有点多,就不贴出来了,有兴趣的自己看源码。
Intent intent = new Intent(MainActivity.this,ScanActivity.class);startActivityForResult(intent,SCAN_REQUEST_CODE);
重写onActivityResult方法,监听扫描结果。
@Overrideprotected void onActivityResult(int requestCode, int resultCode, @Nullable Intent intent) { super.onActivityResult(requestCode, resultCode, intent); if (requestCode == SCAN_REQUEST_CODE && resultCode == RESULT_OK) { String input = intent.getStringExtra(ScanActivity.INTENT_EXTRA_RESULT); showToast("扫描结果:"+input); }}
从相册中选择二维码图片进行识别
首先启动系统相册,从相册中选择一张图片。
Intent innerIntent = new Intent(Intent.ACTION_PICK,MediaStore.Images.Media.EXTERNAL_CONTENT_URI);Intent wrapperIntent = Intent.createChooser(innerIntent, "选择二维码图片");startActivityForResult(wrapperIntent, SELECT_IMAGE_REQUEST_CODE);
然后在onActivityResult中获取选择图片路径,调用BitmapUtil.parseQRcode方法解析二维码图片。
@Overrideprotected void onActivityResult(int requestCode, int resultCode, @Nullable Intent intent) { super.onActivityResult(requestCode, resultCode, intent); if(requestCode==SELECT_IMAGE_REQUEST_CODE){//从图库选择图片 String[] proj = {MediaStore.Images.Media.DATA}; // 获取选中图片的路径 Cursor cursor = this.getContentResolver().query(intent.getData(),proj, null, null, null); if (cursor.moveToFirst()) { int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); String photoPath = cursor.getString(columnIndex); String result= BitmapUtil.parseQRcode(photoPath); if (!TextUtils.isEmpty(result)) { showToast("从图库选择的图片识别结果:"+result); } else { showToast("从图库选择的图片不是二维码图片"); } } cursor.close(); }}
接下来看parseQRcode方法,
/** * 解析二维码图片 * @param bitmapPath 文件路径 * @return */public static String parseQRcode(String bitmapPath){ Bitmap bitmap = BitmapFactory.decodeFile(bitmapPath, null); String result=parseQRcode(bitmap); return result;}
从上面的方法中看到直接把文件路径读取成Bitmap,继续调用parseQRcode方法把Bitmap对象传进去,这里用到了方法重载。
public static String parseQRcode(Bitmap bmp){ bmp=comp(bmp);//bitmap压缩 如果不压缩的话在低配置的手机上解码很慢 int width = bmp.getWidth(); int height = bmp.getHeight(); int[] pixels = new int[width * height]; bmp.getPixels(pixels, 0, width, 0, 0, width, height); QRCodeReader reader = new QRCodeReader(); Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class); hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);//优化精度 hints.put(DecodeHintType.CHARACTER_SET,"utf-8");//解码设置编码方式为:utf-8 try { Result result = reader.decode(new BinaryBitmap( new HybridBinarizer(new RGBLuminanceSource(width, height, pixels))), hints); return result.getText(); } catch (NotFoundException e) { Log.i("ansen",""+e.toString()); e.printStackTrace(); } catch (ChecksumException e) { e.printStackTrace(); } catch (FormatException e) { e.printStackTrace(); } return null;}
如果传入的是一个Bitmap对象,先调用comp方法对Bitmap进行压缩(压缩代码这里不贴出),获取图片宽高,把图像的每个像素颜色转为int值,存入pixels数组。
然后初始化QRCodeReader对象,调用decode方法进行解码,这个方法有两个参数,参数1是一个BinaryBitmap对象,第二个参数是一个Map类型,key的值是DecodeHintType枚举类型,这里我们put了两个值,优化精度跟设置编码方式为。这个方法还会返回一个Result对象,最后调用result.getText()方法获取二维码内容。
生成二维码图片
生成二维码图片调用CreateQRBitmp.createQRCodeBitmap方法生成,这个方法是我们自己封装的,需要传入两个参数,参数1:图片内容、参数2:二维码图片最中间显示的logo(Bitmap对象)。
String contentString = etInput.getText().toString().trim();if(TextUtils.isEmpty(contentString)){ showToast("请输入二维码内容"); return ;}Log.i("ansen","输入的内容:"+contentString);Bitmap portrait = BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher);//两个方法,一个不传大小,使用默认qrCodeBitmap = CreateQRBitmp.createQRCodeBitmap(contentString, portrait);ivQrImage.setImageBitmap(qrCodeBitmap);
createQRCodeBitmap源码如下:
public static Bitmap createQRCodeBitmap(String content,Bitmap portrait) { // 用于设置QR二维码参数 Hashtable<EncodeHintType, Object> qrParam = new Hashtable<>(); // 设置QR二维码的纠错级别——这里选择最高H级别 qrParam.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // 设置编码方式 qrParam.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // 生成QR二维码数据——这里只是得到一个由true和false组成的数组 // 参数顺序分别为:编码内容,编码类型,生成图片宽度,生成图片高度,设置参数 try { BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, qrParam); // 开始利用二维码数据创建Bitmap图片,分别设为黑白两色 int w = bitMatrix.getWidth(); int h = bitMatrix.getHeight(); int[] data = new int[w * h]; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { if (bitMatrix.get(x, y)) data[y * w + x] = 0xff000000;// 黑色 else data[y * w + x] = 0x00ffffff;// -1 相当于0xffffffff 白色 } } // 创建一张bitmap图片,采用最高的图片效果ARGB_8888 Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); // 将上面的二维码颜色数组传入,生成图片颜色 bitmap.setPixels(data, 0, w, 0, 0, w, h); if(portrait!=null){ createQRCodeBitmapWithPortrait(bitmap,initProtrait(portrait)); } return bitmap; } catch (WriterException e) { e.printStackTrace(); } return null;}
大部分代码都有注释,首先就是调用MultiFormatWriter对象的encode方法生成BitMatrix对象,这里我们传入5个参数,参数1:内容、参数2:二维码格式、参数3:图片宽、参数4:图片高、参数5:二维码生成的参数(例如编码方法以及纠错级别)。
拿到BitMatrix对象后开始利用二维码数据创建Bitmap图片,分别设为黑白两色,创建一个宽高一样的Bitmap对象,调用setPixels方法把上面的二维码颜色数组传入,生成图片颜色。如果中间需要添加logo调用createQRCodeBitmapWithPortrait方法。最后把Bitmap对象返回。
长按识别二维码以及保存图片
识别二维码跟从相册中选择图片进行识别功能上很相似,所以就不在做重复介绍了,就介绍一下保存图片功能。
从下面源码中看到,首先获取rootView,从rootView中获取根布局的Bitmap,然后调用ImageUtil.savePicToLocal方法保存图片。
View view = getWindow().getDecorView().getRootView();//找到当前页面的根布局view.setDrawingCacheEnabled(true);//禁用绘图缓存view.buildDrawingCache();Bitmap temBitmap = view.getDrawingCache();ImageUtil.savePicToLocal(temBitmap,MainActivity.this);//禁用DrawingCahce否则会影响性能 ,而且不禁止会导致每次截图到保存的是缓存的位图view.setDrawingCacheEnabled(false);//识别完成之后开启绘图缓存showToast("保存图片到本地成功");
ImageUtil.savePicToLocal方法也比较简单,就是把一个Bitmap保存到本地Sdcard上。需要注意的是记得发送一个广播,不然需要重启手机才能在系统相册中看到这个图片。
public static void savePicToLocal(Bitmap bitmap, Context context) { String filePath=Environment.getExternalStorageDirectory() .getAbsolutePath() + "/screen"+File.separator + System.currentTimeMillis() + ".png"; if (bitmap != null) { try { // 图片文件路径 Log.i("ansen", "filePath:" + filePath); File file = new File(filePath); if (!file.getParentFile().exists()) { file.getParentFile().mkdirs(); } FileOutputStream os = new FileOutputStream(file); bitmap.compress(Bitmap.CompressFormat.PNG, 100, os); Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); Uri uri = Uri.fromFile(new File(filePath)); intent.setData(uri); context.sendBroadcast(intent); os.flush(); os.close(); } catch (Exception e) { } }}
代码终于写完了,接下来看看效果,由于模拟器没有摄像头,而真机又不能录制Gif图片,所以摄像头扫描二维码就不演示啦,大家自己下载源码运行查看效果。
当然少不了源码,下载地址如下:
https://github.com/ansen666/ZxingTest
如果你想第一时间看我的后期文章,扫码关注公众号,长期推送Android开发文章、最新动态、开源项目,让你各种涨姿势。
Android开发666 - 安卓开发技术分享 扫描二维码加关注
相关产品
-
五曰“骗补”。上半年,财政部、工信部等部委对部分企业数据造假、骗取新能源汽车补贴问题进行核查。尽管骗补问题发酵,让持续火爆的新能源汽车很“受伤”,但有关部门的坚决打击,从长远看有利于新能源汽车产业的发展壮大。
-
深圳宝安区人民法院去年12月的一份民事判决书中,原告黄鹏飞等称被深圳市佳创开发有限公司以“联合百度招聘的旗号”诱骗并签订培训贷款协议,通过“百度有钱花”等软件贷款支付了培训费用15800元。法院称,被告承认其未取得办学资格证,被告应将其收取的培训费用返还原告。在裁判文书网上,类似的纠纷并不少见。
-
黄会林表示,周边国家受访者对观看中国电影的偏好程度较弱,对中国传统文化形象认知度较高,对当代文化形象认知度较低。因此,在电影的对外传播中,应注意当代中国社会形象的塑造。
-
然而,在国内的校企合作中,记者调查发现,很多学校只想着把学生送出去,企业只想着把人招进来,至于学生的专业与企业提供的岗位是否匹配,并不在学校与企业的考虑范围之内。
-
至于第一遍回帖称“该路段对通川区和江陵镇无任何意义,青龙村村民修路的意愿不高,如平昌县元石乡愿意修该路段,江陵镇人民政府将配合做好相关工作。”一事,李兴见称,“这是笔误,作为政府来说,不管这条路的意义大不大,村民意愿高不高,都有责任和义务将这条路修通。”
-
据介绍,重庆市公安交管局充分利用4S店、二手车交易市场等民营企业资源,已向重庆全市448家4S店让渡临时号牌核发权限,向74家车驾管社会服务站(其中民营企业65家)让渡注册登记、转移登记、抵押登记、注销登记业务及驾驶证补换证等业务权限,向88家机动车检验机构(其中民营企业83家)让渡检验合格标志发放权限。
-
9月中下旬民调显示,台北市长选情,连胜文、柯文哲支持度大幅拉近,由先前相差13个百分点,缩小至7个百分点,台“未来事件交易所”民调显示,连胜文反超柯文哲1个百分点,而台湾地下赌盘更预测,连胜文将赢柯文哲10万票;台中市选情也差不多,胡志强与林佳龙的民调差距由7月份的 17个百分点,到9月份的7个百分点,台“未来事件交易所”民调显示,两人看好当选几率差距已不足4个百分点,逼近3个百分点的民调误差允许范围内。
-
两岸市场大小悬殊,台湾却在网购领域吞下大逆差,反映出两岸电商业的差距,也说明台湾电商尤其是跨境电商还有很大的成长空间。
热点资讯
- 拒绝评论“土嗨”,尚雯婕是真real还是不包容?2019-06-17
- 低端智能锁玩家抢用户、抢融资、抢份额:谁抢安全?2019-06-17
- 话费充3000送5000?重庆警方破获大型诈骗案2019-06-17
- 苹果在美计划爆增20%员工,特朗普高兴不起来,房产高兴!2019-06-17
- 王文学大撤退2019-06-17
- 双色织物拼接/轻盈透气,贵人鸟飞织网面运动鞋79元2019-06-17
- 特斯拉首席执行官马斯克:那些想走捷径的人最终会绕道而行。2019-06-17
- 对话蓝箭CEO张长武:固体火箭是牛道小试射的液体火箭是未来的IT新闻2019-10-29