基于Java的不固定长度字符集在指定宽度和自适应模型下图片绘制生成实战

article/2025/8/15 20:50:16

目录

前言

一、需求介绍

1、指定宽度生成

2、指定列自适应生成

二、Java生成实现

1、公共方法

2、指定宽度生成

3、指定列自适应生成

三、总结


前言

        在当今数字化与信息化飞速发展的时代,图像的生成与处理技术正日益成为众多领域关注的焦点。从创意设计到数据可视化,从游戏开发到人工智能辅助创作,高效、精准且具有高度适应性的图像生成方案有着广泛而迫切的需求。Java 作为一种强大、稳定且广泛应用的编程语言,在图像绘制领域也发挥着不可忽视的作用。

        在GIS领域,比如图例的生成就会面对以上的问题。由于在进行字符标注时无法预测文本的长度,因此我们需要能有一种自适应文本长度的生成方法,但是同时,也有可能我们需要指定一种宽度从而对字符文本进行绘制的需要。如下两图所示:

自适应宽度生成示意图

指定宽度生成示意图 

        本实战旨在深入探讨基于 Java 的不固定长度字符集在指定宽度和自适应模型下图片绘制生成的方法与技巧。不固定长度字符集为图片绘制带来了独特的挑战与机遇。一方面,其灵活多变的字符组合方式能够创造出丰富多样、极具个性化的图像效果,为创意表达提供了广阔空间;另一方面,如何在保证图像整体协调性与美观性的前提下,合理安排不同长度字符在指定宽度内的布局,实现自适应模型下的高效绘制,需要深入研究与实践。

        通过本次实战,我们期望为读者提供一套完整、实用且具有创新性的基于 Java 的图片绘制解决方案,帮助读者提升在图像生成领域的技术能力,激发他们在数字创作方面的灵感与潜力,从而在各自的应用场景中创造出更具价值与吸引力的图像作品,为推动图像技术的发展与应用贡献一份力量。

一、需求介绍

        在面向地理空间的图例生成过程,我们通常会遇到以下两种情况:第一种是需要指定宽度,比如要求在宽度为200px的图片中,将指定的文字在图片中生成。第二种就是需要根据指定列,即一行展示几列,然后自适应的生成固定宽度的图片。本节将主要介绍这两个需求。这里我们需要展示的是一些不一定长的字符串集合,模拟展示以下这些地名数据,如下所示:

String[] demoTexts = {" 项目管理", "软件开发", "数据分析","人工智能", "云计算", "网络安全","用户体验", "测试验证", "运维部署", "昆明市","曲靖市","玉溪市","保山市","昭通市","丽江市","普洱市","临沧市","楚雄彝族自治州","红河哈尼族彝族自治州","文山壮族苗族自治州","西双版纳傣族自治州","湘西土家族苗族自治州","深圳市","保亭黎族苗族自治县","阿坝藏族羌族自治州","黔西南布依族苗族自治州","克孜勒苏柯尔克孜自治州","双江拉祜族佤族布朗族傣族自治县","积石山保安族东乡族撒拉族自治县","中国石油集团东方地球物理勘探有限责任公司霸州基地管理处居委会","天津市蓟州区京津州河科技产业园管理委员会虚拟社区","窑街煤电集团民勤县瑞霖生态农林有限责任公司生活区","沈阳市于洪区红旗土地股份合作经营有限公司生活区","大理白族自治州","德宏傣族景颇族自治州","怒江傈僳族自治州","迪庆藏族自治州"
};

1、指定宽度生成

        指定宽度生成,即我们对目标成果的图片宽度是有要求的,比如宽度指定为200px。核心需求如下:

        固定总宽度模式

  • 平均分配列宽:根据总宽度和列数计算每列可用宽度

  • 自动换行:根据列数自动计算行数

  • 文本截断:超长文本添加省略号

2、指定列自适应生成

        自适应列宽模式

  • 动态计算列宽:根据每列中最长的条目确定列宽,遍历所有文本,计算每个条目(矩形+间距+文本)的总宽度,确定最大宽度作为图像宽度。

  • 计算高度:基于行数和字体高度计算总高度

  • 自动换行:根据列数自动计算行数

  • 保持完整显示:不截断文本

