JAVA 二维码绘制,可定义背景图与在背景图种的位置,码点绘制避开logo区域10个像素点

news2024/11/17 9:49:55

效果图:

背景图:

直接看代码和代码说明:

方法drawQr() 为绘制核心仅绘制出图上的二维码

方法createQr() 包含 读取背景图和 调用drawQr()绘制出完整的带有背景图的二维码

drawQr()方法参数说明:

     * @param content                            二维码内容
     * @param qrSize                              二维码大小
     * @param logoBarry                         二维码logo字节流
     * @param qrMaDianColor                二维码码点颜色
     * @param qrBgColor                        二维码背景颜色
     * @param bgImg                              包裹二维码的背景图
     * @param qrInBgImgSize                二维码占用背景图内部的大小的百分之多少,1-10之间
     * @param qrInBgImgX                     二维码在背景图内部的位置X坐标
     * @param qrInBgImgY                     二维码在背景图内部的位置Y坐标

二维码绘制保证了logo在二维码中心的位置,且大小仅是占用二维码的20%

码点的绘制避开了logo区域的10个像素点。可以保证二维码在中间的美观性

ErrorCorrectionLevel.M 是错误等级,可自行修改。

二维码的码点形状绘制,敬请期待...

码点绘制开发好后保证全部免费开源

import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
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 lombok.extern.log4j.Log4j2;

import javax.imageio.ImageIO;
import javax.imageio.ImageWriter;
import javax.imageio.stream.FileImageOutputStream;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * <p>
 * 二维码生成工具
 * </p>
 *
 * @author Garcia
 * @since 2023-05-31
 */
@Log4j2
public class QrCodeUtil {

    /**
     * 使用示例
     */
    private static void useExample() throws IOException {
        BufferedImage schoolLogo = ImgUtil.read(FileUtil.file("C:\\Users\\Garcia\\Desktop\\test\\234.png"));
        ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 创建字节输出流
        DataOutputStream dos = new DataOutputStream(baos); // 创建数据输出流,并关联到字节输出流上
        ImageIO.write(schoolLogo, "png", dos);
        byte[] logo = baos.toByteArray();
        byte[] bytes = QrCodeUtil.generateQr("www.baidu.com",logo);
        QrCodeUtil.generateQrPng("www.baidu.com",logo,"C:\\Users\\Garcia\\Desktop\\test\\qq.png");
    }

    /**
     * 直接生成png到指定路径
     * @param content
     * @param logo
     * @param outPath
     */
    public static void generateQrPng(String content, byte[] logo,String outPath){
        try {
            BufferedImage image = createQr(content,logo);
            Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("png");
            ImageWriter writer = writers.next();
            ImgUtil.write(image,writer,new FileImageOutputStream(new File(outPath)),1);
        } catch (Exception e) {
            log.error("创建二维码异常",e);
        }
    }

    /**
     * 返回流字节
     * @param content
     * @param logo
     * @return
     */
    public static byte[] generateQr(String content, byte[] logo){
        try {
            Image image = createQr(content,logo);
            return ImgUtil.toBytes(image,"PNG");
        } catch (Exception e) {
            log.error("创建二维码异常",e);
        }
        return null;
    }

    private static BufferedImage createQr(String content,byte[] logo) throws Exception {
	    //读取背景图
        BufferedImage bgImg = ImgUtil.read(FileUtil.file("C:\\Users\\Garcia\\Desktop\\test\\bg.png"));
        BufferedImage originalImage = drawQr(content,
                1000,
                logo,
                Color.white,
                new Color(0,105,183),
                bgImg,5,-1,213);
        return originalImage;
    }

