二维码的生成、解析


 

概述

前后端都方便做的时候,交给前端来做

后端可以用java生成二维码,前端可以用js生成二维码,如果要保存到服务器,那就后端生成二维码;如果是一次性的、图片不需要保存到服务器,那就前端生成二维码。

后端实现,多个用户同时操作时会加重服务器的负担;前段实现,由用户浏览器完成操作,可以减轻服务器压力。前端生成二维码也比后端要简单一些。最好是前端传递参数,后端做相应处理返回给前端数据,前端拿到数据后生成对应的二维码。
 

要在多个模块中使用的功能,最好写成单独的一个模块

eg. 支付模块,二维码,短信通知

好处:1、解耦,好维护;2、方便复用

 

前端生成二维码

qrcode.js

qrcode.js 是一个用于生成二维码的 js 库,获取dom标签后使用canvas 绘制二维码,不依赖其它库。

<!-- 二维码容器 -->
<div id="qrcode"></div>

<!-- 引入qrcode.js -->
<script src="https://cdn.bootcdn.net/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>

<script type="text/javascript">
    // 容器
    let qrcodeEle = document.getElementById("qrcode");
    // 内容
    let text = "xxxxxxxxxxxxx";
    
    // 生成二维码
    let qrcode1= new QRCode(qrcodeEle,text);
    
    // 可以指定宽高、颜色、纠错等级
    let qrcode2 = new QRCode(qrcodeEle, {
            text: text,
            width: 128,
            height: 128,
            colorDark: "#ff0000",
            correctLevel: QRCode.CorrectLevel.H
        }
    );

    //清空二维码,容器还在
    qrcode1.clear(); 
    
    // 修改二维码的内容
    qrcode1.makeCode("xxxxx");
</script>

 

jquery.qrcode.js

jquery.qrcode.js是jq用于生成二维码的一个插件,依赖jq。

<!-- 二维码容器 -->
<div id="qrcode1"></div>
<div id="qrcode2"></div>

<!-- 引入jq -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

<!-- 引入jquery.qrcode.js -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery.qrcode/1.0/jquery.qrcode.min.js"></script>

<script>
    // 生成二维码
    $('#qrcode1').qrcode("xxxxxxxxxxxxxx");

    // 可以设置宽高
    $('#qrcode2').qrcode({width: 128, height: 128, text: "xxxxxxxxxxxxx"});
</script>

 

后端生成、解析二维码(zxing)

后端常用google的ZXing生成二维码。
 

依赖
<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>core</artifactId>
    <version>3.4.0</version>
</dependency>

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

 

前端
<!-- 上传二维码图片 -->
<form action="./qrcodeHandler" method="post" enctype="multipart/form-data">
    请选择二维码图片:<input name="qrcodeFile" type="file" /><br />
    <button type="submit">上传</button>
</form>

<br />


<!-- 从后端获取二维码 -->
<img id="qrcode" src="./getQrcode" />
<button onclick="flushQrcode()">刷新二维码</button>

<script>
    // 刷新验证码
    function flushQrcode() {
        let img = document.getElementById("qrcode");
        img.src = './getQrcode?' + new Date().getTime();
    }
</script>

 

后端

工具类

public class QrcodeUtil {

    // 生成的二维码格式
    public static final String QRCODE_FORMAT = "PNG";

    // 二维码的宽高
    private static final int QRCODE_SIZE = 300;
    
    // 内嵌图片的宽高
    private static final int INNER_SIZE = 80;

    /**
     * 生成普通二维码
     * 
     * @param text 二维码内容
     * @return BufferedImage 生成的二维码
     */
    public static BufferedImage generateQrcode(String text){
        HashMap<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.MARGIN, 1);