二、Java生成实现

        本小节将根据上面的生成需求来具体讲解如何进行详细的生成。java生成的实现分成三个部分,第一部分是介绍两个公共方法,第二部分介绍如何按照指定宽度生成,第三部分介绍如何进行自适应生成,通过代码实例的方法进行讲解。

1、公共方法

        为了方便对对绘制的文字展示得更加美观,这里我们每进行一次绘制就修改画笔的颜色。因此需要一个生成指定颜色的方法,在java中生成Color对象,并且转为十六进制的颜色表示,核心方法如下:

/**
* - 将color转十六进制字符串
* @param color
* @return
*/
public static String Color2String(Color color) {// 获取 RGB 颜色值,格式为 0x00RRGGBBint rgb = color.getRGB();// 将 RGB 转换为十六进制字符串,去掉前两位的透明度部分(如果是纯不透明颜色)String hexColor = "#" + Integer.toHexString(rgb & 0xffffff);return hexColor;
}

        根据不同字符串生成均匀分布的颜色方法如下:

// 生成可区分颜色(HSV色环均匀分布)
private static Color[] generateDistinctColors(int count) {Color[] colors = new Color[count];float goldenRatio = 0.618033988749895f;  // 黄金分割比例float saturation = 0.8f;  // 饱和度float brightness = 0.9f;  // 亮度for (int i = 0; i < count; i++) {float hue = (i * goldenRatio) % 1.0f;colors[i] = Color.getHSBColor(hue, saturation, brightness);}return colors;
}

         以上两个方法在指定宽度生成和自适应生成中均会使用到,因此在此简单列出来。

2、指定宽度生成

按指定宽度生成的核心方法如下:

// 固定总宽度模式
public static BufferedImage createFixedColumnsImage(String[] texts, int columns,int totalWidth, Font font,int padding, int columnSpacing,int rowSpacing) {BufferedImage tempImg = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);Graphics2D tempG = tempImg.createGraphics();tempG.setFont(font);FontMetrics fm = tempG.getFontMetrics();final int RECT_SIZE = 10;final int ENTRY_SPACING = 5;// 生成颜色序列Color[] colors = generateDistinctColors(texts.length);// 计算列宽int availableWidth = totalWidth - padding * 2 - (columns - 1) * columnSpacing;int columnWidth = availableWidth / columns;int textMaxWidth = columnWidth - RECT_SIZE - ENTRY_SPACING;// 处理文本List<String> processedTexts = new ArrayList<>();for (String text : texts) {processedTexts.add(truncateText(text, textMaxWidth, fm));}// 计算总高度int rows = (int) Math.ceil((double)texts.length / columns);int totalHeight = padding * 2 + rows * (fm.getHeight() + rowSpacing) - rowSpacing;// 创建图像BufferedImage image = new BufferedImage(totalWidth, totalHeight, BufferedImage.TYPE_INT_ARGB);Graphics2D g = image.createGraphics();setupGraphics(g, font);// 绘制背景g.setColor(Color.WHITE);g.fillRect(0, 0, totalWidth, totalHeight);// 绘制条目int yBase = padding + fm.getAscent();int[] columnX = new int[columns];for (int i = 0; i < columns; i++) {columnX[i] = padding + i * (columnWidth + columnSpacing);}for (int i = 0; i < processedTexts.size(); i++) {g.setColor(colors[i]);int col = i % columns;int row = i / columns;int y = yBase + row * (fm.getHeight() + rowSpacing);int rectY = y - fm.getAscent() + (fm.getHeight() - RECT_SIZE)/2;// 绘制矩形g.fillRect(columnX[col], rectY, RECT_SIZE, RECT_SIZE);// 绘制文本g.drawString(processedTexts.get(i), columnX[col] + RECT_SIZE + ENTRY_SPACING, y);}g.dispose();tempG.dispose();return image;
}

        由于在指定宽度的生成方式中,绘制的图片宽度是固定的,而文字的字数是不固定的。因此在绘制的过程中,需要对超长的文本进行截取,超长的部分将使用省略号来进行展示。对超长文本字符进行截断处理的方法如下:

private static String truncateText(String text, int maxWidth, FontMetrics fm) {if (fm.stringWidth(text) <= maxWidth) return text;int ellipsisWidth = fm.stringWidth("...");int availableWidth = maxWidth - ellipsisWidth;int length = text.length();while (length > 0 && fm.stringWidth(text.substring(0, length)) > availableWidth) {length--;}return length > 0 ? text.substring(0, length) + "..." : "";
}

         生成指定宽度的图片调用方法如下:

// 生成固定宽度图片(400px宽,2列)
BufferedImage fixedImage = createFixedColumnsImage(demoTexts, 2, 400,new Font("宋体", Font.PLAIN, 12),15, 20, 10
);
ImageIO.write(fixedImage, "PNG", new File("D:/fixed_columns_250420.png"));

        生成的成果图片如下:

3、指定列自适应生成

        生成指定列的自适应图片生成的核心方法如下:

// 自适应列宽模式public static BufferedImage createAdaptiveColumnsImage(String[] texts, int columns,Font font, int padding, int columnSpacing, int rowSpacing) {BufferedImage tempImg = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);Graphics2D tempG = tempImg.createGraphics();tempG.setFont(font);FontMetrics fm = tempG.getFontMetrics();final int RECT_SIZE = 10;final int ENTRY_SPACING = 5; // 图标与文字间距// 生成颜色序列Color[] colors = generateDistinctColors(texts.length);int index = 0;for (String text : texts) {texts[index] = Color2String(colors[index]) + " " + text; //processedTexts.add(truncateText(text, textMaxWidth, fm));index ++;}// 计算列宽int[] columnWidths = new int[columns];for (int i = 0; i < texts.length; i++) {int col = i % columns;int width = RECT_SIZE + ENTRY_SPACING + fm.stringWidth(texts[i]);if (width > columnWidths[col]) {columnWidths[col] = width;}}// 计算总尺寸int totalWidth = padding * 2;for (int w : columnWidths) {totalWidth += w + columnSpacing;}totalWidth -= columnSpacing; // 最后一列不加间距int rows = (int) Math.ceil((double)texts.length / columns);int totalHeight = padding * 2 + rows * (fm.getHeight() + rowSpacing) - rowSpacing;// 创建图像BufferedImage image = new BufferedImage(totalWidth, totalHeight, BufferedImage.TYPE_INT_ARGB);Graphics2D g = image.createGraphics();setupGraphics(g, font);// 绘制背景g.setColor(Color.WHITE);g.fillRect(0, 0, totalWidth, totalHeight);// 绘制条目int x = padding;int yBase = padding + fm.getAscent();int[] columnX = new int[columns];for (int i = 0; i < columns; i++) {columnX[i] = x;x += columnWidths[i] + columnSpacing;}g.setColor(Color.RED);for (int i = 0; i < texts.length; i++) {g.setColor(colors[i]);int col = i % columns;int row = i / columns;int y = yBase + row * (fm.getHeight() + rowSpacing);int rectY = y - fm.getAscent() + (fm.getHeight() - RECT_SIZE)/2;// 绘制矩形g.fillRect(columnX[col], rectY, RECT_SIZE, RECT_SIZE);// 绘制文本g.drawString(texts[i], columnX[col] + RECT_SIZE + ENTRY_SPACING, y);}g.dispose();tempG.dispose();return image;}

        在自适应生成的过程中,最需要处理的逻辑就是动态的计算宽度等值。最终生成的结果图片如下:

三、总结

        以上就是本文的主要内容,本实战旨在深入探讨基于 Java 的不固定长度字符集在指定宽度和自适应模型下图片绘制生成的方法与技巧。不固定长度字符集为图片绘制带来了独特的挑战与机遇。一方面,其灵活多变的字符组合方式能够创造出丰富多样、极具个性化的图像效果,为创意表达提供了广阔空间;另一方面,如何在保证图像整体协调性与美观性的前提下,合理安排不同长度字符在指定宽度内的布局,实现自适应模型下的高效绘制,需要深入研究与实践。

        通过本次实战,我们期望为读者提供一套完整、实用且具有创新性的基于 Java 的图片绘制解决方案,帮助读者提升在图像生成领域的技术能力,激发他们在数字创作方面的灵感与潜力,从而在各自的应用场景中创造出更具价值与吸引力的图像作品,为推动图像技术的发展与应用贡献一份力量。行文仓促,定有不足之处,欢迎各位朋友在评论区批评指正,不胜感激。

        完整的代码链接如下:Java根据字符串集合生成固定宽度和自适应宽度源码。