    /**
     * 二维码绘制
     * @param content
     * @param qrSize
     * @param logoBarry
     * @param qrMaDianColor
     * @param qrBgColor
     * @param bgImg
     * @param qrInBgImgSize
     * @param qrInBgImgX
     * @param qrInBgImgY
     * @return
     * @throws Exception
     */
    private static BufferedImage drawQr(String content,
                                        int qrSize ,
                                        byte[] logoBarry,
                                        Color qrMaDianColor,
                                        Color qrBgColor,
                                        BufferedImage bgImg,
                                        int qrInBgImgSize,
                                        int qrInBgImgX,
                                        int qrInBgImgY) throws Exception {
        int logoRadius = 10;
        float cornerRadius = 50.525f;
        int prohibitArea = 15;
        Map<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        hints.put(EncodeHintType.MARGIN, 1); //二维码边界距离
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, qrSize, qrSize, hints);
        int matrixWidth = bitMatrix.getWidth();
        int matrixHeight = bitMatrix.getHeight();
        BufferedImage image = new BufferedImage(matrixWidth, matrixHeight, BufferedImage.TYPE_INT_ARGB);
        if (logoBarry!=null&&logoBarry.length>0){
            BufferedImage logo = ImageIO.read(new ByteArrayInputStream(logoBarry));
            BufferedImage borderImage = new BufferedImage(logo.getWidth(), logo.getHeight(), BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2dff1 = borderImage.createGraphics();
            g2dff1.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2dff1.setColor(Color.WHITE);
            g2dff1.fill(new RoundRectangle2D.Float(0, 0, logo.getWidth(), logo.getHeight(), logoRadius * 2, logoRadius * 2));
            g2dff1.setComposite(AlphaComposite.SrcIn);
            g2dff1.drawImage(logo, 0, 0, null);
            g2dff1.dispose();

            //计算放置logo到二维码中的大小
            int widthLogo = image.getWidth()*2/10;
            int heightLogo = image.getHeight()*2/10;

            //计算放置logo到二维码中的位置
            int leftX = (qrSize - widthLogo) / 2;
            int leftY = (qrSize - heightLogo) / 2;

            //logo右下角坐标
            int rightX = leftX + widthLogo;
            int rightY = leftY + heightLogo;

            for (int mx = 0; mx < matrixWidth; mx++) {
                for (int my = 0; my < matrixHeight; my++) {
                    //logo区域禁止画码点
                    if (mx>=leftX-prohibitArea&&mx<=rightX+prohibitArea&&my>=leftY-prohibitArea&&my<=rightY+prohibitArea){
                        image.setRGB(mx, my, qrBgColor.getRGB());
                        continue;
                    }
                    if (!bitMatrix.get(mx, my)){
                        image.setRGB(mx, my, qrBgColor.getRGB());
                        continue;
                    }
                    //码点样式,有机会再修改
                    image.setRGB(mx, my, qrMaDianColor.getRGB());
                }
            }

            //放置logo到二维码
            Graphics2D graph = image.createGraphics();
            graph.drawImage(borderImage, leftX, leftY, widthLogo, heightLogo, null); //将 Logo 插入到二维码中间
            graph.dispose();
        }else {
            for (int mx = 0; mx < matrixWidth; mx++) {
                for (int my = 0; my < matrixHeight; my++) {
                    image.setRGB(mx, my, bitMatrix.get(mx, my)?qrMaDianColor.getRGB():qrBgColor.getRGB());
                }
            }
        }

        //将二维码绘制为圆角矩形
        BufferedImage roundedCornerQRCode = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2dff = roundedCornerQRCode.createGraphics();
        g2dff.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2dff.setColor(Color.white);
        g2dff.fill(new RoundRectangle2D.Float(0, 0, image.getWidth(), image.getHeight(), cornerRadius * 2, cornerRadius * 2));
        g2dff.setComposite(AlphaComposite.SrcIn);
        g2dff.drawImage(image, 0, 0, null);
        g2dff.dispose();

        //背景
        int emw = Math.min(roundedCornerQRCode.getWidth(null), bgImg.getWidth() * qrInBgImgSize / 10),
                emh = roundedCornerQRCode.getHeight(null)>bgImg.getWidth()*qrInBgImgSize/10?(bgImg.getWidth()*qrInBgImgSize/10):roundedCornerQRCode.getWidth(null);

        int X=qrInBgImgX,Y=qrInBgImgY;
        if (qrInBgImgY==-1){
            //计算放置二维码到背景中的位置
            Y = ( bgImg.getHeight() - emh) / 2;
        }
        if (qrInBgImgX==-1){
            //计算放置二维码到背景中的位置
            X = ( bgImg.getWidth() - emw) / 2;
        }
        Graphics2D bg2d = bgImg.createGraphics();
        bg2d.drawImage(roundedCornerQRCode, X, Y, emw, emh, null);
        bg2d.dispose();
        return bgImg;
    }

}

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

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

