之前的项目用到了zxing生成二维码,发现周围的白框大的感人,使用EncodeHintType.MARGIN设置也没什么效果。今天看了一下zxing的源码,才发现其中的缘由。
先来看我原本是怎么使用zxing生成二维码的
/**
* 生成二维码
* @param url 二维码内容
* @return 返回新image
*/
public static BufferedImage createQRcode(String url) throws Exception {
int width = 300;
int height = 300;
Hashtable<EncodeHintType, Object> hints = new Hashtable<>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
hints.put(EncodeHintType.MARGIN, 0);
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, width, height, hints);
// 生成二维码
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
image.setRGB(x, y, bitMatrix.get(x, y) ? BLACK : WHITE);
}
}
return image;
}
顺着源码点下去,最后发现是在renderResult()方法里对宽高做了一系列的处理
我们发现我们设置的hints.put(EncodeHintType.MARGIN, 0)边距并没有直接使用,而是经过一系列的计算得出了 leftPadding 与 topPadding。
private static BitMatrix renderResult(AztecCode code, int width, int height) {
BitMatrix input;
if ((input = code.getMatrix()) == null) {
throw new IllegalStateException();
} else {
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);
int leftPadding = (outputWidth - inputWidth * multiple) / 2;
int topPadding = (outputHeight - inputHeight * multiple) / 2;
BitMatrix output = new BitMatrix(outputWidth, outputHeight);
int inputY = 0;
for(int outputY = topPadding; inputY < inputHeight; outputY += multiple) {
int inputX = 0;
for(int outputX = leftPadding; inputX < inputWidth; outputX += multiple) {
if (input.get(inputX, inputY)) {
output.setRegion(outputX, outputY, multiple, multiple);
}
++inputX;
}
++inputY;
}
return output;
}
}
inputWidth ,inputHeight 是 zxing 根据我们所传的url与指定的BarcodeFormat.QR_CODE规则生成的。
比如我们传入的宽和高为250
可以看到生成的inputWidth 和 inputHeight 为33,
quietZone就是我们之前传入的1,
width,height都是之前设置的250。
multiple=7,
内容区为33x33,而我们需要的大小为250x250,33放大7倍后为231,距离250还差19。
19/2 =9
最后经过计算得出了 leftPadding 与 topPadding 都为 9。
如果此时将margin设为 4, 宽和高还是设为 250
故multiple=6,leftPading =(250 - 33*6)/2 = 26,两边就有很大的空白。
zxing会采用这种策略,是为了提高二维码的容错率,以免出现失真导致二维码无法扫描。
了解了zxing的这种计算机制后,我们就可以根据想要的边框大小来传入相应的值了。
为了解决这种留白自定义问题,我们可以采用另外一种方式——图片缩放
/**
* 生成二维码
* @param url 二维码内容
* @return 返回新image
*/
public static BufferedImage createQRcode(String url) throws Exception {
//二维码容错率,分四个等级:H、L 、M、 Q
//生成二维码中的设置
Hashtable hints = new Hashtable();
//编码、容错率、二维码边框宽度,这里文档说设置0-4
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
hints.put(EncodeHintType.MARGIN, 0);
//二维码图片大小
int size = 200;
//生成bitMatrix
BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, size, size,hints);
//自定义白边边框宽度
int margin = 5;
//生成新的bitMatrix
bitMatrix = updateBit(bitMatrix, margin);
//因为二维码生成时,白边无法控制,去掉原有的白边,再添加自定义白边后,二维码大小与size大小就存在差异了,
//为了让新生成的二维码大小还是size大小,根据size重新生成图片
BufferedImage bi = MatrixToImageWriter.toBufferedImage(bitMatrix);
//根据size放大、缩小生成的二维码
bi = zoomInImage(bi,size,size);
}
/**
*因为二维码边框设置那里不起作用,不管设置多少,都会生成白边,所以根据网上
*的例子进行修改,自定义控制白边宽度,该方法生成自定义白边框后的bitMatrix;
*/
private 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
BitMatrix resMatrix = new BitMatrix(resWidth, resHeight);
resMatrix.clear();
//循环,将二维码图案绘制到新的bitMatrix中
for(int i= margin; i < resWidth- margin; i++){
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;
}
/**
* 图片放大缩小
*/
public static BufferedImage zoomInImage(BufferedImage originalImage, int width, int height){
BufferedImage newImage = new BufferedImage(width,height,originalImage.getType());
Graphics g = newImage.getGraphics();
g.drawImage(originalImage, 0,0,width,height,null);
g.dispose();
return newImage;
}
借鉴的文章地址:
https://www.it610.com/article/1280736011311136768.htm
https://www.cnblogs.com/yjanb11/articles/11655194.html
本文深入解析了Zxing生成二维码时边距过大的原因,揭示了源码中的计算机制,并提供了一种通过自定义边框和图片缩放解决留白问题的方法。
1079

被折叠的 条评论
为什么被折叠?



