Android自由行之走进zxing,轻松实现二维码扫描

现在很多App都集成了扫一扫功能,最常用的微信、QQ、手机助手等。二维码也使得生活变得更加简洁,扫一扫订餐、扫一扫下载等等。那么,说到二维码,我们不得不提Google一个开源的扫码框架:zxing。

开源下载:http://code.google.com/p/zxing/

zxing是基于多种1D/2D条码处理的开源库,是一个完整的项目。它可以通过手机摄像头实现条码的扫描以及解码,功能及其强大。那么如果要实现二维码的扫描以及解码,我们需要在该开源项目的基础上进行简化,并修改。让我们来看一下

      

上图是仿照QQ的扫一扫进行修改的zxing项目,以zxing项目为基础,结合实际应用,这里作了三点改变:

(1)竖屏扫描

(2)自定义取景框

(3)重新定义扫描结果处理

一、第一步:下载zxing项目,并简化出扫描框架

1、首先,下载最新zxing开源项目。 下载地址:http://code.google.com/p/zxing/

2、分析项目结构,明确扫描框架需求。在zxing中,有很多其他的功能,项目结构比较复杂;针对二维码QRCode扫描,我们需要几个包:

(1)com.google.zxing.client.android.Camera  基于Camera调用以及参数配置,核心包

(2)DecodeFormatManager、DecodeThread、DecodeHandler 基于解码格式、解码线程、解码结果处理的解码类

(3)ViewfinderView、ViewfinderResultPointCallBack 基于取景框视图定义的View类

(4)CaptureActivity、CaptureActivityHandler 基于扫描Activity以及扫描结果处理的Capture类

(5)InactivityTimer、BeepManager、FinishListener 基于休眠、声音、退出的辅助管理类

(6)Intents、IntentSource、PrefrencesActivity 基于常量存储的常量类

3、新建工程,添加如下权限:

  <uses-permission android:name="android.permission.CAMERA"/>
         <uses-permission android:name="android.permission.INTERNET" />
         <uses-permission android:name="android.permission.VIBRATE" />
         <uses-permission android:name="android.permission.FLASHLIGHT" />

permission

添加core.jar文件,并BuildPath;将上述类或包加入工程后,会报一系列错误,原因有几点:

(1)资源文件缺乏,将zxing下需要的资源文件copy到新工程下

(2)版本兼容问题,zxing下很多技术都是使用4.0版本及以上,集成到低版本之后,须做相应改动,详情参照项目源码

(3)包结构引用问题,需要重新导入包引用

4、简化CapyureActivity, camera包以及decode各类异常解决以后,即可对CaptureActivity进行代码简化 ,首先看一下capture.xml布局

 1 <merge xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools" >
 3
 4     <!-- 整体透明画布 -->
 5     <SurfaceView
 6         android:id="@+id/preview_view"
 7         android:layout_width="fill_parent"
 8         android:layout_height="fill_parent" />
 9
10     <!-- 扫描取景框 -->
11     <com.karics.library.zxing.view.ViewfinderView
12         android:id="@+id/viewfinder_view"
13         android:layout_width="fill_parent"
14         android:layout_height="fill_parent" />
15
16  <!-- 标题栏 -->
17     <RelativeLayout
18         android:layout_width="fill_parent"
19         android:layout_height="50dp"
20         android:layout_gravity="top"
21         android:background="#99000000">
22
23         <ImageButton
24             android:id="@+id/capture_imageview_back"
25             android:layout_width="42dp"
26             android:layout_height="42dp"
27             android:layout_centerVertical="true"
28             android:background="@drawable/selector_capture_back"/>
29
30         <TextView
31             android:layout_width="wrap_content"
32             android:layout_height="wrap_content"
33             android:layout_centerInParent="true"
34             android:textColor="#ffffffff"
35             android:textSize="20sp"
36             android:text="扫一扫"/>
37
38     </RelativeLayout>
39
40 </merge>

capture.xml

