Android 二维码 生成和识别

今天讲一下目前移动领域很常用的技术——二维码。现在大街小巷、各大网站都有二维码的踪迹,不管是IOS、Android、WP都有相关支持的软件。之前我就想了解二维码是如何工作,最近因为工作需要使用相关技术,所以做了初步了解。今天主要是讲解如何使用ZXing库,生成和识别二维码。这篇文章实用性为主,理论性不会讲解太多,有兴趣可以自己查看源码。


1、ZXing库介绍

  这里简单介绍一下ZXing库。ZXing是一个开放源码的,用Java实现的多种格式的1D/2D条码图像处理库,它包含了联系到其他语言的端口。Zxing可以实现使用手机的内置的摄像头完成条形码的扫描及解码。该项目可实现的条形码编码和解码。目前支持以下格式:UPC-A,UPC-E、EAN-8,EAN-13、39码、93码。ZXing是个很经典的条码/二维码识别的开源类库,以前在功能机上,就有开发者使用J2ME运用ZXing了,不过要支持JSR-234规范(自动对焦)的手机才能发挥其威力。


2、ZXing库主要类
  下面给大家介绍一下,ZXing库里面主要的类以及这些类的作用:
  • CaptureActivity。这个是启动Activity 也就是扫描器。
  • CaptureActivityHandler 解码处理类,负责调用另外的线程进行解码。
  • DecodeThread 解码的线程。
  • com.google.zxing.client.android.camera 包,摄像头控制包。
  • ViewfinderView 自定义的View,就是我们看见的拍摄时中间的框框了。

3、使用ZXing生成二维码
  下面针对二维码生成和解析做个简单介绍,至于详细的使用方法,建议大家还是自己看看源码,使用起来很简单,不过这个开源项目的代码,值得好好看看。首先给出二维码生成的方法:
  1. //Edited by mythou
  2. //http://www.cnblogs.com/mythou/
  3.   //要转换的地址或字符串,可以是中文
  4.     public void createQRImage(String url)
  5.     {
  6.         try
  7.         {
  8.             //判断URL合法性
  9.             if (url == null || "".equals(url) || url.length() < 1)
  10.             {
  11.                 return;
  12.             }
  13.             Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();
  14.             hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
  15.             //图像数据转换,使用了矩阵转换
  16.             BitMatrix bitMatrix = new QRCodeWriter().encode(url, BarcodeFormat.QR_CODE, QR_WIDTH, QR_HEIGHT, hints);
  17.             int[] pixels = new int[QR_WIDTH * QR_HEIGHT];
  18.             //下面这里按照二维码的算法,逐个生成二维码的图片,
  19.             //两个for循环是图片横列扫描的结果
  20.             for (int y = 0; y < QR_HEIGHT; y++)
  21.             {
  22.                 for (int x = 0; x < QR_WIDTH; x++)
  23.                 {
  24.                     if (bitMatrix.get(x, y))
  25.                     {
  26.                         pixels[y * QR_WIDTH + x] = 0xff000000;
  27.                     }
  28.                     else
  29.                     {
  30.                         pixels[y * QR_WIDTH + x] = 0xffffffff;
  31.                     }
  32.                 }
  33.             }
  34.             //生成二维码图片的格式,使用ARGB_8888
  35.             Bitmap bitmap = Bitmap.createBitmap(QR_WIDTH, QR_HEIGHT, Bitmap.Config.ARGB_8888);
  36.             bitmap.setPixels(pixels, 0, QR_WIDTH, 0, 0, QR_WIDTH, QR_HEIGHT);
  37.             //显示到一个ImageView上面
  38.             sweepIV.setImageBitmap(bitmap);
  39.         }
  40.         catch (WriterException e)
  41.         {
  42.             e.printStackTrace();
  43.         }
  44.     }
复制代码
上面就是二维码生成的方法接口,如果你只是使用者方法,很简单,只要传入一个URL即可,就像我截图里面一样,传入一个合法的网址即可。或者像现在一些移动APP的推广,把APP下载地址转为二维码,只要扫一下就可以下载相应的APP。这个也是目前比较流行的APP的推广方式。  上面代码做的事情不多,主要是调用ZXing库里面QRCodeWriter().encode的方法对我们传进去的URL进行编码,具体如何编码,这个我这里就不详细说,有兴趣可以看ZXing的源码。文章最后会给出ZXing的源码和例子代码。  4、扫描二维码获取信息  扫描获取二维码信息的工作稍微复杂一些,主要是需要编写Camera的使用,这个跟我们一般使用Camera一样,需要使用Surfaceview作为预览,这一部我这里就不说了,这个应该不是太复杂。对于使用过Camera做预览的朋友,应该是挺简单的事情。获取二维码数据的关键处理是在Camera的自动对焦回调函数哪里,调用ZXing的解码接口。
  1. //Edited by mythou
  2. //http://www.cnblogs.com/mythou/
  3.   private void restartPreviewAndDecode() {
  4.     if (state == State.SUCCESS) {
  5.       state = State.PREVIEW;
  6.       CameraManager.get().requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
  7.       CameraManager.get().requestAutoFocus(this, R.id.auto_focus);
  8.       activity.drawViewfinder();
  9.     }
  10.   }
