导读:本文使用ZXing 1.6实现条码/二维码识别。ZXing是个很经典的条码/二维码识别的开源类库,long long ago,就有开发者在J2ME上使用ZXing了,不过要支持JSR-234规范(自动对焦)的手机才能发挥其威力。
越来越多的手机具备自动对焦的拍摄功能,这也意味着这些手机可以具备条码扫描的功能.......手机具备条码扫描的功能,可以优化购物流程,快速存储电子名片(二维码)等。
本文使用ZXing 1.6实现条码/二维码识别。ZXing是个很经典的条码/二维码识别的开源类库,long long ago,就有开发者在J2ME上使用ZXing了,不过要支持JSR-234规范(自动对焦)的手机才能发挥其威力,而目前已经有不少Android手机具备自动对焦的功能。
本文使用了ZXing1.6的core,即把\zxing-1.6\core\下的src复制覆盖工程的src;另外还要使用到\zxing-1.6\android\下的PlanarYUVLuminanceSource.java。
PS:\zxing-1.6\android\ 是BarcodeScanner的源码,本文程序相当于BarcodeScanner的精简版,只保留最基本的识别功能。
本文例子必须要开摄像头和自动对焦的权限,不然启动时会报异常,所用的权限如下:
1 | <uses-permission android:name= "android.permission.CAMERA" ></uses-permission> |
2 | <uses-permission android:name= "android.permission.WRITE_EXTERNAL_STORAGE" > |
4 | <uses-feature android:name= "android.hardware.camera" /> |
5 | <uses-feature android:name= "android.hardware.camera.autofocus" /> |
main.xml源码如下,main.xml必须要用到FrameLayout才能重叠控件实现“范围框”的效果:
02 | <?xml version= "1.0" encoding= "utf-8" ?> |
04 | android:id= "@+id/FrameLayout01" |
05 | android:layout_width= "fill_parent" |
06 | android:layout_height= "fill_parent" |
07 | xmlns:android= "http://schemas.android.com/apk/res/android" > |
10 | android:layout_height= "fill_parent" |
11 | android:id= "@+id/sfvCamera" |
12 | android:layout_width= "fill_parent" > |
15 | android:id= "@+id/RelativeLayout01" |
16 | android:layout_height= "fill_parent" |
17 | android:layout_width= "fill_parent" > |
19 | android:id= "@+id/ImageView01" |
20 | android:layout_height= "100dip" |
21 | android:layout_width= "160dip" > |
24 | android:layout_centerVertical= "true" |
25 | android:layout_centerHorizontal= "true" |
26 | android:layout_width= "300dip" |
27 | android:background= "#55FF6666" |
28 | android:id= "@+id/centerView" |
29 | android:layout_height= "180dip" > |
32 | android:layout_centerHorizontal= "true" |
33 | android:layout_width= "wrap_content" |
34 | android:layout_below= "@+id/centerView" |
35 | android:layout_height= "wrap_content" |
36 | android:text= "Scanning..." |
37 | android:id= "@+id/txtScanResult" |
38 | android:textColor= "#FF000000" > |
testCamera.java是主类,负责控制Camera和对图像做解码,源码如下:
04 | import java.util.Timer; |
05 | import java.util.TimerTask; |
06 | import com.google.zxing.BinaryBitmap; |
07 | import com.google.zxing.MultiFormatReader; |
08 | import com.google.zxing.Result; |
09 | import com.google.zxing.Android.PlanarYUVLuminanceSource; |
10 | import com.google.zxing.common.HybridBinarizer; |
11 | import android.app.Activity; |
12 | import android.graphics.Bitmap; |
13 | import android.hardware.Camera; |
14 | import android.os.Bundle; |
15 | import android.view.SurfaceView; |
16 | import android.view.View; |
17 | import android.widget.ImageView; |
18 | import android.widget.TextView; |
20 | public class testCamera extends Activity { |
21 | /** Called when the activity is first created. */ |
22 | private SurfaceView sfvCamera; |
23 | private SFHCamera sfhCamera; |
24 | private ImageView imgView; |
25 | private View centerView; |
26 | private TextView txtScanResult; |
28 | private MyTimerTask mTimerTask; |
30 | final static int width = 480 ; |
31 | final static int height = 320 ; |
32 | int dstLeft, dstTop, dstWidth, dstHeight; |
34 | public void onCreate(Bundle savedInstanceState) { |
35 | super .onCreate(savedInstanceState); |
36 | setContentView(R.layout.main); |
37 | this .setTitle( "Android条码/二维码识别Demo-----hellogv" ); |
38 | imgView = (ImageView) this .findViewById(R.id.ImageView01); |
39 | centerView = (View) this .findViewById(R.id.centerView); |
40 | sfvCamera = (SurfaceView) this .findViewById(R.id.sfvCamera); |
41 | sfhCamera = new SFHCamera(sfvCamera.getHolder(), width, height, |
43 | txtScanResult=(TextView) this .findViewById(R.id.txtScanResult); |
46 | mTimerTask = new MyTimerTask(); |
47 | mTimer.schedule(mTimerTask, 0 , 80 ); |
49 | class MyTimerTask extends TimerTask { |
53 | dstLeft = centerView.getLeft() * width |
54 | / getWindowManager().getDefaultDisplay().getWidth(); |
55 | dstTop = centerView.getTop() * height |
56 | / getWindowManager().getDefaultDisplay().getHeight(); |
57 | dstWidth = (centerView.getRight() - centerView.getLeft())* width |
58 | / getWindowManager().getDefaultDisplay().getWidth(); |
59 | dstHeight = (centerView.getBottom() - centerView.getTop())* height |
60 | / getWindowManager().getDefaultDisplay().getHeight(); |
62 | sfhCamera.AutoFocusAndPreviewCallback(); |
68 | private Camera.PreviewCallback previewCallback = new Camera.PreviewCallback() { |
70 | public void onPreviewFrame( byte [] data, Camera arg1) { |
72 | PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource( |
73 | data, width, height, dstLeft, dstTop, dstWidth, dstHeight); |
75 | Bitmap mBitmap = source.renderCroppedGreyscaleBitmap(); |
77 | imgView.setImageBitmap(mBitmap); |
78 | BinaryBitmap bitmap = new BinaryBitmap( new HybridBinarizer(source)); |
79 | MultiFormatReader reader = new MultiFormatReader(); |
81 | Result result = reader.decode(bitmap); |
82 | String strResult = "BarcodeFormat:" + result.getBarcodeFormat().toString() + " text:" |
84 | txtScanResult.setText(strResult); |
85 | } catch (Exception e) { |
86 | txtScanResult.setText( "Scanning" ); |
SFHCamera.java是Camera控制类,源码如下:
04 | import java.io.IOException; |
05 | import android.graphics.PixelFormat; |
06 | import android.hardware.Camera; |
07 | import android.util.Log; |
08 | import android.view.SurfaceHolder; |
10 | public class SFHCamera implements SurfaceHolder.Callback{ |
11 | private SurfaceHolder holder = null ; |
12 | private Camera mCamera; |
13 | private int width,height; |
14 | private Camera.PreviewCallback previewCallback; |
15 | public SFHCamera(SurfaceHolder holder, int w, int h,Camera.PreviewCallback previewCallback) { |
17 | this .holder.addCallback( this ); |
18 | this .holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); |
21 | this .previewCallback=previewCallback; |
24 | public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { |
25 | Camera.Parameters parameters = mCamera.getParameters(); |
26 | parameters.setPreviewSize(width, height); |
27 | parameters.setPictureFormat(PixelFormat.JPEG); |
28 | mCamera.setParameters(parameters); |
29 | mCamera.startPreview(); |
30 | Log.e( "Camera" , "surfaceChanged" ); |
33 | public void surfaceCreated(SurfaceHolder arg0) { |
34 | mCamera = Camera.open(); |
36 | mCamera.setPreviewDisplay(holder); |
37 | Log.e( "Camera" , "surfaceCreated" ); |
38 | } catch (IOException e) { |
44 | public void surfaceDestroyed(SurfaceHolder arg0) { |
45 | mCamera.setPreviewCallback( null ); |
48 | Log.e( "Camera" , "surfaceDestroyed" ); |
51 | * 自动对焦并回调Camera.PreviewCallback |
53 | public void AutoFocusAndPreviewCallback() |
56 | mCamera.autoFocus(mAutoFocusCallBack); |
61 | private Camera.AutoFocusCallback mAutoFocusCallBack = new Camera.AutoFocusCallback() { |
63 | public void onAutoFocus( boolean success, Camera camera) { |
65 | mCamera.setOneShotPreviewCallback(previewCallback); |
其中testCamera.java的Camera.PreviewCallback previewCallback 是整个程序的逻辑核心,作为回调函数给SFHCamera.java的内部Camera类调用。