目前有越来越多的手机具备自动对焦的拍摄功能,这也意味着这些手机可以具备条码扫描的功能。手机具备条码扫描的功能,可以优化购物流程,快速存储电子名片(二维码)等。
本文所述实例就使用了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程序设计能有所帮助。