Java使用Graphics2D画图,画圆,矩形,透明度等实现

背景

如上图,需要使用Java生成一个图片, 并以base64编码的形式返回给前端展示。

使用Graphics2D类,来进行画图,其中需要画方框、原型、插入图标、写入文字等,同时需要设置透明度等细节点 

环境:Jdk17,springboot2.7.13

代码如下

有详细的注释

package com.demo;import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.FileUtil;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ThreadLocalRandom;/*** <p>* 功能描述:* </p>** @author MILLA* @version 1.0* @since 2024/06/24 9:14*/
@Slf4j
public class ImageDemo {/*** 每个div的高度*/private static final int LINE_HEIGHT = 80;private static final double COLOR_WIDTH = 0.7;/*** 处方笺图片宽*/private static final int PIC_WIDTH = 1200;/*** 顶部与底部留白*/private static final int MARGIN_Y = 52;/*** 左右留白*/private static final int MARGIN_X = 50;/*** 生成图片后缀*/private static final String FILE_SUFFIX = ".jpg";public static void main(String[] args) throws Exception {List<Object> objects = Lists.newArrayList(1, 2, 3, 4, 5, 6);String base64 = new ImageDemo().getImage(objects);System.out.println(base64);}/*** 初始化** @param image    画布* @param graphics 画笔*/private void initiation(BufferedImage image, Graphics2D graphics) {int width = image.getWidth();int height = image.getHeight();graphics.setClip(0, 0, width, height);// 设置画笔颜色graphics.setColor(Color.white);// 绘制背景graphics.fillRect(0, 0, width, height);// 设置抗锯齿graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);}private String getImage(List<Object> objects) throws IOException {//读取图标流InputStream stream = this.getClass().getClassLoader().getResourceAsStream("static/icon.png");BufferedImage avatar = ImageIO.read(stream);// 新建图片BufferedImage image = new BufferedImage(PIC_WIDTH, objects.size() * LINE_HEIGHT + MARGIN_Y * 2, BufferedImage.TYPE_INT_BGR);// 创建画笔Graphics2D graphics = image.createGraphics();// 初始化背景色initiation(image, graphics);// 定义marginMargin margin = new Margin(MARGIN_Y, MARGIN_Y, MARGIN_X, MARGIN_X);// 初始化坐标Point point = new Point(margin.getLeft(), margin.getTop());ThreadLocalRandom random = ThreadLocalRandom.current();for (int i = 0; i < objects.size(); i++) {Color color = new Color(random.nextInt(0, 255), random.nextInt(0, 255), random.nextInt(0, 255));drawDiv(point, image, graphics, color, avatar, "颜色名称: " + (i + 1), "P", "颜色编码:" + (i + 1));}// 销毁画笔,结束绘制graphics.dispose();byte[] bytes = toByteArray(image);//文件生成log.info("文件路径", FileUtil.writeBytes(bytes, "test" + FILE_SUFFIX));String prefix = "data:image/jpg;base64,";return prefix + Base64.encode(bytes);}private void drawDiv(Point point, BufferedImage image, Graphics2D graphics, Color color, BufferedImage avatar, String name, String type, String code) {Font font = new Font("宋体", Font.BOLD, 28);int width = image.getWidth() - 2 * point.getX();// 设置div的绘制区域graphics.setClip(point.getX(), point.getY(), width, LINE_HEIGHT);
//         设置画笔颜色graphics.setColor(color);int firstWidth = (int) (COLOR_WIDTH * width);
//         绘制背景 一行的前半部分graphics.fillRect(point.getX(), point.getY() + 1, firstWidth, LINE_HEIGHT - 2);// 设置画笔int nameX = point.getX() + 18;drawContent(name, graphics, nameX, point.getY(), Color.WHITE, image.getWidth(), point, font);int circleX = firstWidth - 15;drawCircle(point, graphics, circleX);font = new Font("宋体", Font.BOLD, 23);drawContent(type.toUpperCase(Locale.ROOT), graphics, circleX + 5, point.getY(), Color.WHITE, image.getWidth(), point, font);// 绘制背景 一行的后半部分--外部矩形框Color outerColor = new Color(Integer.parseInt("DDDDDD", 16));graphics.setColor(outerColor);int secondWidth = (int) ((1 - COLOR_WIDTH) * width);graphics.fillRect(point.getX() + firstWidth, point.getY(), secondWidth, LINE_HEIGHT);// 绘制背景 一行的后半部分---内部矩形框Color innerColor = new Color(Integer.parseInt("F4F4F4", 16));graphics.setColor(innerColor);graphics.fillRect(point.getX() + firstWidth + 1, point.getY() + 1, secondWidth - 2, LINE_HEIGHT - 2);//图标int avatarHeight = avatar.getHeight() / 2;int avatarX = point.getX() + firstWidth + 31;graphics.drawImage(avatar, avatarX, point.getY() + 1 + (LINE_HEIGHT - avatarHeight) / 2, avatar.getWidth() / 2, avatarHeight, innerColor, null);//图标 --文字int codTextX = avatarX + avatar.getWidth() / 3 + 33;font = new Font("宋体", Font.PLAIN, 20);drawContent(code, graphics, codTextX, point.getY(), Color.BLACK, image.getWidth(), point, font);point.setY(point.y + LINE_HEIGHT - 1);}private void drawCircle(Point point, Graphics2D graphics, int circleX) {Composite composite = graphics.getComposite();//透明度设置AlphaComposite instance = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f);graphics.setComposite(instance);graphics.setColor(Color.BLACK);graphics.fillOval(circleX, point.getY() + (LINE_HEIGHT - 32) / 2, 32, 32);//恢复原来的透明度graphics.setComposite(composite);}private void drawContent(String text, Graphics2D cs, int x, int y, Color color, int width, Point point, Font font) {//临时将需要裁剪区域置空cs.setClip(null);//设置文本颜色cs.setColor(color);//设置文本字体cs.setFont(font);//文本抗锯齿cs.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);cs.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);//为画布添加文字,并居中FontMetrics fm = cs.getFontMetrics(font);int ascent = fm.getAscent();int descent = fm.getDescent();cs.drawString(text, x + 5, y + (LINE_HEIGHT - (ascent + descent)) / 2 + ascent);//恢复之前的裁剪区域cs.setClip(point.getX(), point.getY(), width - 2 * point.getX(), LINE_HEIGHT);}private byte[] toByteArray(BufferedImage image) throws IOException {// 输出png图片ByteArrayOutputStream os = new ByteArrayOutputStream();image.flush();ImageIO.write(image, "png", os);return os.toByteArray();}@Data@AllArgsConstructorpublic static class Margin {/*** 上*/private int top;/*** 底*/private int bottom;/*** 左*/private int left;/*** 右*/private int right;}@Data@AllArgsConstructorpublic static class Point {private int x;private int y;}}

