最近在做一个二维码的相关的应用,顺带整理下相关的知识。在上篇中我们已经知道了彩色二维码如何生成,以及logo、背景、文字、水印的添加(如何制作一个你的专属二维码),但里面那个白边一直占据着我们的视线,今天我们来看看二维码的白边如何去除,以及如何生透明底的二维码。何去除白边

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

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

1、MultiFormatWriter类的encode方法

public BitMatrix encode(...) throws WriterException { Writer writer; switch (format) { ... ... case QR_CODE: //用到的是这个模式 writer = new QRCodeWriter(); break; ... ... } return writer.encode(contents, format, width, height, hints); } }

实际上这个方法就是依据format来选择一种编码方式,我们这里用的是QR_CODE的方式了,然后我们再看QRCodeWriter的encode方法。

2、QRCodeWriter类的encode方法

public BitMatrix encode(...) throws WriterException { if(contents.length() == 0) { ... ... } else if(format != BarcodeFormat.QR_CODE) { ... ... } else if(width >= 0 && height >= 0) { ... ... // 前面的都是做编码前的准备,安全检验,纠错级别设置等 QRCode code1 = new QRCode(); // 这里才是真正的将contents转换成code Encoder.encode(contents, errorCorrectionLevel, hints, code1); // return的时候将code转换成BitMatrix,并加入白边 return renderResult(code1, width, height); } else { ... ... } }

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

4、解决方案

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

有颜色的二维码怎么制作(如何制作一个没有白边或透明底的二维码)(1)

修改后如下:

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

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

有颜色的二维码怎么制作(如何制作一个没有白边或透明底的二维码)(2)

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

有颜色的二维码怎么制作(如何制作一个没有白边或透明底的二维码)(3)

可以看出29*8 != 240;

解决方案1:

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

解决方案2:

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

最终renderResult方法修改如下:

private static BitMatrix renderResult(... ...) { ... ... // 依据用户的输入宽高,计算最后的输出宽高 ... ... //计算缩放比例 int multiple = Math.min(... ...); //重新写一次outputWidth和inputHeight outputWidth = multiple * inputWidth; outputHeight = multiple * inputHeight; BitMatrix output = new BitMatrix(outputWidth, outputHeight); int inputY = 0; // 嵌套循环,将ByteMatrix的内容计算padding后转换成BitMatrix ... ... return output; }

5、效果图

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

有颜色的二维码怎么制作(如何制作一个没有白边或透明底的二维码)(4)

如何生成透明底的二维码

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;// 蓝色 } 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):

有颜色的二维码怎么制作(如何制作一个没有白边或透明底的二维码)(5)

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

2、色彩模式ARGB

A:透明度R:红色G:绿B:蓝

Bitmap.Config ARGB_4444:每个像素占四位,即A=4,R=4,G=4,B=4,那么一个像素点占4 4 4 4=16位

Bitmap.Config ARGB_8888:每个像素占四位,即A=8,R=8,G=8,B=8,那么一个像素点占8 8 8 8=32位

Bitmap.Config RGB_565:每个像素占四位,即R=5,G=6,B=5,没有透明度,那么一个像素点占5 6 5=16位

Bitmap.Config ALPHA_8:每个像素占四位,只有透明度,没有颜色。

透明度对比:

100% — FF50% — 80 0% — 00

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、效果图

有颜色的二维码怎么制作(如何制作一个没有白边或透明底的二维码)(6)

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

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

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) { ... ... // 创建一个新的和SRC长度宽度一样的位图 ... ... //获取透明度 Paint vPaint = selectAlpha(0); ... ... cv.drawBitmap(markBMP, srcBMP.getWidth() - markBMP.getWidth() * 3 / 5, srcBMP.getHeight() * 3 / 7, vPaint); ... ... 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—255 return vPaint; } /** * 选择透明度 * * @param alpha 透明度 1 不透明 0 半透明 * @return Paint 画笔 */ private static Paint selectAlpha(int alpha) { if(alpha == 0){ return setAlpha(75); }else{ return setAlpha(255); } }

4、效果图

有颜色的二维码怎么制作(如何制作一个没有白边或透明底的二维码)(7)

结束语

以上就是跟二维码去除白边和透明底的相关接口总结,希望对你有用。

欢迎大家关注我们微信公众号,来交流程序员的技术。如果能点个在看,小编也是很开心的,非常感谢!

最后需要源码的同学,请关注我们的同名微信公众号“麻辣软硬件”,回复“ 透明二维码 ”查看。

,