现在在实际应用中使用的最为广泛的二维码生成工具就是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. 通俗篇:一文搞定矩阵相关概念及意义
  2. mysql druid 多数据源_SpringBoot使用阿里数据库连接池Druid以及多数据源配置
  3. 面对行业难题,华为云邀请物联网全行业拿出“亮剑”精神
  4. QT4.7.3在dm6446平台上的移植[转]--make[1]: *** [assistant_cs.qm] Error 2
  5. bzoj2208:[Jsoi2010]连通数
  6. react-native ios push 本地view
  7. 【图像计数】基于matlab灰度二值化同类物体简单计数【含Matlab源码 759期】
  8. Creo参数曲面设计视频教程
  9. python绘制小狗_SAI教程:绘画小狗手绘板教程
  10. 飞跃微信小程序一一新风口新模式,你所了解到的小程序有多少?
  11. Android单元测试 - 如何开始?
  12. VirtualBox虚拟机全屏显示
  13. 创新工场王嘉平开讲:low-level的计算机视觉
  14. 单片机复位电路的可靠性设计及精典实用复位电路
  15. 联想拯救者y7000电池耗电快_联想拯救者Y7000游戏本测评之温度、续航双测评
  16. 国际专利:是走PCT还是巴黎公约|湾区人工智能
  17. 如何区别边沿触发和脉冲触发
  18. 【论文简述及翻译】PWC-Net: CNNs for Optical Flow Using Pyramid, Warping, and Cost Volume(CVPR 2018)
  19. Linq to Sql 事务处理
  20. WebPack安装记录

热门文章

  1. 网站建设对于企业发展有哪些重要意义
  2. knime工具介绍(1)
  3. 江苏大学计算机学院在职研究生,江苏大学在职研究生有用吗
  4. 2015年上半年信息系统项目管理师上午真题及答案
  5. 掌财社:怎么写BUI折叠菜单插件?案例分析!
  6. WIFI 4/5/6区别
  7. react中高阶函数与高阶组件的运用—(上)(案例详细解释高阶函数)
  8. Mathematica 清除全部变量的命令
  9. 小目标检测:基于深度学习的小目标检测方法
  10. 不容父母,何以容天下