Bootstrap

Android开发——Android中的二维码生成与扫描

0. 前言

今天这篇文章主要描述二维码的生成与扫描,使用目前流行的Zxing,为什么要讲二维码,因为二维码太普遍了,随便一个Android APP都会有二维码扫描。本篇旨在帮助有需求的同学快速完成二维码生成和扫描的功能。

本篇转载自:http://blog.csdn.net/hai_qing_xu_kong/article/details/51260428

 

1.    Zxing的使用

github上下载项目后,可以看到整体代码结构如下:

这里写图片描述

我们只需将Zxing包下的所有代码copy一份到我们的项目中去,除了这些还需要zxing的jar包,最后相应的资源文件,包括values文件下的ids文件、raw文件中的资源文件(可以替换)、layout文件下的activity_capture.xml(可以进行相应的订制) 和图片资源。

 

2.    生成二维码的实现

等上面工作全部准备完毕后,就可以创建我们的二维码了。如何生成二维码?

需要EncodingUtils这个二维码生成工具类。通过调用工具类中的createQRCode()方法来生成二维码。该方法参数介绍如下:


    
    
  1. /*
  2. * content:二维码内容
  3. * widthPix:二维码宽度
  4. * heightPix:二维码高度
  5. * logoBm:二维码中间的logo对应的Bitmap
  6. */
  7. public static Bitmap createQRCode (String content, int widthPix, int heightPix, Bitmap logoBm)

下面完成的是生成的一个百度地址的二维码,中间LOGO是Android小机器人。并保存图片到本地,方便后续测试二维码的本地读取功能。


    
    
  1. /**
  2. * 创建、展示二维码并将bitmap保存在本地
  3. */
  4. private void create () {
  5. int width = DensityUtil.dip2px( this, 200);
  6. Bitmap bitmap = EncodingUtils.createQRCode( "http://www.baidu.com",
  7. width, width, BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher));
  8. iv_zxing.setImageBitmap(bitmap);
  9. saveBitmap(bitmap);
  10. }
  11. /**
  12. * 将Bitmap保存在本地
  13. *
  14. * @param bitmap
  15. */
  16. public void saveBitmap (Bitmap bitmap) {
  17. // 首先保存图片
  18. File appDir = new File(Environment.getExternalStorageDirectory(), "zxing_image");
  19. if (!appDir.exists()) {
  20. appDir.mkdir();
  21. }
  22. String fileName = "zxing_image" + ".jpg";
  23. File file = new File(appDir, fileName);
  24. try {
  25. FileOutputStream fos = new FileOutputStream(file);
  26. bitmap.compress(CompressFormat.JPEG, 100, fos);
  27. fos.flush();
  28. fos.close();
  29. } catch (Exception e) {
  30. e.printStackTrace();
  31. }
  32. // 把文件插入到系统图库
  33. try {
  34. MediaStore.Images.Media.insertImage( this.getContentResolver(),file.getAbsolutePath(), fileName, null);
  35. } catch (FileNotFoundException e) {
  36. e.printStackTrace();
  37. }
  38. // 通知图库更新
  39. sendBroadcast( new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
  40. Uri.parse( "file://" + "/sdcard/namecard/")));
  41. }

看到如下效果:

这里写图片描述


3.    读取二维码的实现

3.1  摄像头扫描的方式

二维码扫描需要借助于CaptureActivity这个类,打开CaptureActivity界面并进行扫描,扫描完毕后回调onActivityResult()方法,从onActivityResult()中得到扫描后的结果。效果就不演示的,因为使用的是模拟器。详细代码如下:


    
    
  1. /**
  2. * 打开二维码扫描
  3. */
  4. private void open () {
  5. config();
  6. startActivityForResult( new Intent(MainActivity. this,CaptureActivity.class), 0);
  7. }
  8. /**
  9. * 提高屏幕亮度
  10. */
  11. private void config () {
  12. WindowManager. LayoutParams lp = getWindow().getAttributes();
  13. lp.screenBrightness = 1.0f;
  14. getWindow().setAttributes(lp);
  15. }
  16. @Override
  17. protected void onActivityResult (int requestCode, int resultCode, Intent data) {
  18. super.onActivityResult(requestCode, resultCode, data);
  19. if (resultCode == RESULT_OK) {
  20. Bundle bundle = data.getExtras();
  21. String result = bundle.getString( "result");
  22. tv_result.setText(result);
  23. }
  24. }


3.2  本地图片扫描的方式

扫描本地图片需要我们在CaptureActivity中进行相应的修改,为此我在扫描界面底部增加了一个按钮,用来选择本地图片。layout代码这里就不展示,我们直接看点击后的事件处理。


    
    
  1. /**
  2. * 打开本地图片
  3. */
  4. private void openLocalImage () {
  5. // 打开手机中的相册
  6. Intent innerIntent = new Intent(Intent.ACTION_GET_CONTENT);
  7. innerIntent.setType( "image/*");
  8. Intent wrapperIntent = Intent.createChooser(innerIntent, "选择二维码图片");
  9. this.startActivityForResult(wrapperIntent, 0x01);
  10. }

