使用Zxing玩转二维码白边的各个花样
2017-07-27 15:52
423 查看
现在在实际应用中使用的最为广泛的二维码生成工具就是Zxing库,本文以Zxing-1.60版本做的研究分析,获取最新版本的Zxing。
简单介绍一下Zxing二维码库的使用方式,Zxing库很强大,可以生成各种格式的二维码(分析源码部分时再看其他的类型),最常用的就是QR格式。
如果没有Zxing库,可以到我的云盘下载,地址Zxing-1.6
把jar包下载,copy到工程的libs目录下,buildpath即可
BitMatrix是Zxing库定义的一个二维码的数据类。
这个方法主要是生成二维码的BitMatrix,实际上就是一个矩阵,二维数组–!
获取到Bitmap后,就可以随意展示了
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<
1a57c
/li>16
17
18
19
20
下面就分析Zxing的源码以及默认白边的形成
先看generateQRCode里的关键方法MultiFormatWriter类的encode方法(ps:这个方法不重要!)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
实际上这个方法就是依据format来选择一种编码方式,最常用的就是QR_CODE的方式了,还有其他的方式,基本不用~~有兴趣的可以百度下
然后我们再看QRCodeWriter的encode方法(ps:这个方法和白边没关系!)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
下面再看将code转换成BitMatrix,并加入白边的方法renderResult(ps:这个方法很重要,修改白边都可以在这个方法里修改)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
这个方法里的代码不难读懂,所以要去掉白边实际上就很简单了,自定义一个QRCodeWriter类,完全把Zxing包的QRCodeWriter类复制过来,然后将renderResult方法里的padding去掉就可以了(为什么不继承QRCodeWriter,因为它是final类~~)。
下面是去掉padding后的代码
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
效果图(为了区分白边,将整个背景色设置成的#0f0了)
去掉白边前:
去掉白边后:
这个方法就是将Zxing生成的BitMatrix更新一下去掉了周边,并重新设置白边的宽度,见margin
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
在比较新的Zxing包中EncodeHintType有另外一个属性就是Margin,可以设置这个属性来更新,有兴趣的可以去玩玩哈,这里就不贴代码了
当然通过上面的阅读,可以自定义白边的宽度了,下面就介绍下自定义白边颜色的方法;
当然,最简单的自定义白边就是使用一个imageview展示无边的二维码,外层view设置一个白边背景,就可以了~
这里要介绍的方法是修改bitMatrix2Bitmap方法,通过上文知道,通过zxing包生成的只是BitMaxtrix,这是不能直接用在imageview上的。读者如果仔细阅读了上文的bitMatrix2Bitmap方法就应该可以猜到这里要介绍的方法了,不多说,代码如下
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
这个方法就是可以自定义白边颜色的方法,
效果图
这里需要解释下BitMatrix的getEnclosingRectangle()获取到的东西到底是什么,这个方法的源码我就不贴了,这个方法返回一个一维数组,长度为4
left就是二维码内容左上角的x坐标,top就是左上角的y坐标,with就是二维码内容的宽度,height就是二维码内容的高度。
所以当i和j超出二维码内容范围的时候就可以设置自己的边框颜色了~~
逻辑比较简单,获取到二维码的Bitmap后,Logo就是在这个Bitmap中间再绘制一个Bitmap不就可以了么。
代码如下:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
逻辑和添加logo是一样的,只不过这里添加的文字是放置在二维码下方的一段文字,需要测定文字的大小,行高等,代码逻辑我就不解释了,主要是是使用极少,项目中有一个分享需要将这个做成图片分享到微信,后来又嫌弃样式太不美观丢弃了~~~不过可以将文字环绕二维码,这个应该还是比较漂亮的==!读者有兴趣可以依照下面这个方法画瓢啦。
1.生成二维码
简单介绍一下Zxing二维码库的使用方式,Zxing库很强大,可以生成各种格式的二维码(分析源码部分时再看其他的类型),最常用的就是QR格式。
1.1代码
如果没有Zxing库,可以到我的云盘下载,地址Zxing-1.6 把jar包下载,copy到工程的libs目录下,buildpath即可
1.1.1 获取编码后的数据Bitmatrix
BitMatrix是Zxing库定义的一个二维码的数据类。 这个方法主要是生成二维码的BitMatrix,实际上就是一个矩阵,二维数组–!
获取到Bitmap后,就可以随意展示了
public static Bitmap generateQRCode(String content, int width, int height) { try { HashMap<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>(); // 设置编码方式utf-8 hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); //设置二维码的纠错级别为h hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); BitMatrix matrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints); return bitMatrix2Bitmap(matrix); } catch (WriterException e) { e.printStackTrace(); } return null; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1.1.2将数据Bitmatrix转换成Bitmap
private static Bitmap bitMatrix2Bitmap(BitMatrix matrix) { matrix = updateBit(matrix, 0); int w = matrix.getWidth(); int h = matrix.getHeight(); int[] rawData = new int[w * h]; for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { int color = Color.WHITE; if (matrix.get(i, j)) { // 有内容的部分,颜色设置为黑色,当然这里可以自己修改成喜欢的颜色 color = Color.BLACK; } rawData[i + (j * w)] = color; } } Bitmap bitmap = Bitmap.createBitmap(w, h, Config.RGB_565); bitmap.setPixels(rawData, 0, w, 0, 0, w, h); return bitmap; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<
1a57c
/li>16
17
18
19
20
2.源码分析白边的生成过程
下面就分析Zxing的源码以及默认白边的形成 先看generateQRCode里的关键方法MultiFormatWriter类的encode方法(ps:这个方法不重要!)
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height, Map<EncodeHintType, ?> hints) throws WriterException { Writer writer; switch (format) { case EAN_8: writer = new EAN8Writer(); break; case EAN_13: writer = new EAN13Writer(); break; case UPC_A: writer = new UPCAWriter(); break; case QR_CODE: writer = new QRCodeWriter(); break; case CODE_39: writer = new Code39Writer(); break; case CODE_128: writer = new Code128Writer(); break; case ITF: writer = new ITFWriter(); break; case PDF_417: writer = new PDF417Writer(); break; case CODABAR: writer = new CodaBarWriter(); break; default: throw new IllegalArgumentException("No encoder available for format " + format); } return writer.encode(contents, format, width, height, hints); } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
实际上这个方法就是依据format来选择一种编码方式,最常用的就是QR_CODE的方式了,还有其他的方式,基本不用~~有兴趣的可以百度下
然后我们再看QRCodeWriter的encode方法(ps:这个方法和白边没关系!)
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height, Map<EncodeHintType, ?> hints) throws WriterException { if (contents.length() == 0) { throw new IllegalArgumentException("Found empty contents"); } if (format != BarcodeFormat.QR_CODE) { throw new IllegalArgumentException("Can only encode QR_CODE, but got " + format); } if ((width < 0) || (height < 0)) { throw new IllegalArgumentException("Requested dimensions are too small: " + width + 'x' + height); } ErrorCorrectionLevel errorCorrectionLevel = ErrorCorrectionLevel.L; if (hints != null) { ErrorCorrectionLevel requestedECLevel = (ErrorCorrectionLevel)hints.get(EncodeHintType.ERROR_CORRECTION); if (requestedECLevel != null) { errorCorrectionLevel = requestedECLevel; } } // 前面的都是做编码前的准备,安全检验,纠错级别设置等 QRCode code = new QRCode(); // 这里才是真正的将contents转换成code Encoder.encode(contents, errorCorrectionLevel, hints, code); // return的时候将code转换成BitMatrix,并加入白边 return renderResult(code, width, height); }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
下面再看将code转换成BitMatrix,并加入白边的方法renderResult(ps:这个方法很重要,修改白边都可以在这个方法里修改)
private static BitMatrix renderResult(QRCode code, int width, int height) { ByteMatrix input = code.getMatrix(); if (input == null) { throw new IllegalStateException(); } int inputWidth = input.getWidth(); int inputHeight = input.getHeight(); // 这里qrWidth就是原始的二维码的宽度了,包含8单位宽度的白边 int qrWidth = inputWidth + 8; int qrHeight = inputHeight + 8; // 依据用户的输入宽高,计算最后的输出宽高 int outputWidth = Math.max(width, qrWidth); int outputHeight = Math.max(height, qrHeight); //计算缩放比例 int multiple = Math.min(outputWidth / qrWidth, outputHeight / qrHeight); // 计算白边的宽度 int leftPadding = (outputWidth - inputWidth * multiple) / 2; int topPadding = (outputHeight - inputHeight * multiple) / 2; BitMatrix output = new BitMatrix(outputWidth, outputHeight); int inputY = 0; // 嵌套循环,将ByteMatrix的内容计算padding后转换成BitMatrix for (int outputY = topPadding; inputY < inputHeight; outputY += multiple) { int inputX = 0; for (int outputX = leftPadding; inputX < inputWidth; outputX += multiple) { if (input.get(inputX, inputY) == 1) { output.setRegion(outputX, outputY, multiple, multiple); } inputX++; } inputY++; } return output; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
这个方法里的代码不难读懂,所以要去掉白边实际上就很简单了,自定义一个QRCodeWriter类,完全把Zxing包的QRCodeWriter类复制过来,然后将renderResult方法里的padding去掉就可以了(为什么不继承QRCodeWriter,因为它是final类~~)。
下面是去掉padding后的代码
private static BitMatrix renderResult(QRCode code, int width, int height) { ByteMatrix input = code.getMatrix(); if (input == null) { throw new IllegalStateException(); } int inputWidth = input.getWidth(); int inputHeight = input.getHeight(); // 依据用户的输入宽高,计算最后的输出宽高 int outputWidth = Math.max(width, inputWidth); int outputHeight = Math.max(height, inputHeight); //计算缩放比例 int multiple = Math.min(outputWidth / inputWidth, outputHeight / inputHeight); BitMatrix output = new BitMatrix(outputWidth, outputHeight); int inputY = 0; // 嵌套循环,将ByteMatrix的内容计算padding后转换成BitMatrix for (int outputY = 0; inputY < inputHeight; outputY += multiple) { int inputX = 0; for (int outputX = 0; inputX < inputWidth; outputX += multiple) { if (input.get(inputX, inputY) == 1) { output.setRegion(outputX, outputY, multiple, multiple); } inputX++; } inputY++; } return output; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
效果图(为了区分白边,将整个背景色设置成的#0f0了)
去掉白边前:
去掉白边后:
去掉白边的其他方法
方法1:
这个方法就是将Zxing生成的BitMatrix更新一下去掉了周边,并重新设置白边的宽度,见marginprivate static BitMatrix updateBit(BitMatrix matrix, int margin) { int tempM = margin * 2; int[] rec = matrix.getEnclosingRectangle(); // 获取二维码图案的属性 int resWidth = rec[2] + tempM; int resHeight = rec[3] + tempM; BitMatrix resMatrix = new BitMatrix(resWidth, resHeight); // 按照自定义边框生成新的BitMatrix resMatrix.clear(); for (int i = margin; i < resWidth - margin; i++) { // 循环,将二维码图案绘制到新的bitMatrix中 for (int j = margin; j < resHeight - margin; j++) { if (matrix.get(i - margin + rec[0], j - margin + rec[1])) { resMatrix.set(i, j); } } } return resMatrix; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
方法2:
在比较新的Zxing包中EncodeHintType有另外一个属性就是Margin,可以设置这个属性来更新,有兴趣的可以去玩玩哈,这里就不贴代码了
3.自定义白边颜色
当然通过上面的阅读,可以自定义白边的宽度了,下面就介绍下自定义白边颜色的方法; 当然,最简单的自定义白边就是使用一个imageview展示无边的二维码,外层view设置一个白边背景,就可以了~
这里要介绍的方法是修改bitMatrix2Bitmap方法,通过上文知道,通过zxing包生成的只是BitMaxtrix,这是不能直接用在imageview上的。读者如果仔细阅读了上文的bitMatrix2Bitmap方法就应该可以猜到这里要介绍的方法了,不多说,代码如下
private static Bitmap bitMatrix2Bitmap(BitMatrix matrix, Bitmap logBitmap) { int w = matrix.getWidth(); int h = matrix.getHeight(); int[] rec = matrix.getEnclosingRectangle(); int[] rawData = new int[w * h]; for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { int color = Color.WHITE; if (matrix.get(i, j)) { color = Color.BLACK; } // 设置白边的颜色 if (i < rec[0] || j < rec[1] || i > (rec[0] + rec[2]) || j > (rec[1] + rec[3])){ color = Color.RED; } rawData[i + (j * w)] = color; } } Bitmap bitmap = Bitmap.createBitmap(w, h, Config.RGB_565); bitmap.setPixels(rawData, 0, w, 0, 0, w, h); return addLogo(bitmap, logBitmap); }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
这个方法就是可以自定义白边颜色的方法,
效果图
这里需要解释下BitMatrix的getEnclosingRectangle()获取到的东西到底是什么,这个方法的源码我就不贴了,这个方法返回一个一维数组,长度为4
return new int[] { left, top, width, height };
left就是二维码内容左上角的x坐标,top就是左上角的y坐标,with就是二维码内容的宽度,height就是二维码内容的高度。
所以当i和j超出二维码内容范围的时候就可以设置自己的边框颜色了~~
4.二维码添加LOGO(单个文字等)
逻辑比较简单,获取到二维码的Bitmap后,Logo就是在这个Bitmap中间再绘制一个Bitmap不就可以了么。 代码如下:
private static Bitmap addLogo(Bitmap src, Bitmap logo) { if (logo == null) { return src; } // 获取图片的宽高 int srcWidth = src.getWidth(); int srcHeight = src.getHeight(); int logoWidth = logo.getWidth(); int logoHeight = logo.getHeight(); if (logoWidth == 0 || logoHeight == 0) { return src; } // logo大小为二维码整体大小的1/5 float scaleFactor = srcWidth * 1.0f / 5 / logoWidth; Bitmap bitmap = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888); try { Canvas canvas = new Canvas(bitmap); canvas.drawBitmap(src, 0, 0, null); canvas.scale(scaleFactor, scaleFactor, srcWidth / 2, srcHeight / 2); canvas.drawBitmap(logo, (srcWidth - logoWidth) / 2, (srcHeight - logoHeight) / 2, null); canvas.save(Canvas.ALL_SAVE_FLAG); canvas.restore(); } catch (Exception e) { bitmap = null; e.getStackTrace(); } return bitmap; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
5.二维码下方添加文字段落
逻辑和添加logo是一样的,只不过这里添加的文字是放置在二维码下方的一段文字,需要测定文字的大小,行高等,代码逻辑我就不解释了,主要是是使用极少,项目中有一个分享需要将这个做成图片分享到微信,后来又嫌弃样式太不美观丢弃了~~~不过可以将文字环绕二维码,这个应该还是比较漂亮的==!读者有兴趣可以依照下面这个方法画瓢啦。public static Bitmap addTextToBitmap(Bitmap bmpSrc, String text) { int srcWidth = bmpSrc.getWidth(); int srcHeight = bmpSrc.getHeight(); // 先计算text所需要的height int textSize = 20; int padding = 3; int textLinePadding = 1; // 每行的文字 int perLineWords = (srcWidth - 2 * padding) / textSize; int lineNum = text.length() / perLineWords; lineNum = text.length() % perLineWords == 0 ? lineNum : lineNum + 1; int textTotalHeight = lineNum * (textSize + textLinePadding) + 2 * padding; Bitmap bitmap = Bitmap.createBitmap(srcWidth, srcHeight + textTotalHeight, Bitmap.Config.ARGB_8888); try { Canvas canvas = new Canvas(bitmap); canvas.drawColor(Color.WHITE); canvas.drawBitmap(bmpSrc, 0, 0, null); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(Color.BLACK); paint.setTextSize(textSize); String lineText; for (int i = 0, startY = srcHeight + textSize, start, end; i < lineNum; i++) { start = i * perLineWords; end = start + perLineWords; lineText = text.substring(start, end > text.length() ? text.length() : end); canvas.drawText(lineText, padding, startY, paint); startY += textSize + textLinePadding; } canvas.save(Canvas.ALL_SAVE_FLAG); canvas.restore(); } catch (Exception e) { bitmap = null; e.getStackTrace(); } return bitmap; }
相关文章推荐
- 使用Zxing玩转二维码白边的各个花样
- 使用Zxing玩转二维码白边的各个花样
- 使用Zxing玩转二维码白边的各个花样
- java生成二维码使用QRCode和ZXing两种方式
- Android Studio 使用zxing二维码处理
- 二维码开源库zbar、zxing使用心得
- 使用谷歌zxing工具生成二维码(可添加logo)
- 使用zxing生成二维码 - servlet形式
- 二维码识别开源项目zxing的使用和源码分析
- zxing快速使用之生成二维码和扫描二维码
- 关于使用ZXing扫描二维码出现中文乱码的问题
- 在Android上使用ZXing识别条形码/二维码
- 使用zxing生成二维码,边框自定义宽度
- Android 使用Zxing 扫描二维码 和生成二维码
- 使用ZXing开发二维码
- 在Android上使用ZXing识别条形码/二维码
- 使用zxing生成二维码
- Android使用zxing-android-embedded(由zxing开发)实现二维码生成和扫描
- 使用zxing生成嵌图片的二维码【java】
- .NET 使用ZXing.NET 生成条形码,生成二维码,生成中间带图片的二维码