android条码扫描程序
源码下载地址:
地址1:https://github.com/alivebao/BarCodeReader
地址2:http://download.csdn.net/detail/miaoyunzexiaobao/8297201
参考链接:
zxing入门:http://www.cnblogs.com/liuan/archive/2012/01/05/2312714.html
BitmapLuminanceSource类实现:http://blog.csdn.net/xyz_fly/article/details/8089558
目标:完成一个条码扫描程序,能识别出一维码和二维码,并将解析出来的结果显示出来
效果图:扫描中-》扫描成功
扫描成功后:
首先在布局上放置一个预览框,用于实时显示摄像头拍摄到的情况,并在其上绘制一条来回扫描的线条。之后在其下方放一个imageView,用于显示摄像头自动聚焦后获取的图片。
实现:该Activity的整体布局为方向vertical的线性布局。该线性布局内嵌着一个帧布局和另一个线性布局。帧布局中先在底层防止了一个SurfaceView,用于显示摄像头预览图片,再在其上放置了一个自己实现的View类ScanLineView,该类继承自View,主要功能为在SurfaceView上绘制一条来回扫描的红色线条。下面的LinearLayout放置了一个ImageView,用于显示聚焦后获得的图片(程序自动对该图片进行解码)
code:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity" > <FrameLayout android:layout_width="match_parent" android:layout_height="0px" android:layout_weight=".3" > <SurfaceView android:id="@+id/preview_view" android:layout_width="fill_parent" android:layout_height="fill_parent" /> <com.miao.barcodereader.ScanLineView android:id="@+id/capture_viewfinder_view" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@android:color/transparent" /> </FrameLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0px" android:layout_weight=".7" android:orientation="vertical" > <ImageView android:id="@+id/imageView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:src="@drawable/ic_launcher" /> </LinearLayout> </LinearLayout>ScanLineView类:
继承自View类,重载其onDraw函数,在onDraw函数中间隔一段时间发送申请重绘屏幕的请求,drawLine函数的功能为每次被调用时绘制一条横坐标逐渐增加的红线。这个类要是嫌麻烦的话也可以不写,把上面布局文件中的ScanLineView控件删掉就行了,对程序功能没什么影响。
code:
package com.miao.barcodereader; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; public class ScanLineView extends View{ private static final long ANIMATION_DELAY = 10L; private Paint paint; private int xLinePos = 0; private int canvasWidth = 0; private int canvasHeight = 0; public ScanLineView(Context context, AttributeSet attrs) { super(context, attrs); paint = new Paint(Paint.ANTI_ALIAS_FLAG); } @Override public void onDraw(Canvas canvas) { canvasWidth = canvas.getWidth(); canvasHeight = canvas.getHeight(); drawLine(canvas); postInvalidateDelayed(ANIMATION_DELAY, 0, 0, canvasWidth, canvasHeight); } private void drawLine(Canvas canvas) { int iLineBegin = canvasWidth / 5; int iLineEnd = canvasWidth * 4 / 5; int iFrameHigh = canvasHeight ; Rect frame = new Rect(iLineBegin, 0, canvasWidth, iFrameHigh); xLinePos += 10; if (xLinePos > iLineEnd) xLinePos = iLineBegin; paint.setColor(Color.RED); canvas.drawRect(xLinePos, 0, xLinePos + 1, iFrameHigh, paint); } }
CameraManage类:
负责将预览图显示到SurfaceView中,并每隔一段时间自动聚焦,聚焦成功后将获得的图片显示在ImageView控件中,并对该图片进行解析。若解析成功则将结果以对话框形式弹出。在该类的构造函数中,先获取主窗口的activity、imageView控件和SurfaceView控件,然后进行一些其他参数的设置。
本类实现了SurfaceHolder.Callback的接口,因此要实现surfaceChanged、surfaceCreated、surfaceDestroyed三个函数。在surfaceCreated中调用initCamera函数,打开摄像头并将其预览显示在SurfaceView上。
本类实现了一个定时器CameraTimerTask,其功能为在摄像头成功打开的情况下,每间隔一段使摄像头自动聚焦,并在聚焦的同时调用自动聚焦回调函数mAutoFocusCallBack。该函数是自己实现的,其功能为当聚焦成功时,调用预览回调函数previewCallback。这个也是自己实现的,其功能为将获取的预览图片置于ImageView中,并将该图片转为Bitmap格式,传送给类BitmapLuminanceSource(该类收到图片后对图片进行解析,并返回一个string类型变量)。若该类解析成功则会返回解析出的条码内容,若解析失败则返回“empty”。在previewCallback中,若BitmapLuminanceSource返回的string不是“empty”,则证明解析成功,于是将结果显示出来。
code:
package com.miao.barcodereader; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Timer; import java.util.TimerTask; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.ImageFormat; import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.YuvImage; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.hardware.Camera; import android.util.Log; import android.view.Display; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.WindowManager; import android.widget.ImageView; import android.widget.Toast; public class CameraManage implements SurfaceHolder.Callback { private SurfaceHolder surfaceHolder; private Camera camera; private Activity activity; SurfaceView surfaceView; private ImageView imageView; private Timer mTimer; private TimerTask mTimerTask; private Camera.AutoFocusCallback mAutoFocusCallBack; private Camera.PreviewCallback previewCallback; CameraManage(Activity ac, ImageView iv, SurfaceView sv) { activity = ac; imageView = iv; surfaceView = sv; surfaceHolder = surfaceView.getHolder(); surfaceHolder.addCallback(this); surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); AutoFocusSet(); mTimer = new Timer(); mTimerTask = new CameraTimerTask(); mTimer.schedule(mTimerTask, 0, 500); } public void AutoFocusSet() { mAutoFocusCallBack = new Camera.AutoFocusCallback() { @Override public void onAutoFocus(boolean success, Camera camera) { if (success) { // isAutoFocus = true; camera.setOneShotPreviewCallback(previewCallback); } } }; previewCallback = new Camera.PreviewCallback() { @Override public void onPreviewFrame(byte[] data, Camera arg1) { if (data != null) { Camera.Parameters parameters = camera.getParameters(); int imageFormat = parameters.getPreviewFormat(); Log.i("map", "Image Format: " + imageFormat); Log.i("CameraPreviewCallback", "data length:" + data.length); if (imageFormat == ImageFormat.NV21) { // get full picture Bitmap image = null; int w = parameters.getPreviewSize().width; int h = parameters.getPreviewSize().height; Rect rect = new Rect(0, 0, w, h); YuvImage img = new YuvImage(data, ImageFormat.NV21, w, h, null); ByteArrayOutputStream baos = new ByteArrayOutputStream(); if (img.compressToJpeg(rect, 100, baos)) { image = BitmapFactory.decodeByteArray( baos.toByteArray(), 0, baos.size()); image = adjustPhotoRotation(image, 90); imageView.setImageBitmap(image); Drawable d = imageView.getDrawable(); BitmapDrawable bd = (BitmapDrawable) d; Bitmap bm = bd.getBitmap(); String str = BitmapLuminanceSource.getResult(bm); if (!str.equals("empty")) Toast.makeText(activity.getApplication(), str, Toast.LENGTH_SHORT).show(); } } } } }; } class CameraTimerTask extends TimerTask { @Override public void run() { if (camera != null) { camera.autoFocus(mAutoFocusCallBack); } } } @Override public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { // TODO Auto-generated method stub } @Override public void surfaceCreated(SurfaceHolder arg0) { // TODO Auto-generated method stub initCamera(surfaceHolder); } @Override public void surfaceDestroyed(SurfaceHolder arg0) { // TODO Auto-generated method stub if (camera != null) { camera.stopPreview(); camera.release(); camera = null; } previewCallback = null; mAutoFocusCallBack = null; } public void initCamera(SurfaceHolder surfaceHolder) { camera = Camera.open(); if (camera == null) { return; } Camera.Parameters parameters = camera.getParameters(); WindowManager wm = (WindowManager) (activity .getSystemService(Context.WINDOW_SERVICE)); Display display = wm.getDefaultDisplay(); parameters.setPreviewSize(display.getWidth(), display.getHeight()); camera.setParameters(parameters); try { camera.setPreviewDisplay(surfaceHolder); } catch (IOException e) { System.out.println(e.getMessage()); } camera.setDisplayOrientation(90); camera.startPreview(); } public Bitmap adjustPhotoRotation(Bitmap bm, final int orientationDegree) { Matrix m = new Matrix(); m.setRotate(orientationDegree, (float) bm.getWidth() / 2, (float) bm.getHeight() / 2); try { Bitmap bm1 = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), m, true); return bm1; } catch (OutOfMemoryError ex) { } return null; } }这里要记得在AndroidManifest.xml中写权限:
<uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" />最后是BitmapLuminanceSource类:
思路见参考链接
code:
package com.miao.barcodereader; import java.util.HashMap; import java.util.Map; import android.graphics.Bitmap; import com.google.zxing.Binarizer; import com.google.zxing.BinaryBitmap; import com.google.zxing.EncodeHintType; import com.google.zxing.LuminanceSource; import com.google.zxing.MultiFormatReader; import com.google.zxing.NotFoundException; import com.google.zxing.Result; import com.google.zxing.common.HybridBinarizer; public class BitmapLuminanceSource extends LuminanceSource { private byte bitmapPixels[]; protected BitmapLuminanceSource(Bitmap bitmap) { super(bitmap.getWidth(), bitmap.getHeight()); int[] data = new int[bitmap.getWidth() * bitmap.getHeight()]; this.bitmapPixels = new byte[bitmap.getWidth() * bitmap.getHeight()]; bitmap.getPixels(data, 0, getWidth(), 0, 0, getWidth(), getHeight()); for (int i = 0; i < data.length; i++) { this.bitmapPixels[i] = (byte) data[i]; } } @Override public byte[] getMatrix() { return bitmapPixels; } @Override public byte[] getRow(int y, byte[] row) { System.arraycopy(bitmapPixels, y * getWidth(), row, 0, getWidth()); return row; } static public String getResult(Bitmap bitmap){ MultiFormatReader formatReader = new MultiFormatReader(); LuminanceSource source = new BitmapLuminanceSource(bitmap); Binarizer binarizer = new HybridBinarizer(source); BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer); Map hints = new HashMap(); hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); Result result = null; try { result = formatReader.decode(binaryBitmap, hints); } catch (NotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } if(result == null) return "empty"; else return result.toString(); } }来自:http://blog.csdn.net/miaoyunzexiaobao/article/details/42142553