Java生成二维码(前后端分离项目实战)

📍 本文代码已放置 github:Mr-Write/SpringbootDemo: 各种demo案例 (github.com)

文章目录

  • 1.ZXing
    • 1.1 概念
    • 1.2 ZXing 相关依赖
    • 1.3 zxing常用API
      • 🍀 EncodeHintType(编码提示类型)
      • 🍀 MultiFormatWriter(多格式写入程序)
      • 🍀 BarcodeFormat(码格式)
      • 🍀 BitMatrix(位矩阵)
  • 1.4 生成普通黑白二维码
      • 🍀 环境配置
      • 🍀 maven 依赖
      • 🍀 axios.js 文件
      • 🍀 静态页面
      • 🍀 ZXingUtils 工具类
      • 🍀 Controller 类
      • 📑 测试
  • 1.5 生成带 logo 的黑白二维码
      • 🍀 静态页面
      • 🍀 ZXingUtils 工具类方法
      • 🍀 Controller 类方法
      • 📑 测试
  • 2.qrcode-plugin
    • 2.1 基本说明
    • 2.2 相关依赖
    • 2.3 基本使用
      • 🍀 静态页面
        • 📌 生成普通黑白二维码静态页面
        • 📌 生成带 logo 二维码静态页面
        • 📌 生成彩色二维码静态页面
        • 📌 生成带背景图的黑白二维码静态页面
        • 📌 生成特殊形状的二维码静态页面
        • 📌 生成图片填充二维码静态页面
      • 🍀 QrCodePluginUtils 工具类
      • 🍀 QrCodePluginController 控制类

1.ZXing

1.1 概念

ZXing(Zebra Crossing)是一个开源的条码扫描和生成库,用于读取和生成各种类型的条码和二维码。它由 Google 开发并发布,目前由一群开源社区维护。

ZXing 支持多种常见的条码格式,包括一维条码(如EAN-13、Code 39、Code 128等)和二维码(如QR码、Data Matrix等)。它提供了各种编程接口和工具,可轻松地将条码扫描和生成功能集成到各种应用程序中。

主要特点包括:

  • 读取条码:ZXing 库提供了实现条码扫描的功能,可以从各种图像源(如摄像头、图像文件等)中读取条码数据。它可以自动检测和解码各种类型的条码,提供了灵活的接口和配置选项,以满足不同应用场景的需求。
  • 生成条码:ZXing 库还支持生成各种类型的条码和二维码。可以根据需求指定生成的条码类型、内容、尺寸、颜色等参数,并将生成的条码保存为图像文件或直接在应用程序中显示。
  • 跨平台支持:ZXing 是用 Java 语言开发的,因此可以在多个平台上使用,包括 Java SE、Java EE、Android 等。它提供了 Java 编程接口,可以轻松地集成到 Java 应用程序中。此外,它还提供了其他语言的接口和端口,如 .NET、Python、Ruby、Objective-C 等,以便在其他平台上使用。
  • 开源和活跃的社区支持:ZXing 是一个开源项目,其源代码可在 GitHub 上获得。它有一个活跃的开源社区,定期发布新的版本和更新,修复漏洞和改进功能。用户可以通过社区获得支持、提交问题或贡献代码。

ZXing 被广泛应用于各种领域,包括商业应用、物流管理、移动支付、票务系统等,它提供了方便易用的条码扫描和生成功能,为开发人员提供了一种简单而强大的工具来处理条码相关的需求。

1.2 ZXing 相关依赖

<!--zxing依赖-->
<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>javase</artifactId>
    <version>3.1.0</version>
</dependency>

<!--commons-lang依赖-->
<dependency>
    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <version>2.6</version>
</dependency>

1.3 zxing常用API

🍀 EncodeHintType(编码提示类型)

EncodeHintType 是用来设置二维码编码时的一些额外参数的枚举类型,常用枚举值如下:

  • ERROR_CORRECTION
    • 误差校正级别。对于黑白二维码,可选值为 L(7%)、M(15%)、Q(25%)、H(30%),表示二维码允许破损的最大容错率。在二维码出现破损时,根据设置的容错率级别,可以尝试修复二维码中的一些数据。
    • 二维码在生成过程中,可能会出现一些损坏或者缺失的情况,例如打印时墨水耗尽、图像压缩、摄像头拍摄角度不对等。这些问题可能导致二维码无法完全识别,或者识别出来的数据不准确,而误差校正码就是为了解决这些问题而产生的。
    • 例如,选择 L 级别的容错率,相当于允许在二维码的整体颜色区域中,最多可有约 7% 的坏像素点;而选择 H 级别的容错率时,最多可有约 30% 的坏像素点。
    • 注意:误差校正级别的具体值需要通过 ErrorCorrectionLevel 的枚举值来获取。
  • CHARACTER_SET
    • 编码字符集。可以设置使用的字符编码,例如 utf-8、gb2312 等等。
  • MARGIN
    • 二维码的空白区域大小。可以设置二维码周围的留白大小,以便于在不同的嵌入场景中使用二维码。

