【转载】Android进阶 - 二维码生成

zxing.png

摘要

最近,公司业务上有个生成二维码图片的需求(Android端),之后笔者在网上查阅了一些资料,实现了这个功能。最后,给自己做个笔记,给各位做下分享。

什么是二维码?

百度链接:二维码

二维码生成方案(Android端)

在查找二维码生成方案时,发现很多方案的源头都指向了GitHub的开源库https://github.com/zxing/zxing

1. ZXing简介:

ZXing全称zebra crossing,翻译过来就是『斑马线』的意思。ZXing是一个采用Java实现的、开源的、支持多格式(一维/二维)的条形码图像处理库。

其中,QRCode格式就是我们常说的二维码格式。

注:QRCode(Quick Response Code:快速响应码)是二维条形码中最常用的一种格式,所以很多人直接将QRCode翻译为二维码,而且连百度百科都这样称呼,笔者也暂时就这么称呼了。

2. ZXing库引入

对于开发者来讲,我们需要下载ZXing库的一个jar包(core-x.x.x.jar)或者通过添加依赖的方式引入库文件,具体方法如下:

  • 方法一:ZXing提供了Maven库,让我们可以根据自己的需要选择想要的jar包版本进行下载。Maven库:https://repo1.maven.org/maven2/com/google/zxing/core/

  • 方法二(推荐):对于使用AndroidStudio开发的程序员而言,可能更习惯于在.gradle文件中添加依赖。具体代码如下(3.3.0是笔者使用时的最新版本,想知道最新版本是多少可以去Maven库查):

    dependencies {
    
    ......
    
    compile <span class="hljs-string">'com.google.zxing:core:3.3.0'</span>
    

}

3. ZXing库使用

在公司的项目中,需要实现这样一个功能:根据传入的“url字符串”生成一张二维码图片。

也就是说,需要笔者写一个工具方法:接收一个传入的字符串,生成一个Bitmap对象并返回。

注:这里笔者进行了扩展,可以传入任意字符串(包含url字符串)。

接下来,先把笔者的二维码生成工具类附上(使用该工具类的前提:你已完成第2步,导入了ZXing的核心库)。

/**
 * @ClassName: QRCodeUtil
 * @Description: 二维码工具类
 * @Author Wangnan
 * @Date 2017/2/8
 */

public class QRCodeUtil {

<span class="hljs-comment">/**
 * 创建二维码位图
 *
 * <span class="hljs-doctag">@param</span> content 字符串内容(支持中文)
 * <span class="hljs-doctag">@param</span> width 位图宽度(单位:px)
 * <span class="hljs-doctag">@param</span> height 位图高度(单位:px)
 * <span class="hljs-doctag">@return</span>
 */</span>
<span class="hljs-meta">@Nullable</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Bitmap <span class="hljs-title">createQRCodeBitmap</span><span class="hljs-params">(String content, <span class="hljs-keyword">int</span> width, <span class="hljs-keyword">int</span> height)</span></span>{
    <span class="hljs-keyword">return</span> createQRCodeBitmap(content, width, height, <span class="hljs-string">"UTF-8"</span>, <span class="hljs-string">"H"</span>, <span class="hljs-string">"2"</span>, Color.BLACK, Color.WHITE);
}

<span class="hljs-comment">/**
 * 创建二维码位图 (支持自定义配置和自定义样式)
 *
 * <span class="hljs-doctag">@param</span> content 字符串内容
 * <span class="hljs-doctag">@param</span> width 位图宽度,要求&gt;=0(单位:px)
 * <span class="hljs-doctag">@param</span> height 位图高度,要求&gt;=0(单位:px)
 * <span class="hljs-doctag">@param</span> character_set 字符集/字符转码格式 (支持格式:{<span class="hljs-doctag">@link</span> CharacterSetECI })。传null时,zxing源码默认使用 "ISO-8859-1"
 * <span class="hljs-doctag">@param</span> error_correction 容错级别 (支持级别:{<span class="hljs-doctag">@link</span> ErrorCorrectionLevel })。传null时,zxing源码默认使用 "L"
 * <span class="hljs-doctag">@param</span> margin 空白边距 (可修改,要求:整型且&gt;=0), 传null时,zxing源码默认使用"4"。
 * <span class="hljs-doctag">@param</span> color_black 黑色色块的自定义颜色值
 * <span class="hljs-doctag">@param</span> color_white 白色色块的自定义颜色值
 * <span class="hljs-doctag">@return</span>
 */</span>
<span class="hljs-meta">@Nullable</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Bitmap <span class="hljs-title">createQRCodeBitmap</span><span class="hljs-params">(String content, <span class="hljs-keyword">int</span> width, <span class="hljs-keyword">int</span> height,
                                        @Nullable String character_set, @Nullable String error_correction, @Nullable String margin,
                                        @ColorInt <span class="hljs-keyword">int</span> color_black, @ColorInt <span class="hljs-keyword">int</span> color_white)</span></span>{

    <span class="hljs-comment">/** 1.参数合法性判断 */</span>
    <span class="hljs-keyword">if</span>(TextUtils.isEmpty(content)){ <span class="hljs-comment">// 字符串内容判空</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
    }

    <span class="hljs-keyword">if</span>(width &lt; <span class="hljs-number">0</span> || height &lt; <span class="hljs-number">0</span>){ <span class="hljs-comment">// 宽和高都需要&gt;=0</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
    }

    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">/** 2.设置二维码相关配置,生成BitMatrix(位矩阵)对象 */</span>
        Hashtable&lt;EncodeHintType, String&gt; hints = <span class="hljs-keyword">new</span> Hashtable&lt;&gt;();

        <span class="hljs-keyword">if</span>(!TextUtils.isEmpty(character_set)) {
            hints.put(EncodeHintType.CHARACTER_SET, character_set); <span class="hljs-comment">// 字符转码格式设置</span>
        }

        <span class="hljs-keyword">if</span>(!TextUtils.isEmpty(error_correction)){
            hints.put(EncodeHintType.ERROR_CORRECTION, error_correction); <span class="hljs-comment">// 容错级别设置</span>
        }

        <span class="hljs-keyword">if</span>(!TextUtils.isEmpty(margin)){
            hints.put(EncodeHintType.MARGIN, margin); <span class="hljs-comment">// 空白边距设置</span>
        }
        BitMatrix bitMatrix = <span class="hljs-keyword">new</span> QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);

