Java实现生成中间带图标的二维码

Java实现生成中间带图标的二维码

生成Base64格式的二维码,返回html渲染

package your.package;

import com.google.zxing.*;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Base64;
import java.util.HashMap;

public class QRCodeWithLogo {

    public static void main(String[] args) throws Exception {
        String webUrl = "https://www.alibaba.com"; // 目标网址
        String logoPath = "alipay_logo.png"; // Logo图片文件路径
        int qrCodeSize = 200; // 二维码尺寸设置为300x300像素
        int logoSize = 50; // 定义Logo的宽度,留白区域大小

        // 调用函数生成带留白无logo的二维码图像
        BufferedImage qrCodeImage = generateQRCodeImage(webUrl, qrCodeSize, qrCodeSize, logoSize);

        // 调用函数在二维码中心加入支付宝logo
        BufferedImage qrCodeWithLogo = addLogoToQRCode(qrCodeImage, logoPath);

        // 调用函数将带有logo的二维码图像转换为Base64字符串
        String base64Encoded = convertImageToBase64(qrCodeWithLogo);

        System.out.println(base64Encoded); // 输出二维码的Base64编码字符串
    }


    /**
     * 生成带有中部空白区(为Logo预留空间)的二维码图像。
     * @param data 要编码到二维码中的数据字符串
     * @param width 生成的二维码图像宽度
     * @param height 生成的二维码图像高度
     * @param logoSize 预留给logo的空白区域的宽度与高度(假设空白区域为正方形)
     * @return 中央带有空白区域的二维码图像
     * @throws Exception 如果生成二维码时遇到任何错误,则抛出异常
     */
    private static BufferedImage generateQRCodeImage(
            String data, int width, int height, int logoSize) throws Exception {

        // 配置二维码生成参数
        HashMap<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // 指定二维码的编码设置为UTF-8
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // 设置二维码的纠错级别为高(H)
        hints.put(EncodeHintType.MARGIN, 0); // 设置二维码边缘 空背空白(边框大小)为0

        // 根据数据与配置信息生成二维码的比特矩阵
        BitMatrix bitMatrix = new MultiFormatWriter().encode(
                data, BarcodeFormat.QR_CODE, width, height, hints);

        // 将二维码比特矩阵转换为BufferedImage图像,用于最终输出
        BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix);

        // 计算中部logo空白区域的坐标位置
        // 这确保了空间位于二维码的正中心
        int deltaHeight = image.getHeight() - logoSize;
        int deltaWidth = image.getWidth() - logoSize;
        int coordX = deltaWidth / 2;
        int coordY = deltaHeight / 2;

        // 采用图形对象在图像上绘图
        Graphics2D g2 = image.createGraphics();

        // 设置compositing 规则定为SRC,通过AlphaComposite指定透明度效果
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC));

        // 设置Logo区域的填充颜色为白色
        g2.setPaint(Color.WHITE);
        // 绘制一个填充过的矩形以形成预留给logo的空白区域
        g2.fillRect(coordX, coordY, logoSize, logoSize);

        g2.dispose(); // 结束图形编辑并释放系统资源

        return image; // 返回生成的二维码BufferedImage对象
    }

    /**
     * 将一个给定的logo图片添加到二维码中心
     *
     * @param qrCodeImage 二维码的BufferedImage对象
     * @param logoPath logo图片的路径
     * @return 合成后的带有logo的二维码图片
     * @throws IOException 如果读取logo文件失败
     */
    private static BufferedImage addLogoToQRCode(BufferedImage qrCodeImage, String logoPath) throws IOException {
        // 从文件中读取logo图片
        BufferedImage logoImage = ImageIO.read(new File(logoPath));

        // 确定logo的最终权重宽度和高度 - 通常将logo缩小到原来尺寸的1/5
        int logoWidth = logoImage.getWidth() / 5;
        int logoHeight = logoImage.getHeight() / 5;

        // 创建一个新的缓冲区图像,其中包含alpha值(透明度)用来画带边界的logo
        BufferedImage logoWithBorder = new BufferedImage(logoWidth, logoHeight, BufferedImage.TYPE_INT_ARGB);
        // 使用Graphics2D绘制带边界的logo
        Graphics2D gBorder = logoWithBorder.createGraphics();

        // 设置合成规则,表示后续绘图操作将直接替换背景像素
        gBorder.setComposite(AlphaComposite.Src);

        // 设置抗锯齿属性来平滑边缘
        gBorder.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // 绘制一个填满整个logoWithBorder尺寸的白色矩形,形成logo的边界
        gBorder.setColor(Color.WHITE);
        gBorder.fillRect(0, 0, logoWidth, logoHeight);

        // 将logo图片缩放并绘制到logoWithBorder上
        gBorder.drawImage(logoImage.getScaledInstance(logoWidth, logoHeight, Image.SCALE_SMOOTH), 0, 0, null);

        // 不再进行绘制操作,释放此图形的上下文以及它使用的任何系统资源
        gBorder.dispose();

        // 计算二维码和logo的差距,用于将logo置于二维码的中心位置
        int deltaHeight = qrCodeImage.getHeight() - logoWithBorder.getHeight();
        int deltaWidth = qrCodeImage.getWidth() - logoWithBorder.getWidth();

        // 创建一个新的缓冲区图像以容纳原始的二维码和放置其中的logo
        BufferedImage combined = new BufferedImage(qrCodeImage.getHeight(), qrCodeImage.getWidth(), BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = (Graphics2D) combined.getGraphics();

        // 将二维码绘制在新图片的最底层
        g.drawImage(qrCodeImage, 0, 0, null);

        // 设置合成效果来绘制logo,覆盖在之前绘制的内容之上
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f));

        // 在合适的位置绘制带有白边背景框的logo(确保居中)
        g.drawImage(logoWithBorder, Math.round(deltaWidth / 2), Math.round(deltaHeight / 2), null);

        // 完成绘制,释放图形上下文使用的资源
        g.dispose();

        // 返回合成后带有logo的二维码图像
        return combined;
    }

    /**
     * 将图像转换成Base64编码的字符串
     * @param image
     * @return
     * @throws Exception
     */
    private static String convertImageToBase64(BufferedImage image) throws Exception {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); // 创建ByteArrayOutputStream对象
        ImageIO.write(image, "png", outputStream); // 把BufferedImage写入流中
        byte[] imageBytes = outputStream.toByteArray(); // 转换成对应的byte数组
        return Base64.getEncoder().encodeToString(imageBytes); // 进行Base64编码,并返回字符串
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<img src="data:image/png;base64,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">
</body>
</html>