http://www.hkcw.cn/article/vGuKJEDAJK.shtml

相关文章

【C++】 —— 笔试刷题day_29

一、排序子序列 题目解析 一个数组的连续子序列&#xff0c;如果这个子序列是非递增或者非递减的&#xff1b;这个连续的子序列就是排序子序列。 现在给定一个数组&#xff0c;然后然我们判断这个子序列可以划分成多少个排序子序列。 例如&#xff1a;1 2 3 2 2 1 可以划分成 …

企业微信自建应用实现接收消息和发送消息功能(python)

# 这一周我不断的琢磨企业微信自建应用并且实现了自建应用的消息接收和发送功能 1.笔记&#xff0c;记录 第一步&#xff1a;打开企业微信后台 https://work.weixin.qq.com 1.1 如果没有企业可以在这里申请&#xff0c;如果有可以直接扫码登录 1.2 打开后台-应用管理-自建应用…

【Rust多线程】Rust并发编程,如何轻松实现无畏并发

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

2025粤港澳信息学创新大赛备考指南Python,C++,图形化历年真题训练题

官方指导文件 训练题目 ZCM5:Python小学组-单项选择题 1.小明安装软件的时候发现软件要求Windows环境&#xff0c;这 个要求限制的是? A.操作系统 B.计算机内存 C.网络设置 D.程序语言 答案‌&#xff1a;A. 操作系统 解析‌&#xff1a;软件运行的环境通常指的是操作系统&am…

【C++指南】“单身狗问题”——只出现一次的数字 系列问题

. &#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《C指南》 期待您的关注 文章目录 引言一、只出现一次的数字&#xff08;一&#xff09;简单题目描述解题思路代码实现及解释 二…

优化 InfluxDB 写入性能:高效批处理策略实战指南

在处理高吞吐量时序数据时&#xff0c;合理运用批处理&#xff08;Batching&#xff09;策略是提升 InfluxDB 写入性能的关键。本文介绍 时间驱动、大小驱动和混合批处理策略&#xff0c;并通过 Python 代码示例展示如何优化数据写入&#xff0c;平衡 延迟与吞吐量。同时&#…

RedwoodJS:乱拳打倒老师傅 NextJS!

RedwoodJS 是一个全栈的 JavaScript/TypeScript 框架&#xff0c;其作用是帮助开发者高效地构建现代化的 Web 应用。它将前端、后端和数据库集成在一起&#xff0c;并使用一种“JAMstack”架构&#xff08;JavaScript、API 和 Markup&#xff09;来构建可扩展的应用程序。 Star…

【C++】 —— 笔试刷题day_18

一、压缩字符串(一) 题目解析 题目给定一个字符str&#xff0c;让我们将这个字符串进行压缩&#xff1b; **压缩规则&#xff1a;**出现多次的字符压缩成字符数字&#xff1b;例如aaa压缩成a3。如果字符值出现一次&#xff0c;1不用写。 算法思路 这道题总的来说就非常简单了…

谷歌浏览器如何禁用javaScript

通过禁用js&#xff0c;可以访问一些设置权限的内容。 Chrome 地址栏输入 chrome://settings/content 回车。 找到 JavaScript 选项。 切换为 不允许网站使用 JavaScript。 地址栏输入&#xff1a; chrome://settings/content/javascript?searchJavaScript Firefox 地址栏输入…

Java从入门到“放弃”(精通)之旅——类和对象全面解析⑦

Java从入门到“放弃”&#xff08;精通&#xff09;之旅&#x1f680;——类和对象全面解析⑦ 一、面向对象初探 1.1 什么是面向对象&#xff1f; Java是一门纯面向对象的语言(OOP)&#xff0c;在面向对象的世界里&#xff0c;一切皆为对象。面向对象是解决问题的一种思想&am…

【Golang】第七弹----map