 PS:生成的图片如文头,base64编码如下图

 

 但是在移植到docker容器中部署的时候,报以下错误

2024-06-25 16:26:31.019 [http-nio-10008-exec-7] ERROR com.a.mybatis.common.exception.RestfulExceptionHandler - 异常堆栈:
jakarta.servlet.ServletException: Handler dispatch failed: java.lang.UnsatisfiedLinkError: /opt/java/openjdk/lib/libfontmanager.so: Error loading shared library libfreetype.so.6: No such file or directory (needed by /opt/java/openjdk/lib/libfontmanager.so)at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1096)at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:974)at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011)at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903)at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:705)at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)at com.github.xiaoymin.knife4j.extend.filter.basic.JakartaServletSecurityBasicAuthFilter.doFilter(JakartaServletSecurityBasicAuthFilter.java:55)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)at com.huanyu.common.config.filter.TokenFilter.doFilter(TokenFilter.java:58)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:177)at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119)at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400)at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:859)at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1734)at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.lang.UnsatisfiedLinkError: /opt/java/openjdk/lib/libfontmanager.so: Error loading shared library libfreetype.so.6: No such file or directory (needed by /opt/java/openjdk/lib/libfontmanager.so)at java.base/jdk.internal.loader.NativeLibraries.load(Native Method)at java.base/jdk.internal.loader.NativeLibraries$NativeLibraryImpl.open(Unknown Source)at java.base/jdk.internal.loader.NativeLibraries.loadLibrary(Unknown Source)at java.base/jdk.internal.loader.NativeLibraries.loadLibrary(Unknown Source)at java.base/jdk.internal.loader.NativeLibraries.findFromPaths(Unknown Source)at java.base/jdk.internal.loader.NativeLibraries.loadLibrary(Unknown Source)at java.base/java.lang.ClassLoader.loadLibrary(Unknown Source)at java.base/java.lang.Runtime.loadLibrary0(Unknown Source)at java.base/java.lang.System.loadLibrary(Unknown Source)at java.desktop/sun.font.FontManagerNativeLibrary$1.run(Unknown Source)at java.base/java.security.AccessController.doPrivileged(Unknown Source)at java.desktop/sun.font.FontManagerNativeLibrary.<clinit>(Unknown Source)at java.desktop/sun.font.SunFontManager$1.run(Unknown Source)at java.desktop/sun.font.SunFontManager$1.run(Unknown Source)at java.base/java.security.AccessController.doPrivileged(Unknown Source)at java.desktop/sun.font.SunFontManager.initStatic(Unknown Source)at java.desktop/sun.font.SunFontManager.<clinit>(Unknown Source)at java.base/java.lang.Class.forName0(Native Method)at java.base/java.lang.Class.forName(Unknown Source)at java.desktop/sun.font.FontManagerFactory$1.run(Unknown Source)at java.base/java.security.AccessController.doPrivileged(Unknown Source)at java.desktop/sun.font.FontManagerFactory.getInstance(Unknown Source)at java.desktop/java.awt.Font.getFont2D(Unknown Source)at java.desktop/java.awt.Font$FontAccessImpl.getFont2D(Unknown Source)at java.desktop/sun.font.FontUtilities.getFont2D(Unknown Source)at java.desktop/sun.java2d.SunGraphics2D.checkFontInfo(Unknown Source)at java.desktop/sun.java2d.SunGraphics2D.getFontInfo(Unknown Source)at java.desktop/sun.java2d.pipe.GlyphListPipe.drawString(Unknown Source)at java.desktop/sun.java2d.pipe.ValidatePipe.drawString(Unknown Source)at java.desktop/sun.java2d.SunGraphics2D.drawString(Unknown Source)

