首页 > 编程语言 >使用 Java 生成二维码图片

使用 Java 生成二维码图片

时间:2023-08-27 10:22:20浏览次数:40  
标签:Java jakarta image 生成 二维码 com import servlet

0x01 准备

(1)软件版本

  • IntelliJ IDEA 2023.1.3
  • JDK 18
  • Tomcat 10.1.11
  • Maven 3.8.6

(2)技术栈

  • servlet
  • zxing
    • 谷歌项目
    • 生成黑白二维码并可以附上 logo
  • qrcode
    • github 开源项目
    • 基于并拓展 zxing

(3)创建项目

  1. 创建空项目

  2. 在 菜单栏-文件-项目结构 中设置 JDK 及语言级别

  3. 在 菜单栏-文件-设置-构建-构建工具-Maven 中配置 Maven 路径与用户设置文件 \apache-maven-3.8.6\conf\settings.xml

  4. 在项目中创建新模块

  5. 在新模块中通过“添加框架支持”添加 Web Application 4.0

    • 取消“创建 web.xml ”的选中
    • 在项目结构中选择 模块-[模块名称]-Web-Web 资源目录,修改资源目录为项目中 web 的路径,如 [project_name]\[module_name]\web
  6. 修改 pom.xml

    <!-- 打包方式 -->
     <packaging>war</packaging>
    
     <!-- 添加依赖 -->
     <dependencies>
         <!-- https://mvnrepository.com/artifact/jakarta.servlet/jakarta.servlet-api -->
         <dependency>
             <groupId>jakarta.servlet</groupId>
             <artifactId>jakarta.servlet-api</artifactId>
             <version>6.0.0</version>
             <scope>provided</scope>
         </dependency>
         <!-- zxing 依赖 -->
         <dependency>
             <groupId>com.google.zxing</groupId>
             <artifactId>javase</artifactId>
             <version>3.1.0</version>
         </dependency>
         <!-- zxing 需要 commons-lang 依赖 -->
         <dependency>
             <groupId>commons-lang</groupId>
             <artifactId>commons-lang</artifactId>
             <version>2.6</version>
         </dependency>
     </dependencies>
    
  7. 在 菜单栏-运行-编辑配置 中配置 Tomcat 服务器

    • 添加新配置,选择 Tomcat 本地服务器

    • 在 部署栏 中选择添加工件,选择 [module_name]:war exploded

    • 修改 应用上下文 为 /[module_name]

    • 修改 Tomcat 目录下 /conf/logging.properties 文件的内容以避免调试日志乱码

      java.util.logging.ConsoleHandler.encoding = GBK
      

0x02 zxing

(1)创建基础二维码图片

  1. 在 web/index.jsp 中编辑前端页面

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
      <head>
        <title>QRCode</title>
      </head>
      <body>
      <p>输入文本:<input type="text" id="url" /><button onclick="generateQRCode()">生成二维码</button></p>
      <img id="qrcodeImg" />
      <script type="text/javascript">
        function generateQRCode() {
          document.getElementById("qrcodeImg").src = "/myqrcode/generate?url=" + document.getElementById("url").value
        }
      </script>
      </body>
    </html>
    
  2. 新建 src/main/java/com.qrcode.servlets 包并新建 GenerateQRCode.java

    package com.qrcode.servlets;
    
    public class GenerateQRCode extends HttpServlet {
    }
    
  3. 在类中继承 HttpServlet 类并重写 doGet() 方法

    @WebServlet("/generate")
    public class GenerateQRCode extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // super.doGet(req, resp);
        }
    }
    
  4. 在方法中创建 Map 集合来储存二维码相关属性

    Map map = new HashMap();
    // 设置二维码的误差校正级别
    map.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
    // 设置二维码的字符集
    map.put(EncodeHintType.CHARACTER_SET, "utf-8");
    // 设置二维码四周的留白
    map.put(EncodeHintType.MARGIN, 1);
    
    • 校正级别(二维码中最大坏像素点占比):

      L - 7% M - 15% Q - 25% H - 30%

  5. 获取文本对象

    String url = req.getParameter("url");
    
  6. 创建 zxing 的核心对象

    MultiFormatWriter writer = new MultiFormatWriter();
    
    • MultiFormatWriter(多格式写入器)是一个便捷的二维码生成类,可以根据传入的 BarcodeFormat 参数,生成对应的二维码
  7. 传入二维码参数并获取宽高

    BitMatrix bitMatrix = writer.encode(url, BarcodeFormat.QR_CODE, 300, 300, map);
    int height = bitMatrix.getHeight();
    int width = bitMatrix.getWidth();
    
    • BarcodeFormat(码格式)是枚举类,用来指定二维码格式
      • QR_CODE:最常见二维码格式之一
      • AZTEC:高密度高可靠二维码格式
      • PDF_417:储存大量信息的二维码格式
      • DATA_MATRIX:一种小巧的二维码格/式
    • BitMatrix(位矩阵对象)是表示二维码矩阵的数据结构,实际上是一个紧凑型的布尔型二维数组,常用于将编码后的信息转化为矩阵类型,具有以下方法
      • getHeight():获取矩阵高度
      • getWidth():获取矩阵宽度
      • get(x, y):获取指定位置的坐标值,值为true(黑色块)或 false(白色块)
  8. 生成二维码

    // 创建图片对象
    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);
        }
    }
    
  9. 将图片返回到浏览器

    ServletOutputStream servletOutputStream = resp.getOutputStream();
    ImageIO.write(image, "png", servletOutputStream);
    servletOutputStream.flush();
    servletOutputStream.close();
    

