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

目录

前言

一、需求介绍

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 颜色值,格式为 0x00RRGGBB
    int 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根据字符串集合生成固定宽度和自适应宽度源码

评论 57
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜郎king

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值