二维码生成与扫描

转自http://blog.csdn.net/u012702547/article/details/51501350

读取相册二维码

转自http://blog.csdn.net/aaawqqq/article/details/24880209

读取相册二维码报错解决

转自http://blog.csdn.net/huang_xiao_yu/article/details/53419366

注意实现读取相册二维码功能时必须添加权限:

<uses-permission android:name="android.permission.FLASHLIGHT" />
<permission android:name="android.permission.HARDWARE_TEST" />

二维码,我们也称作QRCode,QR表示quick response即快速响应,在很多App中我们都能见到二维码的身影,最常见的莫过于微信了。那么今天我们就来看看怎么样在我们自己的App中集成二维码的扫描与生成功能。OK,废话不多说,我们就开始做吧。

二维码的使用我主要想分为两部分来给大家介绍,一部分就是二维码的生成,这里的知识点都很简单,还有一部分是二维码的识别,这里稍微麻烦一些,不过细心来做其实也很简单。二维码的开发使用我们大多都是使用Google提供的zxing这个类库,使用这个类库我们需要先下载核心jar包,下载地址,如果我们只想生成二维码那么这个就够了,但是如果我们还想做二维码的识别,那么我们需要在刚才的基础上继续添加GitHub上的开源项目,这个我们在后面再说。

1.二维码的生成

先来看一张效果图:

1.1  准备工作

如果我们只做二维码的生成,那么只需要添加核心jar包即可,如下:

1.2  二维码生成

OK,添加完jar包之后我们就可以开始写二维码生成代码了,二维码本身就是一张Bitmap图片,所以我们这里主要就是看怎么样来生成这张图片,我在主界面添加一个按钮和一个ImageView,当点击按钮时生成一张二维码图片显示在ImageView上。布局如下:

[java] view plain copy print ?
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout
  3. xmlns:android="http://schemas.android.com/apk/res/android"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. tools:context="org.mobiletrain.qrwriter.MainActivity">
  8. <Button
  9. android:layout_width="wrap_content"
  10. android:layout_height="wrap_content"
  11. android:onClick="generate"
  12. android:text="生成二维码"/>
  13. <ImageView
  14. android:id="@+id/iv"
  15. android:layout_width="256dp"
  16. android:layout_height="256dp"
  17. android:layout_centerInParent="true"/>
  18. </RelativeLayout>

当我点击按钮时生成二维码图片,那我们就来看看生成二维码图片的核心代码:

[java] view plain copy print ?
  1. private Bitmap generateBitmap(String content,int width, int height) {
  2. QRCodeWriter qrCodeWriter = new QRCodeWriter();
  3. Map<EncodeHintType, String> hints = new HashMap<>();
  4. hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
  5. try {
  6. BitMatrix encode = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
  7. int[] pixels = new int[width * height];
  8. for (int i = 0; i < height; i++) {
  9. for (int j = 0; j < width; j++) {
  10. if (encode.get(j, i)) {
  11. pixels[i * width + j] = 0x00000000;
  12. } else {
  13. pixels[i * width + j] = 0xffffffff;
  14. }
  15. }
  16. }
  17. return Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.RGB_565);
  18. } catch (WriterException e) {
  19. e.printStackTrace();
  20. }
  21. return null;
  22. }

首先这个方法接收三个参数,这三个参数分别表示生成二维码的文本内容(你要把哪一个文本用二维码图片表示出来),第二个和第三个参数分别表示生成的二维码图片的宽和高。在这里,我们首先要获得一个QRCodeWriter实例,该实例中有一个方法叫做encode,通过该方法对文本内容进行编码,该方法共有五个参数,第一个参数表示生成二维码的文本内容,第二个参数表示编码格式,第三个参数表示生成的二维码的宽度,第四个参数表示生成的二维码的高度,第五个参数可选,可以用来设置文本的编码,encode方法的返回值是一个BitMatrix,你可以把BitMatrix理解成一个二维数组,这个二维数组的每一个元素都表示一个像素点是否有数据。OK,接下来我们需要定义一个int数组用来存放Bitmap中所有像素点的颜色,可是我们又怎么知道每一个像素点是什么颜色呢?这个时候就需要我们遍历BitMatrix了,如果BitMatrix上的点表示 该点有数据,那么对应在Bitmap上的像素点就是黑色,否则就是白色。BitMatrix中的get方法的返回值为一个boolean类型,true表示该点有数据,false表示该点没有数据。通过两个嵌套的for循环将BitMatrix遍历一遍,然后给pixels数组都赋上值,OK,pixels数组有值之后,接下来调用Bitmap的createBitmap方法创建一个Bitmap出来就可以了,createBitmap方法共接收6个参数,第一个参数表示Bitmap中所有像素点的颜色,第二个参数表示像素点的偏移量,第三个参数表示Bitmap每行有多少个像素点,第四个参数表示生成的Bitmap的宽度,第五个参数表示生成的Bitmap的高度,第六个参数表示生成的Bitmap的色彩模式,因为二维码只有黑白两种颜色,所以我们可以不用考虑透明度,直接使用RGB_565即可。OK,这样的话我们就获取到了二维码的图片了,最后我们再来看看点击事件:

[java] view plain copy print ?
  1. public void generate(View view) {
  2. Bitmap qrBitmap = generateBitmap("http://www.csdn.net",400, 400);
  3. iv.setImageBitmap(qrBitmap);
  4. }

效果图如下:

1.3  给二维码中心添加Logo

OK,如果你没有特殊的需求那么这样就OK了,但是我们见到的大多数二维码的正中心都有一个Logo,那么这个效果要怎么实现呢?这里就是图片绘制的内容了,我封装了一个方法专门来解决这个问题,代码如下:

[java] view plain copy print ?
  1. private Bitmap addLogo(Bitmap qrBitmap, Bitmap logoBitmap) {
  2. int qrBitmapWidth = qrBitmap.getWidth();
  3. int qrBitmapHeight = qrBitmap.getHeight();
  4. int logoBitmapWidth = logoBitmap.getWidth();
  5. int logoBitmapHeight = logoBitmap.getHeight();
  6. Bitmap blankBitmap = Bitmap.createBitmap(qrBitmapWidth, qrBitmapHeight, Bitmap.Config.ARGB_8888);
  7. Canvas canvas = new Canvas(blankBitmap);
  8. canvas.drawBitmap(qrBitmap, 0, 0, null);
  9. canvas.save(Canvas.ALL_SAVE_FLAG);
  10. float scaleSize = 1.0f;
  11. while ((logoBitmapWidth / scaleSize) > (qrBitmapWidth / 5) || (logoBitmapHeight / scaleSize) > (qrBitmapHeight / 5)) {
  12. scaleSize *= 2;
  13. }
  14. float sx = 1.0f / scaleSize;
  15. canvas.scale(sx, sx, qrBitmapWidth / 2, qrBitmapHeight / 2);
  16. canvas.drawBitmap(logoBitmap, (qrBitmapWidth - logoBitmapWidth) / 2, (qrBitmapHeight - logoBitmapHeight) / 2, null);
  17. canvas.restore();
  18. return blankBitmap;
  19. }

addLogo这个方法接收两个参数,第一个参数就是我们在1.2节中生成的二维码的Bitmap图片,第二个参数就是我们的logo图片,在该方法中我先获取到两张Bitmap各自的宽高,然后创建一个新的空白的Bitmap,这个新的空白的Bitmap的宽高和二维码的宽高一致,然后创建一个Canvas对象,创建Canvas对象的时候将blankBitmap传入,这样我一会绘制的东西相当于都是绘制在了blankBitmap上了。canvas的drawBitmap方法接收四个参数,第一个是你要绘制的Bitmap对象,第二个和第三个是你要绘制的Bitmap的左上角的坐标,第四个参数是一个画笔,一般情况下我们给一个null就可以了,如果你要设置重复模式等等效果的时候可以不给null。我们使用drawBitmap方法先将原本的二维码图片绘制出来,绘制完成之后,调用canvas的save方法,将当前的绘制状态保存下来,然后对画布进行缩放,缩小画布之后我们来绘制Logo,一帮情况下logo的宽高为二维码原图宽高的1/5(中心logo图片不宜过大,否则会影响到二维码的识别),所以我们先通过一个while循环获得缩放比例,然后调用canvas的scale方法对画布进行缩放,前两个参数表示宽高的缩放比例,大于1表示放大,小于1表示缩小,后两个参数表示缩放的中心点。缩放完成之后我们就可以绘制logo了,logo绘制完成之后,调用canvas的restore方法将画布恢复为原来的状态,最后将blankBitmap返回。在点击事件中调用这个方法即可,代码如下:

[java] view plain copy print ?
  1. public void generate(View view) {
  2. Bitmap qrBitmap = generateBitmap("http://www.csdn.net",400, 400);
  3. Bitmap logoBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
  4. Bitmap bitmap = addLogo(qrBitmap, logoBitmap);
  5. iv.setImageBitmap(bitmap);
  6. }

效果图如下:

OK,至此,我们的二维码生成就说完了,就是这么简单。

2.二维码的识别