🍀 MultiFormatWriter(多格式写入程序)

MultiFormatWriter 是一个便捷的二维码生成类,可以根据传入的 BarcodeFormat 参数,生成对应类型的二维码。

MultiFormatWriter 封装了一系列的二维码生成方法,可以生成多种格式的二维码,包括 QR Code、Aztec Code、PDF417、Data Matrix 等。

🍀 BarcodeFormat(码格式)

BarcodeFormat 是枚举类,通过它来制定二维码格式:

  • QR Code:QR Code 是最常见的二维码格式之一,广泛应用于商品包装、票务、扫码支付等领域。QR Code 矩阵有黑白两种颜色,其中黑色部分表示信息的编码,白色部分则用于衬托和辨识。
  • Aztec Code:Aztec Code 是一种高密度、可靠性很高的二维码格式。相比于其他二维码格式,它具有更低的容错率、更小的尺寸和更高的解码效率。因此,它适合用于储存一些核心信息,例如个人信息、证件信息、账户密码等。
  • PDF417:是一种可以储存大量信息的二维码格式,它具有数据密度高、可靠性强等优点,可以应用于许多场景,例如航空机票,运输和配送标签,法律文件等。
  • Data Matrix:是一种小巧的二维码格式,它的编码方式类似于 QR Code,但是其可靠性、识别率、扫描速度和牢固度都比 QR Code 更优秀。由于尺寸较小、可靠性较高,因此 Data Matrix 适合嵌入简单的产品标签、医疗图像、检测数据等领域。

🍀 BitMatrix(位矩阵)

BitMatrix 是 ZXing 库中表示二维码矩阵的数据结构,它是由 0 和 1 构成的二维数组,用于存储二维码的编码信息。在二维码生成过程中,我们通过对BitMatrix 对象的构建和操作,最终生成一个可被扫描解码的二维码图像。

BitMatrix 实际上是一个 紧凑型的布尔型二维数组,往往只需要占用一个字节即可表示 8 位二进制。在使用 BitMatrix 时,我们可以通过其不同的方法,例如get()、set() 等,来获取、设置矩阵中每个位置的值。

在 ZXing 中,BitMatrix 常用于将编码后的信息转化为矩阵形式,并进行图像的生成和输出。在使用 ZXing 生成二维码时,我们首先需要使用MultiFormatWriter.encode() 方法来生成一个 BitMatrix;然后,在对 BitMatrix 进行各种处理和操作后,就可以在 UI 中显示和输出二维码。

总的来说,BitMatrix 是 ZXing 库中非常重要的数据结构之一,它负责存储和处理生成二维码图像所需的二进制信息,是实现二维码生成功能的关键。

BitMatrix 常用 API:

  • getHeight():获取矩阵高度;
  • getWidth():获取矩阵宽度;
  • get(x, y):根据x,y的坐标获取矩阵中该坐标的值。结果是true(黑色)或者false(白色)。

1.4 生成普通黑白二维码

🍀 环境配置

  • JDK17
  • SpringBoot 3.1.2
  • maven 3.9.3

🍀 maven 依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.1.2</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!--zxing依赖-->
    <dependency>
        <groupId>com.google.zxing</groupId>
        <artifactId>javase</artifactId>
        <version>3.1.0</version>
    </dependency>

    <!--commons-lang依赖-->
    <dependency>
        <groupId>commons-lang</groupId>
        <artifactId>commons-lang</artifactId>
        <version>2.6</version>
    </dependency>
</dependencies>

🍀 axios.js 文件

下载地址:https://unpkg.com/axios/dist/axios.min.js

将页面内容另存为 axios.js 文件,保存到 resources/static/js 下即可。

🍀 静态页面

在 resources/static/html/zxing 下新建 CommonBlackWhite.html:

<!doctype html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>生成普通黑白二维码</title>
</head>

<body>
    <input type="text" id="myContent">
    <button id="myBtn">生成二维码</button>
    <hr>
    <img id="myImg">
    
    <script src="/js/axios.js"></script>
    <script>
        const myContent = document.querySelector("#myContent");
        const myImg = document.querySelector("#myImg")
        document.querySelector("#myBtn").addEventListener("click", () => {
            if (myContent.value.trim() === '') {
                return
            }

            axios.get(`http://127.0.0.1:8080/zxing/getCommonBlackWhite?content=${myContent.value.trim()}`).then(response => {
                // data 就是后端传给前端的数据
                myImg.src = "data:image/png;base64," + response.data.imgEncode;
            }).catch(error => {
                // 当请求出现错误时的回调函数
                console.log(error);
            })
        })
    </script>
</body>

</html>

🍀 ZXingUtils 工具类

/**
 * @author 狐狸半面添
 * @create 2023-08-28 21:35
 */
