zoukankan      html  css  js  c++  java
  • Android开发——Android中的二维码生成与扫描

    0. 前言

    今天这篇文章主要描述二维码的生成与扫描,使用目前流行的Zxing,为什么要讲二维码,因为二维码太普遍了,随便一个Android APP都会有二维码扫描。本篇旨在帮助有需求的同学快速完成二维码生成和扫描的功能。

    本篇转载自:http://blog.csdn.net/hai_qing_xu_kong/article/details/51260428

     

    1.    Zxing的使用

    github上下载项目后,可以看到整体代码结构如下:

    这里写图片描述

    我们只需将Zxing包下的所有代码copy一份到我们的项目中去,除了这些还需要zxingjar包,最后相应的资源文件,包括values文件下的ids文件、raw文件中的资源文件(可以替换)、layout文件下的activity_capture.xml(可以进行相应的订制) 和图片资源。

     

    2.    生成二维码的实现

    等上面工作全部准备完毕后,就可以创建我们的二维码了。如何生成二维码?

    需要EncodingUtils这个二维码生成工具类。通过调用工具类中的createQRCode()方法来生成二维码。该方法参数介绍如下:

    /*
    * content:二维码内容
    * widthPix:二维码宽度
    * heightPix:二维码高度
    * logoBm:二维码中间的logo对应的Bitmap
    */
    public static Bitmap createQRCode(String content, int widthPix, int heightPix, Bitmap logoBm)
    

    下面完成的是生成的一个百度地址的二维码,中间LOGOAndroid小机器人。并保存图片到本地,方便后续测试二维码的本地读取功能。

    /**
         * 创建、展示二维码并将bitmap保存在本地
         */
        private void create() {
            int width = DensityUtil.dip2px(this, 200);
            Bitmap bitmap = EncodingUtils.createQRCode("http://www.baidu.com",
                    width, width, BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher));
            iv_zxing.setImageBitmap(bitmap);
            saveBitmap(bitmap);
        }
    
        /**
         * 将Bitmap保存在本地
         * 
         * @param bitmap
         */
        public void saveBitmap(Bitmap bitmap) {
            // 首先保存图片
            File appDir = new File(Environment.getExternalStorageDirectory(),"zxing_image");
            if (!appDir.exists()) {
                appDir.mkdir();
            }
            String fileName = "zxing_image" + ".jpg";
            File file = new File(appDir, fileName);
            try {
                FileOutputStream fos = new FileOutputStream(file);
                bitmap.compress(CompressFormat.JPEG, 100, fos);
                fos.flush();
                fos.close();
            } catch (Exception e) {
                e.printStackTrace();
            } 
    
            // 把文件插入到系统图库
            try {
                MediaStore.Images.Media.insertImage(this.getContentResolver(),file.getAbsolutePath(), fileName, null);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
    
            // 通知图库更新
            sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
                    Uri.parse("file://" + "/sdcard/namecard/")));
    }

    看到如下效果:

    这里写图片描述


    3.    读取二维码的实现

    3.1  摄像头扫描的方式

    二维码扫描需要借助于CaptureActivity这个类,打开CaptureActivity界面并进行扫描,扫描完毕后回调onActivityResult()方法,从onActivityResult()中得到扫描后的结果。效果就不演示的,因为使用的是模拟器。详细代码如下:

         /**
         * 打开二维码扫描
         */
        private void open() {
            config();
            startActivityForResult(new Intent(MainActivity.this,CaptureActivity.class), 0);
        }
        /**
         * 提高屏幕亮度
         */
        private void config() {
            WindowManager.LayoutParams lp = getWindow().getAttributes();
            lp.screenBrightness = 1.0f;
            getWindow().setAttributes(lp);
        }
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            if (resultCode == RESULT_OK) {
                Bundle bundle = data.getExtras();
                String result = bundle.getString("result");
                tv_result.setText(result);
            }
    }
    


    3.2  本地图片扫描的方式

    扫描本地图片需要我们在CaptureActivity中进行相应的修改,为此我在扫描界面底部增加了一个按钮,用来选择本地图片。layout代码这里就不展示,我们直接看点击后的事件处理。

    /**
    * 打开本地图片
    */
    private void openLocalImage() {
        // 打开手机中的相册
        Intent innerIntent = new Intent(Intent.ACTION_GET_CONTENT); 
        innerIntent.setType("image/*");
        Intent wrapperIntent = Intent.createChooser(innerIntent, "选择二维码图片");
        this.startActivityForResult(wrapperIntent, 0x01);
    }
    

    打开系统图片库后选择图片,这时需要重写onActivityResult()方法用于返回图片信息。

    @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            if (resultCode == RESULT_OK) {
                switch (requestCode) {
                case 0x01:
                    // 获取选中图片的路径
                    Cursor cursor = getContentResolver().query(data.getData(),null, null, null, null);
                    if (cursor.moveToFirst()) {
                        photo_path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
                    }
                    cursor.close();
    
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            Result result = scanningImage(photo_path);
                            if (result != null) {
                                handleDecode(result, new Bundle());
                            }
                        }
                    }).start();
                    break;
                }
            }
    }
    

    获取图片路径photo_path,调用scanningImage()方法进行扫描Zxing源码中,扫描到的结果都是存放在Result结果集中。获取到Result后,就进行结果的回传,阅读CaptureActivity源码可以得知最后Result结果集会传递给handleDecode()方法

    /**
         * A valid barcode has been found, so give an indication of success and show
         * the results.
         * 
         * @param rawResult
         *            The contents of the barcode.
         * @param bundle
         *            The extras
         */
        public void handleDecode(Result rawResult, Bundle bundle) {
            inactivityTimer.onActivity();
            beepManager.playBeepSoundAndVibrate();
    
            Intent resultIntent = new Intent();
            bundle.putInt("width", mCropRect.width());
            bundle.putInt("height", mCropRect.height());
            bundle.putString("result", rawResult.getText());
            resultIntent.putExtras(bundle);
            this.setResult(RESULT_OK, resultIntent);
            CaptureActivity.this.finish();
    }
    

    获取到图片路径后需要将其二维码信息包装成Result对象,因此需要解析图片:

     /**
         * 扫描二维码图片的方法
         * 
         * @param path
         * @return
         */
        public Result scanningImage(String path) {
            if (TextUtils.isEmpty(path)) {
                return null;
            }
            Hashtable<DecodeHintType, String> hints = new Hashtable<DecodeHintType, String>();
            hints.put(DecodeHintType.CHARACTER_SET, "UTF8"); // 设置二维码内容的编码
    
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true; // 先获取原大小
            scanBitmap = BitmapFactory.decodeFile(path, options);
            options.inJustDecodeBounds = false; // 获取新的大小
            int sampleSize = (int) (options.outHeight / (float) 200);
            if (sampleSize <= 0)
                sampleSize = 1;
            options.inSampleSize = sampleSize;
            scanBitmap = BitmapFactory.decodeFile(path, options);
            int width = scanBitmap.getWidth();
            int height = scanBitmap.getHeight();
            int[] pixels = new int[width * height];
            scanBitmap.getPixels(pixels, 0, width, 0, 0, width, height);
            /**
             * 第三个参数是图片的像素
             */
            RGBLuminanceSource source = new RGBLuminanceSource(width, height,
                    pixels);
            BinaryBitmap bitmap1 = new BinaryBitmap(new HybridBinarizer(source));
            QRCodeReader reader = new QRCodeReader();
            try {
                return reader.decode(bitmap1, hints);
    
            } catch (NotFoundException e) {
                e.printStackTrace();
            } catch (ChecksumException e) {
                e.printStackTrace();
            } catch (FormatException e) {
                e.printStackTrace();
            }
            return null;
        }
    

    根据路径获取Bitmap,最后通过QRCodeReader 中的decode方法解析成Result对象并返回,最终传递给handleDecode方法。运行程序效果如下,扫描出来的是之前定义的百度地址。

    这里写图片描述

    最后不要忘了申明权限和CaptureActivity

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.VIBRATE"/>
    <activity android:name="com.example.zxingtest.zxing.activity.CaptureActivity"/>
    

  • 相关阅读:
    【IDEA】项目最好强制 utf-8,换行符强制 Unix格式,制表符4个空格
    【Maven】有关 snapshots、releases 的说明
    【Maven】与私服有关的本地操作(上传、拉取jar包;版本发布)
    【Maven】nexus 安装(基于docker)
    【Maven】maven命令(编译、打包、安装、发布)区别
    【Linux、Centos7】添加中文拼音输入
    生成器、列表推导式、生成器表达式
    列表:python基础数据类型
    数据类型之间转化、字符串学习
    while 循环、格式化输出、运算符
  • 原文地址:https://www.cnblogs.com/qitian1/p/6461445.html
Copyright © 2011-2022 走看看