完整代码:

package com.qrcode.servlets;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@WebServlet("/generate")
public class GenerateQRCode extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            String url = req.getParameter("url");
            Map map = new HashMap();
            map.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
            map.put(EncodeHintType.CHARACTER_SET, "utf-8");
            map.put(EncodeHintType.MARGIN, 1);
            MultiFormatWriter writer = new MultiFormatWriter();
            BitMatrix bitMatrix = writer.encode(url, BarcodeFormat.QR_CODE, 300, 300, map);
            int height = bitMatrix.getHeight();
            int width = bitMatrix.getWidth();
            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);
                }
            }
            ServletOutputStream servletOutputStream = resp.getOutputStream();
            ImageIO.write(image, "png", servletOutputStream);
            servletOutputStream.flush();
            servletOutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

(2)带 logo 的二维码生成

  1. 修改前端页面 index.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
      <head>
        <title>QRCode</title>
      </head>
      <body>
      <form action="/myqrcode/generate" method="post" enctype="multipart/form-data">
        输入文本:<input type="text" name="url" /><br />
        logo:<input type="file" name="logo" /><br />
        <input type="submit" value="生成二维码">
      </form>
      </body>
    </html>
    
  2. 添加文件上传注释

    @MultipartConfig(fileSizeThreshold = 1024 * 1024 * 2, maxFileSize = 1024 * 1024 * 10, maxRequestSize = 1024 * 1024 * 100)
    
  3. 在 GenerateQRCode.java 中获取上传的 Logo

    Part logoPart = req.getPart("logo");
    InputStream inputStream = logoPart.getInputStream();
    Image logoImage = ImageIO.read(inputStream);
    
  4. 使用平滑缩放算法进行缩放

    int logoWidth = logoImage.getWidth(null);
    int logoHeight = logoImage.getHeight(null);
    logoWidth = logoWidth > 60 ? 60 : logoWidth;
    logoHeight = logoHeight > 60 ? 60 : logoHeight;
    Image logoImageScaledInstance = logoImage.getScaledInstance(logoWidth, logoHeight, Image.SCALE_SMOOTH);
    
  5. 获取 2D 画笔

    Graphics2D graphics2D = image.createGraphics();
    
  6. 指定开始作画的坐标

    int x = (300 - logoWidth) / 2;
    int y = (300 - logoHeight) / 2;
    
  7. 绘制 Logo

    graphics2D.drawImage(logoImageScaledInstance, x, y, null);
    
    • 绘制圆角矩形

      Shape shape = new RoundRectangle2D.Float(x, y, logoWidth, logoHeight, 10, 10);
      graphics2D.setStroke(new BasicStroke(4f));
      graphics2D.draw(shape);
      
  8. 释放画笔

    graphics2D.dispose();
    

完整代码:

package com.qrcode.servlets;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.MultipartConfig;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.Part;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

