Java如何生成花里胡哨的二维码

news/2024/4/19 10:57:23/文章来源:https://blog.csdn.net/lingbomanbu_lyl/article/details/127213204

目录

  • 一、序言
  • 二、找资料
    • 1、寻觅文档
    • 2、寻觅代码
  • 三、代码示例
    • 1、简单的二维码
    • 2、带颜色的二维码
    • 3、带logo的二维码
  • 四、工具类封装

一、序言

之前在做头马演讲俱乐部哼哈官可视化汇报报告时,为了方便大家移动端查看可视化报告,而不是通过点击链接这种生硬的方式,专门研究了下如何生成二维码。

Github上有个第三方库,来自google的 zxing,这个库能生成各种条形码,如:二维码、支付条形码等。下面是zxing支持的一些格式:
在这里插入图片描述
今天我们重点研究一下关于通过zxing生成二维码的一些参数,以及从哪里找到这些文档和介绍。



二、找资料

1、寻觅文档

有点小尴尬的是,zxing生成二维码Java相关的API并没有明确的相关解释以及使用示例,笔者也是在zxing的github上发现了一个在线生成二维码的网站,在线二维码生成器。
在这里插入图片描述

备注:这个网站需要翻墙,不然访问不了。

然后在Github上找到了这个在线二维码生成器的相关参数描述,这里就勉为其难地翻译一波吧。

在这里插入图片描述
这里重点介绍一下图中error_correction_level 这个参数,二维码支持4种级别的错误校正,错误校正主要用来做缺失、误读或者遮盖数据修复。二维码越冗余也就意味着只能存储更少的数据,错误校正级别主要有如下4级:

  • L - 默认级别,可以做到即使丢失7%的数据也能正常识别。
  • M - 中级,可以做到即使丢失15%的数据也能正常识别。
  • Q - 中上级,可以做到即使丢失25%的数据也能正常识别。
  • H - 高级,可以做到即使丢失30%的数据也能正常识别。

备注:所谓错误校正,说句大白话就是如果二维码有缺失,或者部分二维码有遮挡,还能不能被正常识别。级别越高,容错率也就越高。

当我们用不同级别生成二维码时,二维码的密集度也会不一样,错误校正级别越高,生成的二维码越分散。

2、寻觅代码

前面那个需要翻墙的在线二维码生成器实际上就是一个古老的Servlet应用,在zxing的源码里找到zxingorg这个目录,这就是那个在线二维码生成器的源码了。生成二维码的核心逻辑在ChartServlet这个类里,如下:
在这里插入图片描述
接下来我们直接在doEncode方法里就能找到生成二维码的逻辑,还是非常简单的,代码如下:

private static void doEncode(HttpServletRequest request, HttpServletResponse response, boolean isPost)throws IOException {ChartServletRequestParameters parameters;try {parameters = doParseParameters(request, isPost);} catch (IllegalArgumentException | NullPointerException e) {response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.toString());return;}Map<EncodeHintType,Object> hints = new EnumMap<>(EncodeHintType.class);hints.put(EncodeHintType.MARGIN, parameters.getMargin());if (!StandardCharsets.ISO_8859_1.equals(parameters.getOutputEncoding())) {// Only set if not QR code defaulthints.put(EncodeHintType.CHARACTER_SET, parameters.getOutputEncoding().name());}hints.put(EncodeHintType.ERROR_CORRECTION, parameters.getEcLevel());BitMatrix matrix;try {matrix = new QRCodeWriter().encode(parameters.getText(),BarcodeFormat.QR_CODE,parameters.getWidth(),parameters.getHeight(),hints);} catch (WriterException we) {response.sendError(HttpServletResponse.SC_BAD_REQUEST, we.toString());return;}String requestURI = request.getRequestURI();if (requestURI == null) {response.sendError(HttpServletResponse.SC_BAD_REQUEST);return;}int lastDot = requestURI.lastIndexOf('.');String imageFormat;if (lastDot > 0) {imageFormat = requestURI.substring(lastDot + 1).toUpperCase(Locale.ROOT);// Special-case jpg -> JPEGif ("JPG".equals(imageFormat)) {imageFormat = "JPEG";}} else {imageFormat = "PNG";}String contentType;switch (imageFormat) {case "PNG":contentType = "image/png";break;case "JPEG":contentType = "image/jpeg";break;case "GIF":contentType = "image/gif";break;default:throw new IllegalArgumentException("Unknown format " + imageFormat);}ByteArrayOutputStream imageOut = new ByteArrayOutputStream(1024);MatrixToImageWriter.writeToStream(matrix, imageFormat, imageOut);byte[] imageData = imageOut.toByteArray();response.setContentType(contentType);response.setContentLength(imageData.length);response.setHeader("Cache-Control", "public");response.getOutputStream().write(imageData);}


三、代码示例

首先引入zxing的依赖,如下:

<dependency><groupId>com.google.zxing</groupId><artifactId>javase</artifactId><version>3.5.0</version></dependency>

1、简单的二维码

由于平台上二维码图片会被当做违规,无法查看,因此这里就不贴二维码示例了。

Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, StandardCharsets.UTF_8.name());
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);String content = "https://www.baidu.com";
String qrCodePath = "C:\\Users\\mc\\Desktop\\qrcode.png";QRCodeWriter qrCodeWriter = new QRCodeWriter();
BitMatrix bitMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, 300, 300, hints);
MatrixToImageWriter.writeToPath(bitMatrix, "png", Paths.get(qrCodePath));

2、带颜色的二维码

Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, StandardCharsets.UTF_8.name());
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);String content = "https://www.baidu.com";
String qrCodePath = "C:\\Users\\mc\\Desktop\\qrcode.png";// 生成带颜色的二维码, 指定前景色和后景色即可
MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(Color.GREEN.getRGB(), Color.WHITE.getRGB());QRCodeWriter qrCodeWriter = new QRCodeWriter();
BitMatrix bitMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, 300, 300, hints);
MatrixToImageWriter.writeToPath(bitMatrix, "png", Paths.get(qrCodePath), matrixToImageConfig);

备注:带颜色的二维码只需加上MatrixToImageConfig参数即可。

3、带logo的二维码

我们都知道,微信二维码中间是不是带了个微信的logo,我们同样能实现,这里更多的是awt对图片的相关操作。

Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, StandardCharsets.UTF_8.name());
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);String content = "https://www.baidu.com";
String qrCodePath = "C:\\Users\\mc\\Desktop\\qrcode.png";
String logoPath = "C:\\Users\\mc\\Desktop\\logo_mini.png";QRCodeWriter qrCodeWriter = new QRCodeWriter();
BitMatrix bitMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, 300, 300, hints);// 写入输出流
ByteArrayOutputStream baos = new ByteArrayOutputStream();
MatrixToImageWriter.writeToStream(bitMatrix, DEFAULT_FORMAT, baos);ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
BufferedImage qrCodeImage = ImageIO.read(bais);
Graphics2D graphics2D = qrCodeImage.createGraphics();BufferedImage logoImage = ImageIO.read(Paths.get(logoPath).toFile());
// 这里将logo的位置居中
int logoX = (qrCodeImage.getWidth() - logoImage.getWidth()) / 2;
int logoY = (qrCodeImage.getHeight() - logoImage.getHeight()) / 2;
// 在二维码画布上绘图
graphics2D.drawImage(logoImage, null, logoX, logoY);
graphics2D.dispose();// 输出绘制后logo的二维码图片
ImageIO.write(qrCodeImage, "png", Paths.get(qrCodePath).toFile());

备注:这里需要注意一下logo的图片尺寸,占用太大会导致二维码无法识别,同时最好将error_correction_level设置为高级,增加容错率。



四、工具类封装

核心代码比较简单,随手简单封装了一下,zxing还是很强大的,点个赞。