效果图

在这里插入图片描述

总结

上述代码是一个Java函数,主要目的是将logo图片加到二维码图片的中央位置上,完成之后返回这个合成后的图像,你也改造渲染成图片下载出来。

制作这样的二维码可以增加品牌辨识度或者美观性,在实际操作时,需要满足两个条件:

  1. logo不能过大,以免遮挡二维码导致难以扫描识别
  2. logo最好有一个边界,那样可以让logo与背景二维码区分开,这同样也是为了不影响二维码的可读性。

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

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

相关文章

flask 应用程序

flask 程序示例 创建 hello.py 文件&#xff1a; # 导入 Flask 模块。Flask 类的一个对象是 wsgi 应用程序。 from flask import Flask# 创建app对象, Flask构造函数将当前模块的名称(__name__)作为参数。 app Flask(__name__)# route() 函数是一个装饰器&#xff0c;它告诉应…

Linux上安装mysql指南

最近入职了新单位&#xff0c;申请到了一台cvm。我这个机子是redhat的linux发行版&#xff0c;就用rpm包安装工具就行。下面把我趟过的一些坑写在这里&#xff0c;希望对您有帮助。 一开始&#xff0c;我自己下载了安装包&#xff0c;装了一个这个社区版的&#xff0c;rpm -qa…

鸿蒙入门05-真机运行“遥遥领先”

如果你有一台真的 "遥遥领先"那么是可以直接在手机上真机运行你的项目的我们也来尝试一下运行 一、手机设置开发者模式 打开手机设置 打开手机设置界面 向下滑动到关于手机位置 快速连续点击版本号位置 下图所示位置快速连续点击 打开 3 - 5 次即可 会提示您已经进…

【R语言】动画图:散点图

绘制成如下的散点图&#xff1a; 如果数据量大&#xff0c;有多个年份&#xff0c;就会生成多张图&#xff0c;例如&#xff1a; 具体代码如下&#xff1a; library(gapminder)#加载 gapminder 包&#xff0c;其中包含了从 1952 年至 2007 年各个国家的 GDP、预期寿命和人口数据…

目标检测——鱼类数据集

一、重要性及意义 生物多样性保护与监测&#xff1a; 鱼类识别是生物多样性保护工作的关键一环。通过准确识别不同种类的鱼类&#xff0c;科学家能够更好地了解它们的分布、种群数量以及栖息地状况&#xff0c;从而制定更为有效的保护措施。鱼类是水域生态系统的重要组成部分…

通过阿里云向量检索 Milvus 版和通义千问快速构建基于专属知识库的问答系统

背景介绍 阿里云向量检索 Milvus 版是一款 Serverless 全托管服务&#xff0c;确保了与开源 Milvus 的完全兼容性&#xff0c;并支持无缝迁移。它在开源版本的基础上增强了可扩展性&#xff0c;能提供大规模 AI 向量数据的相似性检索服务。凭借其开箱即用的特性、灵活的扩展能力…

基于百度文心大模型全面重构,小度正式推出AI原生操作系统DuerOS X

4月16日&#xff0c;以“创造未来”为主题的2024百度Create AI开发者大会在深圳举办。百度集团副总裁、小度科技CEO李莹正式发布了小度新一代操作系统DuerOS X&#xff0c;该操作系统是小度基于百度文心大模型推出的全球首个AI原生操作系统。李莹表示&#xff1a;“作为⽂⼼⼤模…

ChatGPT与Python-GEE融合,遥感云大数据分析、管理与可视化