原因分析:

 Graphics2D类在执行文本写入的时候,需要使用字体插件,因为当前的运行环境中没有对应的 Error loading shared library libfreetype.so.6插件,因此就会报上述的错误。

经排查,博主使用的docker镜像是精简版本的,将一些不常用的功能代码都去除了,因此会出现这样那样的问题,最终使用完全的jre17,解决了该问题,备查!

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

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

相关文章

Java面试八股之JVM内存泄漏按照发生的方式可以分为哪几类

JVM内存泄漏按照发生的方式可以分为哪几类 常发性内存泄漏&#xff08;Frequent Memory Leak&#xff09; 这类内存泄漏发生的代码会被频繁执行&#xff0c;每次执行时都会导致一块或多块内存无法被回收。由于泄漏行为重复发生&#xff0c;故称为常发性。这类泄漏通常比较容易…

下一代广域网技术2:SRv6

2.SRv6 SR架构设计之初&#xff0c;就为SR数据平面设计了两种实现方式&#xff1a;一种是SR-MPLS&#xff0c;其重用了MPLS数据平面&#xff0c;可以在现有IP/MPLS网络上增量部署&#xff1b;另一种是SRv6&#xff0c;使用IPv6数据平面&#xff0c;基于IPv6路由扩展头进行扩展…

Docker部署常见应用之Oracle数据库

文章目录 安装部署参考文章 安装部署 使用Docker安装Oracle数据库是一个相对简便的过程&#xff0c;可以避免在本地环境中直接安装Oracle数据库的复杂性。 安装Docker环境&#xff1a;确保你的系统上已经安装了Docker&#xff0c;并且Docker服务正在运行。具体的安装方法可以根…

使用North自部署图床服务

图床 图床可以把图片转为链接&#xff0c;从而方便我们书写、分享博客&#xff0c;目前图床主要分为以下几类: 利用 Git 仓库存储对象存储&#xff08;OSS、COS、七牛云等&#xff09;免费公共图床&#xff08;SM.MS、聚合图床、ImgTP、Postimage等&#xff09; 但上述图床都…

多项式回归(Linear Regression)原理详解及Python代码示例

多项式回归原理详解 多项式回归&#xff08;Polynomial Regression&#xff09;是线性回归&#xff08;Linear Regression&#xff09;的一种扩展形式。它通过在输入变量上添加高次项来拟合非线性关系。虽然多项式回归本质上还是线性模型&#xff0c;但它允许模型在输入特征的多…

if action和Switch之间该怎么选择?

1. Switch 2. If及If Action Subsystem 3.结论 元素很多&#xff0c;用switch 元素少&#xff0c;用if或switch 如果...很多&#xff0c;用if

职业技能大赛引领下大数据专业实训教学的改革研究

随着信息化时代的加速发展&#xff0c;大数据专业作为新兴的热门领域&#xff0c;正日益成为高等职业教育体系中不可或缺的一部分&#xff0c;其承担着为社会培养大批具有高素质应用技能的大数据技术人才的重任。职业技能大赛作为检验和提升学生技能水平的有效平台&#xff0c;…

web学习笔记(六十九)vue2

1. vue2创建脚手架项目 &#xff08;1&#xff09;在cmd窗口输入npm install -g vue/cli命令行&#xff0c;快速搭建脚手架。 &#xff08;2&#xff09; 创建vue2项目 &#xff08;3&#xff09; 选择配置项目&#xff0c;最下面的选项是自己重新配置&#xff0c;第一次创建v…

使用nvm管理node版本及pnpm安装

