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

news2024/11/27 0:18:04

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与背景二维码区分开,这同样也是为了不影响二维码的可读性。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Go语言快速上手(二)】 分支与循环函数讲解

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:Go语言专栏⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多Go语言知识   &#x1f51d;&#x1f51d; Go快速上手 1. 前言2. 分支与循环2.1…

传统零售行业如何做数字化转型?

传统零售行业的数字化转型是一个系统性的过程&#xff0c;涉及到企业的多个方面。以下是一些关键步骤和策略&#xff0c;帮助传统零售企业实现数字化转型&#xff1a; 1、明确转型目标和战略 首先&#xff0c;企业需要明确数字化转型的目标和战略。包括确定企业的核心竞争力、…

生成对抗网络GAN的扩展应用理解

注&#xff1a;本文仅个人学习理解&#xff0c;如需详细内容请看原论文&#xff01; 一、cycleGAN 1.整体架构&#xff1a; 将图片A通过生成器生成图片B&#xff0c;然后通过判别器判别图片B的真假&#xff1b;并且图片B通过另一个生成器生成A‘&#xff0c;让A和A’近似。 2…

Linux 操作系统指令和Vscdoe安装

1、Linux系统介绍 Linux系统的背景介绍我就不介绍了&#xff0c;有兴趣的可以去看看其发展史。 1.1 Linux操作系统的主要特点 Linux操作系统的重要思想&#xff1a;一切皆文件 Linux操作系统的特性&#xff1a; 完全免费 支持多平台 支持多用户、多任务 有良好的界面 完美兼容…

EVI增强型植被指数

​随着遥感技术的发展&#xff0c;我们对地球上的植被状况有了更深入的了解&#xff0c;而其中一种重要的工具就是EVI&#xff08;Enhanced Vegetation Index&#xff0c;增强型植被指数&#xff09;。EVI不仅是一种植被指数&#xff0c;更是一种对植被生态系统健康和生产力评估…

Biome 1.7 发布,支持从 ESLint 和 Prettier 迁移

近日&#xff0c;Biome v1.7 正式发布&#xff01;这个新版本提供了从 ESLint 和 Prettier 迁移的简单路径。它还引入了格式化程序和 linter 的实验性机器可读报告、新的 linter 规则和许多修复。 使用以下命令更新 Biome&#xff1a; npm install --save-dev --save-exact b…

中科国声携新品亮相北京InfoComm China 2024展

4月17日&#xff0c;北京InfoComm China 2024展&#xff08;北京专业视听技术和集成体验解决方案展览会&#xff09;在北京的国家会议中心盛大开幕。展会为期三天。作为备受瞩目的”会议系统国家队“&#xff0c;中科国声携众多优质会议音频产品及全新会议系统解决方案精彩亮相…

隧道中心线提取

作者&#xff1a;迅卓科技 简介&#xff1a;本人从事过多项点云项目&#xff0c;并且负责的项目均已得到好评&#xff01; 公众号&#xff1a;迅卓科技&#xff0c;一个可以让您可以学习点云的好地方 重点&#xff1a;每个模块都有参数如何调试的讲解&#xff0c;即调试某个参数…

黑洞路由、 DDoS 攻击 、 环路

黑洞路由 DDoS 攻击 DDoS 攻击是一种针对服务器、服务或网络的恶意行为。DDoS 攻击通过向目标发送大量流量&#xff0c;使其不堪重负&#xff0c;导致资源和带宽被耗尽。因此&#xff0c;目标可能会变慢或崩溃&#xff0c;无法正常处理合法的流量。DDoS 攻击通常是由僵尸网络…

PMP知识点太多不知道怎么下手咋办?

项目经理知识人人都能学&#xff0c;可以说只要掌握了PMP项目管理体系知识&#xff0c;人人都能是项目经理。但是PMP的知识体系中知识点非常系统化&#xff0c;也非常细化&#xff0c;在认证考试时考点也比较松散&#xff0c;180题就覆盖了好几本PMP考试参考资料。 那么&#…

论文精读 MOG2系列 OpenCV源码提供的论文

本篇博客首先讲述Opencv库中MOG和MOG2的来源&#xff0c;然后对MOG2的一篇论文进行翻译。 图1. OpenCV官网 MOG 算法来自一篇论文&#xff1a; An Improved Adaptive Background Mixture Model for Real-time Tracking with Shadow Detection. 一种用于阴影检测实时跟踪的改进自…

Crossref

https://baijiahao.baidu.com/s?id1766583173146005960&wfrspider&forpc https://zhidao.baidu.com/question/1796197318615421547.html

2024.4.14 机器学习周报

目录 引言 Abstract 文献阅读 1、题目 2、引言 3、过去方案 4、创新点 5、方法 6、混合CNN-LSTM模型 7、实验过程 8、实验结果与评价 深度学习 通过VGG实现图片分类 1.data.py文件&#xff0c;用于处理数据 2.txt.py 将指定文件夹中的特定类型的图片路径和对应的…

如何在 MySQL 中开启日志记录并排查操作记录

在数据库管理中&#xff0c;能够追踪和审查操作记录是至关重要的。这不仅有助于识别和分析正常的数据库活动&#xff0c;还可以在数据泄露或未经授权的更改发生时进行调查和响应。本文将介绍如何在 MySQL 中开启通用日志记录&#xff0c;并如何排查操作记录。 开启 MySQL 通用…

双臂复合机器人平台叠方块例程使用与自启设置

睿尔曼双臂升降复合机器人平台&#xff0c;旨在为机器人教育提供强大的实训平台&#xff0c;该平台全自主研发&#xff0c;实现机器人建图导航、路径规划&#xff0c;机械臂运动学、动力学、轨迹规划、视觉识别等算法和应用&#xff0c;提供开放式的软件框架&#xff0c;为教学…

使用rsync同步备份linux文件内容到windows客户端

把数据库文件、视频、图片文件同步备份到其他机器上是不可缺少的环节&#xff0c;没有备份机制就是耍流氓。 远程linux服务器端安装rsync debian | ubuntu 系统 sudo apt install rsynccentos系统 sudo yum install rsync创建rsync用户和组 sudo adduser --system --group…

读天才与算法:人脑与AI的数学思维笔记03_AlphaGo

1. 国际象棋 1.1. 1997年计算机“深蓝”&#xff08;Deep Blue&#xff09;击败了顶尖国际象棋手&#xff0c;但机器取代数学研究机构还言之尚早 1.2. 下国际象棋与数学的形式化证明颇有相似之处&#xff0c;但学者认为中国围棋的思维方式更能够体现数学家思考的创造性和直觉…

Vue_管道符“|”(单竖线)的用处

目录 1、管道符是什么 2、应用场景 背景&#xff1a;项目中偶遇在 {{ }} 插值表达式里用了 “&#xff5c;”此写法&#xff0c;一开始误以为是写错了&#xff0c;应该是写成 “&#xff5c;&#xff5c;” 双竖线&#xff08; 逻辑或运算符 &#xff09;&#xff0c;结果询问…

Java基于SpringBoot+Vue的蜗牛兼职网系统的研究与实现

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

HTML学习笔记:(二)框架实例

2、 框架实例 注意&#xff1a;frameset不能和body标签共存 <frameset>元素是用于创建框架页面的&#xff0c;它允许在一个浏览器窗口中显示多个HTML页面。然而&#xff0c;<frameset>是一种较旧的方式来构建网页&#xff0c;它不符合现代Web标准&#xff08;比如…