        <span class="hljs-comment">/** 3.创建像素数组,并根据BitMatrix(位矩阵)对象为数组元素赋颜色值 */</span>
        <span class="hljs-keyword">int</span>[] pixels = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[width * height];
        <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> y = <span class="hljs-number">0</span>; y &lt; height; y++){
            <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> x = <span class="hljs-number">0</span>; x &lt; width; x++){
                <span class="hljs-keyword">if</span>(bitMatrix.get(x, y)){
                    pixels[y * width + x] = color_black; <span class="hljs-comment">// 黑色色块像素设置</span>
                } <span class="hljs-keyword">else</span> {
                    pixels[y * width + x] = color_white; <span class="hljs-comment">// 白色色块像素设置</span>
                }
            }
        }

        <span class="hljs-comment">/** 4.创建Bitmap对象,根据像素数组设置Bitmap每个像素点的颜色值,之后返回Bitmap对象 */</span>
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        bitmap.setPixels(pixels, <span class="hljs-number">0</span>, width, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, width, height);
        <span class="hljs-keyword">return</span> bitmap;
    } <span class="hljs-keyword">catch</span> (WriterException e) {
        e.printStackTrace();
    }

    <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
}

}

工具类的方法看不懂没关系,先缕清整体流程。之后,笔者会详解二维码生成方法createQRCodeBitmap。

这里,笔者写了两个重载的createQRCodeBitmap方法。其中第一个方法,笔者进行了默认的参数设置,可以满足生成二维码的大部分需求。

  • createQRCodeBitmap(String content, int width, int height):传入任意字符串和你想要的二维码图片的宽、高,生成一个Bitmap对象并返回。
  • createQRCodeBitmap(String content, int width, int height,@Nullable String character_set, @Nullable String error_correction, @Nullable String margin,@ColorInt int color_black, @ColorInt int color_white):完整的二维码生成方法,支持自定义配置和自定义样式。

接下来,给各位来一个实例,实现二维码生成。

4. 二维码生成(实例)

1.在AndroidStudio中新建一个Android工程。

2.导入ZXing的核心库。

dependencies {
......

compile <span class="hljs-string">'com.google.zxing:core:3.3.0'</span>

}

3.将上面的“QRCodeUtil”工具类添加进工程。

4.在activity_main.xml中放置一个宽、高自适应的ImageView(用于显示二维码图片)。

5.在MainActivity中调用QRCodeUtil工具类中的createQRCodeBitmap方法生成二维码位图,之后将Bitmap对象设置进ImageView中。代码如下:

public class MainActivity extends AppCompatActivity {
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCreate</span><span class="hljs-params">(Bundle savedInstanceState)</span> </span>{
    <span class="hljs-keyword">super</span>.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ImageView mImageView = (ImageView) findViewById(R.id.iv);
    Bitmap mBitmap = QRCodeUtil.createQRCodeBitmap(<span class="hljs-string">"https://www.baidu.com"</span>, <span class="hljs-number">480</span>, <span class="hljs-number">480</span>);
    mImageView.setImageBitmap(mBitmap);
}

}

这里,我们调用3个参数的createQRCodeBitmap方法:传入了一个url字符串(百度链接),传入了图片的宽、高。

接下来,跑一下程序,效果如下图所示:

QRCode_Demo.png.png

我们看到二维码已经生成,如果你有另一部手机就可以用扫码工具扫描验证了。

如果你只有一部手机,那该如何验证二维码信息的正确性呢?

给各位介绍一个简单的方法:微信

