目前有越来越多的手机具备自动对焦的拍摄功能,这也意味着这些手机可以具备条码扫描的功能。手机具备条码扫描的功能,可以优化购物流程,快速存储电子名片(二维码)等。
本文所述实例就使用了zxing 1.6实现条码/二维码识别。zxing是个很经典的条码/二维码识别的开源类库,早在很久以前,就有开发者在j2me上使用zxing了,只不过需要支持jsr-234规范(自动对焦)的手机才能发挥其威力,而目前已经有不少android手机具备自动对焦的功能。
本文代码运行的结果如下,使用91手机助手截图时,无法截取surfaceview的实时图像:
本文使用了zxing1.6的core,即把/zxing-1.6/core/下的src复制覆盖工程的src;另外还要使用到/zxing-1.6/android/下的planaryuvluminancesource.java。
此处需要注意:/zxing-1.6/android/ 是barcodescanner的源码,本文程序相当于barcodescanner的精简版,只保留最基本的识别功能。
本文完整源码点击此处本地下载。
源码目录结果如下图,checksumexception.java下面还有很多源文件,截图尚未列出:
本文例子必须要开摄像头和自动对焦的权限,不然启动时会报异常,所用的权限如下:
1
2
3
4
|
<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" /> |
main.xml源码如下,main.xml必须要用到framelayout才能重叠控件实现“范围框”的效果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<?xml version= "1.0" encoding= "utf-8" ?> <framelayout android:id= "@+id/framelayout01" android:layout_width= "fill_parent" android:layout_height= "fill_parent" xmlns:android= "http://schemas.android.com/apk/res/android" > <surfaceview android:layout_height= "fill_parent" android:id= "@+id/sfvcamera" android:layout_width= "fill_parent" ></surfaceview> <relativelayout android:id= "@+id/relativelayout01" android:layout_height= "fill_parent" android:layout_width= "fill_parent" > <imageview android:id= "@+id/imageview01" android:layout_height= "100dip" android:layout_width= "160dip" ></imageview> <view android:layout_centervertical= "true" android:layout_centerhorizontal= "true" android:layout_width= "300dip" android:background= "#55ff6666" android:id= "@+id/centerview" android:layout_height= "180dip" ></view> <textview android:layout_centerhorizontal= "true" android:layout_width= "wrap_content" android:layout_below= "@+id/centerview" android:layout_height= "wrap_content" android:text= "scanning..." android:id= "@+id/txtscanresult" android:textcolor= "#ff000000" ></textview> </relativelayout> </framelayout> |
testcamera.java是主类,负责控制camera和对图像做解码,源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
package com.testcamera; import java.util.timer; import java.util.timertask; import com.google.zxing.binarybitmap; import com.google.zxing.multiformatreader; import com.google.zxing.result; import com.google.zxing.android.planaryuvluminancesource; import com.google.zxing.common.hybridbinarizer; import android.app.activity; import android.graphics.bitmap; import android.hardware.camera; import android.os.bundle; import android.view.surfaceview; import android.view.view; import android.widget.imageview; import android.widget.textview; public class testcamera extends activity { /** called when the activity is first created. */ private surfaceview sfvcamera; private sfhcamera sfhcamera; private imageview imgview; private view centerview; private textview txtscanresult; private timer mtimer; private mytimertask mtimertask; // 按照标准hvga final static int width = 480 ; final static int height = 320 ; int dstleft, dsttop, dstwidth, dstheight; @override public void oncreate(bundle savedinstancestate) { super .oncreate(savedinstancestate); setcontentview(r.layout.main); this .settitle( "android条码/二维码识别demo-----hellogv" ); imgview = (imageview) this .findviewbyid(r.id.imageview01); centerview = (view) this .findviewbyid(r.id.centerview); sfvcamera = (surfaceview) this .findviewbyid(r.id.sfvcamera); sfhcamera = new sfhcamera(sfvcamera.getholder(), width, height, previewcallback); txtscanresult=(textview) this .findviewbyid(r.id.txtscanresult); // 初始化定时器 mtimer = new timer(); mtimertask = new mytimertask(); mtimer.schedule(mtimertask, 0 , 80 ); } class mytimertask extends timertask { @override public void run() { if (dstleft == 0 ) { //只赋值一次 dstleft = centerview.getleft() * width / getwindowmanager().getdefaultdisplay().getwidth(); dsttop = centerview.gettop() * height / getwindowmanager().getdefaultdisplay().getheight(); dstwidth = (centerview.getright() - centerview.getleft())* width / getwindowmanager().getdefaultdisplay().getwidth(); dstheight = (centerview.getbottom() - centerview.gettop())* height / getwindowmanager().getdefaultdisplay().getheight(); } sfhcamera.autofocusandpreviewcallback(); } } /** * 自动对焦后输出图片 */ private camera.previewcallback previewcallback = new camera.previewcallback() { @override public void onpreviewframe( byte [] data, camera arg1) { //取得指定范围的帧的数据 planaryuvluminancesource source = new planaryuvluminancesource( data, width, height, dstleft, dsttop, dstwidth, dstheight); //取得灰度图 bitmap mbitmap = source.rendercroppedgreyscalebitmap(); //显示灰度图 imgview.setimagebitmap(mbitmap); binarybitmap bitmap = new binarybitmap( new hybridbinarizer(source)); multiformatreader reader = new multiformatreader(); try { result result = reader.decode(bitmap); string strresult = "barcodeformat:" + result.getbarcodeformat().tostring() + " text:" + result.gettext(); txtscanresult.settext(strresult); } catch (exception e) { txtscanresult.settext( "scanning" ); } } }; } |
sfhcamera.java是camera控制类,源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
package com.testcamera; import java.io.ioexception; import android.graphics.pixelformat; import android.hardware.camera; import android.util.log; import android.view.surfaceholder; public class sfhcamera implements surfaceholder.callback{ private surfaceholder holder = null ; private camera mcamera; private int width,height; private camera.previewcallback previewcallback; public sfhcamera(surfaceholder holder, int w, int h,camera.previewcallback previewcallback) { this .holder = holder; this .holder.addcallback( this ); this .holder.settype(surfaceholder.surface_type_push_buffers); width=w; height=h; this .previewcallback=previewcallback; } @override public void surfacechanged(surfaceholder arg0, int arg1, int arg2, int arg3) { camera.parameters parameters = mcamera.getparameters(); parameters.setpreviewsize(width, height); //设置尺寸 parameters.setpictureformat(pixelformat.jpeg); mcamera.setparameters(parameters); mcamera.startpreview(); //开始预览 log.e( "camera" , "surfacechanged" ); } @override public void surfacecreated(surfaceholder arg0) { mcamera = camera.open(); //启动服务 try { mcamera.setpreviewdisplay(holder); //设置预览 log.e( "camera" , "surfacecreated" ); } catch (ioexception e) { mcamera.release(); //释放 mcamera = null ; } } @override public void surfacedestroyed(surfaceholder arg0) { mcamera.setpreviewcallback( null ); mcamera.stoppreview(); //停止预览 mcamera = null ; log.e( "camera" , "surfacedestroyed" ); } /** * 自动对焦并回调camera.previewcallback */ public void autofocusandpreviewcallback() { if (mcamera!= null ) mcamera.autofocus(mautofocuscallback); } /** * 自动对焦 */ private camera.autofocuscallback mautofocuscallback = new camera.autofocuscallback() { @override public void onautofocus( boolean success, camera camera) { if (success) { //对焦成功,回调camera.previewcallback mcamera.setoneshotpreviewcallback(previewcallback); } } }; } |
其中testcamera.java的camera.previewcallback previewcallback 是整个程序的逻辑核心,作为回调函数给sfhcamera.java的内部camera类调用。
希望本文实例对大家学习android程序设计能有所帮助。