二维码的识别是一个稍微麻烦的事情,一般情况下,我们直接使用GitHub上的开源项目zxing即可,这个项目就是在我们之前的那个核心包的基础上完成的(https://github.com/zxing/zxing)

二维码扫描很简单,直接跳转到CaptureActivity.class就可以了

qcodeBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        startActivityForResult(new Intent(getActivity(), CaptureActivity.class),110);
    }
});
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
     barCodeStr = data.getStringExtra("barcodeStr");//我定义的扫描返回字段名
    String barCodeStr1 = data.getStringExtra("result");
//我定义的选择图片返回字段名
}

选取相册需要完善CaptureActivity.class,在布局右上角添加相册按钮

openPicBtn.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View view) {

      Intent innerIntent = new Intent(); // "android.intent.action.GET_CONTENT"
      if (Build.VERSION.SDK_INT < 19) {
         innerIntent.setAction(Intent.ACTION_GET_CONTENT);
      } else {
         innerIntent.setAction(Intent.ACTION_OPEN_DOCUMENT);
      }

      innerIntent.setType("image/*");

      Intent wrapperIntent = Intent.createChooser(innerIntent, "选择二维码图片");

      CaptureActivity.this
            .startActivityForResult(wrapperIntent, REQUEST_CODE);
   }
});

添加onActivityResult事件,里面使用的CaputerUtils是原来demo的Utils

在scanningImage方法里面有地方需要修改:

int[] data = new int[scanBitmap.getWidth() * scanBitmap.getHeight()];
scanBitmap.getPixels(data, 0, scanBitmap.getWidth(), 0, 0, scanBitmap.getWidth(), scanBitmap.getHeight());
RGBLuminanceSource source = new RGBLuminanceSource(scanBitmap.getWidth(),scanBitmap.getHeight(),data);

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
   super.onActivityResult(requestCode, resultCode, data);
   if (resultCode == RESULT_OK) {

      switch (requestCode) {

         case REQUEST_CODE:

            String[] proj = { MediaStore.Images.Media.DATA };
            // 获取选中图片的路径
            Cursor cursor = getContentResolver().query(data.getData(),
                  proj, null, null, null);

            if (cursor.moveToFirst()) {

               int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
               photo_path = cursor.getString(column_index);
               if (photo_path == null) {
                  photo_path = CaputerUtils.getPath(getApplicationContext(),
                        data.getData());
                  Log.i("123path  Utils", photo_path);
               }
               Log.i("123path", photo_path);

            }

            cursor.close();

            new Thread(new Runnable() {

               @Override
               public void run() {

                  Result result = scanningImage(photo_path);
                  // String result = decode(photo_path);
                  if (result == null) {
                     Looper.prepare();
                     Toast.makeText(getApplicationContext(), "图片格式有误",Toast.LENGTH_SHORT)
                           .show();
                     Looper.loop();
                  } else {
                     Log.i("123result", result.toString());
                     // Log.i("123result", result.getText());
                     // 数据返回
                     String recode = recode(result.toString());
                     Intent data = new Intent();
                     data.putExtra("result", recode);
                     setResult(300, data);
                     finish();
                  }
               }
            }).start();
            break;

      }

   }
}
protected Result scanningImage(String path) {
   if (TextUtils.isEmpty(path)) {

      return null;

   }
   // DecodeHintType 和EncodeHintType
   Hashtable<DecodeHintType, String> hints = new Hashtable<DecodeHintType, String>();
   hints.put(DecodeHintType.CHARACTER_SET, "utf-8"); // 设置二维码内容的编码
   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[] data = new int[scanBitmap.getWidth() * scanBitmap.getHeight()];
   scanBitmap.getPixels(data, 0, scanBitmap.getWidth(), 0, 0, scanBitmap.getWidth(), scanBitmap.getHeight());
   RGBLuminanceSource source = new RGBLuminanceSource(scanBitmap.getWidth(),scanBitmap.getHeight(),data);
   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;

}

private String recode(String str) {
   String formart = "";

   try {
      boolean ISO = Charset.forName("ISO-8859-1").newEncoder()
            .canEncode(str);
      if (ISO) {
         formart = new String(str.getBytes("ISO-8859-1"), "GB2312");
         Log.i("1234      ISO8859-1", formart);
      } else {
         formart = str;
         Log.i("1234      stringExtra", str);
      }
   } catch (UnsupportedEncodingException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
   }
   return formart;
}