public class ZXingUtils {
    public static String generateBlackWhiteCode(String content) throws WriterException, IOException {
        // 使用 Google 提供的 zxing 开源库,生成普通的黑白二维码

        // 需要创建一个 Map 集合,使用这个 Map 集合存储二维码相关的属性(参数)
        Map<EncodeHintType, Object> map = new HashMap<>(3);

        // 设置二维码的误差校正级别
        map.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        // 设置二维码的字符集
        map.put(EncodeHintType.CHARACTER_SET, "utf-8");
        // 设置二维码四周的留白,单位为 px
        map.put(EncodeHintType.MARGIN, 1);

        // 创建 zxing 的核心对象,MultiFormatWriter(多格式写入器)
        // 通过 MultiFormatWriter 对象来生成二维码
        MultiFormatWriter writer = new MultiFormatWriter();

        // writer.encode(内容, 什么格式的二维码, 二维码宽度, 二维码高度, 二维码参数)
        // 位矩阵对象(位矩阵对象内部实际上是一个二维数组,二维数组中每一个元素是 boolean 类型,true 代表黑色,false 代表白色)
        BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, 300, 300, map);

        // 获取矩阵的宽度
        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);
            }
        }

        FastByteArrayOutputStream fos = new FastByteArrayOutputStream();
        ImageIO.write(image, "png", fos);
        // 获取二维码图片的 base64 编码
        String imgEncode = Base64.encodeBase64String(fos.toByteArray());
        fos.flush();

        // 返回 base64 编码
        return imgEncode;
    }
}

🍀 Controller 类

/**
 * @author 狐狸半面添
 * @create 2023-08-28 21:35
 */
@CrossOrigin // 允许跨域
@RestController
@RequestMapping("/zxing")
public class ZXingController {
    @GetMapping("/getCommonBlackWhite")
    public Map<String, String> getCommonBlackWhite(@RequestParam("content") String content) throws IOException, WriterException {
        Map<String, String> map = new HashMap<>(1);
        map.put("imgEncode", ZXingUtils.generateBlackWhiteCode(content));
        return map;
    }
}

📑 测试

启动 SpringBoot 应用,访问静态页面:http://localhost:8080/html/zxing/CommonBlackWhite.html

image-20230828223649138

1.5 生成带 logo 的黑白二维码

在 1.4 节代码基础上进行补充即可。

🍀 静态页面

在 resources/static/html/zxing 下新建 ZXingLogo.html:

<%@page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
<!doctype html>
<html>
<head>
  <title>生成带有logo的黑白二维码</title>
  <meta charset="UTF-8">
</head>
<body>
<form action="/myqrcode/generateWithLogo" method="post" enctype="multipart/form-data">
  请输入文本内容:<input type="text" name="url"><br>
  请选择图片:<input type="file" name="logo"><br>
  <input type="submit" value="生成带有logo的二维码"/>
</form>
</body>
</html>

🍀 ZXingUtils 工具类方法

public static String generateLogoCode(String content, MultipartFile logo) throws WriterException, IOException {
    // 使用 Google 提供的 zxing 开源库,生成普通的黑白二维码

    // 需要创建一个 Map 集合,使用这个 Map 集合存储二维码相关的属性(参数)
    Map<EncodeHintType, Object> map = new HashMap<>(3);

    // 设置二维码的误差校正级别
    map.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
    // 设置二维码的字符集
    map.put(EncodeHintType.CHARACTER_SET, "utf-8");
    // 设置二维码四周的留白,单位为 px
    map.put(EncodeHintType.MARGIN, 1);

    // 创建 zxing 的核心对象,MultiFormatWriter(多格式写入器)
    // 通过 MultiFormatWriter 对象来生成二维码
    MultiFormatWriter writer = new MultiFormatWriter();

    // writer.encode(内容, 什么格式的二维码, 二维码宽度, 二维码高度, 二维码参数)
    // 位矩阵对象(位矩阵对象内部实际上是一个二维数组,二维数组中每一个元素是 boolean 类型,true 代表黑色,false 代表白色)
    BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, 300, 300, map);

    // 获取矩阵的宽度
    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);
        }
    }

    // 给二维码添加 Logo
    // 1.获取 logo 图片:通过 ImageIO 的read方法,从输入流中读取,从而获得 logo 图片
    BufferedImage logoImage = ImageIO.read(logo.getInputStream());
    // 2.设置 logo 的宽度和高度
    int logoWidth = Math.min(logoImage.getWidth(), 60);
    int logoHeight = Math.min(logoImage.getHeight(), 60);
    // 3.将 logo 缩放:使用平滑缩放算法对原 logo 图像进行缩放得到一个全新的图像
    Image scaledLogo = logoImage.getScaledInstance(logoWidth, logoHeight, Image.SCALE_SMOOTH);
    // 4.将缩放后的 logo 画到黑白二维码上
    // 4.1 获取一个 2D 的画笔
    Graphics2D graphics2D = image.createGraphics();
    // 4.2 指定开始的坐标 x,y
    int x = (300 - logoWidth) / 2;
    int y = (300 - logoHeight) / 2;
    // 4.3 将缩放后的 logo 画上去
    graphics2D.drawImage(scaledLogo,x,y,null);
    // 4.4 创建一个具有指定位置、宽度、高度和圆角半径的圆角矩形,这个圆角矩形是用来绘制边框的
    Shape shape = new RoundRectangle2D.Float(x,y,logoWidth,logoHeight,10,10);
    // 4.5 使用一个宽度为 4px 的基本笔触
    graphics2D.setStroke(new BasicStroke(4f));
    // 4.6 给 logo 画圆角矩形
    graphics2D.draw(shape);
    // 4.7 释放画笔
    graphics2D.dispose();

    FastByteArrayOutputStream fos = new FastByteArrayOutputStream();
    ImageIO.write(image, "png", fos);
    // 获取二维码图片的 base64 编码
    String imgEncode = Base64.encodeBase64String(fos.toByteArray());
    fos.flush();

    // 返回 base64 编码
    return imgEncode;
}