相关文章

新星计划【数据结构与算法】赛道开启,欢迎报名!

前排提醒&#xff1a;这里是新星计划2023【数据结构与算法】学习方向的报名入口&#xff0c;一经报名&#xff0c;不可更换。 ↓↓↓报名方式&#xff1a;新星计划2023【数据结构与算法】学习方向报名入口&#xff01;-CSDN社区 一、关于本学习方向导师 博客昵称&#xff1a;…

上海亚商投顾:沪指探底回升微跌 减速器概念股大涨

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪 指数今日探底回升&#xff0c;三大股指盘中均跌超1%&#xff0c;随后跌幅逐渐收窄&#xff0c;沪指午后一度拉升翻…

Elasticsearch:使用 SIMD 指令加速向量搜索

作者&#xff1a;Chris Hegarty, Elastic Principal Engineer, Lucene PMC 翻译&#xff1a;杰瑞朱 多年来&#xff0c;Java 平台上运行的代码一直受益于自动向量化 —— HotSpot C2 编译器中的 superword 优化&#xff0c;将多个标量操作打包到 SIMD&#xff08;单指令多数据…

CWDM粗波分复用和DWDM密集波分复用的区别?

WDM波分复用技术提供了一种经济高效的解决方案&#xff0c;无需在现有光纤网络中部署额外的光纤即可增加网络容量。 CWDM 和 DWDM 是两种主要的 WDM 技术&#xff0c;具有不同的波长模式、功能、成本和应用。 CWDM 代表粗波分复用&#xff0c;其中“Coarse” 是指通道之间的波…

分享一个内网的屏幕分享软件inletexemc

分享一个内网的屏幕分享软件inletexemc 参考文章&#xff1a;https://zhuanlan.zhihu.com/p/25912687 原本采用的一个叫veyon的电子教室管理软件&#xff0c;虽然可以实现这个效果&#xff0c;但是比较笨重&#xff0c;操作也比较繁琐&#xff0c;具体可参考&#xff1a;http…

对话商越苗峰:未来十年,采购数字化是ERP后最核心应用之一

“从创立开始&#xff0c;商越就非常清楚要做什么、不做什么&#xff0c;这个定位到现在没变&#xff0c;未来也不会变。” 作者|皮爷 出品|产业家 清晰、理智、坚定、条律分明&#xff0c;这是商越创始人苗峰给我的第一感觉。 在见到他之前&#xff0c;我曾想象过这家短短几…

来酷智生活,Type-C十二合一扩展坞来了

联想最新推出的“来酷智生活Type-C十二合一扩展坞”为用户带来更多接口选择&#xff0c;方便实用。 这款扩展坞包含12个接口&#xff0c;包括2个USB 3.2&#xff0c;2个USB 2.&#xff0c;2个HDMI接口&#xff0c;TF卡插槽&#xff0c;SD卡插槽&#xff0c;DP接口&#xff0c;P…

电压放大器在超声波检测中的应用

电压放大器是一种用于放大电压信号的电子设备&#xff0c;它具有低噪声、高增益、线性度高等特点&#xff0c;被广泛应用于各种电子设备中。在超声波检测中&#xff0c;电压放大器在信号的采集和处理中发挥着非常重要的作用。 超声波检测是一种通过声波的反射和传播来检测物体内…

系统定制开发-安卓输入法将应用顶起问题

