Android 二维码的扫描,识别与生成功能使用简介

1.概述

中国的二维码技术领先全世界,走在大街上,都是二维码的身影,也极大的方便了我们的生活。今天我们就来讲一讲Android开发中二维码的开发与使用。二维码的功能中包括三大部分,第一是二维码的扫描,比如你微信支付,支付宝支付都需要扫描二维码,第二个是二维码的识别,微信中有这样一个功能,长按一张图片可以弹出识别图中二维码的界面,识别后可以跳转相应页面,第三个是二维码的生成,没有生成哪来的扫描呢,生成就是顾名思义,把你想让别人知道的链接或内容生成对应的二维码供别人扫描。

先看几张最后的效果图吧:



好了,看完最后的效果图我们要说一下怎么实现这些功能了,其实这个里面的原理就是把你传过来的string字符串一生成一个像素一个像素的点,最后组合起来。识别生成也是同样的道理,只不过是反向的逻辑罢了。扫描的时候需要调用相机,别忘了开启相机权限,6.0以上还要做权限适配哟。

2.实现过程及核心代码

1.二维码扫描

现在build.gradle中添加 compile 'com.google.zxing:core:3.1.0' 引入二维码功能需要依赖的包。

扫描的主页面采用surfaceView绘制。加入相机自动对焦方法

/**
     * 开始扫描二维码
     */
    public void startScanQr() {
//        if(cameraManager == null){
        cameraManager = new CameraManager(getApplication());
//        }
        handler = null;
        if (isHasSurface) {
            initCamera(scanPreview.getHolder());
        } else {
            scanPreview.getHolder().addCallback(this);
        }
        inactivityTimer.onResume();
        scanLine.startAnimation(animation);
    }

    private void initCamera(SurfaceHolder surfaceHolder) {
        if (surfaceHolder == null) {
            throw new IllegalStateException("No SurfaceHolder provided");
        }
        if (cameraManager.isOpen()) {
            return;
        }
        try {
            cameraManager.openDriver(surfaceHolder);
            if (handler == null) {
                handler = new CaptureActivityHandler(mQrScanListener, cameraManager, DecodeThread.ALL_MODE);
            }

            initCrop();
        } catch (IOException ioe) {
            displayFrameworkBugMessageAndExit();
        } catch (RuntimeException e) {
            displayFrameworkBugMessageAndExit();
        }
    }
private void handleDecode(final Result rawResult, Bundle bundle) {
        inactivityTimer.onActivity();
        //震动
        vibrate();
        handler.postDelayed(new Runnable() {

            @Override
            public void run() {
                Toast.makeText(ScanQRActivity.this, rawResult.getText(), Toast.LENGTH_SHORT).show();
                startScanQr();
            }
        }, 100);
    }
private IQrScanCallback mQrScanListener = new IQrScanCallback() {

        @Override
        public Handler onGetHandler() {
            return handler;
        }

        @Override
        public Camera.Size onGetCameraPreviewSize() {
            return cameraManager.getPreviewSize();
        }

        @Override
        public Rect onGetCropRect() {
            return mCropRect;
        }

        @Override
        public void onHandleDecode(Result result, Bundle bundle) {
            handleDecode(result, bundle);
        }

        @Override
        public void onSetScanResult(int activityResult, Intent intent) {
            setResult(Activity.RESULT_OK, intent);
            finish();
        }
    };

通过这几个方法拿到Result的text也就是字符串。

2.二维码识别功能实现