🍀 Controller 类方法

@PostMapping("/getLogo")
public Map<String, String> getLogo(@RequestParam("content") String content, @RequestParam("logo") MultipartFile logo) throws IOException, WriterException {
    Map<String, String> map = new HashMap<>(1);
    map.put("imgEncode", ZXingUtils.generateLogoCode(content, logo));
    return map;
}

📑 测试

启动 SpringBoot 应用,访问静态页面:http://localhost:8080/html/zxing/ZXingLogo.html

image-20230829211955255

2.qrcode-plugin

2.1 基本说明

  • 使用的是 github 上基于 ZXing 封装的 qrcode 开源插件,github 地址:https://github.com/liuyueyi/quick-media
  • 使用文档:
    • https://github.com/liuyueyi/quick-media/blob/master/plugins/qrcode-plugin/readme.md
    • https://liuyueyi.github.io/quick-media/#/%E6%8F%92%E4%BB%B6/%E4%BA%8C%E7%BB%B4%E7%A0%81/%E4%BA%8C%E7%BB%B4%E7%A0%81%E6%8F%92%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C
  • maven 仓库:https://mvnrepository.com/artifact/com.github.liuyueyi.media/qrcode-plugin

2.2 相关依赖

<dependency>
    <groupId>com.github.liuyueyi.media</groupId>
    <artifactId>qrcode-plugin</artifactId>
    <version>3.0.0</version>
</dependency>

2.3 基本使用

静态文件均在 resources/static/html/qrcodePlugin 下

🍀 静态页面

📌 生成普通黑白二维码静态页面

💻 http://localhost:8080/html/qrcodePlugin/CommonBlackWhiteCode.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>生成普通黑白二维码</title>
</head>
<body>
<input type="text" id="myContent">
<button id="myBtn">生成普通黑白二维码</button>
<hr>
<img id="myImg">
<script src="/js/axios.js"></script>
<script>
    const myContent = document.querySelector("#myContent");
    const myImg = document.querySelector("#myImg")
    document.querySelector("#myBtn").addEventListener("click", () => {
        if (myContent.value.trim() === '') {
            return
        }

        axios.get(`http://127.0.0.1:8080/qrcode-plugin/getCommonBlackWhiteCode?content=${myContent.value.trim()}`).then(response => {
            // data 就是后端传给前端的数据
            myImg.src = "data:image/png;base64," + response.data.imgEncode;
        }).catch(error => {
            // 当请求出现错误时的回调函数
            console.log(error);
        })
    })
</script>
</body>
</html>

📌 生成带 logo 二维码静态页面

💻 http://localhost:8080/html/qrcodePlugin/LogoBlackWhiteCode.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>生成带 logo 的二维码</title>
</head>
<body>
请输入文本内容: <input type="text" name="content" id="myContent"><br>
请选择图片: <input type="file" name="logo" id="myLogo"><br>
<button id="myBtn" id="myBtn">生成带 logo 二维码</button>
<hr>
<img id="myImg">

<script src="/js/axios.js"></script>
<script>
    const myContent = document.querySelector("#myContent");
    const myLogo = document.querySelector("#myLogo")
    const myImg = document.querySelector("#myImg")
    document.querySelector("#myBtn").addEventListener("click", () => {
        if (myContent.value.trim() === '' || myLogo.files.length === 0) {
            return
        }

        axios.post('http://127.0.0.1:8080/qrcode-plugin/getLogoBlackWhiteCode', {
            logo: myLogo.files[0],
            content: myContent.value
        }, {
            headers: {
                "Content-Type": "multipart/form-data",
            },
        }).then(response => {
            // data 就是后端传给前端的数据
            myImg.src = "data:image/png;base64," + response.data.imgEncode;
        }).catch(error => {
            // 当请求出现错误时的回调函数
            console.log(error);
        })
    })
</script>
</body>
</html>

📌 生成彩色二维码静态页面