输入法弹出会导致应用窗口往上移动 InputMethodService.java中有关窗口重置代码 只需要重写onComputeInsets,将outInsets.contentTopInsets 设为decor.getHeight() Overridepublic void onComputeInsets(final InputMethodService.Insets outInsets) {super.onComputeInsets(o…

6.2 文件与目录管理

6.2.1 文件与目录的检视&#xff1a; ls 在Linux中&#xff0c;ls指令最常被执行&#xff0c;因为我们随时都要知道文件或者目录的相关信息。Linux的文件记录信息很多&#xff0c;因此ls没有需要全部都列出来。所以下达ls时&#xff0c;默认的有&#xff1a;非隐藏文件的文件名…

电脑开机太慢!怎么让电脑开机速度变快?

电脑刚买来的时候&#xff0c;开机速度很快&#xff0c;用了一段时间后&#xff0c;开机速度越来越慢&#xff0c;甚至要等上好几分钟&#xff0c;这实在是太让人苦恼了!电脑开机太慢&#xff0c;怎么让电脑开机速度变快&#xff1f;其实想要解决这个问题很简单&#xff0c;我们…

centos安装docker后,ping不能服务器ip

工作中碰的问题&#xff0c;记录下解决过程&#xff1a; 问题描述 2台内网服务器&#xff1a;A&#xff08;172.20.72.77&#xff09;和B&#xff08;172.17.3.222&#xff09;&#xff0c;在A服务上ping B 。 安装 docker之前是可以ping通&#xff0c;安装docker之后确ping不…

周鸿祎考上了清华博士

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 绝大多数人在功成名就后&#xff0c;想做的事&#xff1a;盖一所希望小学、去学校当老师或者当学生。而周鸿祎选择了去清华读博士。 360的老板周鸿祎&#xff0c;在他53岁的时候考上了清华博士&…

【虚拟机】电脑里面VirtualBox虚拟机不见了

非常突然&#xff0c;打开VirtualBox时&#xff0c;发现工具栏里面之前创建的虚拟机都不见了&#xff0c;自己又没有删&#xff0c;咋回事呢&#xff0c;有些慌&#xff0c;之前的撸力全没有了&#x1f47f;。。。之前有关注过存储文件路径&#xff0c;去找了一下发现*.vdi和*.…

多模态超省钱!JinaChat 面向开发者的大模型服务

2023年6月25日 Jina AI 发布了 JinaChat&#xff0c;一个面向开发者和终端用户的多模态大模型API。传统大型语言模型往往将竞争力建立在「参数多」和「刷分强」的基础上&#xff0c;然而对于应用开发者来说&#xff0c;传统模型商的 API 并不能很好地让开发者低成本的实现解决方…

记录spring boot引入JWT遇到的问题---突然自己展现登录页面

才用了两天的swagger&#xff0c;本来一切如常&#xff0c;焦头烂额写个带token的登录&#xff0c;终于写好了&#xff0c;准备验证一把&#xff0c;就发现swagger莫名其妙自己出现登录界面了&#xff0c;也不知道账号密码&#xff0c;慌得一批 1. 现象说明 试了自己写的登录账…

centos7下部署python

1.在liunx上安装python运行环境 [rootlocalhost ~]# yum -y install gcc[rootlocalhost ~]# yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel libffi-devel2.进入到安…

HQChart使用教程30-K线图如何对接第3方数据38-通达信指标K线数据

HQChart使用教程30-K线图如何对接第3方数据38-通达信指标K线数据 指标内K线数据协议名称协议日志截图请求字段说明ExplainRequestData KLineDataTimeRange 返回json数据结构日K线分钟K线 HQChart代码地址交流 指标内K线数据 通达信指标计算过程中会用到K线数据&#xff0c;一般…

【Java面试】为什么匿名内部类只能访问外部类的final类型局部变量?

先来看一下下面一段代码 public class InnerClassTest {public static void main(String[] args) {int a 10;new Service() {Overridepublic void method() {System.out.println("a" a);}}.method();a 11;}}interface Service {public void method(); }这段代码并…

官宣自营品质快递服务,菜鸟显露“鸿鹄之志”?

菜鸟迎来分拆发展后又一重磅动作。6月28日&#xff0c;菜鸟在全球智慧物流峰会现场&#xff0c;宣布推出自营的品质快递业务&#xff1a;菜鸟速递。菜鸟集团CEO万霖确认&#xff0c;已经获得“快递牌照”。 菜鸟速递的推出处于一个特殊的背景下&#xff0c;它作为阿里拆分后上…