zoukankan      html  css  js  c++  java
  • Zxing二维码扫描

    源代码地址  有问题能够加QQ:312122330


    之前对于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;
    }


    @Override
    public 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);
    }
    }
    }
    }
    ---自己定义查找框--支持横屏---主要方法
    /**
    * 矫正矩形框
    * @param w
    * @param h
    * @return
    */
    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;
    }
    @Override
    protected 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;


    @Override
    protected 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();
    }


    @Override
    public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    }


    private boolean roate90 = false;


    @Override
    public 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) {
    @Override
    public 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);
    }
    };


    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    try {
    mCamera = Camera.open();
    fixPool = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS, workQueue);
    } catch (Exception e) {
    mCamera = null;
    }
    }


    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    if (mCamera != null) {
    mCamera.setPreviewCallback(null);
    mCamera.release();
    mCamera = null;
    }
    if (null != fixPool && !fixPool.isShutdown()) {
    fixPool.shutdownNow();
    }
    }
    }

  • 相关阅读:
    Class类和ClassLoader类的简单介绍
    【IDEA】IDEA中配置tomcat虚拟路径的两种方法
    layui利用jQuery设置下拉列表的值
    SpringMVC可以配置多个拦截后缀*.action和.do等
    【IDEA】IDEA设置新建文件的模板
    【IDEA】与Eclipse "Link with Editor"等价功能设置
    Java集合详解
    【Git】git clone与git pull区别
    使用maven打包项目遇到错误: http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
    自动阈值分割-场景中直线个数的检测
  • 原文地址:https://www.cnblogs.com/clnchanpin/p/7288919.html
Copyright © 2011-2022 走看看