Java实现二维码编码与解码
1、构建maven项目,导入对应依赖
这里引用谷歌的zxing包实现二维码的编码与解码,导入依赖如下所示
<!-- 谷歌二维码 -->
<dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.3.0</version>
</dependency>
2、编写编码与解码方法
二维码生成工具类如下所示
import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Base64;
import java.util.Hashtable;
import javax.imageio.ImageIO;import com.google.zxing.*;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;public class QrCodeUtil {private static final String CHARSET = "utf-8";private static final String IMAGE_SUFFIX = "JPG";/*** 二维码尺寸*/private static final int QRCODE_SIZE = 300;/*** LOGO宽度*/private static final int WIDTH = 60;/*** LOGO高度*/private static final int HEIGHT = 60;/*** 生成二维码图片, 可自定义容错率* @param content 二维码内容* @param logoPath logo图片路径* @param needCompress 是否需要压缩* @param level L-7% M-15% Q-25% H-30% 容错级别* @return* @throws Exception*/private static BufferedImage createImage(String content, String logoPath, boolean needCompress, ErrorCorrectionLevel level) throws Exception {Hashtable hints = new Hashtable();hints.put(EncodeHintType.ERROR_CORRECTION, level);hints.put(EncodeHintType.CHARACTER_SET, CHARSET);hints.put(EncodeHintType.MARGIN, 1);//生成二维码BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints);int width = bitMatrix.getWidth();int height = bitMatrix.getHeight();BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);//构建图片for (int x = 0; x < width; x++) {for (int y = 0; y < height; y++) {image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);}}if (logoPath == null || "".equals(logoPath)) {return image;}// 插入图片,即中间显示的logoinsertImage(image, logoPath, needCompress);return image;}/*** 生成二维码图片* @param content 二维码文字内容* @param logoPath logo图片路径* @param needCompress 是否需要压缩* @return* @throws Exception*/private static BufferedImage createImage(String content, String logoPath, boolean needCompress) throws Exception {return createImage(content, logoPath, needCompress, ErrorCorrectionLevel.H);}/*** 往二维码插入图片(logo)* @param source 二维码图片* @param imgPath logo路径* @param needCompress 是否需要压缩* @throws Exception*/private static void insertImage(BufferedImage source, String imgPath, boolean needCompress) throws Exception {File file = new File(imgPath);if (!file.exists()) {System.err.println("" + imgPath + " 该文件不存在!");return;}//获取源图片Image image = ImageIO.read(new File(imgPath));int width = image.getWidth(null);int height = image.getHeight(null);// 压缩LOGOif (needCompress) {width = width > WIDTH ? WIDTH : width;height = height > HEIGHT ? HEIGHT : height;image = image.getScaledInstance(width, height, Image.SCALE_SMOOTH);BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);Graphics g = tag.getGraphics();// 绘制缩小后的图g.drawImage(image, 0, 0, null);g.dispose();}// 插入LOGOGraphics2D graph = source.createGraphics();int x = (QRCODE_SIZE - width) / 2;int y = (QRCODE_SIZE - height) / 2;graph.drawImage(image, x, y, width, height, null);Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);graph.setStroke(new BasicStroke(3f));graph.draw(shape);graph.dispose();}/*** 编码生成二维码图片,固化到硬盘* @param content 二维码文字内容* @param logoPath 插入的logo路径* @param destPath 生成的二维码输出路径* @param needCompress 是否需要压缩* @param level 容错率* @throws Exception*/public static void encode(String content, String logoPath, String destPath, boolean needCompress, ErrorCorrectionLevel level) throws Exception {mkdirs(destPath);ImageIO.write(createImage(content, logoPath, needCompress, level), IMAGE_SUFFIX, new File(destPath));}/*** 编码生成二维码图片,固化到硬盘* @param content 二维码文字内容* @param logoPath logo图片路径* @param destPath 生成的二维码输出路径* @param needCompress 是否需要压缩* @throws Exception*/public static void encode(String content, String logoPath, String destPath, boolean needCompress) throws Exception {mkdirs(destPath);ImageIO.write(createImage(content, logoPath, needCompress), IMAGE_SUFFIX, new File(destPath));}/*** 编码生成二维码图片,固化到硬盘* @param content 二维码文字内容* @param logoPath logo图片路径* @param destPath 生成的二维码输出路径* @throws Exception*/public static void encode(String content, String logoPath, String destPath) throws Exception {encode(content, logoPath, destPath, false);}/*** 编码生成二维码图片,固化到硬盘* @param content 二维码文字内容* @param destPath 生成的二维码输出路径* @throws Exception*/public static void encode(String content, String destPath) throws Exception {encode(content, null, destPath, false);}/*** 编码生成二维码图片,输出到流* @param content 二维码文字内容* @param logoPath logo图片路径* @param output 输出流* @param needCompress 是否需要压缩* @throws Exception*/public static void encode(String content, String logoPath, OutputStream output, boolean needCompress) throws Exception {ImageIO.write(createImage(content, logoPath, needCompress), IMAGE_SUFFIX, output);}/*** 编码生成二维码图片,输出到流* @param content 二维码文字内容* @param output 输出流* @throws Exception*/public static void encode(String content, OutputStream output) throws Exception {encode(content, null, output, false);}/*** 编码生成二维码图片,转化为base64字符串* @param content 二维码文字内容* @param imgPath logo图片路径* @param needCompress 是否需要压缩* @param level 容错率* @param imageSuffix 生成的图片后缀* @return* @throws Exception*/public static String encode(String content, String imgPath, boolean needCompress, ErrorCorrectionLevel level, String imageSuffix) throws Exception {imageSuffix = (imageSuffix == null || "".equals(imageSuffix)) ? IMAGE_SUFFIX : imageSuffix;BufferedImage image = createImage(content, imgPath, needCompress, level);ByteArrayOutputStream stream = new ByteArrayOutputStream();ImageIO.write(image, imageSuffix, stream);return Base64.getEncoder().encodeToString(stream.toByteArray());}/*** 编码生成二维码图片,直接返回图片对象* @param content 二维码文字内容* @param logoPath logo图片路径* @param needCompress 是否需要压缩* @return* @throws Exception*/public static BufferedImage encode(String content, String logoPath, boolean needCompress) throws Exception {return createImage(content, logoPath, needCompress);}/*** 二维码解码读取文字信息* @param image 二维码图片* @return* @throws Exception*/public static String decode(BufferedImage image) throws Exception {if (image == null) { return null; }BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));Hashtable hints = new Hashtable();//设置编码方式hints.put(DecodeHintType.CHARACTER_SET, CHARSET);//优化精度,解决com.google.zxing.NotFoundExceptionhints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);//开启PURE_BARCODE模式(复杂模式)hints.put(DecodeHintType.PURE_BARCODE, Boolean.TRUE);Result result = new MultiFormatReader().decode(bitmap, hints);return result.getText();}/*** 二维码解码读取文字信息* @param file 二维码图片* @return* @throws Exception*/public static String decode(File file) throws Exception {return decode(ImageIO.read(file));}/*** 二维码解码读取文字信息* @param base64Str 二维码图片base64格式字符串* @return* @throws Exception*/public static String decode(String base64Str) throws Exception{return decode(ImageIO.read(new ByteArrayInputStream(Base64.getDecoder().decode(base64Str))));}/*** 创建文件夹* @param destPath 文件夹路径*/public static void mkdirs(String destPath) {File file = new File(destPath);// 当文件夹不存在时,mkdirs会自动创建多层目录,区别于mkdir.(mkdir如果父目录不存在则会抛出异常)if (!file.exists() && !file.isDirectory()) {file.mkdirs();}}public static class BufferedImageLuminanceSource extends LuminanceSource {private final BufferedImage image;private final int left;private final int top;public BufferedImageLuminanceSource(BufferedImage image) {this(image, 0, 0, image.getWidth(), image.getHeight());}public BufferedImageLuminanceSource(BufferedImage image, int left, int top, int width, int height) {super(width, height);int sourceWidth = image.getWidth();int sourceHeight = image.getHeight();if (left + width > sourceWidth || top + height > sourceHeight) {throw new IllegalArgumentException("Crop rectangle does not fit within image data.");}for (int y = top; y < top + height; y++) {for (int x = left; x < left + width; x++) {if ((image.getRGB(x, y) & 0xFF000000) == 0) {image.setRGB(x, y, 0xFFFFFFFF); // = white}}}this.image = new BufferedImage(sourceWidth, sourceHeight, BufferedImage.TYPE_BYTE_GRAY);this.image.getGraphics().drawImage(image, 0, 0, null);this.left = left;this.top = top;}@Overridepublic byte[] getRow(int y, byte[] row) {if (y < 0 || y >= getHeight()) {throw new IllegalArgumentException("Requested row is outside the image: " + y);}int width = getWidth();if (row == null || row.length < width) {row = new byte[width];}image.getRaster().getDataElements(left, top + y, width, 1, row);return row;}@Overridepublic byte[] getMatrix() {int width = getWidth();int height = getHeight();int area = width * height;byte[] matrix = new byte[area];image.getRaster().getDataElements(left, top, width, height, matrix);return matrix;}@Overridepublic boolean isCropSupported() {return true;}@Overridepublic LuminanceSource crop(int left, int top, int width, int height) {return new BufferedImageLuminanceSource(image, this.left + left, this.top + top, width, height);}@Overridepublic boolean isRotateSupported() {return true;}@Overridepublic LuminanceSource rotateCounterClockwise() {int sourceWidth = image.getWidth();int sourceHeight = image.getHeight();AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, sourceWidth);BufferedImage rotatedImage = new BufferedImage(sourceHeight, sourceWidth, BufferedImage.TYPE_BYTE_GRAY);Graphics2D g = rotatedImage.createGraphics();g.drawImage(image, transform, null);g.dispose();int width = getWidth();return new BufferedImageLuminanceSource(rotatedImage, top, sourceWidth - (left + width), getHeight(), width);}}
}
主要方法功能描述如下:
- createImage():生成二维码图片
createImage()重载了两个方法,其中 createImage(String content, String logoPath, boolean needCompress, ErrorCorrectionLevel level)方法可通过level参数调节二维码容错率;createImage(String content, String logoPath, boolean needCompress)方法使用固定的容错率:ErrorCorrectionLevel.H。
- insertImage():往二维码插入图片(logo),可以调用此方法在二维码中间位置插入一个logo
- encode():进行二维码编码
此方法重载了几个方法返回不同的结果,如:直接生成二维码图片固化到硬盘;生成BASE64字符串返回;直接返回BufferedImage图片对象。 - decode():对二维码进行解码,获取文字内容
3、编写测试代码
编写测试代码进行不同返回对象的测试,测试代码如下所示
public static void main(String[] args) throws Exception {// 存放在二维码中的内容String text = "使用 com.google.zxing 依赖生成二维码图片,encode()方法生成二维码图片,decode()方法将二维码解码获取文字内容\n" ;// 嵌入二维码的图片(logo)路径String imgPath = "E:/templates/0.jpg";// 生成的二维码的路径及名称String destPath = "E:/templates/qrcode/1.jpg";// 生成的二维码的路径及名称String destPath1 = "E:/templates/qrcode/2.jpg";//生成不带logo的二维码QrCodeUtil.encode(text, null, destPath, true, ErrorCorrectionLevel.L);//生成带logo的二维码QrCodeUtil.encode(text, imgPath, destPath1, true, ErrorCorrectionLevel.L);// 解析二维码String str = QrCodeUtil.decode(new File(destPath1));// 打印出解析出的内容System.out.println(str);//图片生成base64字符串String base64 = QrCodeUtil.encode(text, imgPath, true, ErrorCorrectionLevel.L, "png");System.out.println("\nbase64字符串:" + base64);System.out.println("\n二维码解码内容:" + QrCodeUtil.decode(base64));}
4、可能遇到的问题
- 解析二维码报错com.google.zxing.NotFoundException
原因:二维码所有的bit都是0,生成二维码时白色像素使用透明色填充。在显示时因为背景是白色,所以看上去和用手机扫都没有问题,但是在代码识别的时候会把透明色识别为黑色,这样就导致整个二维码图片全是黑色像素,抛出com.google.zxing.NotFoundException异常。
解决方案:优化精度,解码时配置参数
//优化精度,解决com.google.zxing.NotFoundExceptionhints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);//开启PURE_BARCODE模式(复杂模式)hints.put(DecodeHintType.PURE_BARCODE, Boolean.TRUE);
- 扫码时由于文字太多无法识别
解决方案: 调整ErrorCorrectionLevel 参数,适当调整容错率(7%~30%)。
对应四个级别:
ErrorCorrectionLevel.L (7%)
ErrorCorrectionLevel.M (15%)
ErrorCorrectionLevel.Q (25%)
ErrorCorrectionLevel.H (30%)
容错率越高,二维码的有效像素点越多。
Java实现二维码编码与解码相关推荐
- Java利用QRCode.jar包实现二维码编码与解码
QRcode是日本人94年开发出来的.首先去QRCode的官网http://swetake.com/qrcode/java/qr_java.html,把要用的jar包下下来,导入到项目里去.qrcod ...
- 条形码和二维码编码解码工具类源码
有一个好的工具,会让你的开发事半功倍.再将讲这个工具类之前,我先给小白补充一点条形码和二维码(以下基础知识选自,我本科阶段的一本教材:<物联网导论>(刘云浩 编著).有对物联网感兴趣的,可 ...
- java二维码编码生成并转换成流传入前端页面
java二维码编码生成并转换成流传入前端页面 这里主要用了com.google.zxing的依赖,这个依赖主要可以完成图片叠加.二维码生成和图片加文字等功能. ①添加依赖 <dependency ...
- Java 生成二维码 zxing生成二维码 条形码 服务端生成二维码 Java生成条形码
Java 生成二维码 zxing生成二维码 条形码 服务端生成二维码 Java生成条形码 一.关于ZXing 1.ZXing是谷歌开源的支持二维码.条形码 等图形的生成类库:支持生成.和解码功能. G ...
- java 生成二维码后叠加LOGO并转换成base64
1.代码 见文末推荐 2.测试 测试1:生成base64码 public static void main(String[] args) throws Exception {String data = ...
- java实现二维码生成的几个方法
java实现二维码生成的几个方法 分类: J2EE2013-06-13 20:32 10390人阅读 评论(1) 收藏 举报 1: 使用SwetakeQRCode在Java项目中生成二维码 http ...
- java 生成 二维码
blog迁移至 : http://www.micmiu.com 周末试用下Android手机的二维码扫描软件,扫描了下火车票.名片等等,觉得非常不错很有意思的.当然Java也可以实现这些,现在就分享下 ...
- Java实现二维码生成与识别
java实现QRCODE二维码的编码与解码实例 众所周知,爪哇,是一种神奇的编程语言,用JAVA 实现某一个功能,只是随便上网找一些对应的实现JAR包即可,于是,有了像JAR114这样专门提供给 爪哇 ...
- java 生成二维码 QRCode、zxing 两种方式
版权声明:本文为 testcs_dn(微wx笑) 原创文章,非商用自由转载-保持署名-注明出处,谢谢. https://blog.csdn.net/testcs_dn/article/details/ ...
最新文章
- vue 热更新无反应_不吹不黑谈谈 vue 的 SFC 和 template
- Linux kdb命令
- stm32f103电子钟心得体会_浅谈STM32_RTC闹钟
- android webView的使用
- 数据库编程起别名的3中方式
- Unity按钮禁用和变灰
- Python数据分析学习
- 如何在生产环境下用好EFCore
- 【BZOJ4774】修路 [斯坦纳树]
- ApacheCN 交流社区一周热点 2019.4 wk1
- SAP License:SAP中的报表查询
- List求交并补集--IEqualityComparer实现
- bootstrap框架写手机端app模板也很漂亮
- 小白爬虫入门~python爬取职友集招聘职位信息
- 如何在WordPress菜单中显示图标[WordPress插件]
- 还爱着你心中曾经那朵红玫瑰吗?
- 十年带队经验,万字长文分享:如何管理好一个程序员团队?
- 如何一次打开多个Word文档
- c汇编语言例题,第三章 汇编语言程序设计例题习题
- python爬取知乎回答并进行舆情分析:爬取数据部分