Android二维码的创建、解析及NotFoundException

本文介绍了在Android中如何生成和解析二维码,包括遇到的NotFoundException及其解决方案。生成二维码的核心在于将信息编码为像素数组,解析过程则是解码像素数组得到原始信息。在处理过程中,未对Bitmap进行缩小操作会导致Zxing库抛出NotFoundException,缩小Bitmap尺寸后问题解决。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本篇博客主要记录一下Android生成及解析二维码的基本方法,
同时记录一下遇到的NotFoundException及对应解决方法。


如今很多APK都集成了二维码,其本质不过是将信息按照0、1的方式写入到图片中,
0、1分别对应了不同的颜色。

从APK调用api的角度来看,生成和解析二维码是非常容易的,
真正的难度其实还是在信息的编码及图像的识别上,而这就比较依赖于专业知识了。

对于普通开发者而言,在项目中引用google的支持库后,就能够开发基本的功能了。

我自己写demo时,在Android Studio中引用的支持库为com.google.zxing:core:3.3.0。

整个demo的界面非常简单,如下图所示:

基本功能就是点击GENERATE按键后,在界面下方生成二维码;
点击SCAN按键后,从二维码图片中得到对应的信息。


其中,生成二维码的核心代码如下:

    private void generateQRCode() {
        //得到信息对应的像素数组
        int[] pixels = generatePixels();

        if (pixels != null) {
            Bitmap bitmap = Bitmap.createBitmap(
                    QR_WIDTH, QR_HEIGHT, Bitmap.Config.ARGB_8888);

            //根据像素数组生成bitmap
            //这部分参数含义查看一下API描述,比较容易弄懂
            bitmap.setPixels(pixels, 0, QR_WIDTH, 0, 0, QR_WIDTH, QR_HEIGHT);

            //将bitmap显示到界面上
            mImageView.setImageBitmap(bitmap);

            mScanButton.setEnabled(true);
        }
    }

容易看出,上面代码的重点部分在于生成像素数组。

这部分内容如下所示:

    private int[] generatePixels() {
        //得到需要写入的信息
        String data = createData();

        int[] pixels = null;

        //定义编码的附加信息,这里指定以utf-8编码
        Hashtable<EncodeHintType, Object> hints = new Hashtable<>();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");

        try {
            //这里以QRcodeWriter,将信息编码成矩阵
            //参数分别为信息、编码格式、矩阵宽、矩阵高及附加信息
            BitMatrix bitMatrix = new QRCodeWriter()
                    .encode(data, BarcodeFormat.QR_CODE, QR_WIDTH, QR_HEIGHT, hints);

            //得到矩阵后,就可以根据矩阵得到像素数组
            pixels = new int[QR_WIDTH * QR_HEIGHT];
            for (int y = 0; y < QR_HEIGHT; ++y) {
                for (int x = 0; x < QR_WIDTH; ++x) {
                    //轮寻矩阵的每一个元素
                    //我在这里比较传统的,用黑白来形成像素数组
                    //按需可进行调整
                    pixels[y * QR_WIDTH + x] =
                            bitMatrix.get(x, y) ? Color.BLACK : Color.WHITE;
                }
            }
        } catch (WriterException e) {
            Log.d("ZJTest", e.toString());
        }

        return pixels;
    }

最后这一部分是用于生成信息的:

    private String createData() {
        String data = null;

        try {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("author", "ZhangJianIsAStark");
            jsonObject.put("url", "http://blog.csdn.net/gaugamela");

            data = jsonObject.toString();
        } catch (JSONException e) {
            Log.d("ZJTest", e.toString());
        }

        return data;
    }

可以按照需要写入任何信息,只要最后以String表示即可。
我在这里是以JSONObject的信息,生成String。

按照上述代码,点击GENERATE按键后,就可以得到二维码了,如下图所示:

图中,我的长宽的数值均为1000。

根据上面的代码,我们知道形成二维码的逻辑是:
1、得到String字符;
2、将String字符编码为像素数组;
3、根据像素数组,得到Bitmap。


接下来,我们看看解析二维码的基本方法。