把当前截屏图片发送给自己的“微信小号”或“微信朋友”,利用微信的图片显示工具查看(长按图片,有二维码时会自动识别),如下所示:

arcode_wechat.gif

事实证明,笔者生成的二维码是正确的,微信跳转到了“百度一下”这个链接。

5. createQRCodeBitmap方法细节详解

虽然,笔者在createQRCodeBitmap方法中加了很多注释帮助各位理解二维码创建的流程,但可能各位对createQRCodeBitmap这个方法有些疑惑,这些配置参数有什么作用?ZXing这个库到底帮我们做了什么?接下来,我们详解这几个细节。

1.character_set(字符集/字符转码格式)这个参数有什么用?

笔者在3个参数的重载方法中设置的字符集是"UTF-8"。(代码如下:)

utf-8.png

ZXing源码默认使用的是"ISO-8859-1",而"ISO-8859-1"本身是不支持中文的。如果你的url中包含中文,字符集最好选用"UTF-8"。

接下来,给各位做个关于字符集的小实验。

笔者将字符集改为"ISO-8859-1"。

iso-8859-1.png

我们将“百度链接”换成“中文字符串”,如下所示:

modify_main.png

之后,笔者生成二维码在微信中进行识别,识别结果如下:

decode_error.png

我们看到中文字符都解码失败了。

之后,我们将"ISO-8859-1"改回"UTF-8"。再生成二维码在微信中识别,识别结果如下:

decode_success.png

我们可以看到识别成功了。(我们从这里也可以看出“微信”的使用的解码规则是"UTF-8")

2.error_correction(容错级别)这个参数有什么作用?

讲这个问题前,先给各位解释下什么是"容错"?

不知道各位有没有注意过这些扫码细节:二维码图片有时出现部分缺失(或破损)也能扫描成功;我们近距离扫二维码时,图形还没扫全就提示扫描成功了;有些二维码中间贴了一个小图标,扫码也能成功......这其实都归功于二维码有很强大的容错性

回到代码,笔者3个参数的createQRCodeBitmap方法使用的是"H",代码如下所示:

error_correction_set.png

这个"H"是什么鬼?看下源码,各位就懂了(“红色字体”是笔者加的“截图注释”)。

error_correction_source.png

有兴趣的朋友可以试下,同一个字符串使用不同容错率生成的二维码图形是不一样的,但扫出的信息是相同的。

3.margin(空白边距)这个参数有什么作用?

笔者3个参数的createQRCodeBitmap方法中传入的是"2"(如下图所示)。

margin_set.png

接下来,我们分别传入"0","1","2"看看二维码的图形有什么变化。(如下图所示)

margin_result.png
4.color_black,color_white 这两个参数有什么作用?

其实就是字面意思,黑色和白色。(这里只是建议颜色,笔者代码如下)

black_white.png

这里,我们换几种颜色试试。(效果图如下)

colors_test.png

当然,笔者还是建议使用主流的黑色和白色。因为在实际项目中玩花样,如果导致部分手机扫描不出来,就有点作死了...o(╯□╰)o。

5.ZXing这个库到底帮我们做了什么?

看下图,红线圈出的这两行代码是整个方法的核心,是笔者借助ZXing实现的。

zxing_core.png

BitMatrix是ZXing库中的一个类,我们将配置参数传入到QRCodeWriter的编码方法中,在encode的执行过程中ZXing库进行了相应的计算(计算哪个像素点应该是黑色,哪个像素点是白色),之后会生成一个BitMatrix对象存放最后的计算结果。

之后,如果你想知道矩阵中的哪个像素点是什么颜色可以调用bitMatrix.get(x,y)方法。如果该方法返回true,那么该像素点应该填充黑色,反之,应该填充白色。

细节解释就到这了,如果还有不懂的地方,笔者建议各位去看下ZXing的源码。

题外话

做项目时,笔者导入的ZXing的库大小是541KB,我们项目组的同事是一个“Geek”(做事追求极致的人),它感觉我这种方式太偷懒了。

因为ZXing这个库不仅仅提供了二维码生成的功能,还有比如二维码识别等其他功能。也就是说,有很多功能我们项目是用不到的。换句话说:jar包(或库文件)中的很多类都是用不到的

最后在同事的强烈建议下,我把ZXing生成二维码需要用到的类都提取了出来,重新进行了封装。最后提取了23个类,文件总大小144KB

但是,同事还是觉得库还是有点大(o(>_<)o 这同事一定是“处女座”的)。最后我只能在源码文件中一个类、一个类的找,把没有使用到的方法一一剔除。最后文件大小削减到了130KB

看到这里,我猜你是不是想问:还能不能再削减?

答案:能。还可以把源码中的所有注释全删了。但估计一段时间后,你再看源码就看不懂了。(一开始笔者也想删注释,但想了想还是放弃了)

发表一下自己的感慨:

best_friend.png

最后,附上Demo地址(包含ZXing删减库):https://github.com/sinawangnan7/QRCodeDemo
封装工具类:Android进阶 - 二维码生成(花式效果)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值