掌握Earth Engine的实际应用能力&#xff0c;以Python为基础&#xff0c;结合实例讲解平台搭建、影像数据分析、经典应用案例、本地与云端数据管理&#xff0c;以及云端数据论文出版级可视化等技能。 为提高教学质量&#xff0c;将融入ChatGPT 4、Claude Opus、Gemini、文心一…

读《SQL基础教程 第二版 上》的一些总结

1. 数据库语言 DDL: Data Definition Language&#xff0c;数据定义语言&#xff08;库、表的操作&#xff09; DML: Data Manipulation Language&#xff0c; 数据操控语言&#xff08;对表中数据的增删改&#xff09; DQL: Data Query Language&#xff0c;数据库查询语言…

SAP是什么?SAP介绍

一、概述 ​SAP,为“System Applications and Products”的简称,是SAP公司的产品——企业管理解决方案的软件名称。​ SAP含义 第一,SAP是公司名称,即SAP公司(纽交所代码:SAP),它是成立于1972年总部位于德国沃尔多夫市的全球最大的企业管理和协同化电子商务解决方案…

SpringBoot多数据源(一)

SpringBoot多数据源&#xff08;一&#xff09; 1.多数据源使用场景1.1 业务复杂&#xff08;数据量大&#xff09;1.2 读写分离 2.多数据源配置3.应用4.测试 1.多数据源使用场景 1.1 业务复杂&#xff08;数据量大&#xff09; 简单理解就是业务量复杂&#xff0c;将庞大的数…

UML/SysML建模工具更新情况-截至2024年4月(1)5款-Trufun建模平台 v2024

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 工具最新版本&#xff1a;itemis CREATE 5.2.2 更新时间 2024年3月22日 工具简介 原名YAKINDU Statechart Tools。状态机建模工具&#xff0c;支持各种语言的代码生成&#xff0c;提…

1000kW 柴油发电机组测试负载箱的核心功能

随着科技的不断发展&#xff0c;电力系统的稳定性和安全性日益受到重视。柴油发电机组作为一种重要的备用电源设备&#xff0c;其性能和可靠性直接关系到电力系统的稳定运行。为了确保柴油发电机组的性能和可靠性&#xff0c;对其进行定期的检测和维护是必不可少的。 在这个过程…

电磁仿真--基本操作-CST-(1)

目录 1. 开启-备忘 2. 从调用最简单的Dipole天线开始 2.1 查找示例 2.2 运行示例 2.3 进度与消息 2.4 查看结果 2.4.1 Port signals 2.4.2 S-Parameter 2.4.3 Reference Impedance 2.4.4 Balance 2.4.5 Power 2.4.6 Energy 2.4.7 Discrete Ports 2.4.8 2D/3D Res…

Spring Boot后端+Vue前端:打造高效二手车交易系统

作者介绍&#xff1a;✌️大厂全栈码农|毕设实战开发&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。 &#x1f345;获取源码联系方式请查看文末&#x1f345; 推荐订阅精彩专栏 &#x1f447;&#x1f3fb; 避免错过下次更新 Springboot项目精选实战案例 更多项目…

Linux服务器硬件及RAID配置

一、服务器硬件 塔式服务器&#xff1a;最初的服务器形态之一&#xff0c;类似于传统的台式电脑&#xff0c;但具有更强的处理能力和稳定性&#xff0c;适合小型企业或部门使用。 机架式服务器&#xff1a;设计为可安装在标准化机架内的模块化单元&#xff0c;可以有效地节省空…

好用的AI绘画工具,5个一键AI自动生成绘画推荐

在数字时代&#xff0c;AI绘画软件开启了人们展现创意的全新篇章。如果你对AI一键生成绘画的感兴趣&#xff0c;那就跟着我一起来了解一下吧&#xff01; 1.爱制作AI 爱制作AI是一款功能强大的人工智能软件&#xff0c;它不仅拥有超强的AI问答能力&#xff0c;还能轻松搞定绘画…

Aigtek功率放大器的使用方法有哪些

功率放大器是一种将小信号放大为大信号的电子设备&#xff0c;广泛应用于无线通信、音频系统、雷达等领域。在使用功率放大器时&#xff0c;需要注意以下几个方面&#xff1a; 电源供应&#xff1a;功率放大器需要提供稳定的电源供应以保证正常工作。通常情况下&#xff0c;功率…

2021年全国大学生电子设计竞赛D题——基于互联网的摄像测量系统(三)

13 测试方案和测量结果 测量一个边长为1米的正方形&#xff0c;取三个顶点分别作为O、A、B点。 在O点上方&#xff0c;用细线悬挂激光笔&#xff0c;激光笔常亮向下指示&#xff0c;静止时激光笔的光点和O点重合。 将两个D8M摄像头子卡插到DE10-Nano开发板上&#xff0c;放…

按摩上门小程序源码系统 带完整的安装代码包以及搭建教程

随着人们生活节奏的加快&#xff0c;越来越多的人开始追求便捷、高效的生活方式。按摩服务作为一种放松身心、缓解压力的方式&#xff0c;受到了广大消费者的青睐。然而&#xff0c;传统的按摩服务往往受到时间、地点等因素的限制&#xff0c;难以满足消费者的即时需求。因此&a…