现在在实际应用中使用的最为广泛的二维码生成工具就是Zxing库,本文以Zxing-1.60版本做的研究分析,获取最新版本的Zxing。

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-8hints.put(EncodeHintType.CHARACTER_SET, "utf-8");//设置二维码的纠错级别为hhints.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.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;}

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);}}

实际上这个方法就是依据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转换成codeEncoder.encode(contents, errorCorrectionLevel, hints, code);// return的时候将code转换成BitMatrix,并加入白边return renderResult(code, width, height);}

下面再看将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后转换成BitMatrixfor (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;}

这个方法里的代码不难读懂,所以要去掉白边实际上就很简单了,自定义一个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后转换成BitMatrixfor (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;
}

效果图(为了区分白边,将整个背景色设置成的#0f0了)
去掉白边前:

去掉白边后:

去掉白边的其他方法

方法1:

这个方法就是将Zxing生成的BitMatrix更新一下去掉了周边,并重新设置白边的宽度,见margin

    private 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); // 按照自定义边框生成新的BitMatrixresMatrix.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;}

方法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);}

这个方法就是可以自定义白边颜色的方法,
效果图

这里需要解释下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/5float 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;}

5.二维码下方添加文字段落

逻辑和添加logo是一样的,只不过这里添加的文字是放置在二维码下方的一段文字,需要测定文字的大小,行高等,代码逻辑我就不解释了,主要是是使用极少,项目中有一个分享需要将这个做成图片分享到微信,后来又嫌弃样式太不美观丢弃了~~~不过可以将文字环绕二维码,这个应该还是比较漂亮的==!读者有兴趣可以依照下面这个方法画瓢啦。

    public static Bitmap addTextToBitmap(Bitmap bmpSrc, String text) {int srcWidth = bmpSrc.getWidth();int srcHeight = bmpSrc.getHeight();// 先计算text所需要的heightint 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;}

实际上,最后的这2个部分都应该是Bitmap和Canvas的内容,这期就先到这里了,自己不动手,代码永远也不是你的!共勉!

使用Zxing玩转二维码白边的各个花样相关推荐

  1. JAVA C# Zxing生成的二维码数据转换为1bit的bmp下发到点阵终端。QRCode去白边,以bmp格式字节流发送,BMP图片解析

    BMP图像文件完全解析 - 知乎 注意: 小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中.越向后地址越高,比如00  01  02,02的地址是2,是高. BMP文 ...

  2. Zxing生成自定义二维码样式

    Zxing生成自定义二维码样式 现在几乎每个app都带有二维码,但是google提供的zxing包,只给我们提供了核心的二维码算法,而开发过程中经常有自定义二维码的样式的需求,这时候我们就要自己写工具 ...

  3. 【Python】玩转二维码:生成、伪造和识别

    玩转二维码 前言及视频 一.二维码的生成 1.1 导包和相关说明 1.2 设置当前目录 1.3 设置保存目录 1.4 设置图标文件 1.5 清空输入项 1.6 初始化二维码 1.7 生成二维码图片主程 ...

  4. java二维码生成-谷歌(Google.zxing)开源二维码生成学习及实例

    java二维码生成-谷歌(Google.zxing)开源二维码生成的实例及介绍  这里我们使用比特矩阵(位矩阵)的QR码编码在缓冲图片上画出二维码 实例有以下一个传入参数 OutputStream o ...

  5. Android Zxing识别图片二维码识别率低

    1.使用Zxing对图片进行识别二维码 在gradle中引入识别库: implementation 'com.google.zxing:core:3.4.1' 对Bitmap进行识别二维码: int[ ...

  6. Android zxing,轻松实现二维码扫描、生成

    Android  zxing,轻松实现二维码扫描.生成 一.二维码与条形码工作原理 目前的很多应用上都有扫码功能,当时微信推出二维码扫码功能时,觉得imagine,通过一张简单的图片就能扫描添加还有, ...

  7. Android实现二维码扫描功能-ZXing识别图片二维码,相册选图

    文章目录 1.演示 2.权限问题 3.实现步骤 4.工具类 5.图片Uri处理(重要更新) 1.演示 2.权限问题 部分朋友在打开相册时遇到读写权限未授权的问题,我在开发的时候没有遇到,也没有注册读写 ...

  8. 开发技术-修正二维码白边

    1.现状: 在前后端代码都一样的情况下,不同服务器上,生成二维码白边间距不一样. 扒拉了下先前伙伴写的代码,定义了二维码整体的宽和高,但是并没有定义最外围白边的区域. 从网上找了一段代码,亲测可用 / ...

  9. Java,jQuery玩转二维码

    zxing就是这么一只Google开源的java二维码生成工具包,它能很好的支持utf-8编码. 这里基于maven构建,使用它首先得引入其jar包. [code lang="xml&quo ...

最新文章

  1. 保存Java程序状态及设置Properties文件
  2. 从源码分析DEARGUI之添加字体
  3. python有趣代码-Python有哪些有趣的代码呢,这些代码让
  4. 解决weblogic Managed Server启动非常慢的情况
  5. JavaScript Book Plan
  6. Fiddler过滤指定域名
  7. 两个线程同时从服务器接收消息_一文看懂I/O多路复用技术(mysql线程池)
  8. Serverless 实战 —— 阿里云函数计算配合SpringBoot项目
  9. 星河经纬加入会员可靠吗_星河湾外墙防水补漏 星河湾外墙防水补漏公司 星河湾外墙防水补漏师傅 星河湾外墙防水补漏施工队电话...
  10. Unity调试外部DLL
  11. iOS之路10-给xib设置约束注意
  12. android dbinfo函数,android SQLiteDatabase中的update函数用法?
  13. 软件实习周软件设计报告
  14. CPDA项目数据分析师和CDA数据分析师有什么区别?
  15. tas5707php,TAS5707PHP
  16. Error while trying to use the following icon from the Manifest
  17. 路由器间歇性断网,而且不重启路由器不会自动恢复的问题
  18. PHP压缩文件下载,提示压缩包损坏及打不开的解决方法
  19. ieTEST停止工作bug修复
  20. MYSQL_DQL语言的学习(1)

热门文章

  1. 『1157』Anniversary
  2. 中石油大学22春季《毛泽东思想和中国特色社会主义理论体系概论#》第一阶段在线作业
  3. android 分区丢失,分区数据恢复
  4. AWS STS - 以正确的方式设计IAM用户密钥
  5. 报错与解决 | AttributeError: module ‘librosa.feature‘ has no attribute ‘rmse‘
  6. 做外贸SOHO,真的能实现时间和财富自由吗
  7. linux redis自动重启,Linux Redis自动启动,Redis开机启动,Linux Redis设置开机启动
  8. 有关UnrealEngine材质编辑器中的Custom节点的一些小贴士
  9. 多测师肖sir_高级讲师_练习题001
  10. css音乐字幕,css3实现音乐动画播放【原创】