capture.xml布局去掉结果显示,添加标题栏。那么captureActivity中,onCreate(),onPause(),onResume(),onDestroy涉及到Camera的初始化或销毁

 1 @Override
 2     public void onCreate(Bundle icicle) {
 3         super.onCreate(icicle);
 4         // 保持Activity处于唤醒状态
 5         Window window = getWindow();
 6         window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
 7         setContentView(R.layout.capture);
 8
 9         hasSurface = false;
10
11         inactivityTimer = new InactivityTimer(this);
12         beepManager = new BeepManager(this);
13
14         imageButton_back = (ImageButton) findViewById(R.id.capture_imageview_back);
15         imageButton_back.setOnClickListener(new View.OnClickListener() {
16
17             @Override
18             public void onClick(View v) {
19                 finish();
20             }
21         });
22     }
23
24     @Override
25     protected void onResume() {
26         super.onResume();
27
28         // CameraManager必须在这里初始化,而不是在onCreate()中。
29         // 这是必须的,因为当我们第一次进入时需要显示帮助页,我们并不想打开Camera,测量屏幕大小
30         // 当扫描框的尺寸不正确时会出现bug
31         cameraManager = new CameraManager(getApplication());
32
33         viewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view);
34         viewfinderView.setCameraManager(cameraManager);
35
36         handler = null;
37
38         SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
39         SurfaceHolder surfaceHolder = surfaceView.getHolder();
40         if (hasSurface) {
41             // activity在paused时但不会stopped,因此surface仍旧存在;
42             // surfaceCreated()不会调用,因此在这里初始化camera
43             initCamera(surfaceHolder);
44         } else {
45             // 重置callback,等待surfaceCreated()来初始化camera
46             surfaceHolder.addCallback(this);
47         }
48
49         beepManager.updatePrefs();
50         inactivityTimer.onResume();
51
52         source = IntentSource.NONE;
53         decodeFormats = null;
54         characterSet = null;
55     }
56
57     @Override
58     protected void onPause() {
59         if (handler != null) {
60             handler.quitSynchronously();
61             handler = null;
62         }
63         inactivityTimer.onPause();
64         beepManager.close();
65         cameraManager.closeDriver();
66         if (!hasSurface) {
67             SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
68             SurfaceHolder surfaceHolder = surfaceView.getHolder();
69             surfaceHolder.removeCallback(this);
70         }
71         super.onPause();
72     }
73
74     @Override
75     protected void onDestroy() {
76         inactivityTimer.shutdown();
77         super.onDestroy();
78     }

surfaceview是基于Camera而实现,surfaceview的使用需要实现SurfaceHolder.Callback接口,在开启屏幕surfaceview的时候初始化camera

 1 @Override
 2     public void surfaceCreated(SurfaceHolder holder) {
 3         if (!hasSurface) {
 4             hasSurface = true;
 5             initCamera(holder);
 6         }
 7     }
 8
 9     @Override
10     public void surfaceDestroyed(SurfaceHolder holder) {
11         hasSurface = false;
12     }
13
14     @Override
15     public void surfaceChanged(SurfaceHolder holder, int format, int width,
16             int height) {
17
18     }

接下来看如何初始化Camera,代码简化之后如下

 1 private void initCamera(SurfaceHolder surfaceHolder) {
 2         if (surfaceHolder == null) {
 3             throw new IllegalStateException("No SurfaceHolder provided");
 4         }
 5         if (cameraManager.isOpen()) {
 6             return;
 7         }
 8         try {
 9             // 打开Camera硬件设备
10             cameraManager.openDriver(surfaceHolder);
11             // 创建一个handler来打开预览,并抛出一个运行时异常
12             if (handler == null) {
13                 handler = new CaptureActivityHandler(this, decodeFormats,
14                         decodeHints, characterSet, cameraManager);
15             }
16         } catch (IOException ioe) {
17             Log.w(TAG, ioe);
18             displayFrameworkBugMessageAndExit();
19         } catch (RuntimeException e) {
20             Log.w(TAG, "Unexpected error initializing camera", e);
21             displayFrameworkBugMessageAndExit();
22         }
23     }

