不耽误大家时间,直接上解决代码
依赖:
implementation 'cn.bingoogolapple:bga-qrcode-zxing:1.3.7'
解决方法
/**
* 参考OneDimensionalCodeWriter源码中对于条码边距的计算
* @param width 条码宽度
* @param contents 条码内容
*/
private int getNewWidth(int width, String contents) {
Code128Writer code128Writer = new Code128Writer();
boolean[] code = code128Writer.encode(contents);
int inputWidth = code.length;
int outputWidth = Math.max(width, inputWidth);
int remain = outputWidth % inputWidth;
return outputWidth - remain;
}
生成条码
Bitmap bitmapBar = QRCodeEncoder.syncEncodeBarcode(contents, getNewWidth(width, contents), height, 0);
imageView.setImageBitmap(bitmapBar);
复制上面那个方法,生成条码的时候重新计算一遍条码宽度,生成出来的条码就不会有两边空白的问题,对于条码的识别没有任何影响,在项目中已得到验证。
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
hints.put(EncodeHintType.MARGIN, 0);
完整方法如下
/**
* 同步创建条形码图片
*
* @param content 要生成条形码包含的内容
* @param width 条形码的宽度,单位px
* @param height 条形码的高度,单位px
* @param textSize 字体大小,单位px,如果等于0则不在底部绘制文字
* @return 返回生成条形的位图
*/
public static Bitmap syncEncodeBarcode(String content, int width, int height, int textSize) {
if (TextUtils.isEmpty(content)) {
return null;
}
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
hints.put(EncodeHintType.MARGIN, 0);
try {
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.CODE_128, width, height, hints);
int[] pixels = new int[width * height];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
if (bitMatrix.get(x, y)) {
pixels[y * width + x] = 0xff000000;
} else {
pixels[y * width + x] = 0xffffffff;
}
}
}
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
if (textSize > 0) {
bitmap = showContent(bitmap, content, textSize);
}
return bitmap;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
好了现在无论你是直接使用zxing,还是使用大神封装的库,都可以解决zxing生成条码边距的问题了。如果你有时间的话可以看下原理,非常简单。
我们从MultiFormatWriter().encode方法入手
@Override
public BitMatrix encode(String contents,
BarcodeFormat format,
int width, int height,
Map<EncodeHintType,?> hints) throws WriterException {
Writer writer;
switch (format) {
...
case CODE_128:
writer = new Code128Writer();
break;
...
default:
throw new IllegalArgumentException("No encoder available for format " + format);
}
return writer.encode(contents, format, width, height, hints);
}
省略了无关代码,最终会调到Code128Writer的encode方法
@Override
public BitMatrix encode(String contents,
BarcodeFormat format,
int width,
int height,
Map<EncodeHintType,?> hints) throws WriterException {
if (format != BarcodeFormat.CODE_128) {
throw new IllegalArgumentException("Can only encode CODE_128, but got " + format);
}
return super.encode(contents, format, width, height, hints);
}
我们点击super进入它的父类OneDimensionalCodeWriter
@Override
public BitMatrix encode(String contents,
BarcodeFormat format,
int width,
int height,
Map<EncodeHintType,?> hints) throws WriterException {
if (contents.isEmpty()) {
throw new IllegalArgumentException("Found empty contents");
}
if (width < 0 || height < 0) {
throw new IllegalArgumentException("Negative size is not allowed. Input: "
+ width + 'x' + height);
}
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);
}
第一点,这里取sidesMargin 的时候会判断hints中是否有EncodeHintType.MARGIN,如果有的话,就回去这个里面的值,这也是我们为什么要增加如下方法的原因,当然另外两个参数现在看来也没啥用,可以删掉
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
hints.put(EncodeHintType.MARGIN, 0);
第二点,我们接着往下看
/**
* @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;
int leftPadding = (outputWidth - (inputWidth * multiple)) / 2;
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 就是条码边距产生的罪魁祸首,具体的计算可以自己debug看下,产生边距的原因就是
int multiple = outputWidth / fullWidth;
这里的计算丢失了精度,如果我们给outputWidth 减去一个差值,让它刚好可以整除,那么算出的leftPadding就一定是0,也就解决了边距问题,OK。
遇到问题不要慌,拿出手机拍个照,发个。。。骚瑞,串词了
总结下来就是,我们遇到问题不要慌,很多时候看一下源码就可以解决,很多时候源码复杂是因为,涉及的类比较多,来回跳转,但是理一理,也很简单,好了,到这吧,bye~