摘要
最近,公司业务上有个生成二维码图片的需求(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 'com.google.zxing:core:3.3.0' }
3. ZXing库使用
在公司的项目中,需要实现这样一个功能:根据传入的“url字符串”生成一张二维码图片。
也就是说,需要笔者写一个工具方法:接收一个传入的字符串,生成一个Bitmap对象并返回。
注:这里笔者进行了扩展,可以传入任意字符串(包含url字符串)。
接下来,先把笔者的二维码生成工具类附上(使用该工具类的前提:你已完成第2步,导入了ZXing的核心库)。
/**
* @ClassName: QRCodeUtil
* @Description: 二维码工具类
* @Author Wangnan
* @Date 2017/2/8
*/
public class QRCodeUtil {
/**
* 创建二维码位图
*
* @param content 字符串内容(支持中文)
* @param width 位图宽度(单位:px)
* @param height 位图高度(单位:px)
* @return
*/
@Nullable
public static Bitmap createQRCodeBitmap(String content, int width, int height){
return createQRCodeBitmap(content, width, height, "UTF-8", "H", "2", Color.BLACK, Color.WHITE);
}
/**
* 创建二维码位图 (支持自定义配置和自定义样式)
*
* @param content 字符串内容
* @param width 位图宽度,要求>=0(单位:px)
* @param height 位图高度,要求>=0(单位:px)
* @param character_set 字符集/字符转码格式 (支持格式:{@link CharacterSetECI })。传null时,zxing源码默认使用 "ISO-8859-1"
* @param error_correction 容错级别 (支持级别:{@link ErrorCorrectionLevel })。传null时,zxing源码默认使用 "L"
* @param margin 空白边距 (可修改,要求:整型且>=0), 传null时,zxing源码默认使用"4"。
* @param color_black 黑色色块的自定义颜色值
* @param color_white 白色色块的自定义颜色值
* @return
*/
@Nullable
public static 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){
/** 1.参数合法性判断 */
if(TextUtils.isEmpty(content)){ // 字符串内容判空
return null;
}
if(width < 0 || height < 0){ // 宽和高都需要>=0
return null;
}
try {
/** 2.设置二维码相关配置,生成BitMatrix(位矩阵)对象 */
Hashtable hints = new Hashtable<>();
if(!TextUtils.isEmpty(character_set)) {
hints.put(EncodeHintType.CHARACTER_SET, character_set); // 字符转码格式设置
}
if(!TextUtils.isEmpty(error_correction)){
hints.put(EncodeHintType.ERROR_CORRECTION, error_correction); // 容错级别设置
}
if(!TextUtils.isEmpty(margin)){
hints.put(EncodeHintType.MARGIN, margin); // 空白边距设置
}
BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
/** 3.创建像素数组,并根据BitMatrix(位矩阵)对象为数组元素赋颜色值 */
int[] pixels = new int[width * height];
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
if(bitMatrix.get(x, y)){
pixels[y * width + x] = color_black; // 黑色色块像素设置
} else {
pixels[y * width + x] = color_white; // 白色色块像素设置
}
}
}
/** 4.创建Bitmap对象,根据像素数组设置Bitmap每个像素点的颜色值,之后返回Bitmap对象 */
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
return bitmap;
} catch (WriterException e) {
e.printStackTrace();
}
return null;
}
}
工具类的方法看不懂没关系,先缕清整体流程。之后,笔者会详解二维码生成方法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 'com.google.zxing:core:3.3.0'
}
3.将上面的“QRCodeUtil”工具类添加进工程。
4.在activity_main.xml中放置一个宽、高自适应的ImageView(用于显示二维码图片)。
5.在MainActivity中调用QRCodeUtil工具类中的createQRCodeBitmap方法生成二维码位图,之后将Bitmap对象设置进ImageView中。代码如下:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView mImageView = (ImageView) findViewById(R.id.iv);
Bitmap mBitmap = QRCodeUtil.createQRCodeBitmap("https://www.baidu.com", 480, 480);
mImageView.setImageBitmap(mBitmap);
}
}
这里,我们调用3个参数的createQRCodeBitmap方法:传入了一个url字符串(百度链接),传入了图片的宽、高。
接下来,跑一下程序,效果如下图所示:
我们看到二维码已经生成,如果你有另一部手机就可以用扫码工具扫描验证了。
如果你只有一部手机,那该如何验证二维码信息的正确性呢?
给各位介绍一个简单的方法:微信
把当前截屏图片发送给自己的“微信小号”或“微信朋友”,利用微信的图片显示工具查看(长按图片,有二维码时会自动识别),如下所示:
事实证明,笔者生成的二维码是正确的,微信跳转到了“百度一下”这个链接。
5. createQRCodeBitmap方法细节详解
虽然,笔者在createQRCodeBitmap方法中加了很多注释帮助各位理解二维码创建的流程,但可能各位对createQRCodeBitmap这个方法有些疑惑,这些配置参数有什么作用?ZXing这个库到底帮我们做了什么?接下来,我们详解这几个细节。
1.character_set(字符集/字符转码格式)这个参数有什么用?
笔者在3个参数的重载方法中设置的字符集是"UTF-8"。(代码如下:)
ZXing源码默认使用的是"ISO-8859-1",而"ISO-8859-1"本身是不支持中文的。如果你的url中包含中文,字符集最好选用"UTF-8"。
接下来,给各位做个关于字符集的小实验。
笔者将字符集改为"ISO-8859-1"。
我们将“百度链接”换成“中文字符串”,如下所示:
之后,笔者生成二维码在微信中进行识别,识别结果如下:
我们看到中文字符都解码失败了。
之后,我们将"ISO-8859-1"改回"UTF-8"。再生成二维码在微信中识别,识别结果如下:
我们可以看到识别成功了。(我们从这里也可以看出“微信”的使用的解码规则是"UTF-8")
2.error_correction(容错级别)这个参数有什么作用?
讲这个问题前,先给各位解释下什么是"容错"?
不知道各位有没有注意过这些扫码细节:二维码图片有时出现部分缺失(或破损)也能扫描成功;我们近距离扫二维码时,图形还没扫全就提示扫描成功了;有些二维码中间贴了一个小图标,扫码也能成功......这其实都归功于二维码有很强大的容错性。
回到代码,笔者3个参数的createQRCodeBitmap方法使用的是"H",代码如下所示:
这个"H"是什么鬼?看下源码,各位就懂了(“红色字体”是笔者加的“截图注释”)。
有兴趣的朋友可以试下,同一个字符串使用不同容错率生成的二维码图形是不一样的,但扫出的信息是相同的。
3.margin(空白边距)这个参数有什么作用?
笔者3个参数的createQRCodeBitmap方法中传入的是"2"(如下图所示)。
接下来,我们分别传入"0","1","2"看看二维码的图形有什么变化。(如下图所示)
4.color_black,color_white 这两个参数有什么作用?
其实就是字面意思,黑色和白色。(这里只是建议颜色,笔者代码如下)
这里,我们换几种颜色试试。(效果图如下)
当然,笔者还是建议使用主流的黑色和白色。因为在实际项目中玩花样,如果导致部分手机扫描不出来,就有点作死了...o(╯□╰)o。
5.ZXing这个库到底帮我们做了什么?
看下图,红线圈出的这两行代码是整个方法的核心,是笔者借助ZXing实现的。
BitMatrix是ZXing库中的一个类,我们将配置参数传入到QRCodeWriter的编码方法中,在encode的执行过程中ZXing库进行了相应的计算(计算哪个像素点应该是黑色,哪个像素点是白色),之后会生成一个BitMatrix对象存放最后的计算结果。
之后,如果你想知道矩阵中的哪个像素点是什么颜色可以调用bitMatrix.get(x,y)方法。如果该方法返回true,那么该像素点应该填充黑色,反之,应该填充白色。
细节解释就到这了,如果还有不懂的地方,笔者建议各位去看下ZXing的源码。
题外话
做项目时,笔者导入的ZXing的库大小是541KB,我们项目组的同事是一个“Geek”(做事追求极致的人),它感觉我这种方式太偷懒了。
因为ZXing这个库不仅仅提供了二维码生成的功能,还有比如二维码识别等其他功能。也就是说,有很多功能我们项目是用不到的。换句话说:jar包(或库文件)中的很多类都是用不到的。
最后在同事的强烈建议下,我把ZXing生成二维码需要用到的类都提取了出来,重新进行了封装。最后提取了23个类,文件总大小144KB。
但是,同事还是觉得库还是有点大(o(>_<)o 这同事一定是“处女座”的)。最后我只能在源码文件中一个类、一个类的找,把没有使用到的方法一一剔除。最后文件大小削减到了130KB。
看到这里,我猜你是不是想问:还能不能再削减?
答案:能。还可以把源码中的所有注释全删了。但估计一段时间后,你再看源码就看不懂了。(一开始笔者也想删注释,但想了想还是放弃了)
发表一下自己的感慨:
最后,附上Demo地址(包含ZXing删减库):https://github.com/sinawangnan7/QRCodeDemo
封装工具类:Android进阶 - 二维码生成(花式效果)