三木猿 发表于 2021-12-27 10:41

用ZXING生成二维码的那些坑和去坑代码

本帖最后由 三木猿 于 2021-12-27 10:42 编辑

最近做的一个批量生成二维码的工具用到了二维码生成,本以为会很简单,结果发现,全是坑呀
坑一、生成的二维码有白边,ZXING提供的设置白边大小的方法有bug。。
这个着实坑人,提供了设置白边的方法,结果用了白边反而变大了,并且不受控制了
从别的地方截取出来的,大概就长这样,这玩意能用???简直奇葩了

ZXING提供的办法(有坑)
Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
hints.put(EncodeHintType.MARGIN, 0);//这里实际上设置的就是白边宽度,但是在源码里不是按照你想的那样设置几就是几,计算白边的宽度时用到了二维码宽度和高度当参数,这就造成想设置0px,结果出现10px白边的情况
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, intEwmWidth, intEwmHeight,
hints);
源码里计算白边宽度的方法,我给他封装出来了,可以直接用
/**
* 获取白边宽度
* @Param code
* @param width
* @param height
* @param quietZone
* @return
*/
public Integer getPadding(QRCode code, int width, int height, int quietZone) {
ByteMatrix input = code.getMatrix();
int inputWidth = input.getWidth();
int inputHeight = input.getHeight();
int qrWidth = inputWidth + (quietZone << 1);
int qrHeight = inputHeight + (quietZone << 1);
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;
return leftPadding;
}
其中QRCode的生成方式是
ErrorCorrectionLevel errorCorrectionLevel = ErrorCorrectionLevel.valueOf(hints.get(EncodeHintType.ERROR_CORRECTION).toString());
//contents这个就是二维码的文本,一般是url,自己设置的,hints上文出现过,可以往上滑看一下
Encoder.encode(contents, errorCorrectionLevel, hints)
解决办法:百度上提供了一种办法,的确是有用的
这个方法种的margin单位是像素(px)(手动量过,绝对是像素{:301_1004:})
//删除白边
    private static BitMatrix updateBit(BitMatrix matrix, int margin) {
      int tempM = margin * 2;
      int[] rec = matrix.getEnclosingRectangle(); // 获取二维码图案的属性 集合中前两个是白边的宽和高,后两个是二维码去白边之后的宽度和高度
      int resWidth = rec + tempM;
      int resHeight = rec + 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, j - margin + rec)) {
                  resMatrix.set(i, j);
                }
            }
      }
      return resMatrix;
    }
坑二、去白边后二维码缩小
这个方法的坑
这个方法实际上就是在原来二维码的数据上进行截取白边的操作matrix.get(i - margin + rec, j - margin + rec)
这个意思就是获取每一个像素的x和y的坐标的时候从自己设置的像素位置开始。
所以坑就来了,我生成二维码的时候设置的100x100大小,结果白边是去了,二维码变小了,这哪能行,并且原来白边越大,缩小的越多
这个坑的解决办法
之前研究了几个小时,几乎就改源码重新写一个生成逻辑了,然后突然就茅塞顿开
他缩小了,我给他放大不就完了。。
BitMatrix 是需要转成BufferedImage 输出的,BufferedImage 就是个存图片的,既然是图片就肯定能放大,并且因为去掉的白边后的大小和去白边之前的大小差距并不大,既然如此,那我为啥不直接放大二维码呢。。
先转BufferedImage
int intEwmWidth1 = bitMatrix.getWidth();
      int intEwmHeight1 = bitMatrix.getHeight();

      BufferedImage image = new BufferedImage(intEwmWidth1, intEwmHeight1, BufferedImage.TYPE_INT_RGB);
      for (int x = 0; x < intEwmWidth1; x++) {
            for (int y = 0; y < intEwmHeight1; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
      }
然后放大,设置二维码大小
    private static BufferedImage zoomInImage(BufferedImage originalImage, int maxWidth, int maxHeight) {
      BufferedImage newImage = new BufferedImage(maxWidth, maxHeight, originalImage.getType());
      Graphics g = newImage.getGraphics();
      g.drawImage(originalImage, 0, 0, maxWidth, maxHeight, null);
      g.dispose();
      return newImage;
    }
至此二维码的算是填了吧,至少比原来强,但是最好的方式是改源码,我提供的方法会导致白边大小不是设置的4,而是等比例放大的(当然差距其实不大)
附一张我生成的二维码(别扫,扫了就知道我忙的什么项目了{:301_998:})



附带的完整代码(1cb不过分吧{:301_997:},或者你也可以看我的文章,里面代码也都有)







xiaolong23330 发表于 2021-12-27 10:58

谢谢分享个人经验

金冰 发表于 2021-12-27 11:13

xymoc 发表于 2021-12-27 11:17

感谢分享!

denghuibq 发表于 2021-12-27 11:50

感谢分享~

MOEYU_VANILLA 发表于 2021-12-27 11:53

感谢分享!!

kenxy 发表于 2021-12-27 11:57

谢谢分享经验

thysut 发表于 2022-1-10 14:04

感谢分享

傲天越 发表于 2022-1-18 19:14

感谢楼主分享,学习了!
页: [1]
查看完整版本: 用ZXING生成二维码的那些坑和去坑代码