【android应用】详解基于ZXing生成的二维码,文末附带源码---去除白边,以及透明底

本文主要是介绍【android应用】详解基于ZXing生成的二维码,文末附带源码---去除白边,以及透明底,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

最近在做一个二维码的相关的应用,顺带整理下相关的知识。今天我们来看看二维码的白边如何去除,以及如何生透明底的二维码。

前篇回顾:【android应用】基于ZXing生成的二维码,文末附带源码---添加logo、彩色、背景、文字、水印在这里都能找到

在上篇中我们已经知道了彩色二维码如何生成,以及logo、背景、文字、水印的添加,但里面那个白边一直占据着我们的视线,今天就来讲讲如何去除掉这个白边。

目录

何去除白边

1、MultiFormatWriter类的encode方法

2、QRCodeWriter类的encode方法

3、方法renderResult

4、解决方案

如何生成透明底的二维码

1、再来看下生成二维码图的函数

2、色彩模式ARGB

3、解决方案

4、效果图

如何添加半透明的水印和logo

1、了解下drawBitmap方法

2、看下添加水印的代码

3、解决方案

4、效果图

源码

结束语


何去除白边

下面我们来跟一下二维码生成的源码流程。首先是调用位置:

BitMatrix matrix = new MultiFormatWriter().encode(content,BarcodeFormat.QR_CODE, width, height, hints);

1、MultiFormatWriter类的encode方法

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方法。

2、QRCodeWriter类的encode方法

    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");} else if(format != BarcodeFormat.QR_CODE) {throw new IllegalArgumentException("Can only encode QR_CODE, but got " + format);} else if(width >= 0 && height >= 0) {ErrorCorrectionLevel errorCorrectionLevel = ErrorCorrectionLevel.L;if(hints != null) {ErrorCorrectionLevel code = (ErrorCorrectionLevel)hints.get(EncodeHintType.ERROR_CORRECTION);if(code != null) {errorCorrectionLevel = code;}}// 前面的都是做编码前的准备,安全检验,纠错级别设置等QRCode code1 = new QRCode();// 这里才是真正的将contents转换成codeEncoder.encode(contents, errorCorrectionLevel, hints, code1);// return的时候将code转换成BitMatrix,并加入白边return renderResult(code1, width, height);} else {throw new IllegalArgumentException("Requested dimensions are too small: " + width + 'x' + height);}}

下面再看将code转换成BitMatrix,并加入白边的方法renderResult

3、方法renderResult

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

4、解决方案

这个方法里的代码不难读懂,所以要去掉白边实际上就很简单了,自定义一个QRCodeWriter类,完全把Zxing包的QRCodeWriter类复制过来,然后将renderResult方法里的padding去掉就可以了(为什么不继承QRCodeWriter,因为它是final类~~)。 


修改后如下:

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

但是你还是会发现,还是有一点点小小的白边。而且整体往上偏了效果图如下:

在renderResult方法中加上调试log在看下:

可以看出29*8 != 240;

解决方案1:

尝试修改inputWidth和inputHeight为29的倍数是可以解决的,但是每次都需要计算传值这样很是麻烦。

解决方案2:

在renderResult方法得到multiple后重新赋值一次给inputWidth和inputHeight,这样比较方便不需要每次计算传值。

最终renderResult方法修改如下:

    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);//重新写一次outputWidth和inputHeightoutputWidth = multiple * inputWidth;outputHeight = multiple * inputHeight;Log.d(TAG, "renderResult: outputWidth " +outputWidth +" outputHeight "+outputHeight);Log.d(TAG, "renderResult: inputHeight " +inputWidth +" inputHeight "+inputHeight);Log.d(TAG, "renderResult: multiple " + multiple);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;}

这样就能完美的去除白边了效果图如下:

后面我会把源码贴上,如果对你有用,希望能给我一个赞。谢谢!!!

如何生成透明底的二维码

1、再来看下生成二维码图的函数