复制代码
这里稍微多说一句,由于解码需要一定时间,所以ZXing的解码调用,都是使用了Handler作为线程通信机制,解码的工作都是放在独立线程里面使用的,如果你直接在主线程解码,恐怕ANR问题是避免不了。
  1. //Edited by mythou
  2. //http://www.cnblogs.com/mythou/
  3. public void handleMessage(Message message) {
  4.     switch (message.what) {
  5.       case R.id.auto_focus:
  6.         //Log.d(TAG, "Got auto-focus message");
  7.         // When one auto focus pass finishes, start another. This is the closest thing to
  8.         // continuous AF. It does seem to hunt a bit, but I'm not sure what else to do.
  9.         if (state == State.PREVIEW) {
  10.           CameraManager.get().requestAutoFocus(this, R.id.auto_focus);
  11.         }
  12.         break;
  13.       case R.id.restart_preview:
  14.         Log.d(TAG, "Got restart preview message");
  15.         restartPreviewAndDecode();
  16.         break;
  17.       case R.id.decode_succeeded:
  18.     //解码成功,获取到界面的结果和原来的二维码数据
  19.         Log.d(TAG, "Got decode succeeded message");
  20.         state = State.SUCCESS;
  21.         Bundle bundle = message.getData();
  22.         Bitmap barcode = bundle == null ? null :
  23.             (Bitmap) bundle.getParcelable(DecodeThread.BARCODE_BITMAP);
  24.         activity.handleDecode((Result) message.obj, barcode);
  25.         break;
  26.       case R.id.decode_failed:
  27.         // We're decoding as fast as possible, so when one decode fails, start another.
  28.         state = State.PREVIEW;
  29.         CameraManager.get().requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
  30.         break;
  31.       case R.id.return_scan_result:
  32.         Log.d(TAG, "Got return scan result message");
  33.         activity.setResult(Activity.RESULT_OK, (Intent) message.obj);
  34.         activity.finish();
  35.         break;
  36.       case R.id.launch_product_query:
  37.         Log.d(TAG, "Got product query message");
  38.         String url = (String) message.obj;
  39.         Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
  40.         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
  41.         activity.startActivity(intent);
  42.         break;
  43.     }
  44.   }
复制代码
上面是解码的线程处理不同状态的时候需要注意的地方,我们这里只看获取图像成功的地方,成功获取图片解码的实在DecodeThread里面实现,DecodeThread里面解码成功后,会把数据序列化,然后保存到Bundle里面,我们可以直接通过Bundle的序列化,获取到图片数据。同时会把解码后的结果保存到MSG里面,然后就可以根据实际情况进行处理,例如上面代码,解码成功后,会调用一个处理函数:
  1. //Edited by mythou
  2. //http://www.cnblogs.com/mythou/
  3.   public void handleDecode(final Result obj, Bitmap barcode)
  4.     {
  5.         inactivityTimer.onActivity();
  6.         playBeepSoundAndVibrate();
  7.         AlertDialog.Builder dialog = new AlertDialog.Builder(this);
  8.         if (barcode == null)
  9.         {
  10.             dialog.setIcon(null);
  11.         }
  12.         else
  13.         {

  14.             Drawable drawable = new BitmapDrawable(barcode);
  15.             dialog.setIcon(drawable);
  16.         }
  17.         dialog.setTitle("扫描结果");
  18.         dialog.setMessage(obj.getText());
  19.         dialog.setNegativeButton("确定", new DialogInterface.OnClickListener()
  20.         {
  21.             @Override
  22.             public void onClick(DialogInterface dialog, int which)
  23.             {
  24.                 //用默认浏览器打开扫描得到的地址
  25.                 Intent intent = new Intent();
  26.                 intent.setAction("android.intent.action.VIEW");
  27.                 Uri content_url = Uri.parse(obj.getText());
  28.                 intent.setData(content_url);
  29.                 startActivity(intent);
  30.                 finish();
  31.             }
  32.         });
  33.         dialog.setPositiveButton("取消", new DialogInterface.OnClickListener()
  34.         {
  35.             @Override
  36.             public void onClick(DialogInterface dialog, int which)
  37.             {
  38.                 finish();
  39.             }
  40.         });
  41.         dialog.create().show();
  42.     }
复制代码
上面就是整个二维码的解码流程,里面因为涉及很多Camera的使用,所以你如果需要使用二维码识别,需要注意一下你的程序需要申请下面的权限,一般的Camera使用以及Camera的自动对焦等。
  1. //Edited by mythou
  2. //http://www.cnblogs.com/mythou/
  3. <uses-permission android:name="android.permission.CAMERA"></uses-permission>
  4. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
  5. <uses-feature android:name="android.hardware.camera" />
  6. <uses-feature android:name="android.hardware.camera.autofocus" />
复制代码
5、结语  上面就是生成和识别二维码的关键流程和代码,有兴趣的朋友可以自己查看ZXing的源码,里面有很多图像分析的知识可以学习。具体使用也可以参考我下面给出的Demo。二维码对于现在移动开发来说很是很常用的技术,所以有空可以了解一下,说不定什么时候就用上了。另外,ZXing库除了二维码外,其实对于条形码也是支持的,只是我这里没有介绍。有需要的自己去看看源码即可。 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值