@WebServlet("/generate")
@MultipartConfig(fileSizeThreshold = 1024 * 1024 * 2, maxFileSize = 1024 * 1024 * 10, maxRequestSize = 1024 * 1024 * 100)
public class GenerateQRCode extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            String url = req.getParameter("url");
            Map map = new HashMap();
            map.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
            map.put(EncodeHintType.CHARACTER_SET, "utf-8");
            map.put(EncodeHintType.MARGIN, 1);
            MultiFormatWriter writer = new MultiFormatWriter();
            BitMatrix bitMatrix = writer.encode(url, BarcodeFormat.QR_CODE, 300, 300, map);
            int height = bitMatrix.getHeight();
            int width = bitMatrix.getWidth();
            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);
                }
            }
            Part logoPart = req.getPart("logo");
            InputStream inputStream = logoPart.getInputStream();
            Image logoImage = ImageIO.read(inputStream);
            int logoWidth = logoImage.getWidth(null);
            int logoHeight = logoImage.getHeight(null);
            logoWidth = Math.min(logoWidth, 60);
            logoHeight = Math.min(logoHeight, 60);
            Image logoImageScaledInstance = logoImage.getScaledInstance(logoWidth, logoHeight, Image.SCALE_SMOOTH);
            Graphics2D graphics2D = image.createGraphics();
            int x = (300 - logoWidth) / 2;
            int y = (300 - logoHeight) / 2;
            graphics2D.drawImage(logoImageScaledInstance, x, y, null);
            Shape shape = new RoundRectangle2D.Float(x, y, logoWidth, logoHeight, 10, 10);
            graphics2D.setStroke(new BasicStroke(4f));
            graphics2D.draw(shape);
            graphics2D.dispose();
            ImageIO.write(image, "png", resp.getOutputStream());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

0x03 qrcode

在 pom.xml 中添加依赖

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

(1)黑白二维码

package com.qrcode.servlets;

import com.github.hui.quick.plugin.qrcode.wrapper.QrCodeGenWrapper;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;

@WebServlet("/generate")
public class GenerateQRCode extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            String url = req.getParameter("url");
            BufferedImage image = QrCodeGenWrapper.of(url).asBufferedImage();
            ImageIO.write(image, "png", resp.getOutputStream());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • of():设置二维码内容
  • asBufferedImage():生成二维码图片

(2)logo 二维码

package com.qrcode.servlets;

import com.github.hui.quick.plugin.qrcode.wrapper.QrCodeGenWrapper;
import com.github.hui.quick.plugin.qrcode.wrapper.QrCodeOptions;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.MultipartConfig;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;

@WebServlet("/generate")
@MultipartConfig(fileSizeThreshold = 1024 * 1024 * 2, maxFileSize = 1024 * 1024 * 10, maxRequestSize = 1024 * 1024 * 100)
public class GenerateQRCode extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            String url = req.getParameter("url");
            BufferedImage image = QrCodeGenWrapper.of(url)
                    .setLogo(req.getPart("logo").getInputStream())
                    .setLogoRate(7)
                    .setLogoStyle(QrCodeOptions.LogoStyle.ROUND)
                    .asBufferedImage();
            ImageIO.write(image, "png", resp.getOutputStream());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • setLogo():设置 Logo 文件
  • setLogoRate(x):设置 Logo 缩放比,logo 宽高占二维码宽高的 x 分之一
  • setLogoStyle():设置 Logo 样式

(3)彩色二维码

BufferedImage image = QrCodeGenWrapper.of(url)
                    .setDrawPreColor(Color.BLUE)
                    .asBufferedImage();
  • setDrawPreColor():设置前景色

(4)背景图二维码

BufferedImage image = QrCodeGenWrapper.of(url)
                    .setBgImg(req.getPart("logo").getInputStream())
                    .setBgOpacity(0.7F)
                    .asBufferedImage();
  • setBgImg():设置背景图
  • setBgOpacity():设置背景图透明度

(5)特殊形状二维码

BufferedImage image = QrCodeGenWrapper.of(url)
                    .setDrawEnableScale(true)
                    .setDrawStyle(QrCodeOptions.DrawStyle.DIAMOND)
                    .asBufferedImage();
  • setDrawEnableScale(true):启用二维码绘制时的缩放功能
  • setDrawStyle():设置绘制样式

