Android中使用ZXing识别条形码/二维码
2017-09-20 08:00:21
本文例子必须要开摄像头和自动对焦的权限,不然启动时会报异常,所需权限如下:
本文代码运行的结果如下,使用91手机助手截图时,无法截取SurfaceView的实时图像:
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类调用。
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"); } } }; } #p#分页标题#e#SFHCamera.java是Camera控制类,源码如下:
本文使用了ZXing1.6的core,即把/zxing-1.6/core/下的src复制覆盖工程的src;另外还要使用到/zxing-1.6/android/下的PlanarYUVLuminanceSource.java。
本文使用ZXing 1.6实现条码/二维码识别。ZXing是个很经典的条码/二维码识别的开源类库,很早有开发者在J2ME上使用ZXing了,不过要支持JSR-234规范(自动对焦)的手机才能发挥其威力,而目前已经有不少Android手机具备自动对焦的功能。
源码目录结果如下图,ChecksumException.java下面还有很多源文件,截图尚未列出:
PS:/zxing-1.6/android/ 是BarcodeScanner的源码,本文程序相当于BarcodeScanner的精简版,只保留基本的识别功能。
testCamera.java是主类,负责控制Camera和对图像做解码,源码如下:
现在大部分的手机都具备自动对焦的拍摄功能,这意味着这些手机可以具备条码扫描的功能,手机具备条码扫描的功能,可以优化购物流程,快速存储电子名片(Android二维码)等。
本文源码工程下载地址:二维码Demo.rar
main.xml源码如下,main.xml必须要用到FrameLayout才能重叠控件实现“范围框”的效果:
- 上一篇:1.偏差溯源
- 下一篇:6家企业试点乳粉安全追溯体系 消费者可拿手机查