笔上得来终觉浅,绝知此事要躬行 &#x1f525; 个人主页&#xff1a;星云爱编程 &#x1f525; 所属专栏&#xff1a;Golang &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 1基本介绍 Go语言中的 map …

C/C++程序员为什么要了解汇编?了解汇编有哪些好处?如何学习汇编?

目录 1、概述 2、从汇编的角度去理解问题的若干实例说明 2.1、使用空指针去访问类的数据成员或调用类的虚函数为什么会引发崩溃? 2.2、从汇编代码的角度去理解多线程的执行细节,去理解多线程在访问共享资源时为什么要加锁 2.3、使用Windbg静态分析dump时先从崩溃的那条汇…

基于谐波线性化方法的跟网型GFL并网变流器/VSC宽频序阻抗建模及扫频(Matlab/Simulink平台)及文献复现

目录 1、课程及模型介绍 2、谐波线性化方法介绍 3、跟网型及构网型并网变流器的特点 4、跟网型变流器/VSC拓扑及控制结构 5、不同坐标系下VSC序阻抗建模推导过程 5.1 abc三相坐标系下的VSC序阻抗建模 5.2 d-q旋转坐标系下的VSC序阻抗建模 5.2.1 Park变换及频率偏移效应…

C++“STL之String”

​ 🌹个人主页🌹:喜欢草莓熊的bear 🌹专栏🌹:C++入门 目录 ​编辑 前言 一、STL简介 1.1 STL是什么? 1.2 STL的版本(这个不是很重要了解即可) 1.3 STL的六大组件 二、 String类 2.1为什么要学习String类? 2.1.1 C语言中的字符串…

C++之多态

开始新的征程啦———多态&#xff0c;它也是C的三大特性之一。 文章目录 一、多态的概念二、多态的定义和实现2.1多态的定义2.2 实现动态多态所需要的条件&#xff08;2个&#xff09;2.3 虚函数的定义2.4 虚函数的重写/覆盖2.5 虚函数重写中的问题2.5.1 协变2.5.2 析构函数的…

【第十六届蓝桥杯省赛】比赛心得与经验分享(PythonA 组)

文章目录 一、我的成绩二、我的备赛经历三、如何备赛&#xff08;个人观点&#xff09;1. 基础语法2. 数据结构3. 算法4. 数学 四、做题技巧与注意事项五、我的题解试题A 偏蓝 &#x1f3c6;100%试题B IPV6 &#x1f3c6;0%试题C 2025图形 &#x1f3c6;100%试题D 最大数字 &am…

21天Python计划:零障碍学语法(更新完毕)

文章目录 前言Python 部分MySQL 部分目录结语资料截图 前言 此技术博客专栏围绕 Python 编程和 MySQL 数据库展开了系统且循序渐进的知识讲解&#xff0c;共包含 21 篇文章。 Python 部分 从基础入门逐步深入到高级应用。首先介绍了 Python 的下载和开发工具&#xff0c;为后续…

JavaScript--js基础(详细 全面)

目录 前言: JavaScript 是什么&#xff1f;JavaScript 简介 1.JavaScript历史 2.JavaScript 具有以下特点 第一个JavaScript程序 1.在脚本文件中编写JavaScript代码 2.JavaScript代码执行顺序 基本语法 1.变量 2.数据类型 3.算术运算符 4.赋值运算 5.字符串运算符 6…

Java识别图片或扫描PDF中的文字

目录 使用工具 Java识别图片中的文字 Java识别扫描PDF中的文字 注意事项 图片和扫描文件通常以非文本格式存在&#xff0c;这使得其中的文字信息难以直接编辑、搜索或复制。为了解决这个问题&#xff0c;光学字符识别&#xff08;OCR&#xff09;技术应运而生。OCR通过分析…

【C++】C++11新特性详解:可变参数模板与emplace系列的应用

C语法相关知识点可以通过点击以下链接进行学习一起加油&#xff01;命名空间缺省参数与函数重载C相关特性类和对象-上篇类和对象-中篇类和对象-下篇日期类C/C内存管理模板初阶String使用String模拟实现Vector使用及其模拟实现List使用及其模拟实现容器适配器Stack与QueuePriori…