当我们使用zxing生成的二维码时,可能会发现二维码有个很大的内边距,通过阅读源码,可以找到zxing的渲染代码如下:
public final class QRCodeWriter implements Writer {
......
private static BitMatrix renderResult(QRCode code, int width, int height, int quietZone) {
ByteMatrix input;
if ((input = code.getMatrix()) == null) {
throw new IllegalStateException();
} else {
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;
int topPadding = (outputHeight - inputHeight * multiple) / 2;
BitMatrix output = new BitMatrix(outputWidth, outputHeight);
......
return output;
}
}
}
从上面代码中,我们可以找到出现内边距的“罪魁祸首”:
int outputWidth = Math.max(width, qrWidth);
int outputHeight = Math.max(height, qrHeight);
int multiple = Math.min(outputWidth / qrWidth, outputHeight / qrHeight);
可以发现如下问题:
1、输出图像的宽高可能与期望宽高不符。
2、multiple是int,如果输出尺寸与二维码尺寸不是倍数关系,即尺寸不能被整除,就会出现较大的内边距。
为了解决这些问题,我重新封装了下面这个工具类,可以直接引入项目使用,同时也提升了渲染的效率。
public class QRCodeUtil {
@Nullable
public static Bitmap createQRCodeBitmap(String contents, int size) {
return createQRCodeBitmap(contents, "UTF-8", size, size, 1, ErrorCorrectionLevel.L, Color.WHITE, 0x50888888);
}
@Nullable
public static Bitmap createQRCodeBitmap(String contents, String characterSet, int width, int height, int margin, ErrorCorrectionLevel errorCorrectionLevel, int codeColor, int backColor) {
if (TextUtils.isEmpty(contents) || width <= 0 || height <= 0) {
return null;
}
margin = Math.max(0, margin);
Map<EncodeHintType, Object> hints = new EnumMap<>(EncodeHintType.class);
hints.put(EncodeHintType.CHARACTER_SET, characterSet);
try {
QRCode qrCode = Encoder.encode(contents, errorCorrectionLevel, hints);
ByteMatrix input = qrCode.getMatrix();
if (input == null) {
return null;
}
return renderBitmap(input, width, height, margin, codeColor, backColor);
} catch (WriterException e) {
e.printStackTrace();
}
return null;
}
private static Bitmap renderBitmap(@NonNull ByteMatrix input, int width, int height, int margin, int codeColor, int backColor) {
int inputWidth = input.getWidth();
int inputHeight = input.getHeight();
int qrWidth = inputWidth + (margin << 1);
int qrHeight = inputHeight + (margin << 1);
float outputAspectRatio = 1f * width / height;
float qrAspectRatio = 1f * qrWidth / qrHeight;
int offsetX;
int offsetY;
float multiple;
if (outputAspectRatio == qrAspectRatio) {
offsetX = 0;
offsetY = 0;
multiple = 1f * width / qrWidth;
} else if (outputAspectRatio < qrAspectRatio) {
offsetX = 0;
offsetY = ((int) (height - width / qrAspectRatio)) >> 1;
multiple = 1f * width / qrWidth;
} else {
offsetX = ((int) (width - height * qrAspectRatio)) >> 1;
offsetY = 0;
multiple = 1f * height / qrHeight;
}
Bitmap output = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
canvas.drawColor(backColor);
Paint paint = new Paint();
paint.setColor(codeColor);
paint.setStyle(Paint.Style.FILL);
for (int y = 0; y < inputHeight; y++) {
float top = offsetY + (y + margin) * multiple;
for (int x = 0; x < inputWidth; x++) {
if (input.get(x, y) == 1) {
float left = offsetX + (x + margin) * multiple;
canvas.drawRect(left, top, left + multiple, top + multiple, paint);
}
}
}
return output;
}
}
完毕!!!
网友评论