之前对于Zbar的二位码扫描,到项目上线以后才发现扫描过于灵敏,导致有时候扫描到半截就启动了。
后来翻看ZXING的源码,没有想象的复杂,复杂的地方在于zxing自带的demo项目过于复杂导致初学者对其理解不很明白,修改源码相对麻烦 于是试图简化代码重写了一个demo相对简单。 功能包含1.扫描区自定义2.利用线程池并行解析3.支持横屏/竖屏无缝切换4.支持条形码,二维码..具体查看zxing库 ---文件解释 com.xiaoqiang.zxing.DecodeData.java 自定义解析数据包 com.xiaoqiang.zxing.DecodeRunable.java 解析线程 com.xiaoqiang.zxing.FinderView.java 自定义查找框--支持横屏 com.xiaoqiang.zxing.ZxingTools.java 抽取的zxing工具 com.xiaoqiang.zxing.ZxingBarCodeActivity.java 扫描页面,在SurfaceHolder回调中启动关闭线程池
---主要方法解析
--解析数据包 public class DecodeData { private byte[] data;private Size sourceSize;private Rect preRect;...get/set } --解析线程 public class DecodeRunable implements Runnable { public static final String TAG = "DecodeRunable";public SoftReference<WeakHandler<ZxingBarCodeActivity>> handlerReference;public DecodeData decodeData;public boolean roate90;public DecodeRunable(WeakHandler<ZxingBarCodeActivity> handler, DecodeData decodeData, boolean roate90) { handlerReference = new SoftReference<WeakHandler<ZxingBarCodeActivity>>(handler);this.decodeData = decodeData;this.roate90 = roate90;}@Overridepublic void run() { Result result = ZxingTools.decodeDecodeData(decodeData, roate90);if (null != result) { WeakHandler<ZxingBarCodeActivity> weakHandler = handlerReference.get();if (null != weakHandler) { ZxingBarCodeActivity qrFinderActivity = weakHandler.activiceReference.get();if (null == qrFinderActivity || qrFinderActivity.isReciveReuslt()) { return;}//通知扫描页面已经扫描到结果了qrFinderActivity.setReciveReuslt(true);Message obtainMessage = weakHandler.obtainMessage(0);BarcodeFormat barcodeFormat = result.getBarcodeFormat();String text = result.getText();Bundle data = new Bundle();data.putSerializable("BarcodeFormat", barcodeFormat);data.putString("text", text);obtainMessage.setData(data);obtainMessage.sendToTarget();LogUtils.d(TAG, "BarcodeFormat:" + barcodeFormat.toString() + " 内容:" + text);}}} } ---自定义查找框--支持横屏---主要方法/*** 矫正矩形框* w* h* */public Rect getScanImageRect(Size cameraPreviewSize) { Rect reusltRect = null;if (measureedWidth < measureedHeight) { //图片宽度被拉伸的比例float temp = (float) cameraPreviewSize.height / (float) measureedWidth;//图片在高度被拉伸的比例float tempH = (float) cameraPreviewSize.width / (float) measureedHeight;reusltRect = new Rect(middleRect.top, middleRect.left, middleRect.bottom, middleRect.right);reusltRect.left = (int) (reusltRect.left * tempH);reusltRect.top = (int) (reusltRect.top * temp);reusltRect.right = (int) (reusltRect.right * tempH);reusltRect.bottom = (int) (reusltRect.bottom * temp);} else { //图片在宽度被拉伸的比例float tempW = (float) cameraPreviewSize.width / (float) measureedWidth;//图片高度被拉伸的比例float tempH = (float) cameraPreviewSize.height / (float) measureedHeight;reusltRect = new Rect(middleRect);reusltRect.left = (int) (reusltRect.left * tempW);reusltRect.top = (int) (reusltRect.top * tempH);reusltRect.right = (int) (reusltRect.right * tempW);reusltRect.bottom = (int) (reusltRect.bottom * tempH);}return reusltRect;}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec);measureedWidth = MeasureSpec.getSize(widthMeasureSpec);measureedHeight = MeasureSpec.getSize(heightMeasureSpec);//处理横屏 int borderWidth = (measureedWidth < measureedHeight ? measureedWidth : measureedHeight) / 2;middleRect.set((measureedWidth - borderWidth) / 2, (measureedHeight - borderWidth) / 2, (measureedWidth - borderWidth) / 2 + borderWidth, (measureedHeight - borderWidth) / 2 + borderWidth);lineRect.set(middleRect);lineRect.bottom = lineRect.top + lineHeight;leftRect.set(0, middleRect.top, middleRect.left, middleRect.bottom);topRect.set(0, 0, measureedWidth, middleRect.top);rightRect.set(middleRect.right, middleRect.top, measureedWidth, middleRect.bottom);bottomRect.set(0, middleRect.bottom, measureedWidth, measureedHeight);} ----抽取的zxing工具 public class ZxingTools { private static Hashtable<DecodeHintType, Object> decodeConfig = new Hashtable<DecodeHintType, Object>();static { List<BarcodeFormat> allFormats = new ArrayList<BarcodeFormat>();allFormats.add(BarcodeFormat.CODABAR);allFormats.add(BarcodeFormat.CODE_39);allFormats.add(BarcodeFormat.CODE_93);allFormats.add(BarcodeFormat.CODE_128);allFormats.add(BarcodeFormat.DATA_MATRIX);allFormats.add(BarcodeFormat.EAN_8);allFormats.add(BarcodeFormat.EAN_13);allFormats.add(BarcodeFormat.ITF);allFormats.add(BarcodeFormat.QR_CODE);allFormats.add(BarcodeFormat.RSS_14);allFormats.add(BarcodeFormat.EAN_13);allFormats.add(BarcodeFormat.RSS_EXPANDED);allFormats.add(BarcodeFormat.UPC_A);allFormats.add(BarcodeFormat.UPC_E);decodeConfig.put(DecodeHintType.POSSIBLE_FORMATS, allFormats);}/*** 解析DecodeData* @param decodeData* @param roate90* @return*/public static Result decodeDecodeData(DecodeData decodeData, boolean roate90) { Bitmap barCodeBitMap = getBarCodeBitMap(decodeData, roate90);Rect previewRect = new Rect(0, 0, barCodeBitMap.getWidth(), barCodeBitMap.getHeight());return decodeBitmap(barCodeBitMap, previewRect);}/*** 从PlanarYUVLuminanceSource获取Bitmap* @param source* @param roate90* @return*/public static Bitmap getBarCodeBitMap(PlanarYUVLuminanceSource source, boolean roate90) { int[] pixels = source.renderThumbnail();int width = source.getThumbnailWidth();int height = source.getThumbnailHeight();Bitmap sourceBitmap = Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.ARGB_4444);if (roate90) { return roate90Bitmap(sourceBitmap);} else { return sourceBitmap;}}/*** 根据DecodeData获取Bitmap* @param decodeData* @param roate90* @return*/public static Bitmap getBarCodeBitMap(DecodeData decodeData, boolean roate90) { byte[] data = decodeData.getData();Size size = decodeData.getSourceSize();Rect preRect = decodeData.getPreRect();PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(data, size.width, size.height, preRect.left, preRect.top, preRect.width(), preRect.height(), false);return getBarCodeBitMap(source, roate90);}/*** 将Bitmap旋转90* @param sourceBitmap* @return*/public static Bitmap roate90Bitmap(Bitmap sourceBitmap) { Matrix matrix = new Matrix();matrix.reset();matrix.setRotate(90);Bitmap resultBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0, sourceBitmap.getWidth(), sourceBitmap.getHeight(), matrix, true);if (!sourceBitmap.isRecycled())sourceBitmap.recycle();return resultBitmap;}/*** 解析PlanarYUVData* @param data* @param width* @param height* @param previewRect* @param roate90* @return*/public static Result decodePlanarYUVData(byte[] yuvData, Size size, Rect previewRect, boolean roate90) { if (roate90) { yuvData = roate90YUVdata(yuvData, size);}PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(yuvData, size.width, size.height, previewRect.left, previewRect.top, previewRect.width(), previewRect.height(), false);BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(source));return decodeBinaryBitmap(binaryBitmap);}/*** 将yuvData旋转90度* @param yuvData* @param size* @return*/public static byte[] roate90YUVdata(byte[] yuvData, Size size) { byte[] rotatedData = new byte[yuvData.length];for (int y = 0; y < size.height; y++) { for (int x = 0; x < size.width; x++)rotatedData[x * size.height + size.height - y - 1] = yuvData[x + y * size.width];}int tmp = size.width;size.width = size.height;size.height = tmp;return rotatedData;}/*** 解析Bitmap* @param bitmap* @param previewRect* @param needResultBitmap* @return*/private static Result decodeBitmap(Bitmap bitmap, Rect previewRect) { int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()];bitmap.getPixels(pixels, 0, bitmap.getWidth(), previewRect.left, previewRect.top, previewRect.right, previewRect.bottom);RGBLuminanceSource source = new RGBLuminanceSource(bitmap.getWidth(), bitmap.getHeight(), pixels);BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(source));return decodeBinaryBitmap(binaryBitmap);}/*** 解析BinaryBitmap* @param binaryBitmap* @return*/private static Result decodeBinaryBitmap(BinaryBitmap binaryBitmap) { MultiFormatReader multiFormatReader = new MultiFormatReader();multiFormatReader.setHints(decodeConfig);Result decode = null;try { decode = multiFormatReader.decode(binaryBitmap);} catch (NotFoundException e) { } finally { multiFormatReader.reset();}return decode;}// 生成 ////*** 生成二维码* @param content* @param needWidth* @param needHeight* @return* @throws Exception*/public static Bitmap encodeQr(String content, int needWidth, int needHeight) throws Exception { Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");MultiFormatWriter writer = new MultiFormatWriter();BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, needWidth, needHeight);return convertBitMatrix2BitMap(bitMatrix);}/*** 生成一维码(128)* @param content* @param needWidth* @param needHeight* @return* @throws Exception*/public static Bitmap encodeBarcode(String content, int needWidth, int needHeight) throws Exception { Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");MultiFormatWriter writer = new MultiFormatWriter();BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.CODE_128, needWidth, needHeight);return convertBitMatrix2BitMap(bitMatrix);}/*** 将BitMatrix转化为Bitmap* @param bitMatrix* @return*/private static Bitmap convertBitMatrix2BitMap(BitMatrix bitMatrix) { int bitmapWidth = bitMatrix.getWidth();int bitmapHeight = bitMatrix.getHeight();int[] pixels = new int[bitmapWidth * bitmapHeight];for (int x = 0; x < bitmapWidth; x++) { for (int y = 0; y < bitmapHeight; y++) { if (bitMatrix.get(x, y)) { pixels[y * bitmapWidth + x] = 0xff000000; // black pixel} else { pixels[y * bitmapWidth + x] = 0xffffffff; // white pixel}}}Bitmap createBitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_4444);createBitmap.setPixels(pixels, 0, bitmapWidth, 0, 0, bitmapWidth, bitmapHeight);return createBitmap;} } ---扫描页面 public class ZxingBarCodeActivity extends Activity implements SurfaceHolder.Callback { public static final String TAG = "ZbarFinderActivity";public static final String ResultType = "ResultType";public static final String ResultContent = "ResultContent";private Camera mCamera;private SurfaceHolder mHolder;protected SurfaceView surface_view;protected FinderView finder_view;private ImageView imageView;private Handler autoFocusHandler;private ThreadPoolExecutor fixPool;private LinkedBlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>();private boolean reciveReuslt = false;@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);setContentView(R.layout.ac_zbar_finder);//打开返回init();}@SuppressWarnings("deprecation")private void init() { imageView = (ImageView) findViewById(R.id.imageView);surface_view = (SurfaceView) findViewById(R.id.surface_view);finder_view = (FinderView) findViewById(R.id.finder_view);//扫描mHolder = surface_view.getHolder();//在2.3的系统中需要mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);mHolder.addCallback(this);autoFocusHandler = new Handler();}@Overridepublic void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig);}private boolean roate90 = false;@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { if (mHolder.getSurface() == null) { return;}try { mCamera.stopPreview();} catch (Exception e) { }try { if (width < height) { roate90 = true;mCamera.setDisplayOrientation(90);} else { roate90 = false;mCamera.setDisplayOrientation(0);}mCamera.setPreviewDisplay(mHolder);mCamera.setPreviewCallback(previewCallback);mCamera.startPreview();mCamera.autoFocus(autoFocusCallback);} catch (Exception e) { }}public boolean isReciveReuslt() { return reciveReuslt;}public void setReciveReuslt(boolean reciveReuslt) { this.reciveReuslt = reciveReuslt;}/*** 结果*/private QrActivityHandler handler = new QrActivityHandler(this) { @Overridepublic void handleMessage(Message msg) { if (activiceReference.get() != null) { if (msg.what == 0) { if (!fixPool.isShutdown()) { fixPool.shutdownNow();}Intent intent = new Intent(MainActivity.ACTION_SAO_RESULT);intent.putExtras(msg.getData());startActivity(intent);finish();}}}};/*** 预览数据*/private PreviewCallback previewCallback = new PreviewCallback() { public void onPreviewFrame(byte[] data, Camera camera) { if (!reciveReuslt && !fixPool.isShutdown() && fixPool.getActiveCount() < 5) { Camera.Parameters parameters = camera.getParameters();Size size = parameters.getPreviewSize();//获取预览图的大小Rect preRect = finder_view.getScanImageRect(size);DecodeData decodeData = new DecodeData(data, size, preRect);imageView.setImageBitmap(ZxingTools.getBarCodeBitMap(decodeData, roate90));Runnable command = new DecodeRunable(handler, decodeData, roate90);fixPool.execute(command);}}};private static class QrActivityHandler extends WeakHandler<ZxingBarCodeActivity> { public QrActivityHandler(ZxingBarCodeActivity qrFinderActivity) { super(qrFinderActivity);}}/*** 自动对焦回调*/AutoFocusCallback autoFocusCallback = new AutoFocusCallback() { public void onAutoFocus(boolean success, Camera camera) { autoFocusHandler.postDelayed(doAutoFocus, 1000);}};//自动对焦private Runnable doAutoFocus = new Runnable() { public void run() { if (null == mCamera || null == autoFocusCallback) { return;}mCamera.autoFocus(autoFocusCallback);}};@Overridepublic void surfaceCreated(SurfaceHolder holder) { try { mCamera = Camera.open();fixPool = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS, workQueue);} catch (Exception e) { mCamera = null;}}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) { if (mCamera != null) { mCamera.setPreviewCallback(null);mCamera.release();mCamera = null;}if (null != fixPool && !fixPool.isShutdown()) { fixPool.shutdownNow();}} }