(6)图片填充二维码

BufferedImage image = QrCodeGenWrapper.of(url)
                    .setErrorCorrection(ErrorCorrectionLevel.H)
                    .setDrawStyle(QrCodeOptions.DrawStyle.IMAGE)
                    .addImg(1, 1, req.getPart("logo").getInputStream())
                    .asBufferedImage();
  • setErrorCorrection():设置二维码的错误校正级别

  • setDrawStyle():绘制二维码时采用图片填充

  • addImg():添加图片

-End-

标签:Java,jakarta,image,生成,二维码,com,import,servlet
From: https://www.cnblogs.com/SRIGT/p/17659924.html

相关文章

  • Git查看本机 ssh 公钥或生成公钥
    第一步查看git的ssh公钥是否存在在安装目录中打开GitBash并打开,然后在GitBash输入以下命名查看是否有密钥:ls-al~/.ssh第二步查看git的ssh公钥内容,并复制git的ssh公钥存储在id_rsa.pub文件中,如果id_rsa.pub文件,直接输入命令查看git公钥:cat~/.ssh/id_rsa.pub......
  • keytool生成证书
    配置jdk下载jdk  https://www.oracle.com/java/technologies/downloads/#java8-linux解压文件tar-xvfjdk-8u381-linux-x64.tar.gz 配置环境变量exportPATH=$PATH:/root/jdk1.8.0_381/bin注意:此处仅配置了建议环境变量,若需要配置jdk完整环境变量,可自行检索配置......
  • JavaScript中的不可变原始值和可变对象引用
    在JavaScript中,原始值(undefined、null、布尔值、数字和字符串)与对象(包括数组和函数)之间存在着根本的区别。原始值是不可变的,意味着它们的值无法改变。这对于数字和布尔值很容易理解:修改它们的值是没有意义的。然而,对于字符串来说,这可能会稍微不太直观。由于字符串类似于字符数组,可......
  • Java实现数据导出到excel文件
    Java实现数据导出到excel文件使用的依赖:Apache提供的poi包首先导入依赖<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.2</version></dependency>核心实现//创建一个工作簿,也就是Excel......
  • java中的图算法
    Java中有许多用于图算法的库和框架。下面是一些常见的图算法及其在Java中的实现方式:广度优先搜索(BFS):BFS用于在图中搜索最短路径。在Java中,可以使用LinkedList和HashSet来实现BFS算法。深度优先搜索(DFS):DFS用于在图中搜索路径或查找连通分量。在Java中,可以使用递归或栈来实现DFS算法......
  • Java实现数据导出到excel文件
    Java实现数据导出到excel文件使用的依赖:Apache提供的poi包首先导入依赖<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.2</version></dependency>核心实现//创建一个工作簿,也就是Excel......
  • 基于JavaWeb的游戏信息管理系统设计与实现-计算机毕业设计源码
    摘要随着信息技术的发展,基于web模式的管理系统逐渐普及,网上查找信息是目前广受欢迎的模式。基于JavaWeb的游戏信息管理系统可以适应现代化快节奏的游戏方式,满足各类人群足不出户的在线查找游戏,利用基于JavaWeb的游戏信息管理系统可以获取游戏的排名信息,并可以记录个人的游戏数据,......
  • 基于Java的学生管理系统-计算机毕业设计源码+LW文档
    摘 要计算机信息技术的迅猛发展,改变了人们的生产生活方式。越来越多的教务管理使用管理系统进行管理,用来提高管理效率。在传统的教学管理中,往往通过大量的人力和物力进行管理,通过手工记录课程信息,统计科目资料。这种传统的管理方法容易出错,而且不能适应现代化、信息化的发展过程......
  • Java字符串替换
    JavaStringreplaceAll详解总结:Java编译期\为转义符,运行期正则表达式\为转义符,正则表达式匹配\需使用\\。replace为普通字符串替换,replaceAll为正则表达式替换(第一个参数为正则表达式,第二个参数中\为转义字符,$为正则字符),第二个参数表示\需使用\\。示例:替换字符串中的""......
  • Java实现数据导出到excel文件
    使用的依赖:Apache提供的poi包首先导入依赖<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.2</version></dependency> 核心实现//创建一个工作簿,也就是Excel文件HSSFWorkbookwb=n......