在CaptureActivity中,有一个核心方法,用来返回并处理解码结果,也即扫描结果。handleDecode(),如果需要对解码后的内容进行自己的处理,需要对该方法进行改动,这里修改        为将解码的bitmap以及内容回传到开启扫描的Activiity进行处理。

 1 public void handleDecode(Result rawResult, Bitmap barcode, float scaleFactor) {
 2         inactivityTimer.onActivity();
 3
 4         boolean fromLiveScan = barcode != null;
 5         //这里处理解码完成后的结果,此处将参数回传到Activity处理
 6         if (fromLiveScan) {
 7             beepManager.playBeepSoundAndVibrate();
 8
 9             Toast.makeText(this, "扫描成功", Toast.LENGTH_SHORT).show();
10
11             Intent intent = getIntent();
12             intent.putExtra("codedContent", rawResult.getText());
13             intent.putExtra("codedBitmap", barcode);
14             setResult(RESULT_OK, intent);
15             finish();
16         }
17
18     }

5、将指定Url生成二维码

 1 /**
 2      * 生成QRCode(二维码)
 3      *
 4      * @param str
 5      * @return
 6      * @throws WriterException
 7      */
 8     public static Bitmap createQRCode(String url) throws WriterException {
 9
10         if (url == null || url.equals("")) {
11             return null;
12         }
13
14         // 生成二维矩阵,编码时指定大小,不要生成了图片以后再进行缩放,这样会模糊导致识别失败
15         BitMatrix matrix = new MultiFormatWriter().encode(url,
16                 BarcodeFormat.QR_CODE, 300, 300);
17
18         int width = matrix.getWidth();
19         int height = matrix.getHeight();
20
21         // 二维矩阵转为一维像素数组,也就是一直横着排了
22         int[] pixels = new int[width * height];
23
24         for (int y = 0; y < height; y++) {
25             for (int x = 0; x < width; x++) {
26                 if (matrix.get(x, y)) {
27                     pixels[y * width + x] = 0xff000000;
28                 }
29
30             }
31         }
32
33         Bitmap bitmap = Bitmap.createBitmap(width, height,
34                 Bitmap.Config.ARGB_8888);
35         bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
36         return bitmap;
37     }

通过以上四步,zxing项目的简化工作基本完成。至于一些类需要进行小修小改,希望可以对着源码进行,这里不再赘述。二维码扫描的整体构架主要包含三部分:

1、定义取景框,也即扫描的View,通过surfaceview进行绘制

2、Camera, 扫描的核心在于camera的配置使用,包括预览,自动聚焦,打开设备等处理

3、Decode解码,扫描完成后整个工程的核心

除去以上三个模块,需要明确的就是CaptureActivitiy中handleDeCode()方法做自己的处理。

点击下面链接,即可下载源码

http://pan.baidu.com/s/1c0yADUS

时间: 2024-12-05 11:27:43

Android自由行之走进zxing,轻松实现二维码扫描的相关文章

Android开源之行之走进zxing,轻松实现二维码扫描(一)

现在很多App都集成了扫一扫功能,最常用的微信.QQ.手机助手等.二维码也使得生活变得更加简洁,扫一扫订餐.扫一扫下载等等.那么,说到二维码,我们不得不提Google一个开源的扫码框架:zxing. 开源下载:http://code.google.com/p/zxing/ zxing是基于多种1D/2D条码处理的开源库,是一个完整的项目.它可以通过手机摄像头实现条码的扫描以及解码,功能及其强大.那么如果要实现二维码的扫描以及解码,我们需要在该开源项目的基础上进行简化,并修改.让我们来看一下  

Android开源之行之走进zxing,轻松实现二维码扫描(二)

对于Zxing开源项目的简化上文已给出,源码经过测试且不断修改.众所周知,Zxing项目的扫描是横向的,这么引用的用户体验确实不好:然而盲目的修改会出现拉伸以及样本采集的偏离.所以这里说一下如何将横屏修改为竖屏扫描 解决办法引用原文:http://blog.csdn.net/aaawqqq/article/details/24804939 一.Zxing扫描框架竖屏切换 1.menifest.xml中,Activitiy必须要设为竖屏的,添加属性 android:screenOrientatio

