解決源碼
不耽誤大家時間,直接上解決代碼
依賴:
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);
複製上面那個方法,生成條碼的時候重新計算一遍條碼寬度,生成出來的條碼就不會有兩邊空白的問題,對於條碼的識別沒有任何影響,在項目中已得到驗證。
如果沒有使用bga-qrcode-zxing庫生成條碼的話,還要增加如下代碼
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~