/*** @author 刘亚楼* @date 2022/9/22*/
public abstract class QrCodeUtils {/*** 默认生成的文件*/private static final String DEFAULT_FORMAT = "png";/*** 默认额外参数:可设置字符集、容错级别*/private static final Map<EncodeHintType, Object> DEFAULT_HINTS = new HashMap<>();static {DEFAULT_HINTS.put(EncodeHintType.CHARACTER_SET, StandardCharsets.UTF_8.name());DEFAULT_HINTS.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);}/*** 生成绿码* @param content 二维码展示内容* @param width 二维码图片宽度* @param height 二维码图片高度* @return 图片二进制流* @throws Exception*/public static byte[] generateGreenQrCodeAsByteArray(String content, int width, int height) throws Exception {return generateQrCodeAsByteArray(content, width, height, Color.GREEN.getRGB(), Color.WHITE.getRGB());}/*** 生成二维码并转为二进制流* @param content 二维码展示内容* @param width 二维码图片宽度* @param height 二维码图片高度* @param onColorAsRGB 二维码数据图案颜色* @param offColorAsRGB 二维码背景色* @return 图片二进制流* @throws Exception*/public static byte[] generateQrCodeAsByteArray(String content, int width, int height, int onColorAsRGB, int offColorAsRGB) throws Exception {ByteArrayOutputStream baos = new ByteArrayOutputStream();generateQrCodeAsByteArray(baos, content, width, height, onColorAsRGB, offColorAsRGB);return baos.toByteArray();}/*** 生成二维码* @param os 输出流* @param content 二维码展示内容* @param width 二维码图片宽度* @param height 二维码图片高度* @param onColorAsRGB 二维码数据图案颜色* @param offColorAsRGB 二维码背景色* @throws Exception*/public static void generateQrCodeAsByteArray(OutputStream os, String content, int width, int height, int onColorAsRGB, int offColorAsRGB) throws Exception {QRCodeWriter qrCodeWriter = new QRCodeWriter();BitMatrix bitMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, width, height, DEFAULT_HINTS);MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(onColorAsRGB, offColorAsRGB);MatrixToImageWriter.writeToStream(bitMatrix, DEFAULT_FORMAT, os, matrixToImageConfig);}/*** 生成二维码* @param path 文件路径* @param content 二维码展示内容* @param width 二维码图片宽度* @param height 二维码图片高度* @param onColorAsRGB 二维码数据图案颜色* @param offColorAsRGB 二维码背景色* @throws Exception*/public static void generateQrCodeAsByteArray(String path, String content, int width, int height, int onColorAsRGB, int offColorAsRGB) throws Exception {QRCodeWriter qrCodeWriter = new QRCodeWriter();BitMatrix bitMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, width, height, DEFAULT_HINTS);MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(onColorAsRGB, offColorAsRGB);MatrixToImageWriter.writeToPath(bitMatrix, DEFAULT_FORMAT, Paths.get(path), matrixToImageConfig);}public static byte[] attachLogoInTheMiddle(InputStream qrCodeIs, InputStream logoIs) throws Exception {ByteArrayOutputStream baos = new ByteArrayOutputStream();attachLogoInTheMiddle(qrCodeIs, logoIs, baos);return baos.toByteArray();}/*** 二维码中间插入logo* @param qrCodeIs 二维码输入流* @param logoIs logo输入流* @param dest 输出路径* @throws Exception*/public static void attachLogoInTheMiddle(InputStream qrCodeIs, InputStream logoIs, OutputStream dest) throws Exception {BufferedImage qrCodeImage = ImageIO.read(qrCodeIs);BufferedImage logoImage = ImageIO.read(logoIs);Graphics2D graphics2D = qrCodeImage.createGraphics();// 这里将logo的位置居中int logoX = (qrCodeImage.getWidth() - logoImage.getWidth()) / 2;int logoY = (qrCodeImage.getHeight() - logoImage.getHeight()) / 2;graphics2D.drawImage(logoImage, null, logoX, logoY);graphics2D.dispose();ImageIO.write(qrCodeImage, DEFAULT_FORMAT, dest);}/*** 重置图片大小* @param rawImage 原图片* @param targetWidth 目标图片宽度* @param targetHeight 目标图片高度* @return*/public static BufferedImage resizeImage(BufferedImage rawImage, int targetWidth, int targetHeight) {Image scaledImage = rawImage.getScaledInstance(targetWidth, targetHeight, Image.SCALE_AREA_AVERAGING);BufferedImage resizedImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB);resizedImage.getGraphics().drawImage(scaledImage, 0, 0, null);return resizedImage;}}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_398791.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android 面试java知识小结

1.-1的二进制是多少&#xff0c;怎么算出来的&#xff1f; 1111 1111 在计算机里是以补码的形式存在的&#xff0c;那为什么要使用补码呢&#xff1f; 计算机中的有符号数有三种表示方法&#xff0c;即原码、反码和补码。三种表示方法均有符号位和数值位两部分&#xff0c;符号…

如何使用界面控件DevExpress WinForms自带的UI模板?其实很简单

DevExpress WinForm拥有180组件和UI库&#xff0c;能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForms能完美构建流畅、美观且易于使用的应用程序&#xff0c;无论是Office风格的界面&#xff0c;还是分析处理大批量的业务数据&#xff0c;它都能轻松胜任…

科研工具总结

科研工具总结 1、论文检索网站2、自己收集数据集----并构建数据集2.1数据集来演方式:3种3、怎么进行一个算法的调研?泛读论文:精读论文:1、论文检索网站 Connected papers:一个基于知识图谱的论文检索网站 特点:圆圈的半径越大表示论文越经典,引用数量比较多; 论文的新…

python与人工智能:KNN近邻法识别手写数字

机器学习分类&#xff1f; 1 特征&#xff08;feature&#xff09; 数据是区分事物和事物的关键。 举例&#xff1a;不同类型的书&#xff0c;我们用书的内容来对它进行分类 2 标签&#xff08;label&#xff09; 数据的标签&#xff0c;显示的分类结果。 举例&#xff1a;书属…

每日面试题2道、算法两道

目录 一、 面试题 i、i的自增问题 写一个Singleton实例 二、数组 算法 寻找数组的中心索引 搜索插入位置 一、 面试题 i、i的自增问题 /*** packageName: com.sofwin.mianshi* user: wentao* date: 2022/10/10 14:31* email 1660420659qq.com* description: i、i的 面…

(附源码)计算机毕业设计SSM志愿者活动管理平台

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

pytorch:本地使用tensorboard可视化

摘要&#xff1a; tensorboard是tensorflow用来可视化训练和测试过程的模块&#xff0c;而pytorch并没有可视化模块&#xff0c;但是pytoch1.2.0版本以上开始支持tensorboard。 目录一、 安装tensorboard二、 使用tensorboard1、首先导入模块&#xff1a;2、初始化&#xff1a;…

深度神经网络怎么用

深度学习 对硬件的要求 之前热衷于学习理论知识&#xff0c;目前想跑代码了发现不知道从何下手&#xff0c;自己电脑上搭建的平台基本就是个摆设&#xff0c;因为跑不起来呀。今天我们就来看看想做深度学习应该怎么下手。 首先了解下基础知识&#xff1a;1、深度学习用cpu训练…

2.Jenkins项目创建

Jenkins项目创建1.新建项目 2.创建一个freestyle的项目 3.填写描述信息 4.可以选择丢弃旧的构建 每次构建都会产生一个任务&#xff0c;这个任务想保留多少天&#xff0c;可以设置保留构建的天数 保留最大的个数&#xff1a;例如设置为10个&#xff0c;当任务达到了10个之…

Spring Rest Docs使用

今天给大家分享一个能通过代码自动生成文档技术&#xff0c;Spring Rest Doc过在单元测试中额外添加 API 信息描述&#xff0c;从而自动生成对应的文档片段。 下面通过一个简单的例子演示下如何快速上手的。在Spring Boot项目中添加maven 依赖 <dependency><groupId&g…

Android 使用Jenkins 自动化多渠道打包并且分发到蒲公英、下发到钉钉通知【即拿即用】

前言 一、tomcat 安装启动 二、jenkins war 包下载并安装 三、jenkins 配置教程 四、jenkins items 工程配置 五、android gradle 脚本编码 六、分发到蒲公英脚本编码以及七、通知钉钉逻辑编码 前言 Android 在每个版本测试阶段&#xff0c;通常会因为修复BUG 去验证&#x…

理解vue中的.sync和.$emit

首先来说一下 .sync 修饰符的作用 第一步&#xff1a;先用一句话解释 .sync修饰符可以实现子组件与父组件的双向绑定&#xff0c;并且可以实现子组件同步修改父组件的值。 第二步&#xff1a;具体解释 一般情况下&#xff0c;想要实现父子组件间值的传递&#xff0c;通常使用…

英文论文要怎么查重?

英文论文查重和中文查重一样&#xff0c;只是在渠道选择方面会有些许差别。今天就具体聊聊英文论文怎么查重&#xff0c;并向大家推荐几个比较常用的英文论文查重工具。 英文论文怎么查重&#xff1a; 1、论文为什么要查重 2、论文查重的原理 3、英文论文怎么查重 4、选择…

柳州楼顶种植水稻 国稻种芯·中国水稻节:广西12万亩米飘香

柳州楼顶种植水稻 国稻种芯中国水稻节&#xff1a;广西12万亩米飘香 广西新闻网-南国今报柳江讯&#xff08;记者钟华 通讯员梁睿&#xff09;新闻中国采编网 中国新闻采编网 谋定研究中国智库网 中国农民丰收节国际贸易促进会 国稻种芯中国水稻节 中国三农智库网-功能性农业农…

RabbitMQ常用消息模式

目录 1、RabitMQ工作队列 2、交换机 3、RabbitMQ Fanout 发布订阅--- Fanout exchange(扇型交换机) 3.1、创建连接代码 3.1、生产者代码 3.2、消费者代码 4、Direct路由模式 4.1、生产者代码 4.2、消费者代码 5、Topic主题模式 5.1、生产者代码 5.2、消费者代码 1、…

分享两套企业级进销存管理系统源码

▶▶▶▶1&#xff1a;SpringBoot企业级进销存ERP管理系统源码 00189 本系统采用企业级开发标准&#xff0c;使用SpringBoot架构&#xff0c;数据访问层采用Spring Data Jpa&#xff0c;业务控制层采用SpringMvc&#xff0c;安全框架采用Shiro&#xff0c;实现了完整权限系…

风控模型别只会KS、AUC了,来看看其他衡量模型好坏的一些重要指标吧|含实操

当我们训练好一个机器学习模型之后&#xff0c;必然会对模型的综合性能进行评估&#xff0c;针对分类、回归、聚类等不同类型的算法模型&#xff0c;可以采用相关的评价指标&#xff0c;例如分类模型的Accuracy、KS等&#xff1b;回归模型的MAE、MSE等&#xff1b;聚类模型的SS…

Linux下编写C使用的GDB调试器

目录 1.GDB调试器 2.GDB使用 3.实例程序调试 &#xff08;1&#xff09;编写一段C程序 &#xff08;2&#xff09;对C程序进行编译 &#xff08;3&#xff09;调试阶段 ①启动调试 ②查看文件 ③设置断点 ④查看断点情况 ⑤运行代码 ⑥单步运行 ⑦恢复程序 ⑧查看…

数字孪生建筑工程系统开发案例方案,如何选择数孪平台?

据统计&#xff0c;全国建筑业增长值在 GDP 增长中所占比重连续十年保持在 6. 85%以上&#xff0c;其支柱产业的地位依然保持。但是我国建筑业产值利润率已连续五年下滑&#xff0c;部分原因是其生产方式粗放、信息化水平不高、科技创新能力不足等。因此&#xff0c;在发展数字…

java类加载机制解析

一&#xff1a;类加载流程 public class Math {public static final int initData 666;public static User user new User();public int compute(){int a 1;int b 2;return ab;};public static void main(String[] args){Math math new Math();math.compute();} } 当我们…