一般像微信扫一扫这样的功能,都依赖于对Camera的操作。
自己对这一块不是很熟,因此是照着其他人的demo学习的,链接如下。
http://www.cnblogs.com/weixing/archive/2013/08/28/3287120.html
这个demo的主体应该是Zxing的示例代码,其中在Android 5.1之后的版本上使用时,
需要修改代码获取Camera的运行时权限。
此外,该demo中Camera的用法太老了,现在都应该使用Camera2的接口,简单看看就好。

在这里我仅记录一下,直接从图像中解析信息的步骤,略去Camera获取图片等操作。

    private void scanQRCode() {
        //将ImageView的drawable转化为BitmapDrawable
        //然后获取Bitmap
        Bitmap bitmap = ((BitmapDrawable)mImageView.getDrawable()).getBitmap();

        //按比例缩小Bitmap
        Matrix matrix = new Matrix();
        matrix.postScale(0.1f, 0.1f);
        Bitmap resizeBitmap = Bitmap.createBitmap(bitmap, 0, 0,
                bitmap.getWidth(), bitmap.getHeight(), matrix, true);

        int width = resizeBitmap.getWidth();
        int height = resizeBitmap.getHeight();

        //从Bitmap中获取像素矩阵
        int[] pixels = new int[width * height];
        resizeBitmap.getPixels(pixels, 0, width, 0, 0, width, height);

        //利用像素矩阵得到RGBLuminanceSource
        //ZXing库中定义了LuminanceSource及其子类
        RGBLuminanceSource rgbLuminanceSource =
                new RGBLuminanceSource(width, height, pixels);

        //利用LuminanceSource、HybridBinarizer得到BinaryBitmap
        BinaryBitmap binaryBitmap = new BinaryBitmap(
                new HybridBinarizer(rgbLuminanceSource));

        //定义解码附加信息
        Hashtable<DecodeHintType, Object> hints = new Hashtable<>();
        hints.put(DecodeHintType.CHARACTER_SET, "utf-8");

        try {
            //利用MultiFormatReader得到解码结果
            //本例也可以使用QRCodeReader
            Result result = new MultiFormatReader().decode(binaryBitmap, hints);

            try {
                //利用Result的getText方法获取String对象
                //以下是JSONObject的基本解析
                JSONObject jsonObject = new JSONObject(result.getText());
                String name = jsonObject.getString("author");
                String url = jsonObject.getString("url");
                Log.d("ZJTest", "name: " + name + ", url: " + url);
            } catch (JSONException e) {
                Log.d("ZJTest", e.toString());
            }
        } catch (NotFoundException e) {
            Log.d("ZJTest", e.toString());
            e.printStackTrace();
        }
    }

解析图像后的log信息如下:

03-20 21:41:42.675 5781-5781/stark.a.is.zhang.zxingtest D/ZJTest: name: ZhangJianIsAStark, url: http://blog.csdn.net/gaugamela

与之前写入的一致。

从上面的代码可以看出,二维码的解析,基本上是生成的逆过程:
1、根据Bitmap,得到像素数组;
2、根据像素数组解码出字符;
3、从字符中得到之前写入的信息。

其中解码的过程比较复杂,使用了大量Zxing库中的类。


最后记录一下,写代码遇到的问题。

最初写demo时,自己在解析二维码时,
从ImageView中获取Bitmap后,并没有对Bitmap进行缩小的操作。
于是,遇到了Zxing库抛出的NotFoundException。

自己仔细看了代码,没觉得有什么问题。
结果修改ImageView的宽、高为200以下时,就能正确解析出结果。

根据这个现象,首先推测是否从bitmap获取像素数组时,丢失了部分信息。
于是进行测试,发现在宽、高为1000时,比较生成和解析的像素数组,发现完全一致。
因此,图片与像素数组之间的转换没有问题,应该是Zxing库的原因。

目前的根本原因没有找到,个人推测是否Zxing库限制了像素数组大小的上限,
当像素信息超过上限后,会丢失掉部分信息?

在主动缩小Bitmap后,问题就解决了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值