Zxing 生成二维码和条形码去掉白边
阅读原文时间:2021年04月25日阅读:1

源码下载:

https://github.com/AndroidZmm123/ZxingApplication

需求:根据输入内容,生成条形码或者二维码。

我们大多数会选择Zxing。因为jar包较小。且使用简单。根据内容生成二维码的工具类也是一搜一大堆。上面的源码里面也提供了一个。但是我们仔细看了下。会发现。不管生成的是条形码还是二维码都会有一部分的白边。如图:

我们可以看到周围有白边。那我们怎么去掉呢。

我们先把zxing的源码下载下来。然后看下这个白边是如果产生的。

首先是二维码的。

            BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, widthPix,
                heightPix, hints);

这是根据我们输入的内容。产生一个矩阵。我们可以看到QRCodeWriter的encode()方法里面的最后两行:

   QRCode code = Encoder.encode(contents, errorCorrectionLevel, hints);
        return renderResult(code, width, height, quietZone);

第一句是将我们输入的内容转换成code.不涉及宽高。

第二句是将code转换成矩阵。加入白边的代码就在这里面。

private static BitMatrix renderResult(QRCode code, int width, int height, int quietZone) {
        ByteMatrix input = code.getMatrix();
        if (input == null) {
            throw new IllegalStateException();
        }
        int inputWidth = input.getWidth();
        int inputHeight = input.getHeight();

        //这里就是在我们给定的宽高的基础上。增加了大小。
        //int qrWidth = inputWidth + (quietZone * 2);
        //int qrHeight = inputHeight + (quietZone * 2);

        //修改--》去掉间距
        int qrWidth = inputWidth;
        int qrHeight = inputHeight;

        int outputWidth = Math.max(width, qrWidth);
        int outputHeight = Math.max(height, qrHeight);

        int multiple = Math.min(outputWidth / qrWidth, outputHeight / qrHeight);
        // Padding includes both the quiet zone and the extra white pixels to accommodate the requested
        // dimensions. For example, if input is 25x25 the QR will be 33x33 including the quiet zone.
        // If the requested size is 200x160, the multiple will be 4, for a QR of 132x132. These will
        // handle all the padding from 100x100 (the actual QR) up to 200x160.

        //计算白边的大小。
        //int leftPadding = (outputWidth - (inputWidth * multiple)) / 2;
        //int topPadding = (outputHeight - (inputHeight * multiple)) / 2;

        //修改--》去掉间距
        int leftPadding = 0;
        int topPadding = 0;
        BitMatrix output = new BitMatrix(outputWidth, outputHeight);

        for (int inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple) {
            // Write the contents of this row of the barcode
            for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) {
                if (input.get(inputX, inputY) == 1) {
                    output.setRegion(outputX, outputY, multiple, multiple);
                }
            }
        }

        return output;
    }

这样就二维码的白边就去掉了。

效果图:

再来看条形码的。条形码的修改稍微麻烦点。

条形码的解析类是:Code128Writer。进去同样可以找到encode()。调用的是父类的encode()。

 int sidesMargin = getDefaultMargin();
        if (hints != null && hints.containsKey(EncodeHintType.MARGIN)) {
            sidesMargin = Integer.parseInt(hints.get(EncodeHintType.MARGIN).toString());
        }

        boolean[] code = encode(contents);
        return renderResult(code, width, height, sidesMargin);

这里有个sideMargin..emmm。看着像是白边的大小的样子。我试着先把这个值修改为0.默认是10.修改以后。运行起来可以发现。还是有白边。看来这不是全部。看下renderResult()方法。

 /**
     * @return a byte array of horizontal pixels (0 = white, 1 = black)
     */
    private static BitMatrix renderResult(boolean[] code, int width, int height, int sidesMargin) {
        int inputWidth = code.length;
        // Add quiet zone on both sides.

        int fullWidth = inputWidth + sidesMargin;

        int outputWidth = Math.max(width, fullWidth);


        int outputHeight = Math.max(1, height);
        int multiple = outputWidth / fullWidth;

        Log.e("zmm", outputWidth + "renderResult-->" + inputWidth + "--->" + multiple);
        int leftPadding = (outputWidth - (inputWidth * multiple)) / 2;
        Log.e("zmm", "间距----------->" + leftPadding);
        BitMatrix output = new BitMatrix(outputWidth, outputHeight);
        for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX +=
            multiple) {
            if (code[inputX]) {
                output.setRegion(outputX, 0, multiple, outputHeight);
            }
        }
        return output;

    }

我们可以看到leftPadding。我试着把这个值修改为0.发现还是不行,有白边。

仔细看下。这个规则。我们的宽度是700px.我们刚刚已经把sideMargin修改成0了。所以

fullWidth=700;

inputWidth:是根据我们的内容根据128编码生成的一个数组的长度。我们输入1234567890:这里的inputWidth:90

multiple=700/90=7.77777;但是这里是int。所以multiple=7;这就产生了误差。multiple看成是竖线之间的增量。也就是,第一个竖线坐标是0,第二个竖线就应该在0+multiple的位置,以此类推。总共有90个竖线。那90*7<700.那还剩下的70.就只能平分当做左右的白边。

leftPadding=(outputWidth - (inputWidth * multiple)) / 2;也就是(700-90*7)/2=35.所以我们算出白边应该是35。

