ZXing实现二维码的生成与解析

大概一年前的扫码风潮彻底把二维码推向大众,现在什么下载,加好友,关注,都要扫一扫,这里道长絮叨一下google旗下的ZXing,用ZXing实现二维码的生成和解析。

一、二维码的生成

这里道长用的是3.1.0版本的ZXing,如果要使用可以自己下载,也可以使用道长Demo中的。和以前一样,Demo道长放在文章最后。如果想看一下ZXing的源码可以点击传送门

1.带边界的二维码

  • 传递要生成二维码的数据
    private void initData() {

        String filePath = Environment.getDataDirectory().getPath() + File.separator + "data" + File.separator;
        String fileName = "zxing.png";
        json = new JSONObject();
        try {
            json.put("url", "https://github.com/zxing/zxing");
            json.put("author", "yushan");
            json.put("filepath", filePath);
            json.put("filename", fileName);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
  • 创建工具类,并传递参数
  EncodingHelper encodingHelper = new EncodingHelper(HomeActivity.this, json, 350);
  Bitmap bitmap = encodingHelper.getBitmap(true);
  tv_show.setVisibility(View.GONE);
  iv_client_ewm.setVisibility(View.VISIBLE);
  iv_client_ewm.setBackgroundDrawable(new BitmapDrawable(bitmap));
  • 生成二维码的代码
    /**
     * 获取带边界的二维码
     *
     * @param hasBK
     * @return
     */
    public Bitmap getBitmap(Boolean hasBK) {
        BitMatrix bitMatrix = null;
        try {
            bitMatrix = dealData();
        } catch (WriterException e) {
            e.printStackTrace();
        }

        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        int[] pixels = new int[width * height];
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                if (bitMatrix.get(x, y)) {
                    pixels[y * width + x] = BLACK;
                } else {
                    pixels[y * width + x] = WHITE;
                }
            }
        }
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);
        bitmap.setPixels(pixels, 0, width, 0, 0, width, height);

        // 画边框
        if (hasBK != null && hasBK == true) {
            Paint paint = new Paint();
            Canvas canvas = new Canvas(bitmap);

            drawBK(paint, canvas);
        }

        return bitmap;
    }

    /**
     * 生成二维码矩阵
     *
     * @return
     * @throws WriterException
     */
    private BitMatrix dealData() throws WriterException {

        String content = json.toString();

        Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); // 字符编码
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M); // 纠错等级
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content,
                BarcodeFormat.QR_CODE, width, height, hints); // 生成矩阵

        return bitMatrix;
    }
  • 效果图
    这里写图片描述

2.带图标的二维码

  • 调用方法
                EncodingHelper encodingHelper = new EncodingHelper(HomeActivity.this, json, 350);
                Bitmap bitmap = encodingHelper.getBitmapWithSingOrBK(R.drawable.ewm_hulu, true);
                tv_show.setVisibility(View.GONE);
                iv_client_ewm.setVisibility(View.VISIBLE);
                iv_client_ewm.setBackgroundDrawable(new BitmapDrawable(bitmap));
  • 生成二维码的代码
    /**
     * 获取带图标或边界的二维码
     *
     * @param drawableId
     * @param hasBK
     * @return
     */
    public Bitmap getBitmapWithSingOrBK(int drawableId, Boolean hasBK) {
        mBitmap = toRoundCorner(((BitmapDrawable) mContext.getResources().getDrawable(drawableId)).getBitmap(), 10);

        if (mBitmap != null) {
            Bitmap bitmapWithSign = bitmapWithSign(getBitmap(hasBK));

            return bitmapWithSign;
        } else {
            return getBitmap(hasBK);
        }
    }

    /**
     * 生成带图标的二维码
     *
     * @param bitmap
     * @return
     */
    private Bitmap bitmapWithSign(Bitmap bitmap) {

        Paint paint = new Paint();
        Canvas canvas = new Canvas(bitmap);
        canvas.drawARGB(0, 0, 0, 0);// 透明色
        Rect outDst = new Rect();
        outDst.left = width * 2 / 5 - 6;
        outDst.top = height * 2 / 5 - 6;
        outDst.right = width * 3 / 5 + 6;
        outDst.bottom = height * 3 / 5 + 6;
        canvas.drawBitmap(((BitmapDrawable) mContext.getResources().getDrawable(
                R.drawable.ewm_bg)).getBitmap(), null, outDst, paint);
        Rect inDst = new Rect();

        inDst.left = width * 2 / 5;
        inDst.top = height * 2 / 5;
        inDst.right = width * 3 / 5;
        inDst.bottom = height * 3 / 5;

        canvas.drawBitmap(mBitmap, null, inDst, paint);

        inDst = null;
        outDst = null;
        paint = null;
        canvas = null;

        return bitmap;
    }
  • 效果图

这里写图片描述

到这里道长已经把二维码的生成已经说完了,至于传参啊什么的这里道长就不说了,然后咱们说一下二维码的解析。

二、二维码的解析

这里咱么不止要初始化相机,还要自定义扫码界面。
效果图如下:
这里写图片描述