💻 http://localhost:8080/html/qrcodePlugin/ColorCode.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>生成彩色二维码</title>
</head>
<body>
<input type="text" id="myContent">
<button id="myBtn">生成彩色二维码</button>
<hr>
<img id="myImg">
<script src="/js/axios.js"></script>
<script>
    const myContent = document.querySelector("#myContent");
    const myImg = document.querySelector("#myImg")
    document.querySelector("#myBtn").addEventListener("click", () => {
        if (myContent.value.trim() === '') {
            return
        }

        axios.get(`http://127.0.0.1:8080/qrcode-plugin/getColorCode?content=${myContent.value.trim()}`).then(response => {
            // data 就是后端传给前端的数据
            myImg.src = "data:image/png;base64," + response.data.imgEncode;
        }).catch(error => {
            // 当请求出现错误时的回调函数
            console.log(error);
        })
    })
</script>
</body>
</html>

📌 生成带背景图的黑白二维码静态页面

💻 http://localhost:8080/html/qrcodePlugin/BgBlackWhiteCode.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>生成带背景图的黑白二维码</title>
</head>
<body>
请输入文本内容: <input type="text" name="content" id="myContent"><br>
请选择图片: <input type="file" name="logo" id="myBgImg"><br>
<button id="myBtn" id="myBtn">生成带背景图的黑白二维码</button>
<hr>
<img id="myImg">

<script src="/js/axios.js"></script>
<script>
    const myContent = document.querySelector("#myContent");
    const myBgImg = document.querySelector("#myBgImg")
    const myImg = document.querySelector("#myImg")
    document.querySelector("#myBtn").addEventListener("click", () => {
        if (myContent.value.trim() === '' || myBgImg.files.length === 0) {
            return
        }

        axios.post('http://127.0.0.1:8080/qrcode-plugin/getBgBlackWhiteCode', {
            backgroundImage: myBgImg.files[0],
            content: myContent.value
        }, {
            headers: {
                "Content-Type": "multipart/form-data",
            },
        }).then(response => {
            // data 就是后端传给前端的数据
            myImg.src = "data:image/png;base64," + response.data.imgEncode;
        }).catch(error => {
            // 当请求出现错误时的回调函数
            console.log(error);
        })
    })
</script>
</body>
</html>

📌 生成特殊形状的二维码静态页面

💻 http://localhost:8080/html/qrcodePlugin/ShapeCode.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>生成特殊形状的二维码</title>
</head>
<body>
<input type="text" id="myContent">
<button id="myBtn">生成特殊形状的二维码</button>
<hr>
<img id="myImg">
<script src="/js/axios.js"></script>
<script>
    const myContent = document.querySelector("#myContent");
    const myImg = document.querySelector("#myImg")
    document.querySelector("#myBtn").addEventListener("click", () => {
        if (myContent.value.trim() === '') {
            return
        }

        axios.get(`http://127.0.0.1:8080/qrcode-plugin/getShapeCode?content=${myContent.value.trim()}`).then(response => {
            // data 就是后端传给前端的数据
            myImg.src = "data:image/png;base64," + response.data.imgEncode;
        }).catch(error => {
            // 当请求出现错误时的回调函数
            console.log(error);
        })
    })
</script>
</body>
</html>

📌 生成图片填充二维码静态页面

💻 http://localhost:8080/html/qrcodePlugin/ImgFillCode.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>生成图片填充二维码</title>
</head>
<body>
请输入文本内容: <input type="text" name="content" id="myContent"><br>
请选择图片: <input type="file" name="logo" id="myFillImg"><br>
<button id="myBtn" id="myBtn">生成图片填充二维码</button>
<hr>
<img id="myImg">

<script src="/js/axios.js"></script>
<script>
    const myContent = document.querySelector("#myContent");
    const myFillImg = document.querySelector("#myFillImg")
    const myImg = document.querySelector("#myImg")
    document.querySelector("#myBtn").addEventListener("click", () => {
        if (myContent.value.trim() === '' || myFillImg.files.length === 0) {
            return
        }

        axios.post('http://127.0.0.1:8080/qrcode-plugin/getImgFillCode', {
            fillImg: myFillImg.files[0],
            content: myContent.value
        }, {
            headers: {
                "Content-Type": "multipart/form-data",
            },
        }).then(response => {
            // data 就是后端传给前端的数据
            myImg.src = "data:image/png;base64," + response.data.imgEncode;
        }).catch(error => {
            // 当请求出现错误时的回调函数
            console.log(error);
        })
    })
</script>
</body>
</html>

🍀 QrCodePluginUtils 工具类

/**
 * @author 狐狸半面添
 * @create 2023-08-29 21:41
 */
public class QrCodePluginUtils {

    private static String imageParseBase64(BufferedImage image) throws IOException {
        FastByteArrayOutputStream fos = new FastByteArrayOutputStream();
        ImageIO.write(image, "png", fos);
        // 获取二维码图片的 base64 编码
        String imgEncode = Base64.encodeBase64String(fos.toByteArray());
        fos.flush();
        return imgEncode;
    }

