zoukankan      html  css  js  c++  java
  • Android 二维码 生成和识别(附Demo源码)

      今天讲一下目前移动领域很常用的技术——二维码。现在大街小巷、各大网站都有二维码的踪迹,不管是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规范(自动对焦)的手机才能发挥其威力。

      下面是ZXing的demo运行,我这里创建了一个二维码,内容是我博客的网址,大伙可以用微信的扫一扫功能,试一下。就可以直接打开我博客。
     (PS:新建的QQ群,有兴趣可以加入一起讨论:Android群:322599434)
     
     
    2、ZXing库主要类

      下面给大家介绍一下,ZXing库里面主要的类以及这些类的作用:

    • CaptureActivity。这个是启动Activity 也就是扫描器。
    • CaptureActivityHandler 解码处理类,负责调用另外的线程进行解码。
    • DecodeThread 解码的线程。
    • com.google.zxing.client.android.camera 包,摄像头控制包。
    • ViewfinderView 自定义的View,就是我们看见的拍摄时中间的框框了。

    3、使用ZXing生成二维码

      下面针对二维码生成和解析做个简单介绍,至于详细的使用方法,建议大家还是自己看看源码,使用起来很简单,不过这个开源项目的代码,值得好好看看。首先给出二维码生成的方法:

        
    //Edited by mythou
    //http://www.cnblogs.com/mythou/
      //要转换的地址或字符串,可以是中文
        public void createQRImage(String url)
        {
            try
            {
                //判断URL合法性
                if (url == null || "".equals(url) || url.length() < 1)
                {
                    return;
                }
                Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();
                hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
                //图像数据转换,使用了矩阵转换
                BitMatrix bitMatrix = new QRCodeWriter().encode(url, BarcodeFormat.QR_CODE, QR_WIDTH, QR_HEIGHT, hints);
                int[] pixels = new int[QR_WIDTH * QR_HEIGHT];
                //下面这里按照二维码的算法,逐个生成二维码的图片,
                //两个for循环是图片横列扫描的结果
                for (int y = 0; y < QR_HEIGHT; y++)
                {
                    for (int x = 0; x < QR_WIDTH; x++)
                    {
                        if (bitMatrix.get(x, y))
                        {
                            pixels[y * QR_WIDTH + x] = 0xff000000;
                        }
                        else
                        {
                            pixels[y * QR_WIDTH + x] = 0xffffffff;
                        }
                    }
                }
                //生成二维码图片的格式,使用ARGB_8888
                Bitmap bitmap = Bitmap.createBitmap(QR_WIDTH, QR_HEIGHT, Bitmap.Config.ARGB_8888);
                bitmap.setPixels(pixels, 0, QR_WIDTH, 0, 0, QR_WIDTH, QR_HEIGHT);
                //显示到一个ImageView上面
                sweepIV.setImageBitmap(bitmap);
            }
            catch (WriterException e)
            {
                e.printStackTrace();
            }
        }

      上面就是二维码生成的方法接口,如果你只是使用者方法,很简单,只要传入一个URL即可,就像我截图里面一样,传入一个合法的网址即可。或者像现在一些移动APP的推广,把APP下载地址转为二维码,只要扫一下就可以下载相应的APP。这个也是目前比较流行的APP的推广方式。

      上面代码做的事情不多,主要是调用ZXing库里面QRCodeWriter().encode的方法对我们传进去的URL进行编码,具体如何编码,这个我这里就不详细说,有兴趣可以看ZXing的源码。文章最后会给出ZXing的源码和例子代码。

    4、扫描二维码获取信息

      扫描获取二维码信息的工作稍微复杂一些,主要是需要编写Camera的使用,这个跟我们一般使用Camera一样,需要使用Surfaceview作为预览,这一部我这里就不说了,这个应该不是太复杂。对于使用过Camera做预览的朋友,应该是挺简单的事情。获取二维码数据的关键处理是在Camera的自动对焦回调函数哪里,调用ZXing的解码接口。

      
    //Edited by mythou
    //http://www.cnblogs.com/mythou/
      private void restartPreviewAndDecode() {
        if (state == State.SUCCESS) {
          state = State.PREVIEW;
          CameraManager.get().requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
          CameraManager.get().requestAutoFocus(this, R.id.auto_focus);
          activity.drawViewfinder();
        }
      }

      这里稍微多说一句,由于解码需要一定时间,所以ZXing的解码调用,都是使用了Handler作为线程通信机制,解码的工作都是放在独立线程里面使用的,如果你直接在主线程解码,恐怕ANR问题是避免不了。

    //Edited by mythou
    //http://www.cnblogs.com/mythou/
    public void handleMessage(Message message) {
        switch (message.what) {
          case R.id.auto_focus:
            //Log.d(TAG, "Got auto-focus message");
            // When one auto focus pass finishes, start another. This is the closest thing to
            // continuous AF. It does seem to hunt a bit, but I'm not sure what else to do.
            if (state == State.PREVIEW) {
              CameraManager.get().requestAutoFocus(this, R.id.auto_focus);
            }
            break;
          case R.id.restart_preview:
            Log.d(TAG, "Got restart preview message");
            restartPreviewAndDecode();
            break;
          case R.id.decode_succeeded:
        //解码成功,获取到界面的结果和原来的二维码数据 Log.d(TAG,
    "Got decode succeeded message"); state = State.SUCCESS; Bundle bundle = message.getData(); Bitmap barcode = bundle == null ? null : (Bitmap) bundle.getParcelable(DecodeThread.BARCODE_BITMAP); activity.handleDecode((Result) message.obj, barcode); break; case R.id.decode_failed: // We're decoding as fast as possible, so when one decode fails, start another. state = State.PREVIEW; CameraManager.get().requestPreviewFrame(decodeThread.getHandler(), R.id.decode); break; case R.id.return_scan_result: Log.d(TAG, "Got return scan result message"); activity.setResult(Activity.RESULT_OK, (Intent) message.obj); activity.finish(); break; case R.id.launch_product_query: Log.d(TAG, "Got product query message"); String url = (String) message.obj; Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); activity.startActivity(intent); break; } }

      上面是解码的线程处理不同状态的时候需要注意的地方,我们这里只看获取图像成功的地方,成功获取图片解码的实在DecodeThread里面实现,DecodeThread里面解码成功后,会把数据序列化,然后保存到Bundle里面,我们可以直接通过Bundle的序列化,获取到图片数据。同时会把解码后的结果保存到MSG里面,然后就可以根据实际情况进行处理,例如上面代码,解码成功后,会调用一个处理函数:

        
    //Edited by mythou
    //http://www.cnblogs.com/mythou/
      public void handleDecode(final Result obj, Bitmap barcode)
        {
            inactivityTimer.onActivity();
            playBeepSoundAndVibrate();
            AlertDialog.Builder dialog = new AlertDialog.Builder(this);
            if (barcode == null)
            {
                dialog.setIcon(null);
            }
            else
            {
    
                Drawable drawable = new BitmapDrawable(barcode);
                dialog.setIcon(drawable);
            }
            dialog.setTitle("扫描结果");
            dialog.setMessage(obj.getText());
            dialog.setNegativeButton("确定", new DialogInterface.OnClickListener()
            {
                @Override
                public void onClick(DialogInterface dialog, int which)
                {
                    //用默认浏览器打开扫描得到的地址
                    Intent intent = new Intent();
                    intent.setAction("android.intent.action.VIEW");
                    Uri content_url = Uri.parse(obj.getText());
                    intent.setData(content_url);
                    startActivity(intent);
                    finish();
                }
            });
            dialog.setPositiveButton("取消", new DialogInterface.OnClickListener()
            {
                @Override
                public void onClick(DialogInterface dialog, int which)
                {
                    finish();
                }
            });
            dialog.create().show();
        }

      上面就是整个二维码的解码流程,里面因为涉及很多Camera的使用,所以你如果需要使用二维码识别,需要注意一下你的程序需要申请下面的权限,一般的Camera使用以及Camera的自动对焦等。

    //Edited by mythou
    //http://www.cnblogs.com/mythou/
    <uses-permission android:name="android.permission.CAMERA"></uses-permission>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />

    5、结语

      上面就是生成和识别二维码的关键流程和代码,有兴趣的朋友可以自己查看ZXing的源码,里面有很多图像分析的知识可以学习。具体使用也可以参考我下面给出的Demo。二维码对于现在移动开发来说很是很常用的技术,所以有空可以了解一下,说不定什么时候就用上了。另外,ZXing库除了二维码外,其实对于条形码也是支持的,只是我这里没有介绍。有需要的自己去看看源码即可。

    2013-8-16 

    Edited by 泡泡糖

    ZXing开源项目Google Code地址:https://code.google.com/p/zxing/

    ZXingDemo下载:ZXingDemo2013-8-25.rar

     

    Edited by mythou

    原创博文,转载请标明出处:http://www.cnblogs.com/mythou/p/3280023.html 

  • 相关阅读:
    高精度计算
    高精度除以低精度
    P1258 小车问题
    POJ 2352 stars (树状数组入门经典!!!)
    HDU 3635 Dragon Balls(超级经典的带权并查集!!!新手入门)
    HDU 3938 Portal (离线并查集,此题思路很强!!!,得到所谓的距离很巧妙)
    POJ 1703 Find them, Catch them(确定元素归属集合的并查集)
    HDU Virtual Friends(超级经典的带权并查集)
    HDU 3047 Zjnu Stadium(带权并查集,难想到)
    HDU 3038 How Many Answers Are Wrong(带权并查集,真的很难想到是个并查集!!!)
  • 原文地址:https://www.cnblogs.com/mythou/p/3280023.html
Copyright © 2011-2022 走看看