Android之二维码生成与识别 读取相册相关推荐

  1. 玩转Android之二维码生成与识别

    二维码,我们也称作QRCode,QR表示quick response即快速响应,在很多App中我们都能见到二维码的身影,最常见的莫过于微信了.那么今天我们就来看看怎么样在我们自己的App中集成二维码的 ...

  2. Android之二维码生成和识别

    二维码 1.ZXing库介绍 这里简单介绍一下ZXing库.ZXing是一个开放源码的,用Java实现的多种格式的1D/2D条码图像处理库,它包含了联系到其他语言的端口.Zxing可以实现使用手机的内 ...

  3. 【二维码识别】基于matlab GUI灰度+二值化+校正二维码生成与识别【含Matlab源码 635期】

    ⛄一.二维码生成与识别简介 如今,移动互联网技术日新月异,随着5G时代的来临,广泛应用于数据处理过程中的二维码信息安全日益成为人们越来越关注的问题.以QR码为代表的二维码,以其在信息存储.传输和识别技 ...

  4. 【二维码识别】灰度+二值化+校正二维码生成与识别【含GUI Matlab源码 635期】

    ⛄一.二维码生成与识别简介 如今,移动互联网技术日新月异,随着5G时代的来临,广泛应用于数据处理过程中的二维码信息安全日益成为人们越来越关注的问题.以QR码为代表的二维码,以其在信息存储.传输和识别技 ...

  5. python识别发票二维码_Python 实现二维码生成和识别

    今天突然想给自己自己做个头像,然后还是二维码的形式,这样只要扫一扫就可以访问我的主页.然后就开始自己的苦逼之路... 其实实现二维码java,c#,C++等都可以实现:由于自己正在学python,所以 ...

  6. python 二维码生成与识别

    python 二维码生成与识别 1.生成二维码 1.1 qrcode 安装qrcode模块 pip install qrcode 示例: # author:mlnt# createdate:2022/ ...

  7. Qt开发二维码工具QR二维码生成和识别支持批量生成免费使用

    简介 Qt编写,使用第三方库libqrencode和QZxing,支持QR二维码生成和识别,二维码可批量生成,支持中文,还可以设置二维码大小颜色.免费使用,下载链接在本文底部,拿走不用谢,假如您慷慨大 ...

  8. Android 二维码 生成和识别

    今天讲一下目前移动领域很常用的技术--二维码.现在大街小巷.各大网站都有二维码的踪迹,不管是IOS.Android.WP都有相关支持的软件.之前我就想了解二维码是如何工作,最近因为工作需要使用相关技术 ...

  9. Android 二维码 生成和识别(附Demo源码)

    Posted on 2013-08-25 23:15 泡泡糖 阅读( 20424) 评论( 7) 编辑 收藏 今天讲一下目前移动领域很常用的技术--二维码.现在大街小巷.各大网站都有二维码的踪迹,不管 ...

最新文章

  1. 适用于Windows和Linux的Yolo-v3和Yolo-v2(上)
  2. 激光雷达(LiDAR)点云数据知多少?
  3. python的语法结构_Python特点、语法结构、编码知识
  4. check_mk自定义监控实践之powershell
  5. mysql获取表_MySQL获取表格信息
  6. 工业机器人工具中心点标定的意义_如何理解工业机器人的工具中心点
  7. conda安装特定版本的包
  8. APP 上传之后出现invalid binary 问题解决汇总
  9. Font Awesome图标字体
  10. 5G/NR LTE: 物理层抽象 PHY abstraction - SLS LLS 系统级仿真和链路级仿真
  11. 通过思翼SIYI MK15E回传Realsense D435i 的 RGB图像
  12. 哈工大计算机学院崔启航,2014-2015年度哈尔滨工业大学学生先进集体及先进个人评选结果公示...
  13. Apache Struts2远程代码执行漏洞(S2-019)复现
  14. 如何在ps中添加图片上的塑料布效果
  15. python echarts城市热力图_python如何画热力图?
  16. liunx下设置自动完成任务(每周六晚一点整,系统自动把/home目录文件下到所有文件做一个备份,备份到/var/backups/home.tar.gz))
  17. QSocketNotifier: Socket notifiers cannot be enabled or disabled from another
  18. # 7-3 二分法求多项式单根
  19. 华为鸿蒙系统启示,华为的机遇——鸿蒙系统启示录
  20. VMware 15 出现的EFI VMware Virtual SCSI Hard Drive(0,0) …. unsuccessful、Directory “EZBOOT“ not found问题

热门文章

  1. 如何申请使用FSC的商标
  2. 【工控老马】modbus tcp详解
  3. Windows文件对象
  4. 华为荣耀7i手动更改DNS,提高网页加载速度
  5. 路飞学城-Python 爬虫实战密训-第 1 章
  6. CSS - 引入CSS
  7. Python函数求今天日期getCurrentDate
  8. PHP-SOCKETS读书笔记
  9. 交易服務助力大數據產業生態系統完善
  10. 商业图表案例7-独角兽企业估值