这样一下来我们就知道该怎么修改这个长度了。我们值修改leftPadding=0的话。那就会剩下70的空白。所以。不行。我们要做的事修改原始的图片大小。故修改成:

 /**
     * @return a byte array of horizontal pixels (0 = white, 1 = black)
     */
    private static BitMatrix renderResult(boolean[] code, int width, int height, int sidesMargin) {
        int inputWidth = code.length;
        // Add quiet zone on both sides.

        int fullWidth = inputWidth + sidesMargin;

        int outputWidth = Math.max(width, fullWidth);


        int outputHeight = Math.max(1, height);
        int multiple = outputWidth / fullWidth;
        //先判断是不是可以整除。如果可以整除。那leftPadding肯定为0,就不需要修改。
        // 如果不能整除。需要把原始的大小修改成outputWidth = multiple * fullWidth;这样以后。leftPadding也就为0了。
        if (outputHeight % fullWidth != 0) {
            outputWidth = multiple * fullWidth;
        }
        Log.e("zmm", outputWidth + "renderResult-->" + inputWidth + "--->" + multiple);
        int leftPadding = (outputWidth - (inputWidth * multiple)) / 2;
        Log.e("zmm", "间距----------->" + leftPadding);
        BitMatrix output = new BitMatrix(outputWidth, outputHeight);
        for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX +=
            multiple) {
            if (code[inputX]) {
                output.setRegion(outputX, 0, multiple, outputHeight);
            }
        }
        return output;

    }

这样以后。我们还需要在生成条形码那里把真实大小修改成我们改过以后的。也就是:

/**
     * 绘制条形码
     *
     * @param content       要生成条形码包含的内容
     * @param widthPix      条形码的宽度
     * @param heightPix     条形码的高度
     * @param isShowContent 否则显示条形码包含的内容
     * @return 返回生成条形的位图
     */
    public static Bitmap createBarcode(String content, int widthPix, int heightPix, boolean isShowContent) {
        if (TextUtils.isEmpty(content)) {
            return null;
        }
        //配置参数
        Map<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        // 容错级别 这里选择最高H级别
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        MultiFormatWriter writer = new MultiFormatWriter();

        try {
            // 图像数据转换,使用了矩阵转换 参数顺序分别为:编码内容,编码类型,生成图片宽度,生成图片高度,设置参数
            BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.CODE_128, widthPix, heightPix, hints);

            //增加:把宽度修改我们修改过后的真实的宽度
            widthPix = bitMatrix.getWidth();
            // Log.e("zmm", "---------->" + widthPix + "--->" + height);
            int[] pixels = new int[widthPix * heightPix];
//             下面这里按照条形码的算法,逐个生成条形码的图片,
            // 两个for循环是图片横列扫描的结果
            for (int y = 0; y < heightPix; y++) {
                for (int x = 0; x < widthPix; x++) {
                    if (bitMatrix.get(x, y)) {
                        pixels[y * widthPix + x] = 0xff000000; // 黑色
                    } else {
                        pixels[y * widthPix + x] = 0xffffffff;// 白色
                    }
                }
            }
            Bitmap bitmap = Bitmap.createBitmap(widthPix, heightPix, Bitmap.Config.ARGB_8888);
            bitmap.setPixels(pixels, 0, widthPix, 0, 0, widthPix, heightPix);
            if (isShowContent) {
                bitmap = showContent(bitmap, content);
            }
            return bitmap;
        } catch (WriterException e) {
            e.printStackTrace();
        }

        return null;
    }

运行看下效果:

至此百边就去掉了。当然这样不好看。你也可以。自己来定一个固定的白边的宽度。我觉得还是不要去掉的比较好。因为。毕竟zxing这样设计肯定有一定的原因。

每日语录:

看到一个故事叫“刻舟求剑”,心里觉得这个人好傻,世上怎么会有这样的人,难道不知道剑在江中央掉下了水,跑到江边是找不到的?然而长大后发现,在这条岁月的长河里,很多人在某个节点遗失的东西,之后一次又一次返回寻找,却不知道自己只是站在船边徘徊,江中央已经回不去了。看到一个故事叫“掩耳盗铃”,心里想,这又是一个傻瓜,捂着耳朵偷东西骗的了谁?然而长大后发现,自己和同学一起逃课、一起抄作业、一起考试作弊,一起做许多明知道不应该做却克制不住自己的事情。没有被抓到就沾沾自喜,其实警告的铃声早已响起,只是自己捂着耳朵假装听不到。看到一个故事叫“朝三暮四”,心里偷笑,这群猴子怎么如此好骗,明明就是七个栗子,早晨三个晚上四个变成早晨四个晚上三个就一个个被哄得服服帖帖。然而长大后发现,女孩儿被渣男伤害,对面一个道歉就还是原谅了他;商家使个小小的心眼儿,几块钱红包就引得全国人趋之若鹜……我们不比猴子聪明多少。看到一个故事叫“削足适履”,心里哀叹,怎么会有这样的蠢人,居然会蠢到砍自己的脚去适应鞋子,换一双鞋子就那么难吗?然而长大后发现,明明知道自己的权益被损害,明明知道这样的环境和体系并不科学,然而在这其中的每个人却都默不作声,甘心忍受。看到一个故事叫“邯郸学步”,心里崩溃,为什么成语故事里的人一个比一个傻?别人走路姿势好看就去模仿,到了最后居然忘了自己怎么走路?然而长大后却发现,这个世界的确被一股股潮流所带领,今天“假装生活”,明天“佛系青年”;今天都在比拼“跳一跳”,明天都在晒“养青蛙”。现在谁能想象,自己扔掉手机生活的样子?原来,成语中那些傻事儿可能没有人会去干,但是,成语里那些傻瓜,却是真实地存在着    ---------------------------------来自知乎(作者:雾雨之灵)

单曲循环《曾经的你》第一次找工作那段时间天天听。。因为太迷茫了。太惶恐了。听着这首歌。沿着一条路。一直走。一直走。想把以后的路想明白,想清楚。其实。。根本毫无用处。路都是走着走着就明白了。愿看到这段话的你。可以少些苦恼。少些惶恐。加油!!!