    /**
     * 生成普通黑白二维码
     *
     * @param content 文本内容
     * @return 图片base64编码
     */
    public static String generateBlackWhiteCode(String content) throws IOException, WriterException {
        return imageParseBase64(QrCodeGenWrapper.of(content).asBufferedImage());
    }

    /**
     * 生成带 logo 的黑白二维码
     *
     * @param content 文本内容
     * @param logo    logo文件
     * @return 图片base64编码
     */
    public static String generateLogoBlackWhiteCode(String content, MultipartFile logo) throws IOException, WriterException {
        BufferedImage image = QrCodeGenWrapper.of(content)
                .setLogo(logo.getInputStream())
                // 设置 logo 图片与二维码之间的比例,10 表示 logo 的宽度等于二维码的 1/10
                .setLogoRate(10)
                // 设置 logo 图片的样式,将 logo 的边框形状设置为圆形
                .setLogoStyle(QrCodeOptions.LogoStyle.ROUND)
                .asBufferedImage();
        return imageParseBase64(image);
    }

    /**
     * 生成彩色二维码
     *
     * @param content 文本内容
     * @param color   颜色
     * @return 图片base64编码
     */
    public static String generateColorCode(String content, Color color) throws IOException, WriterException {
        BufferedImage image = QrCodeGenWrapper.of(content)
                // 指定画笔颜色
                .setDrawPreColor(color)
                .asBufferedImage();
        return imageParseBase64(image);
    }

    /**
     * 生成带背景图片的黑白二维码
     *
     * @param content         文本内容
     * @param backgroundImage 背景图文件
     * @return 图片base64编码
     */
    public static String generateBgBlackWhiteCode(String content, MultipartFile backgroundImage) throws IOException, WriterException {
        BufferedImage image = QrCodeGenWrapper.of(content)
                // 设置背景图
                .setBgImg(backgroundImage.getInputStream())
                // 设置背景图透明度
                .setBgOpacity(0.7F)
                .asBufferedImage();
        return imageParseBase64(image);
    }

    /**
     * 生成带特殊形状的二维码
     *
     * @param content   文本内容
     * @param drawStyle 绘制样式
     * @return 图片base64编码
     */
    public static String generateShapeCode(String content, QrCodeOptions.DrawStyle drawStyle) throws IOException, WriterException {
        BufferedImage image = QrCodeGenWrapper.of(content)
                // 启用二维码绘制时的缩放功能
                .setDrawEnableScale(true)
                // 指定绘制样式
                .setDrawStyle(drawStyle)
                .asBufferedImage();
        return imageParseBase64(image);
    }

    /**
     * 生成图片填充二维码
     *
     * @param content 文本内容
     * @param fillImg 填充图片
     * @return 图片base64编码
     */
    public static String generateImgFillCode(String content, MultipartFile fillImg) throws IOException, WriterException {
        BufferedImage image = QrCodeGenWrapper.of(content)
                // 设置二维码的错误纠正级别
                .setErrorCorrection(ErrorCorrectionLevel.H)
                // 绘制二维码时采用图片填充
                .setDrawStyle(QrCodeOptions.DrawStyle.IMAGE)
                // 设置填充的图片
                .addImg(1, 1, fillImg.getInputStream())
                .asBufferedImage();
        return imageParseBase64(image);
    }
    
}

🍀 QrCodePluginController 控制类

/**
 * @author 狐狸半面添
 * @create 2023-08-29 21:37
 */
@CrossOrigin
@RestController
@RequestMapping("/qrcode-plugin")
public class QrCodePluginController {

    /**
     * 生成普通黑白二维码
     *
     * @param content 文本内容
     * @return 图片base64编码
     */
    @GetMapping("/getCommonBlackWhiteCode")
    public Map<String, String> getCommonBlackWhiteCode(@RequestParam("content") String content) throws IOException, WriterException {
        Map<String, String> map = new HashMap<>(1);
        map.put("imgEncode", QrCodePluginUtils.generateBlackWhiteCode(content));
        return map;
    }

    /**
     * 生成带 logo 的黑白二维码
     *
     * @param content 文本内容
     * @param logo    logo文件
     * @return 图片base64编码
     */
    @PostMapping("/getLogoBlackWhiteCode")
    public Map<String, String> getLogoBlackWhiteCode(@RequestParam("content") String content, @RequestParam("logo") MultipartFile logo) throws IOException, WriterException {
        Map<String, String> map = new HashMap<>(1);
        map.put("imgEncode", QrCodePluginUtils.generateLogoBlackWhiteCode(content, logo));
        return map;
    }