        BitMatrix bitMatrix = null;
        BufferedImage bufferedImage = null;
        MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(0xFF000001, 0xFFFFFFFF);
        try {
            bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints);
            bufferedImage = MatrixToImageWriter.toBufferedImage(bitMatrix,matrixToImageConfig);
        } catch (WriterException e) {
            e.printStackTrace();
        }

        return bufferedImage;
    }


    /**
     * 生成内嵌图片的二维码
     *
     * @param text 二维码内容
     * @param innerImagePath 内嵌图片的路径
     * @return BufferedImage 生成的二维码
     */
    public static BufferedImage generateQrcode(String text, String innerImagePath) {
        HashMap<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        hints.put(EncodeHintType.MARGIN, 1);

        BitMatrix bitMatrix = null;
        try {
            bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints);
        } catch (WriterException e) {
            e.printStackTrace();
        }

        BufferedImage image=null;
        if (bitMatrix!=null){
            int width = bitMatrix.getWidth();
            int height = bitMatrix.getHeight();
            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);
                }
            }
            // 插入图片
            insertImage(image, innerImagePath);
        }

        return image;
    }


    /**
     * 内嵌图片
     *
     * @param qrCodeImage 二维码图片
     * @param innerImagePath 内嵌图片的路径
     */
    private static void insertImage(BufferedImage qrCodeImage, String innerImagePath) {
        File file = new File(innerImagePath);
        if (file.exists()) {
            Image innerImage = null;
            try {
                innerImage = ImageIO.read(file);
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (innerImage!=null){
                int width = innerImage.getWidth(null);
                int height = innerImage.getHeight(null);
                // 缩放LOGO
                if (width > INNER_SIZE) {
                    width = INNER_SIZE;
                }
                if (height > INNER_SIZE) {
                    height = INNER_SIZE;
                }
                Image image = innerImage.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();
                innerImage = image;

                // 插入LOGO
                Graphics2D graph = qrCodeImage.createGraphics();
                int x = (QRCODE_SIZE - width) / 2;
                int y = (QRCODE_SIZE - height) / 2;
                graph.drawImage(innerImage, 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 file 上传的二维码图片
     * @return 二维码中的文本
     */
    public static String resolveQrcode(MultipartFile file) {
        HashMap<DecodeHintType, Object> hints = new HashMap<>(2);
        hints.put(DecodeHintType.CHARACTER_SET, "utf-8");

        String resultStr = null;
        try {
            BufferedImage image = ImageIO.read(file.getInputStream());
            BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
            Result result = new MultiFormatReader().decode(bitmap, hints);
            resultStr = result.getText();
        } catch (IOException | NotFoundException e) {
            e.printStackTrace();
        }

        return resultStr;
    }

    
}

 

controller

@Controller
public class QRCodeController {

    /**
     * 解析上传的二维码图片
     */
    @PostMapping("/qrcodeHandler")
    @ResponseBody
    public String excelHandler(@RequestParam("qrcodeFile") MultipartFile file) {
        String text = QrcodeUtil.resolveQrcode(file);
        return "二维码中的文本:" + text;
    }


    /**
     * 获取二维码图片
     */
    @GetMapping("/getQrcode")
    public void getQrcodeImage(HttpServletResponse response) {
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        //如果是jpg,此处改成jpeg
        response.setContentType("image/png");

        //二维码内容
        String text = Math.random() + "";
        //内嵌图片
        String innerImagePath = "C:/Users/chy/Desktop/1.jpg";

        //生成普通二维码
        BufferedImage bufferedImage = QrcodeUtil.generateQrcode(text);
        //生成内嵌图片的二维码
        // BufferedImage bufferedImage = QrcodeUtil.generateQrcode(text,innerImagePath);

        //输出到浏览器
        OutputStream os = null;
        try {
            os = response.getOutputStream();
            ImageIO.write(bufferedImage, QrcodeUtil.QRCODE_FORMAT, os);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (os!=null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    
}
  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面我来为你介绍具体的操作步骤。 1. 二维码生成实验 首先你需要安装 qrcode 库,可以使用 pip 进行安装: ``` pip install qrcode ``` 接着,你可以通过如下代码生成二维码并保存: ```python import qrcode data = "https://github.com/" # 二维码中保存的信息 img = qrcode.make(data) # 生成二维码图片 img.save("github.png") # 保存图片 ``` 这里我们以 GitHub 的链接为例生成二维码,并将其保存为 `github.png` 文件。可以看到,生成二维码如下图所示: ![github.png](https://cdn.jsdelivr.net/gh/wu529778790/image/blog/python/github.png) 2. 二维码解析实验 接下来我们使用 pyzbar 库对二维码进行解析。安装 pyzbar 库可以使用如下命令: ``` pip install pyzbar ``` 然后,你可以使用如下代码对生成二维码进行解析: ```python from pyzbar.pyzbar import decode from PIL import Image img = Image.open("github.png") # 打开二维码图片 data = decode(img) # 解析二维码 print(data[0].data.decode()) # 输出二维码中的信息 ``` 这里我们使用 `decode` 函数对二维码进行解析,并输出其中的信息。可以看到,输出的信息为 `https://github.com/`,与我们之前生成二维码时保存的信息一致。 3. 使用 tkinter 设计二维码生成解析程序 最后,我们可以使用 tkinter 设计一个简单的界面,将二维码生成解析整合到一起。 ```python import qrcode from pyzbar.pyzbar import decode from PIL import Image import tkinter as tk from tkinter.filedialog import askopenfilename, asksaveasfilename class App(tk.Frame): def __init__(self, master=None): super().__init__(master) self.master = master self.pack() self.create_widgets() def create_widgets(self): # 生成二维码按钮 self.gen_qr_btn = tk.Button(self) self.gen_qr_btn["text"] = "生成二维码" self.gen_qr_btn["command"] = self.generate_qr self.gen_qr_btn.pack(side="top") # 解析二维码按钮 self.parse_qr_btn = tk.Button(self) self.parse_qr_btn["text"] = "解析二维码" self.parse_qr_btn["command"] = self.parse_qr self.parse_qr_btn.pack(side="top") # 显示文本框 self.text = tk.Text(self) self.text.pack(side="bottom") def generate_qr(self): # 获取用户输入 data = self.text.get("1.0", tk.END).strip() if data: # 生成二维码 img = qrcode.make(data) # 保存二维码图片 filename = asksaveasfilename(defaultextension=".png", filetypes=[("PNG 图片", "*.png")]) if filename: img.save(filename) def parse_qr(self): # 选择图片文件 filename = askopenfilename(filetypes=[("PNG 图片", "*.png")]) if filename: # 打开图片并解析二维码 img = Image.open(filename) data = decode(img) if data: self.text.delete("1.0", tk.END) self.text.insert(tk.END, data[0].data.decode()) root = tk.Tk() app = App(master=root) app.mainloop() ``` 这里我们使用 `tkinter` 构建一个简单的界面,包括生成二维码按钮、解析二维码按钮和一个文本框用于输入和显示信息。在生成二维码时,我们使用了 `asksaveasfilename` 函数让用户选择保存图片的路径和文件名;在解析二维码时,我们使用了 `askopenfilename` 函数让用户选择要解析的图片文件。运行程序后,你可以在界面上输入信息并生成二维码,也可以选择图片文件并解析其中的二维码信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值