/**
     * 根据图片路径识别二维码
     *
     * @param path
     * @return
     */
    protected Result scanningImage(String path) {
        if (TextUtils.isEmpty(path)) {
            return null;
        }
        Hashtable<DecodeHintType, String> hints = new Hashtable<>();
        hints.put(DecodeHintType.CHARACTER_SET, "utf-8"); // 设置二维码内容的编码
        // boolean isUrlPath = Util.adjustIsURL(path);// 是否为网络地址
        // if (isUrlPath) { // 是网络图片
        mScanBitmap = getBitmapFromUrl(path);
        // } else { // 是本地图片
        // mScanBitmap = getBitmapFromUrl(path);
        // }
        if (mScanBitmap == null) {
            return null;
        }
        int width = mScanBitmap.getWidth();
        int height = mScanBitmap.getHeight();
        int[] data = new int[width * height];
        mScanBitmap.getPixels(data, 0, width, 0, 0, width, height);
        Result result = null;
        RGBLuminanceSource source = new RGBLuminanceSource(width, height, data);
        BinaryBitmap bitmap1 = new BinaryBitmap(new HybridBinarizer(source));
        QRCodeReader reader = new QRCodeReader();
        try {
            result = reader.decode(bitmap1, hints);
        } catch (NotFoundException e) {
            e.printStackTrace();
        } catch (ChecksumException e) {
            e.printStackTrace();
        } catch (FormatException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
        return result;
    }
/**
     * 根据图片的url路径获得Bitmap对象
     *
     * @param url
     * @return
     */
    private Bitmap getBitmapFromUrl(String url) {
        Bitmap bitmap = null;
        try {
            bitmap = Glide.with(this).load(url).asBitmap().into(300, 300).get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bitmap;
    }
通过图片的path生成一个bitmap,对这个bitmap进行解析,从而生成result返回。原理也是一个像素一个像素点的解析。当然了跟扫描的过程是一样的,都是耗时操作,所以都需要在子线程中进行操作,result通过handler返回到主线程。

3.二维码的生成

/** 二维码工具类
 */
public class QrCodeUtil {

	/** 
	 * 生成二维码Bitmap 
	 * 
	 * @param data   文本内容
	 * @param size 二维码宽高
	 * @return 合成后的bitmap 
	 */
	public static Bitmap createQRImage(String data, int size) {
		if (size <= 0 || size <= 0) {
			size = 400;
		}
		try {
			if (data == null || data.length() == 0) {
				return null;
			}

			//配置参数   
			Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
			hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
			//容错级别   
			hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
			//设置空白边距的宽度   
			hints.put(EncodeHintType.MARGIN, 0); //default is 4   

			// 图像数据转换,使用了矩阵转换   
			BitMatrix bitMatrix = new QRCodeWriter().encode(data, BarcodeFormat.QR_CODE, size, size, hints);
			int[] pixels = new int[size * size];
			// 下面这里按照二维码的算法,逐个生成二维码的图片,   
			// 两个for循环是图片横列扫描的结果   
			for (int y = 0; y < size; y++) {
				for (int x = 0; x < size; x++) {
					if (bitMatrix.get(x, y)) {
						pixels[y * size + x] = 0xff000000;
					} else {
						pixels[y * size + x] = 0xffffffff;
					}
				}
			}

			// 生成二维码图片的格式,使用ARGB_8888   
			Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.RGB_565);
			bitmap.setPixels(pixels, 0, size, 0, 0, size, size);

			return bitmap;
			//必须使用compress方法将bitmap保存到文件中再进行读取。直接返回的bitmap是没有任何压缩的,内存消耗巨大!   
			//return bitmap != null && bitmap.compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStream(filePath));   
		} catch (Exception e) {
			e.printStackTrace();
		}

		return null;
	}

	/**
	 * 生成带logo的二维码,logo默认为二维码的1/10
	 *
	 * @param text 需要生成二维码的文字、网址等
	 * @param mBitmap logo文件
	 * @param size 需要生成二维码的大小()
	 * @return bitmap
	 */
	public static Bitmap createQRCodeWithLogo(String text, Bitmap mBitmap, int size) {
		try {
			int logoImageHalfSize = size / 10;
			Hashtable<EncodeHintType, Object> hints = new Hashtable<>();
			hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
			/*
			 * 设置容错级别,默认为ErrorCorrectionLevel.L
			 * 因为中间加入logo所以建议你把容错级别调至H,否则可能会出现识别不了
			 */
			hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
			//设置空白边距的宽度   
			hints.put(EncodeHintType.MARGIN, 0); //default is 4   
			BitMatrix bitMatrix = new QRCodeWriter().encode(text, BarcodeFormat.QR_CODE, size, size, hints);

			int width = bitMatrix.getWidth();//矩阵高度
			int height = bitMatrix.getHeight();//矩阵宽度
			int halfW = width / 2;
			int halfH = height / 2;

			Matrix m = new Matrix();
			float sx = (float) 2 * logoImageHalfSize / mBitmap.getWidth();
			float sy = (float) 2 * logoImageHalfSize / mBitmap.getHeight();
			m.setScale(sx, sy);
			//设置缩放信息
			//将logo图片按martix设置的信息缩放
			mBitmap = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(), mBitmap.getHeight(), m, false);

			int[] pixels = new int[size * size];
			for (int y = 0; y < size; y++) {
				for (int x = 0; x < size; x++) {
					if (x > halfW - logoImageHalfSize && x < halfW + logoImageHalfSize && y > halfH - logoImageHalfSize
							&& y < halfH + logoImageHalfSize) {
						//该位置用于存放图片信息
						//记录图片每个像素信息
						pixels[y * width + x] = mBitmap.getPixel(x - halfW + logoImageHalfSize, y - halfH + logoImageHalfSize);
					} else {
						if (bitMatrix.get(x, y)) {
							pixels[y * size + x] = 0xff000000;
						} else {
							pixels[y * size + x] = 0xffffffff;
						}
					}
				}
			}
			Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
			bitmap.setPixels(pixels, 0, size, 0, 0, size, size);
			return bitmap;
		} catch (WriterException e) {
			e.printStackTrace();
			return null;
		}
	}

}
先贴最主要代码,这个工具类有两个方法,一个是通过String生成最普通的二维码,第二个是通过String,bitmap生成带logo的二维码(这个比较常见,我们生活中的二维码很多都是这样的).

这样就完全可以集成二维码三大功能了,最底层的代码都是骨灰级别的人物写的,我们只需要会调用就可以了.好了,这些干货带给大家,以后项目中如果需要二维码相关功能可以借鉴一下。


需要完整代码的可以在下面留言邮箱地址,请叫我雷锋。







评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值