    /**
     * 生成彩色二维码
     *
     * @param content 文本内容
     * @return 图片base64编码
     */
    @GetMapping("/getColorCode")
    public Map<String, String> getColorCode(@RequestParam("content") String content) throws IOException, WriterException {
        Map<String, String> map = new HashMap<>(1);
        // 二维码颜色可以由前端传过来进行指定
        map.put("imgEncode", QrCodePluginUtils.generateColorCode(content, Color.BLUE));
        return map;
    }

    /**
     * 生成带背景图片的黑白二维码
     *
     * @param content         文本内容
     * @param backgroundImage 背景图文件
     * @return 图片base64编码
     */
    @PostMapping("/getBgBlackWhiteCode")
    public Map<String, String> getBgBlackWhiteCode(@RequestParam("content") String content, @RequestParam("backgroundImage") MultipartFile backgroundImage) throws IOException, WriterException {
        Map<String, String> map = new HashMap<>(1);
        map.put("imgEncode", QrCodePluginUtils.generateBgBlackWhiteCode(content, backgroundImage));
        return map;
    }

    /**
     * 生成带特殊形状的二维码
     *
     * @param content 文本内容
     * @return 图片base64编码
     */
    @GetMapping("/getShapeCode")
    public Map<String, String> getShapeCode(@RequestParam("content") String content) throws IOException, WriterException {
        Map<String, String> map = new HashMap<>(1);
        // 绘制样式可以由前端传过来进行指定,这里设定为 钻石
        map.put("imgEncode", QrCodePluginUtils.generateShapeCode(content, QrCodeOptions.DrawStyle.DIAMOND));
        return map;
    }

    /**
     * 生成图片填充二维码
     *
     * @param content 文本内容
     * @param fillImg 填充图片
     * @return 图片base64编码
     */
    @PostMapping("/getImgFillCode")
    public Map<String, String> getImgFillCode(@RequestParam("content") String content, @RequestParam("fillImg") MultipartFile fillImg) throws IOException, WriterException {
        Map<String, String> map = new HashMap<>(1);
        map.put("imgEncode", QrCodePluginUtils.generateImgFillCode(content, fillImg));
        return map;
    }
}

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

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

相关文章

Android Activity启动过程一:从Intent到Activity创建

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、人工智能等&#xff0c;希望大家多多支持。 目录 一、概览二、应用内启动源码流程 (startActivity)2.1 startActivit…

财务数据分析?奥威BI数据可视化工具很擅长

BI数据可视化工具通常是可以用户各行各业&#xff0c;用于不同主题的数据可视化分析&#xff0c;但面对财务数据分析这块难啃的骨头&#xff0c;能够好好地完成的&#xff0c;还真不多。接下来要介绍的这款BI数据可视化工具不仅拥有内存行列计算模型这样的智能财务指标计算功能…

我们的第一个 Qt 窗口程序

Qt 入门实战教程&#xff08;目录&#xff09; Windows Qt 5.12.10下载与安装 为何使用Qt Creator开发QT 本文介绍用Qt自带的集成开发工具Qt Creator创建Qt默认的窗口程序。 本文不需要你另外安装Visual Studio 2022这样的集成开发环境&#xff0c;也不需要你再在Visual St…

精准高效农业作业,植保无人机显身手

中国作为农业大国&#xff0c;拥有约18亿亩的农田&#xff0c;每年都需要进行种子喷洒和农药施用等农业作业&#xff0c;对于普通农户来说&#xff0c;这是一项耗时耗力的工程&#xff0c;同时&#xff0c;人工喷洒农药极易造成农药慢性中毒&#xff0c;对农民的身体健康产生极…

摄像头的调用和视频识别

CV_tutorial3 摄像头调用实时播放保存视频 运动目标识别帧差法背景减除法 摄像头调用 创建视频捕捉对象&#xff1a;cv2.VideoCapture() 参数为视频设备的索引号&#xff0c;就一个摄像投的话写0默认&#xff1b; 或者是指定要读取视频的路径。 实时播放 import cv2 import …

基于亚马逊云科技无服务器服务快速搭建电商平台——部署篇

受疫情影响消费者习惯发生改变&#xff0c;刺激了全球电商行业的快速发展。除了依托第三方电商平台将产品销售给消费者之外&#xff0c;企业通过品牌官网或者自有电商平台销售商品也是近几年电商领域快速发展的商业模式。独立站电商模式可以进行多方面、全渠道的互联网市场拓展…

clickhouse 系列2:clickhouse 离线安装

1.下载rpm包 Altinity/clickhouse - Packages packagecloud 使用wget下载到本地目录 wget --content-disposition https://packagecloud.io/Altinity/clickhouse/packages/el/7/clickhouse-common-static-20.8.3.18-1.el7.x86_64.rpm/download.rpm wget

如何通过四个步骤清理网络防火墙规则

组织必须确保适当的安全策略到位&#xff0c;以保护其投资并优化其安全有效性。然而&#xff0c;随着网络的扩展和复杂性的增加&#xff0c;网络运营团队面临着管理来自多个供应商的大量防火墙和网络设备的挑战。他们必须解决分散的基础设施、职能孤岛、人员配置问题、分散的管…