打开系统图片库后选择图片,这时需要重写onActivityResult()方法用于返回图片信息。


    
    
  1. @Override
  2. protected void onActivityResult (int requestCode, int resultCode, Intent data) {
  3. super.onActivityResult(requestCode, resultCode, data);
  4. if (resultCode == RESULT_OK) {
  5. switch (requestCode) {
  6. case 0x01:
  7. // 获取选中图片的路径
  8. Cursor cursor = getContentResolver().query(data.getData(), null, null, null, null);
  9. if (cursor.moveToFirst()) {
  10. photo_path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
  11. }
  12. cursor.close();
  13. new Thread( new Runnable() {
  14. @Override
  15. public void run () {
  16. Result result = scanningImage(photo_path);
  17. if (result != null) {
  18. handleDecode(result, new Bundle());
  19. }
  20. }
  21. }).start();
  22. break;
  23. }
  24. }
  25. }

获取图片路径photo_path后,调用scanningImage()方法进行扫描,Zxing源码中,扫描到的结果都是存放在Result结果集中。获取到Result后,就进行结果的回传,阅读CaptureActivity源码可以得知最后Result结果集会传递给handleDecode()方法。


    
    
  1. /**
  2. * A valid barcode has been found, so give an indication of success and show
  3. * the results.
  4. *
  5. * @param rawResult
  6. * The contents of the barcode.
  7. * @param bundle
  8. * The extras
  9. */
  10. public void handleDecode (Result rawResult, Bundle bundle) {
  11. inactivityTimer.onActivity();
  12. beepManager.playBeepSoundAndVibrate();
  13. Intent resultIntent = new Intent();
  14. bundle.putInt( "width", mCropRect.width());
  15. bundle.putInt( "height", mCropRect.height());
  16. bundle.putString( "result", rawResult.getText());
  17. resultIntent.putExtras(bundle);
  18. this.setResult(RESULT_OK, resultIntent);
  19. CaptureActivity. this.finish();
  20. }

获取到图片路径后需要将其二维码信息包装成Result对象,因此需要解析图片:


    
    
  1. /**
  2. * 扫描二维码图片的方法
  3. *
  4. * @param path
  5. * @return
  6. */
  7. public Result scanningImage (String path) {
  8. if (TextUtils.isEmpty(path)) {
  9. return null;
  10. }
  11. Hashtable<DecodeHintType, String> hints = new Hashtable<DecodeHintType, String>();
  12. hints.put(DecodeHintType.CHARACTER_SET, "UTF8"); // 设置二维码内容的编码
  13. BitmapFactory. Options options = new BitmapFactory.Options();
  14. options.inJustDecodeBounds = true; // 先获取原大小
  15. scanBitmap = BitmapFactory.decodeFile(path, options);
  16. options.inJustDecodeBounds = false; // 获取新的大小
  17. int sampleSize = ( int) (options.outHeight / ( float) 200);
  18. if (sampleSize <= 0)
  19. sampleSize = 1;
  20. options.inSampleSize = sampleSize;
  21. scanBitmap = BitmapFactory.decodeFile(path, options);
  22. int width = scanBitmap.getWidth();
  23. int height = scanBitmap.getHeight();
  24. int[] pixels = new int[width * height];
  25. scanBitmap.getPixels(pixels, 0, width, 0, 0, width, height);
  26. /**
  27. * 第三个参数是图片的像素
  28. */
  29. RGBLuminanceSource source = new RGBLuminanceSource(width, height,
  30. pixels);
  31. BinaryBitmap bitmap1 = new BinaryBitmap( new HybridBinarizer(source));
  32. QRCodeReader reader = new QRCodeReader();
  33. try {
  34. return reader.decode(bitmap1, hints);
  35. } catch (NotFoundException e) {
  36. e.printStackTrace();
  37. } catch (ChecksumException e) {
  38. e.printStackTrace();
  39. } catch (FormatException e) {
  40. e.printStackTrace();
  41. }
  42. return null;
  43. }

根据路径获取Bitmap,最后通过QRCodeReader 中的decode方法解析成Result对象并返回,最终传递给handleDecode方法。运行程序效果如下,扫描出来的是之前定义的百度地址。

这里写图片描述

最后不要忘了申明权限和CaptureActivity。


    
    
  1. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  2. <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
  3. <uses-permission android:name="android.permission.CAMERA"/>
  4. <uses-permission android:name="android.permission.VIBRATE"/>
  5. <activity android:name="com.example.zxingtest.zxing.activity.CaptureActivity"/>

转载于:https://www.cnblogs.com/qitian1/p/6461445.html

;