文章目录 GithubWindows 环境Mac/Linux 使用脚本进行安装或更新Mac/Linux 环境变量nvm 常用命令npm 常用命令npm 安装 pnpmNode 历史版本 Github https://github.com/nvm-sh/nvm Windows 环境 https://nvm.uihtm.com/nvm.html Mac/Linux 使用脚本进行安装或更新 curl -o- …

VTable导出当前页和导出所有页数据

表格导出的是当前显示的表格&#xff0c;如果是分页表格想导出全部的数据话。有两种方法可以实现 表格先显示的全量数据&#xff0c;导出后再恢复当前页。新建一个隐藏的表格实例显示全量数据导出这个隐藏的表格实例。 下面是全量代码&#xff1a; <template><div&…

快速创建条形热力图

Excel中的条件格式可以有效的凸显数据特征&#xff0c;如下图中B列所示。 现在需要使用图表展现热力条形图&#xff0c;如下图所示。由于颜色有多个过渡色&#xff0c;因此手工逐个设置数据条的颜色&#xff0c;基本上是不可能完成的任务&#xff0c;使用VBA代码可以快速创建这…

【pytorch03】pytorch基本数据类型

问题&#xff1a;String类型在pytorch中如何表示&#xff1f; 很遗憾&#xff0c;pytorch不是完备的语言库&#xff0c;而是面向数据计算的一个GPU加速库&#xff0c;因此没有内建对string的支持 我们会在做NLP的时候会遇到all string处理的问题&#xff0c;就比如说一句话&am…

华硕PRIME B450M-K主板开启虚拟化

1.判断电脑是否开启了虚拟化 按下CtrlShiftESC打开任务管理器&#xff0c;切换到性能页面&#xff0c;选择查看CPU 如果在右下角看到虚拟化&#xff1a;已禁用&#xff0c;则没有开启虚拟化 2.进入BIOS 重启或开机时&#xff0c;按下DEL或F2进入BIOS设置界面。 屏幕提示&am…

SAP系统中如何用事务码图形视图寻找MD04增强开发实施点

在之前发布的文章中&#xff0c;介绍了善用事务码的图形视图以观察事务的执行流程以及如何在MD04中实施增强以改变生产订单的显示顺序。本文结合两者&#xff0c;介绍一下如何利用事务码的图形视图找到增强开发的实施点。 在事务码中输入SE93&#xff0c;进入图形视图&#xf…

生命在于学习——Python人工智能原理(4.6)

在这里插一句话&#xff0c;我有两个好兄弟的github项目&#xff0c;感兴趣的可以去看一下&#xff0c;star一下&#xff0c;谢谢。 https://github.com/fliggyaa/fscanpoc https://github.com/R0A1NG/Botgate_bypass 四、Python的程序结构与函数 4.1 Python的分支结构 &…

如何将个人电脑做P2V备份到虚拟化平台

背景&#xff1a;公司员工个人电脑绑定了商用软件的license&#xff0c;现在员工离职&#xff0c;license又需要使用&#xff0c;电脑就一直被占用。 解决方法&#xff1a;利用VMware Vcenter Converter Standalone将此台式电脑上载到公司虚拟化平台上 具体做法&#xff0c;下…

.NET C# 树遍历、查询、拷贝与可视化

.NET C# 树遍历、查询、拷贝与可视化 目录 .NET C# 树遍历、查询、拷贝与可视化1 组件安装1.1 NuGet包管理器安装&#xff1a;1.2 控制台安装&#xff1a; 2 接口1.1 ITree\<TTreeNode\>1.2 ITree\<TKey, TTreeNode\>1.3 IObservableTree\<TTreeNode\>1.4 IO…

昇思25天学习打卡营第7天 | 模型训练

内容介绍&#xff1a; 模型训练一般分为四个步骤&#xff1a; 1. 构建数据集。 2. 定义神经网络模型。 3. 定义超参、损失函数及优化器。 4. 输入数据集进行训练与评估。 具体内容&#xff1a; 1. 导包 import mindspore from mindspore import nn from mindspore.dataset…

手把手教你使用kimi创建流程图【实践篇】

学境思源&#xff0c;一键生成论文初稿&#xff1a; AcademicIdeas - 学境思源AI论文写作 引言 在昨日的文章中&#xff0c;我们介绍了如何使用Kimi生成论文中的流程图。今天&#xff0c;我们将更进一步&#xff0c;通过实践案例来展示Kimi在生成流程图方面的应用。这不仅将加…

【大数据技术原理与应用(概念、存储、处理、分析与应用)】第1章-大数据概述习题与知识点回顾

文章目录 单选题多选题知识点回顾几次信息化浪潮主要解决什么问题&#xff1f;信息科技为大数据时代提供哪些技术支撑&#xff1f;数据产生方式有哪些变革&#xff1f;大数据的发展历程大数据的四个特点&#xff08;4V&#xff09;大数据对思维方式的影响大数据有哪些关键技术&…