强化自主可控,润开鸿发布基于RISC-V架构的开源鸿蒙终端新品

2023 RISC-V中国峰会于8月23日至25日在北京召开,峰会以“RISC-V生态共建”为主题,结合当下全球新形势,把握全球新时机,呈现RISC-V全球新观点、新趋势。本次大会邀请了RISC-V国际基金会、业界专家、企业代表及社区伙伴等共同探讨RISC-V发展趋势与机遇,吸引超过百余家业界企业、高…

指针(个人学习笔记黑马学习)

1、指针的定义和使用 #include <iostream> using namespace std;int main() {int a 10;int* p;p &a;cout << "a的地址为&#xff1a;" << &a << endl;cout << "a的地址为&#xff1a;" << p << endl;…

Doris数据库BE——rowset版本追踪

rowset代码位置be/src/olap/version_graph.cpp&#xff0c;字面意思行集合&#xff0c;由一行或多行组成。rowset版本简单理解为rowset编号&#xff0c;每次导入生成一个rowset&#xff0c;比如insert执行10次会生成10个rowset&#xff0c;一次streamload生成一个rowset。 版本…

Mac OS 13.4.1 搜狗输入法导致的卡顿问题

一、Mac OS 系统版本 搜狗输入法已经更新到最新 二、解决方案 解决方案一 在我的电脑上面需要关闭 VSCode 和 Chrmoe 以后&#xff0c;搜狗输入法回复正常。 解决方案二 强制重启一下搜狗输入法。 可以用 unix 定时任务去隔 2个小时自动 kill 掉一次进程 # kill 掉 mac …

【JS案例】JS实现手风琴效果

JS案例手风琴 &#x1f31f;效果展示 &#x1f31f;HTML结构 &#x1f31f;CSS样式 &#x1f31f;实现思路 &#x1f31f;具体实现 1.绑定事件 2.自定义元素属性 3.切换菜单 &#x1f31f;完整JS代码 &#x1f31f;写在最后 &#x1f31f;效果展示 &#x1f31f;HTML…

excel功能区(ribbonx)编程笔记--2 button控件与checkbox控件

我们上一章简单先了解了ribbonx的基本内容,以及使用举例实现自己修改ribbox的内容,本章紧接上一章,先讲解一下ribbonx的button控件。 在功能区的按钮中,可以使用内置图像或提供自已的图像,可以指定大按钮或者更小的形式,添加少量的代码甚至可以同时提供标签。此外,可以利…

C++ 多线程编程

C 多线程编程 点击获取更多的C学习笔记 1. 线程库的基本使用 创建线程 要创建线程&#xff0c;我们需要一个可调用的函数或函数对象&#xff0c;作为线程的入口点。在C11中&#xff0c;我们可以使用函数指针、函数对象或lambda表达式来实现。创建线程的基本语法如下&#x…

16、Flink 的table api与sql之连接外部系统: 读写外部系统的连接器和格式以及Apache Hive示例(6)

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…

开发工具——IDE安装 / IDEA子module依赖导入失败编译提示xx找不到符号 / IDEA在Git提交时卡顿

近期换了工作电脑&#xff0c;公司的IT团队不够给力&#xff0c;不能复制电脑系统&#xff0c;所以又到了需要重装IDE配置开发环境的时候了&#xff1b;在安装和导入Java编译器IDEA的时候遇到一些"棘手"问题&#xff0c;这里整理下解决方法以备不时之需&#xff1b; …

R语言空气污染数据的地理空间可视化和分析:颗粒物2.5(PM2.5)和空气质量指数(AQI)...

原文链接&#xff1a;http://tecdat.cn/?p23800 由于空气污染对公众健康的不利影响&#xff0c;人们一直非常关注。世界各国的环境部门都通过各种方法&#xff08;例如地面观测网络&#xff09;来监测和评估空气污染问题&#xff08;点击文末“阅读原文”获取完整代码数据&…

ChatGPT⼊门到精通(4):ChatGPT 为何⽜逼

⼀、通⽤型AI 在我们原始的幻想⾥&#xff0c;AI是基于对海量数据的学习&#xff0c;锻炼出⼀个⽆所不知⽆所不能的模 型&#xff0c;并借助计算机的优势&#xff08;计算速度、并发可能&#xff09;等碾压⼈类。 但我们⽬前的AI&#xff0c;不管是AlphaGo还是图像识别算法&am…

加强版python连接飞书通知——本地电脑PC端通过网页链接打开本地已安装软件(调用注册表形式,以漏洞扫描工具AppScan为例)

前言 如果你想要通过超链接来打开本地应用,那么你首先你需要将你的应用添入windows注册表中(这样网页就可以通过指定代号来调用程序),由于安全性的原因所以网页无法直接通过输入绝对路径来调用本地文件。 一、通过创建reg文件自动配置注册表 创建文本文档,使用记事本打开…