private static Bitmap bitMatrix2Bitmap(BitMatrix matrix) {int WIDTH = matrix.getWidth();int HEIGHT = matrix.getHeight();int[] pixels = new int[WIDTH * HEIGHT];for (int y = 0; y < WIDTH; y++) {for (int x = 0; x < HEIGHT; x++) {int color = Color.WHITE;if (matrix.get(x, y)) {// 有内容的部分,颜色设置为渐变,当然这里可以自己修改成喜欢的颜色color = 0xFF0094FF + y/2;// 蓝色
//              if (x < WIDTH / 2 && y < HEIGHT / 2) {
//                   color = 0xFF0094FF;// 蓝色
//                   //Integer.toHexString(new Random().nextInt());
//              } else if (x < WIDTH / 2 && y > HEIGHT / 2) {
//                   color = 0xFFFED545;// 黄色
//              } else if (x > WIDTH / 2 && y > HEIGHT / 2) {
//                   color = 0xFF5ACF00;// 绿色
//              } else {
//                   color = 0xFF000000;// 黑色
//              }}pixels[x + (y * WIDTH)] = color;}}Bitmap bitmap = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.RGB_565);bitmap.setPixels(pixels, 0, WIDTH, 0, 0, WIDTH, HEIGHT);return bitmap;
}

我们只需要将color的初始值设置成我们我们想要的颜色,就能得到我们想要的底色。比如蓝色(0xFF0094FF):

是不是感觉自己马上就能搞出透明底的只需要将FF改成8F就木有问题了,可结果不是这样,不要慌。我们再来回顾下色彩模式。你就知道哪不对了。

2、色彩模式ARGB

可以查看我转载的一篇博客,飞机票:常用色彩模式ARGB详解

3、解决方案

半透明:

  • 将0xFF0094FF改成0x800094FF
  • Bitmap.Config.RGB_565模式修改成Bitmap.Config.ARGB_8888模式
    private static Bitmap bitMatrix2Bitmap(BitMatrix matrix) {int WIDTH = matrix.getWidth();int HEIGHT = matrix.getHeight();int[] pixels = new int[WIDTH * HEIGHT];for (int y = 0; y < WIDTH; y++) {for (int x = 0; x < HEIGHT; x++) {//int color = 0xFFFFFFFF;int color = 0x800094FF;if (matrix.get(x, y)) {// 有内容的部分,颜色设置为黑色,当然这里可以自己修改成喜欢的颜色color = 0xFF000000;}pixels[x + (y * WIDTH)] = color;}}Bitmap bitmap = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_8888);bitmap.setPixels(pixels, 0, WIDTH, 0, 0, WIDTH, HEIGHT);return bitmap;}

4、效果图

透明的只需要在透明上修改颜色即可(将0xFF0094FF改成0x000094FF),这里就不贴效果图了。

1、了解下drawBitmap方法

drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint);

Rect src: 是对图片进行裁截,若是空null则显示整个图片

RectF dst:是图片在Canvas画布中显示的区域,
           大于src则把src的裁截区放大,
           小于src则把src的裁截区缩小。

Paint paint :该类保存了绘制几何图形、文本和位图的样式和颜色信息。

2、看下添加水印的代码

    public static Bitmap composeWatermark(Bitmap srcBMP, Bitmap markBMP) {if (srcBMP == null) {return null;}// 创建一个新的和SRC长度宽度一样的位图Bitmap newb = Bitmap.createBitmap(srcBMP.getWidth(),srcBMP.getHeight(), Bitmap.Config.ARGB_8888);Canvas cv = new Canvas(newb);// 在 0,0坐标开始画入原图cv.drawBitmap(srcBMP, 0, 0, null);// 在原图的右下角画入水印cv.drawBitmap(markBMP, srcBMP.getWidth() - markBMP.getWidth() * 3 / 5,srcBMP.getHeight() * 3 / 7, null);// 保存cv.save(Canvas.ALL_SAVE_FLAG);// 存储cv.restore();return newb;}

Paint 表示画笔 Canvas 表示画布,画板。可以看出Paint 传入的null,说明使用默认的。我们可以通过画笔Paint来设置,比如:画笔大小,颜色值,透明度,填充样式等等。这样就简单了。

3、解决方案

    public static Bitmap composeWatermark(Bitmap srcBMP, Bitmap markBMP) {if (srcBMP == null) {return null;}// 创建一个新的和SRC长度宽度一样的位图Bitmap newb = Bitmap.createBitmap(srcBMP.getWidth(),srcBMP.getHeight(), Bitmap.Config.ARGB_8888);//获取透明度Paint vPaint = selectAlpha(0);Canvas cv = new Canvas(newb);// 在 0,0坐标开始画入原图cv.drawBitmap(srcBMP, 0, 0, null);// 在原图的右下角画入水印cv.drawBitmap(markBMP, srcBMP.getWidth() - markBMP.getWidth() * 3 / 5,srcBMP.getHeight() * 3 / 7, vPaint);// 保存cv.save(Canvas.ALL_SAVE_FLAG);// 存储cv.restore();return newb;}/*** 设置透明度** @param alpha    透明度* @return Paint    画笔*/private static Paint setAlpha(int alpha) {// 建立Paint 物件Paint vPaint = new Paint();vPaint .setStyle( Paint.Style.STROKE );   //空心vPaint .setAlpha(alpha);   //0—255return vPaint;}/*** 选择透明度** @param alpha    透明度  1 不透明 0 半透明* @return Paint    画笔*/private static Paint selectAlpha(int alpha) {if(alpha == 0){return setAlpha(75);}else{return setAlpha(255);}}

4、效果图

源码

飞机票:【源码】二维码透明底和去除白边功能

结束语

以上就是跟二维码去除白边和透明底的相关接口总结,希望对你有用。欢迎大家关注我们微信公众号,来交流程序员的技术。如果能留言或者点个赞,我也是很开心的,非常感谢!

å¨è¿éæå¥å¾çæè¿°

部分图片来自互联网

参考:https://blog.csdn.net/pxr1989104/article/details/51283585

这篇关于【android应用】详解基于ZXing生成的二维码,文末附带源码---去除白边,以及透明底的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/944361

相关文章

Rust 数据类型详解

《Rust数据类型详解》本文介绍了Rust编程语言中的标量类型和复合类型,标量类型包括整数、浮点数、布尔和字符,而复合类型则包括元组和数组,标量类型用于表示单个值,具有不同的表示和范围,本文介绍的非... 目录一、标量类型(Scalar Types)1. 整数类型(Integer Types)1.1 整数字

Python使用qrcode库实现生成二维码的操作指南

《Python使用qrcode库实现生成二维码的操作指南》二维码是一种广泛使用的二维条码,因其高效的数据存储能力和易于扫描的特点,广泛应用于支付、身份验证、营销推广等领域,Pythonqrcode库是... 目录一、安装 python qrcode 库二、基本使用方法1. 生成简单二维码2. 生成带 Log

Java操作ElasticSearch的实例详解

《Java操作ElasticSearch的实例详解》Elasticsearch是一个分布式的搜索和分析引擎,广泛用于全文搜索、日志分析等场景,本文将介绍如何在Java应用中使用Elastics... 目录简介环境准备1. 安装 Elasticsearch2. 添加依赖连接 Elasticsearch1. 创

Redis缓存问题与缓存更新机制详解

《Redis缓存问题与缓存更新机制详解》本文主要介绍了缓存问题及其解决方案,包括缓存穿透、缓存击穿、缓存雪崩等问题的成因以及相应的预防和解决方法,同时,还详细探讨了缓存更新机制,包括不同情况下的缓存更... 目录一、缓存问题1.1 缓存穿透1.1.1 问题来源1.1.2 解决方案1.2 缓存击穿1.2.1

PyTorch使用教程之Tensor包详解

《PyTorch使用教程之Tensor包详解》这篇文章介绍了PyTorch中的张量(Tensor)数据结构,包括张量的数据类型、初始化、常用操作、属性等,张量是PyTorch框架中的核心数据结构,支持... 目录1、张量Tensor2、数据类型3、初始化(构造张量)4、常用操作5、常用属性5.1 存储(st

Python 中 requests 与 aiohttp 在实际项目中的选择策略详解

《Python中requests与aiohttp在实际项目中的选择策略详解》本文主要介绍了Python爬虫开发中常用的两个库requests和aiohttp的使用方法及其区别,通过实际项目案... 目录一、requests 库二、aiohttp 库三、requests 和 aiohttp 的比较四、requ

将Python应用部署到生产环境的小技巧分享

《将Python应用部署到生产环境的小技巧分享》文章主要讲述了在将Python应用程序部署到生产环境之前,需要进行的准备工作和最佳实践,包括心态调整、代码审查、测试覆盖率提升、配置文件优化、日志记录完... 目录部署前夜:从开发到生产的心理准备与检查清单环境搭建:打造稳固的应用运行平台自动化流水线:让部署像

VUE动态绑定class类的三种常用方式及适用场景详解

《VUE动态绑定class类的三种常用方式及适用场景详解》文章介绍了在实际开发中动态绑定class的三种常见情况及其解决方案,包括根据不同的返回值渲染不同的class样式、给模块添加基础样式以及根据设... 目录前言1.动态选择class样式(对象添加:情景一)2.动态添加一个class样式(字符串添加:情

Python在固定文件夹批量创建固定后缀的文件(方法详解)

《Python在固定文件夹批量创建固定后缀的文件(方法详解)》文章讲述了如何使用Python批量创建后缀为.md的文件夹,生成100个,代码中需要修改的路径、前缀和后缀名,并提供了注意事项和代码示例,... 目录1. python需求的任务2. Python代码的实现3. 代码修改的位置4. 运行结果5.

Go Gorm 示例详解

《GoGorm示例详解》Gorm是一款高性能的GolangORM库,便于开发人员提高效率,本文介绍了Gorm的基本概念、数据库连接、基本操作(创建表、新增记录、查询记录、修改记录、删除记录)等,本... 目录1. 概念2. 数据库连接2.1 安装依赖2.2 连接数据库3. 数据库基本操作3.1 创建表(表关