@关于Zxing 生成地二维码去除白边, 设置的MARGIN 当成像素空白而不是按照比例
Zxing 去除多余的白边
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.Writer;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.google.zxing.qrcode.encoder.ByteMatrix;
import com.google.zxing.qrcode.encoder.Encoder;
import com.google.zxing.qrcode.encoder.QRCode;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.Map;
/**
* Author:wz
*/
public class QRCodeDemo1 implements Writer {
private static final int QUIET_ZONE_SIZE = 4;
private static String s = "www.zkong.com";
public static void main(String[] args) throws Exception {
new QRCodeDemo1().createQRCode(s, 120, 120);
}
/**
* 生成二维码方法
*
* @param content
* @param width
* @param height
* @return
* @throws Exception
*/
public void createQRCode(String content, int width, int height) throws Exception {
HashMap<EncodeHintType, Comparable> hints = new HashMap<EncodeHintType, Comparable>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
hints.put(EncodeHintType.MARGIN, 2);
BitMatrix bitMatrix = encode(content, BarcodeFormat.QR_CODE, width, height, hints);
BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(bitMatrix);
ImageIO.write(bufferedImage, "bmp", new FileOutputStream(new File("d://testQRcode_n.bmp")));
}
@Override
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height)
throws WriterException {
return encode(contents, format, width, height, null);
}
@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);
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).
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 outputWidth = width % inputWidth == 0 ? width : (width / inputWidth + 1) * inputWidth;
int outputHeight = height % inputHeight == 0 ? height : (height / inputHeight + 1) * inputHeight;
int multiple = Math.min(outputWidth / inputWidth, outputHeight / inputHeight);
// 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 = quietZone;
int topPadding = quietZone;
BitMatrix output = new BitMatrix(outputWidth + quietZone * 2, outputHeight + quietZone * 2);
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;
}
}
第一次发博客,时间很晚要睡觉了,有问题欢迎留言$
下面更新一下条形码 Code128 格式的去除白边
import com.google.zxing.*;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* Author wz
*/
public class CodeBarDemo2 implements Writer {
public static void main(String[] args) throws Exception {
getCodeBar("A0A3B807F372", 335, 40);
/*long l = System.currentTimeMillis();
BitMatrix encode = new MultiFormatWriter().encode("www.zkong.com.cn", BarcodeFormat.CODE_128, 250, 40);
BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(encode);
ImageIO.write(bufferedImage, "bmp", new FileOutputStream(new File("d://testBarcode.bmp")));
System.out.println("耗时:" + (System.currentTimeMillis() - l));*/
}
/**
* 生成条码方法
*
* @param content
* @param width
* @param height
* @return
* @throws Exception
*/
public static void getCodeBar(String content, int width, int height) throws Exception {
HashMap<EncodeHintType, Comparable> hints = new HashMap<EncodeHintType, Comparable>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
hints.put(EncodeHintType.MARGIN, 3);
BitMatrix encode = new CodeBarDemo2().encode(content, BarcodeFormat.CODE_128, width, height, hints);
BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(encode);
ImageIO.write(bufferedImage, "bmp", new FileOutputStream(new File("d://testBarcode_1.bmp")));
}
@Override
public final BitMatrix encode(String contents, BarcodeFormat format, int width, int height)
throws WriterException {
return encode(contents, format, width, height, null);
}
/**
* Encode the contents following specified format.
* {@code width} and {@code height} are required size. This method may return bigger size
* {@code BitMatrix} when specified size is too small. The user can set both {@code width} and
* {@code height} to zero to get minimum size barcode. If negative value is set to {@code width}
* or {@code height}, {@code IllegalArgumentException} is thrown.
*/
@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 = 2;
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);
}
/**
* @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;
int fullWidth = inputWidth;
int outputWidth;
if (width % inputWidth == 0) {
outputWidth = width;
}
outputWidth = width > inputWidth ? width / inputWidth * inputWidth : (width / inputWidth + 1) * inputWidth;
int outputHeight = Math.max(1, height);
int multiple = outputWidth / fullWidth;
int leftPadding = sidesMargin;
// System.out.println(outputWidth);
// System.out.println(outputHeight);
// System.out.println(multiple);
BitMatrix output = new BitMatrix(outputWidth + 2 * sidesMargin, outputHeight);
for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) {
if (code[inputX]) {
output.setRegion(outputX, 0, multiple, outputHeight);
}
}
return output;
}
/**
* @param target encode black/white pattern into this array
* @param pos position to start encoding at in {@code target}
* @param pattern lengths of black/white runs to encode
* @param startColor starting color - false for white, true for black
* @return the number of elements added to target.
*/
protected static int appendPattern(boolean[] target, int pos, int[] pattern, boolean startColor) {
boolean color = startColor;
int numAdded = 0;
for (int len : pattern) {
for (int j = 0; j < len; j++) {
target[pos++] = color;
}
numAdded += len;
color = !color; // flip color after each segment
}
return numAdded;
}
public boolean[] encode(String contents) {
int length = contents.length();
// Check length
if (length < 1 || length > 80) {
throw new IllegalArgumentException(
"Contents length should be between 1 and 80 characters, but got " + length);
}
// Check content
for (int i = 0; i < length; i++) {
char c = contents.charAt(i);
switch (c) {
case ESCAPE_FNC_1:
case ESCAPE_FNC_2:
case ESCAPE_FNC_3:
case ESCAPE_FNC_4:
break;
default:
if (c > 127) {
// support for FNC4 isn't implemented, no full Latin-1 character set available at the moment
throw new IllegalArgumentException("Bad character in input: " + c);
}
}
}
Collection<int[]> patterns = new ArrayList<>(); // temporary storage for patterns
int checkSum = 0;
int checkWeight = 1;
int codeSet = 0; // selected code (CODE_CODE_B or CODE_CODE_C)
int position = 0; // position in contents
while (position < length) {
//Select code to use
int newCodeSet = chooseCode(contents, position, codeSet);
//Get the pattern index
int patternIndex;
if (newCodeSet == codeSet) {
// Encode the current character
// First handle escapes
switch (contents.charAt(position)) {
case ESCAPE_FNC_1:
patternIndex = CODE_FNC_1;
break;
case ESCAPE_FNC_2:
patternIndex = CODE_FNC_2;
break;
case ESCAPE_FNC_3:
patternIndex = CODE_FNC_3;
break;
case ESCAPE_FNC_4:
if (codeSet == CODE_CODE_A) {
patternIndex = CODE_FNC_4_A;
} else {
patternIndex = CODE_FNC_4_B;
}
break;
default:
// Then handle normal characters otherwise
switch (codeSet) {
case CODE_CODE_A:
patternIndex = contents.charAt(position) - ' ';
if (patternIndex < 0) {
// everything below a space character comes behind the underscore in the code patterns table
patternIndex += '`';
}
break;
case CODE_CODE_B:
patternIndex = contents.charAt(position) - ' ';
break;
default:
// CODE_CODE_C
patternIndex = Integer.parseInt(contents.substring(position, position + 2));
position++; // Also incremented below
break;
}
}
position++;
} else {
// Should we change the current code?
// Do we have a code set?
if (codeSet == 0) {
// No, we don't have a code set
switch (newCodeSet) {
case CODE_CODE_A:
patternIndex = CODE_START_A;
break;
case CODE_CODE_B:
patternIndex = CODE_START_B;
break;
default:
patternIndex = CODE_START_C;
break;
}
} else {
// Yes, we have a code set
patternIndex = newCodeSet;
}
codeSet = newCodeSet;
}
// Get the pattern
patterns.add(CODE_PATTERNS[patternIndex]);
// Compute checksum
checkSum += patternIndex * checkWeight;
if (position != 0) {
checkWeight++;
}
}
// Compute and append checksum
checkSum %= 103;
patterns.add(CODE_PATTERNS[checkSum]);
// Append stop code
patterns.add(CODE_PATTERNS[CODE_STOP]);
// Compute code width
int codeWidth = 0;
for (int[] pattern : patterns) {
for (int width : pattern) {
codeWidth += width;
}
}
// Compute result
boolean[] result = new boolean[codeWidth];
int pos = 0;
for (int[] pattern : patterns) {
pos += appendPattern(result, pos, pattern, true);
}
return result;
}
private static CType findCType(CharSequence value, int start) {
int last = value.length();
if (start >= last) {
return CType.UNCODABLE;
}
char c = value.charAt(start);
if (c == ESCAPE_FNC_1) {
return CType.FNC_1;
}
if (c < '0' || c > '9') {
return CType.UNCODABLE;
}
if (start + 1 >= last) {
return CType.ONE_DIGIT;
}
c = value.charAt(start + 1);
if (c < '0' || c > '9') {
return CType.ONE_DIGIT;
}
return CType.TWO_DIGITS;
}
private static int chooseCode(CharSequence value, int start, int oldCode) {
CType lookahead = findCType(value, start);
if (lookahead == CType.ONE_DIGIT) {
return CODE_CODE_B;
}
if (lookahead == CType.UNCODABLE) {
if (start < value.length()) {
char c = value.charAt(start);
if (c < ' ' || (oldCode == CODE_CODE_A && c < '`')) {
// can continue in code A, encodes ASCII 0 to 95
return CODE_CODE_A;
}
}
return CODE_CODE_B; // no choice
}
if (oldCode == CODE_CODE_C) { // can continue in code C
return CODE_CODE_C;
}
if (oldCode == CODE_CODE_B) {
if (lookahead == CType.FNC_1) {
return CODE_CODE_B; // can continue in code B
}
// Seen two consecutive digits, see what follows
lookahead = findCType(value, start + 2);
if (lookahead == CType.UNCODABLE || lookahead == CType.ONE_DIGIT) {
return CODE_CODE_B; // not worth switching now
}
if (lookahead == CType.FNC_1) { // two digits, then FNC_1...
lookahead = findCType(value, start + 3);
if (lookahead == CType.TWO_DIGITS) { // then two more digits, switch
return CODE_CODE_C;
} else {
return CODE_CODE_B; // otherwise not worth switching
}
}
// At this point, there are at least 4 consecutive digits.
// Look ahead to choose whether to switch now or on the next round.
int index = start + 4;
while ((lookahead = findCType(value, index)) == CType.TWO_DIGITS) {
index += 2;
}
if (lookahead == CType.ONE_DIGIT) { // odd number of digits, switch later
return CODE_CODE_B;
}
return CODE_CODE_C; // even number of digits, switch now
}
// Here oldCode == 0, which means we are choosing the initial code
if (lookahead == CType.FNC_1) { // ignore FNC_1
lookahead = findCType(value, start + 1);
}
if (lookahead == CType.TWO_DIGITS) { // at least two digits, start in code C
return CODE_CODE_C;
}
return CODE_CODE_B;
}
private static final int CODE_START_A = 103;
private static final int CODE_START_B = 104;
private static final int CODE_START_C = 105;
private static final int CODE_CODE_A = 101;
private static final int CODE_CODE_B = 100;
private static final int CODE_CODE_C = 99;
private static final int CODE_STOP = 106;
// Dummy characters used to specify control characters in input
private static final char ESCAPE_FNC_1 = '\u00f1';
private static final char ESCAPE_FNC_2 = '\u00f2';
private static final char ESCAPE_FNC_3 = '\u00f3';
private static final char ESCAPE_FNC_4 = '\u00f4';
private static final int CODE_FNC_1 = 102; // Code A, Code B, Code C
private static final int CODE_FNC_2 = 97; // Code A, Code B
private static final int CODE_FNC_3 = 96; // Code A, Code B
private static final int CODE_FNC_4_A = 101; // Code A
private static final int CODE_FNC_4_B = 100; // Code B
// Results of minimal lookahead for code C
private enum CType {
UNCODABLE,
ONE_DIGIT,
TWO_DIGITS,
FNC_1
}
static final int[][] CODE_PATTERNS = {
{2, 1, 2, 2, 2, 2}, // 0
{2, 2, 2, 1, 2, 2},
{2, 2, 2, 2, 2, 1},
{1, 2, 1, 2, 2, 3},
{1, 2, 1, 3, 2, 2},
{1, 3, 1, 2, 2, 2}, // 5
{1, 2, 2, 2, 1, 3},
{1, 2, 2, 3, 1, 2},
{1, 3, 2, 2, 1, 2},
{2, 2, 1, 2, 1, 3},
{2, 2, 1, 3, 1, 2}, // 10
{2, 3, 1, 2, 1, 2},
{1, 1, 2, 2, 3, 2},
{1, 2, 2, 1, 3, 2},
{1, 2, 2, 2, 3, 1},
{1, 1, 3, 2, 2, 2}, // 15
{1, 2, 3, 1, 2, 2},
{1, 2, 3, 2, 2, 1},
{2, 2, 3, 2, 1, 1},
{2, 2, 1, 1, 3, 2},
{2, 2, 1, 2, 3, 1}, // 20
{2, 1, 3, 2, 1, 2},
{2, 2, 3, 1, 1, 2},
{3, 1, 2, 1, 3, 1},
{3, 1, 1, 2, 2, 2},
{3, 2, 1, 1, 2, 2}, // 25
{3, 2, 1, 2, 2, 1},
{3, 1, 2, 2, 1, 2},
{3, 2, 2, 1, 1, 2},
{3, 2, 2, 2, 1, 1},
{2, 1, 2, 1, 2, 3}, // 30
{2, 1, 2, 3, 2, 1},
{2, 3, 2, 1, 2, 1},
{1, 1, 1, 3, 2, 3},
{1, 3, 1, 1, 2, 3},
{1, 3, 1, 3, 2, 1}, // 35
{1, 1, 2, 3, 1, 3},
{1, 3, 2, 1, 1, 3},
{1, 3, 2, 3, 1, 1},
{2, 1, 1, 3, 1, 3},
{2, 3, 1, 1, 1, 3}, // 40
{2, 3, 1, 3, 1, 1},
{1, 1, 2, 1, 3, 3},
{1, 1, 2, 3, 3, 1},
{1, 3, 2, 1, 3, 1},
{1, 1, 3, 1, 2, 3}, // 45
{1, 1, 3, 3, 2, 1},
{1, 3, 3, 1, 2, 1},
{3, 1, 3, 1, 2, 1},
{2, 1, 1, 3, 3, 1},
{2, 3, 1, 1, 3, 1}, // 50
{2, 1, 3, 1, 1, 3},
{2, 1, 3, 3, 1, 1},
{2, 1, 3, 1, 3, 1},
{3, 1, 1, 1, 2, 3},
{3, 1, 1, 3, 2, 1}, // 55
{3, 3, 1, 1, 2, 1},
{3, 1, 2, 1, 1, 3},
{3, 1, 2, 3, 1, 1},
{3, 3, 2, 1, 1, 1},
{3, 1, 4, 1, 1, 1}, // 60
{2, 2, 1, 4, 1, 1},
{4, 3, 1, 1, 1, 1},
{1, 1, 1, 2, 2, 4},
{1, 1, 1, 4, 2, 2},
{1, 2, 1, 1, 2, 4}, // 65
{1, 2, 1, 4, 2, 1},
{1, 4, 1, 1, 2, 2},
{1, 4, 1, 2, 2, 1},
{1, 1, 2, 2, 1, 4},
{1, 1, 2, 4, 1, 2}, // 70
{1, 2, 2, 1, 1, 4},
{1, 2, 2, 4, 1, 1},
{1, 4, 2, 1, 1, 2},
{1, 4, 2, 2, 1, 1},
{2, 4, 1, 2, 1, 1}, // 75
{2, 2, 1, 1, 1, 4},
{4, 1, 3, 1, 1, 1},
{2, 4, 1, 1, 1, 2},
{1, 3, 4, 1, 1, 1},
{1, 1, 1, 2, 4, 2}, // 80
{1, 2, 1, 1, 4, 2},
{1, 2, 1, 2, 4, 1},
{1, 1, 4, 2, 1, 2},
{1, 2, 4, 1, 1, 2},
{1, 2, 4, 2, 1, 1}, // 85
{4, 1, 1, 2, 1, 2},
{4, 2, 1, 1, 1, 2},
{4, 2, 1, 2, 1, 1},
{2, 1, 2, 1, 4, 1},
{2, 1, 4, 1, 2, 1}, // 90
{4, 1, 2, 1, 2, 1},
{1, 1, 1, 1, 4, 3},
{1, 1, 1, 3, 4, 1},
{1, 3, 1, 1, 4, 1},
{1, 1, 4, 1, 1, 3}, // 95
{1, 1, 4, 3, 1, 1},
{4, 1, 1, 1, 1, 3},
{4, 1, 1, 3, 1, 1},
{1, 1, 3, 1, 4, 1},
{1, 1, 4, 1, 3, 1}, // 100
{3, 1, 1, 1, 4, 1},
{4, 1, 1, 1, 3, 1},
{2, 1, 1, 4, 1, 2},
{2, 1, 1, 2, 1, 4},
{2, 1, 1, 2, 3, 2}, // 105
{2, 3, 3, 1, 1, 1, 2}
};
}