别人的代码
先放一下一份抄到的代码,一般的ZXing都是差不多这样写的
/**
* @param args
*/
public static void main(String[] args) {
try {
String content = "{\"server\":4407}";
Integer width = 100;
Integer height = 100;
Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
hints.put(EncodeHintType.MARGIN, 0);
QRCodeWriter writer = new QRCodeWriter();
BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
MatrixToImageWriter.writeToStream(bitMatrix, "jpg", new FileOutputStream("你好.jpg"));
}
catch (Exception e) {
e.printStackTrace();
}
}
结果图如下
白边问题
尺寸为100,100的时候,白边情况比较严重,左右上下都有8个像素的白边。
先考究一下为什么会产生白边,能不能去掉。
看一下encode方法。
@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 (format != BarcodeFormat.QR_CODE) {
throw new IllegalArgumentException("Can only encode QR_CODE, but got " + format);
}
if (width < 0 || height < 0) {
throw new IllegalArgumentException("Requested dimensions are too small: " + width + 'x' +
height);
}
ErrorCorrectionLevel errorCorrectionLevel = ErrorCorrectionLevel.L;
int quietZone = QUIET_ZONE_SIZE;
if (hints != null) {
if (hints.containsKey(EncodeHintType.ERROR_CORRECTION)) {
errorCorrectionLevel = ErrorCorrectionLevel.valueOf(hints.get(EncodeHintType.ERROR_CORRECTION).toString());
}
if (hints.containsKey(EncodeHintType.MARGIN)) {
quietZone = Integer.parseInt(hints.get(EncodeHintType.MARGIN).toString());
}
}
//没有涉及到宽高,仅仅和内容相关,那么我们的内容变成二维码就是这里
QRCode code = Encoder.encode(contents, errorCorrectionLevel, hints);
//和宽高、以及刚刚生成的二维码相关,其中还有一个quietZone参数。
return renderResult(code, width, height, quietZone);
}
// Note that the input matrix uses 0 == white, 1 == black, while the output matrix uses
// 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap).
// 假定初始输出的width为100,height为100
private static BitMatrix renderResult(QRCode code, int width, int height, int quietZone) {
ByteMatrix input = code.getMatrix();
//计算出来的二维码大小,假设二维码最小大小为21
int inputWidth = input.getWidth();
int inputHeight = input.getHeight();
//计算留白空间,设的0会在这里生效
int qrWidth = inputWidth + (quietZone * 2);
int qrHeight = inputHeight + (quietZone * 2);
//计算二维码大小和我们提供给系统的尺寸比较,取最大值。
int outputWidth = Math.max(width, qrWidth);
int outputHeight = Math.max(height, qrHeight);
//计算二维码与提供尺寸的倍率关系,用于放大缩小。如100/21=4
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.
//上述主要解释leftPadding和topPadding右边的计算赋值是什么意思。
//计算左上分别空多少空间,(100-21*4)=8
int leftPadding = (outputWidth - (inputWidth * multiple)) / 2;
int topPadding = (outputHeight - (inputHeight * multiple)) / 2;
//取尺寸最大值的画布大小
BitMatrix output = new BitMatrix(outputWidth, outputHeight);
//从空出的第8个像素点开始,把二维码点1x1的结果放大至4x4写入画布中。
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;
}
可以看到,在renderResult方法中,QRCodeWriter直接是将原本二维码像素值直接以整数倍率扩增,因为内容的大小导致对应尺寸和二维码像素值无法整除关系,为了适应用户输入的尺寸,所以才产生了白边。
所以去白边,本质上是将100x100变成84x84这种情况。
那么我们直接重新实现Writer,把其他代码基本照抄,然后把renderResult改写。
PS:为什么不是继承重写,是因为QRCodeWriter是一个被final修饰的类,不允许继承。
白边解决方案
// Note that the input matrix uses 0 == white, 1 == black, while the output matrix uses
// 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap).
// 假定初始输出的width为100,height为100
private static BitMatrix renderResult(QRCode code, int width, int height, int quietZone) {
ByteMatrix input = code.getMatrix();
int inputWidth = input.getWidth();
int inputHeight = input.getHeight();
int qrWidth = inputWidth + (quietZone * 2);
int qrHeight = inputHeight + (quietZone * 2);
int outputWidth = Math.max(width, qrWidth);
int outputHeight = Math.max(height, qrHeight);
int multiple = Math.min(outputWidth / qrWidth, outputHeight / qrHeight);
outputWidth = qrWidth * multiple;// 改动点
outputHeight = qrWidth * multiple;// 改动点
// 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;
leftPadding = 0 ;//改动点
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;
}
如上,添加4行代码就可以完成去白边的功能需求。
启动代码
public static void main(String[] args) {
try {
String content = "{\"server\":4407}";
Integer width = 100;
Integer height = 100;
Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
hints.put(EncodeHintType.MARGIN, 0);
QCCodeWriterSelf writer = new QCCodeWriterSelf();//复制QCCodeWriter实现的类,仅仅添加了上述说明的4行代码
BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
MatrixToImageWriter.writeToStream(bitMatrix, "jpg", new FileOutputStream("你好.jpg"));
}
catch (Exception e) {
e.printStackTrace();
}
}
文件图片结果如下所示
结论
二维码的生成分为两部分:
第一部分是根据你的内容生成对应的二维码大小,如上图二维码的最小大小为21x21.
第二部分是根据用户输入的大小,如100x100就是先扩大成84x84,剩余16x16就变成4个方位的8x8白边。
因此白边是可以去除的,但是去除后白边的二维码因为是21*21,只能整数倍放大,做不到浮点值放大,因为最小单元像素点不能够再划分。