美文网首页
去除zxing生成二维码的内边距

去除zxing生成二维码的内边距

作者: 徒步青云 | 来源:发表于2021-02-23 22:28 被阅读0次

当我们使用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;
    }
}

完毕!!!

相关文章

网友评论

      本文标题:去除zxing生成二维码的内边距

      本文链接:https://www.haomeiwen.com/subject/esidfltx.html