使用ZXing代码实现二维码扫描

1 首先下载Zxing的源码,然后将其中Android的版本导入到Android Studio 2 因为只需要二维码扫描的功能,所以只留下其中的四个包 其中 camera管理相机,decoding解析扫描到的二维码,view定义扫码的视图,MipcaActivityCapture是扫码的界面. 3 将res文件下的文件拷贝过来,注意是合并,不是简单的替换 4 修改AndroidMinifest.xml 5 修改由R引用带来的错误? 6 添加jar包,jar包导入不是简单的复制,要右键 add a

【转】Android 基于google Zxing实现二维码、条形码扫描,仿微信二维码扫描效果--不错

原文网址:http://blog.csdn.net/xiaanming/article/details/10163203 转载请注明出处:http://blog.csdn.net/xiaanming/article/details/10163203 了解二维码这个东西还是从微信中,当时微信推出二维码扫描功能,自己感觉挺新颖的,从一张图片中扫一下竟然能直接加好友,不可思议啊,那时候还不了解二维码,呵呵,然后做项目的时候,老板说要加上二维码扫描功能,然后自己的屁颠屁颠的去百度,google啥的,发现

条码扫描二维码扫描—ZXing android 改进版本

看了Vurtexゞ. 文章<[Android实例] 条码扫描二维码扫描——ZXing android 源码简化 (附:支持中文) >的基础上对代码进行了修改 1.增加了将代码嵌套入自己工程后传值的办法(初学,如果有更好的方法也希望告诉我,先谢谢了) 2.扫码界面进行了处理(初步实现了现有某些软件的样子,至于长的像谁就不说了) //画四个角的代码<br>paint.setColor(frameColor); canvas.drawRect(15 + frame.left, 15 +

Android 基于google Zxing实现二维码、条形码扫描,仿微信二维码扫描效果

了解二维码这个东西还是从微信中,当时微信推出二维码扫描功能.自己感觉挺新颖的,从一张图片中扫一下居然能直接加好友,不可思议啊,那时候还不了解二维码.呵呵,然后做项目的时候.老板说要加上二维码扫描功能.然后自己的屁颠屁颠的去百度,google啥的.发现非常多朋友都有介绍二维码扫描的功能,然后我就跟着人家的介绍自己搞起了二维码扫描功能,跟着人家的帖子,非常快我的项目就增加了扫描二维码的功能,然后自己还非常开心. 随着微信的到来,二维码越来越火爆,随处能看到二维码,比方商城里面,肯德基,餐厅等等.对于

Zxing图片拉伸解决 Android 二维码扫描

二维码扫描  Android Zxing图片拉伸解决 Zxing是google提供的二维码扫描工程 默认是横屏的  转换成竖屏后图片出现拉伸 这里提供解决办法: Zxing  修改 CameraConfigurationManager.java文件的 void initFromCameraParameters(Camera camera)方法 在 Log.d(TAG, "Screen resolution: " + screenResolution);这句之后增加 Point scre

在Android用ZXing.jar识别二维码的精简版(简化了配置和代码)

最近公司做了一款OTP令牌激活的产品,由于之前激活手机令牌需要输入很多的激活信息才能进行激活.经过一段使用后,发现易用性不是很强,考虑如果加入二维码的的扫码功能岂不是大大增加了易用性.     在网上搜了很多资料,要不是配置太多,要不就是代码量太大,最后没办法就硬着头皮去写和去精简,最后压缩至目前的版本.如果有更好的版本可以联系我. 具体DEMO可以通过 下载http://download.csdn.net/detail/fugui6611634/7341277下载 本文代码运行的结果如下: 代

Android—ZXing二维码扫描遇到的问题

最近工作中需要开发带有二维码扫描功能的软件(基于开源项目ZXing),遇到的问题记录一下,也希望给大家带来帮助. 1.首先因为扫描要开摄像机所以加权限是一定的,不然后面什么都不能进行 <uses-permission android:name="android.permission.CAMERA" /> 2.设置扫描框的大小: 在com.zxing.camera包中查找 private static final int MIN_FRAME_WIDTH = 240;  pri