Java - 使用ZXing生成解析一维码和二维码
什么是ZXing
ZXing是一个开放源代码的多格式1D/2D条码图像处理库,采用Java实现。
要实现的功能
- 输入内容生成条码或二维码。
- 解析图片中的二维码。
一维码生成解析
import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Map;
/**
* @author Flicker
*/
public class BarCode {
private static final String FORMAT = "png";
/**
* 生成条形码
* 条形码的宽度不能等于图片的宽度,否则解析不出来,如果解析不出来,请加大offset的值
*
* @param contents 内容
* @param dest 条形码图片地址
* @param width 宽度
* @param height 高度
* @param offset 偏移量
* @throws WriterException
* @throws FileNotFoundException
* @throws IOException
*/
public static void encode(String contents, String dest, int width, int height, int offset) throws WriterException, FileNotFoundException, IOException {
contents = new String(contents.getBytes("UTF-8"), "ISO-8859-1");
//这里是生成CODE-39条形码,如果生成EAN-13条形码,请将CODE_36改成EAN_13,并在生成时先校验内容。
BitMatrix matrix = new MultiFormatWriter().encode(contents, BarcodeFormat.CODE_39, width - offset, height);
MatrixToImageWriter.writeToStream(matrix, FORMAT, new FileOutputStream(new File(dest)));
}
/**
* 解析条形码
*
* @param dest 要解码的图片地址
* @return String 条形码内容
* @throws IOException
* @throws NotFoundException
*/
public static String decode(String dest) throws IOException {
BufferedImage image = ImageIO.read(new File(dest));
LuminanceSource source = new BufferedImageLuminanceSource(image);
BinaryBitmap imageBinaryBitmap = new BinaryBitmap(new HybridBinarizer(source));
MultiFormatReader multiFormatReader = new MultiFormatReader();
try {
Result result;
result = multiFormatReader.decode(imageBinaryBitmap);
return result.getText();
} catch (NotFoundException e) {
return "图片中没有条形码";
}
}
/**
* 条形码校验
* 参考:http://baike.baidu.com/view/13740.htm?fr=aladdin 百度百科-条形码
*
* @return String 校验码
* @throws Exception
*/
public static String checksum(String countryCode, String factoryCode, String productCode) throws Exception {
String temp = countryCode + factoryCode + productCode;
if (!(isNumber(countryCode) && isNumber(factoryCode) && isNumber(productCode))) {
throw new Exception("不能含有非数字字符");
}
if (countryCode.length() != 3) {
throw new Exception("国家地区代码不合规范,必须3位");
}
if (factoryCode.length() != 5) {
throw new Exception("厂商代码不合规范,必须5位");
}
if (productCode.length() != 4) {
throw new Exception("产品代码不合规范,必须4位");
}
char[] code = temp.toCharArray();
int oddSum = 0;
int evenSum = 0;
for (int i = 0; i < code.length; i++) {
if ((i + 1) % 2 == 1) {
oddSum += Integer.valueOf(code[i] + "");
} else {
evenSum += Integer.valueOf(code[i] + "");
}
}
int digit = (10 - ((oddSum + evenSum * 3) % 10)) % 10;
return temp + digit;
}
/**
* 校验数字
*
* @param number 数字
* @return Boolean
*/
public static boolean isNumber(String number) {
if (null == number || "".equals(number)) {
return false;
}
String regex = "[0-9]*";
return number.matches(regex);
}
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//EAN-13条形码才需要校验
//System.out.println("校验并写入:" + checksum("695", "32321", "2155"));
BarCode.encode("QWE456789", "D:\\test\\BarCode.png", 400, 40, 20);
System.out.println("解析结果:" + BarCode.decode("D:\\test\\BarCode.jpg"));
}
}
二维码生成解析
import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
import com.google.zxing.qrcode.QRCodeWriter;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class QRCode {
private static final String FORMAT = "png";
/**
* 生成二维码
*
* @param contents 内容
* @param dest 生成二维码图片地址
* @param width 宽度
* @param height 高度
* @throws WriterException
* @throws FileNotFoundException
* @throws IOException
*/
public static void encode(String contents, String dest, int width, int height) throws WriterException, IOException {
contents = new String(contents.getBytes("UTF-8"), "ISO-8859-1");
QRCodeWriter writer = new QRCodeWriter();
BitMatrix matrix = writer.encode(contents, BarcodeFormat.QR_CODE, width, height);
MatrixToImageWriter.writeToStream(matrix, FORMAT, new FileOutputStream(new File(dest)));
}
/**
* 解析二维码
*
* @param dest 目标地址
* @return String 二维码信息
* @throws IOException
* @throws ChecksumException
* @throws FormatException
*/
public static String decode(String dest) throws IOException, ChecksumException, FormatException {
QRCodeReader reader = new QRCodeReader();
//MultiFormatReader reader = new MultiFormatReader();
//Map<DecodeHintType, Object> tmpHintsMap = new EnumMap<>(DecodeHintType.class);
//tmpHintsMap.put(DecodeHintType.CHARACTER_SET,"UTF-8");
//tmpHintsMap.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
BufferedImage image = ImageIO.read(new File(dest));
LuminanceSource source = new BufferedImageLuminanceSource(image);
Binarizer binarizer = new HybridBinarizer(source);
BinaryBitmap imageBinaryBitmap = new BinaryBitmap(binarizer);
try {
Result result = reader.decode(imageBinaryBitmap);
// Result result = reader.decode(imageBinaryBitmap, tmpHintsMap);
// System.out.println("result = "+ result.toString());
// System.out.println("resultFormat = "+ result.getBarcodeFormat());
// System.out.println("resultText = "+ result.getText());
return result.getText();
} catch (NotFoundException e) {
return "图片中未发现二维码";
}
}
public static void main(String[] args) throws WriterException, IOException, NotFoundException, ChecksumException, FormatException {
QRCode.encode("Hello World", "D:\\test\\QRCode.png", 200, 200);
System.out.println("解析结果:" + QRCode.decode("D:\\test\\QRCode.png"));
}
}
遇到的问题
最开始测试生成解析图片都没有问题,因为解析是直接解析生成的图片。
后面发现如果一维码在一张图片中(比如一张图片的某个角落有一条一维码),那么就解析不到一维码,二维码则没有问题。
然后开始找原因,发现还有一个带hints的解析方法。
/**
* Decode an image using the hints provided. Does not honor existing state.
*
* @param image The pixel data to decode
* @param hints The hints to use, clearing the previous state.
* @return The contents of the image
* @throws NotFoundException Any errors which occurred
*/
@Override
public Result decode(BinaryBitmap image, Map<DecodeHintType,?> hints) throws NotFoundException {
setHints(hints);
return decodeInternal(image);
}
打开DecodeHintType
,发现里面原来里面还有这么些东西,就不贴代码了,自己去看吧。
然后设置了hints,就能正常解析了,如下。
/**
* 解析条形码
*
* @param dest 要解码的图片地址
* @return String 条形码内容
* @throws IOException
* @throws NotFoundException
*/
public static String decode(String dest) throws IOException {
Map<DecodeHintType, Object> tmpHintsMap = new EnumMap<>(DecodeHintType.class);
tmpHintsMap.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
tmpHintsMap.put(DecodeHintType.POSSIBLE_FORMATS, EnumSet.allOf(BarcodeFormat.class));
tmpHintsMap.put(DecodeHintType.PURE_BARCODE, Boolean.FALSE);
BufferedImage image = ImageIO.read(new File(dest));
LuminanceSource source = new BufferedImageLuminanceSource(image);
BinaryBitmap imageBinaryBitmap = new BinaryBitmap(new HybridBinarizer(source));
MultiFormatReader multiFormatReader = new MultiFormatReader();
try {
Result result;
result = multiFormatReader.decode(imageBinaryBitmap, tmpHintsMap);
return result.getText();
} catch (NotFoundException e) {
return "图片中没有条形码";
}
}
参考资料
当前页面是本站的「Google AMP」版。查看和发表评论请点击:完整版 »