这里的自定义View是用画笔和画布实现的,这里道长就不贴代码了。

  • 添加权限
    记得在AndroidManifest.xml添加权限:
    <uses-permission android:name="android.permission.CAMERA" />
  • 初始化相机
        viewfinderView.setShowInfoType(ViewfinderView.TEXTCONTENTTYPE_SCAN);
        CameraManager.frameSize = 2;
        CameraManager.init(getApplication());
  • 开启扫描
    @Override
    protected void onResume() {
        super.onResume();
        SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
        SurfaceHolder surfaceHolder = surfaceView.getHolder();

        if (hasSurface) {
            initCamera(surfaceHolder);
        } else {
            surfaceHolder.addCallback(this);
            surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        }

        decodeFormats = null;
        characterSet = null;
    }

    private void initCamera(SurfaceHolder surfaceHolder) {
        try {
            CameraManager.get().openDriver(surfaceHolder);
        } catch (IOException ioe) {
            Toast.makeText(this, "请授予相应权限,再使用扫一扫!", Toast.LENGTH_SHORT).show();
            finish();// 获取系统相机事件被拒绝后,直接finish()掉本activity
        } catch (RuntimeException e) {
            Toast.makeText(this, "请授予相应权限,再使用扫一扫!", Toast.LENGTH_SHORT).show();
            finish();// 获取系统相机事件被拒绝后,直接finish()掉本activity
        }

        if (handler == null) {
            handler = new CaptureActivityHandler(this, decodeFormats, characterSet);
        }
    }
  • 开启一个线程decodeThread,用来扫描解析图片
    public CaptureActivityHandler(ScanActivity activity, Vector<BarcodeFormat> decodeFormats,
                                  String characterSet) {
        this.activity = activity;
        decodeThread = new DecodeThread(activity, decodeFormats, characterSet,
                new ViewfinderResultPointCallback(activity.getViewfinderView()));
        decodeThread.start();
        state = State.SUCCESS;
        manager = CameraManager.get();
        // Start ourselves capturing previews and decoding.
        manager.startPreview();
        restartPreviewAndDecode();
    }
  • decodeThread线程在Handler中处理数据
    /**
     * Decode the data within the viewfinder rectangle, and time how long it took. For efficiency,
     * reuse the same reader objects from one decode to the next.
     *
     * @param data   The YUV preview frame.
     * @param width  The width of the preview frame.
     * @param height The height of the preview frame.
     */
    private void decode(byte[] data, int width, int height) {
        if ((data == null) || (data.length <= 0)) {
            return;
        } // 判断以防null指针异常
        long start = System.currentTimeMillis();
        Result rawResult = null;

        // modify here
        byte[] rotatedData = new byte[data.length];
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++)
                rotatedData[x * height + height - y - 1] = data[x + y * width];
        }
        int tmp = width; // Here we are swapping, that's the difference to #11
        width = height;
        height = tmp;

        PlanarYUVLuminanceSource source = CameraManager.get().buildLuminanceSource(rotatedData, width, height);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        try {
            rawResult = multiFormatReader.decodeWithState(bitmap);
        } catch (ReaderException re) {
            // continue
        } finally {
            multiFormatReader.reset();
        }

        if (rawResult != null) {
            long end = System.currentTimeMillis();
            Log.e("yushan", "Found barcode (" + (end - start) + " ms):\n" + rawResult.toString());
            Message message = Message.obtain(activity.getHandler(), R.id.decode_succeeded, rawResult);
            Bundle bundle = new Bundle();
            bundle.putParcelable(DecodeThread.BARCODE_BITMAP, source.renderCroppedGreyscaleBitmap());
            message.setData(bundle);
            // Log.d(TAG, "Sending decode succeeded message...");
            message.sendToTarget();
        } else {
            Message message = Message.obtain(activity.getHandler(), R.id.decode_failed);
            message.sendToTarget();
        }
    }
  • 处理完成的数据通过message发送到另一个Handler
 @Override
  public void handleMessage(Message message) {
      switch (message.what) {
          case R.id.auto_focus:
              //Log.d(TAG, "Got auto-focus message");
              // When one auto focus pass finishes, start another. This is the closest thing to
              // continuous AF. It does seem to hunt a bit, but I'm not sure what else to do.
              if (state == State.PREVIEW) {
                  manager.requestAutoFocus(this, R.id.auto_focus);
              }
              break;
          case R.id.restart_preview:
              Log.d(TAG, "Got restart preview message");
              restartPreviewAndDecode();
              break;
          case R.id.decode_succeeded:
              Log.d(TAG, "Got decode succeeded message");
              state = State.SUCCESS;
              Bundle bundle = message.getData();

              /***********************************************************************/
//                Bitmap barcode = bundle == null ? null : (Bitmap) bundle.getParcelable(DecodeThread.BARCODE_BITMAP);
//                activity.handleDecode((Result) message.obj, barcode);
              String resultString = ((Result) message.obj).getText() + "";
              activity.handleDecode(resultString);// 返回数据
              /***********************************************************************/
              break;
          case R.id.decode_failed:
              // We're decoding as fast as possible, so when one decode fails, start another.
              state = State.PREVIEW;
              manager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
              break;
          case R.id.return_scan_result:
              Log.d(TAG, "Got return scan result message");
              activity.setResult(Activity.RESULT_OK, (Intent) message.obj);
              activity.finish();
              break;
          case R.id.launch_product_query:
              Log.d(TAG, "Got product query message");
              String url = (String) message.obj;
              Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
              intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
              activity.startActivity(intent);
              break;
      }
  }
  • 把解析数据返回到主界面
    /**
     * 扫描返回数据
     *
     * @param resultString
     */
    public void handleDecode(String resultString) {
        inactivityTimer.onActivity();

        Log.e("yushan", resultString);

        Intent intent = this.getIntent();
        intent.putExtra("resultString", resultString);
        this.setResult(RESULT_OK, intent);
        this.finish();
    }
  • 展示解析结果
    这里写图片描述

好了,到了这里ZXing实现二维码的生成与解析都已经实现了,希望这篇博客能够为你提供一些帮助。

源码下载

ZXingDemo


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值