Geotools结合SLD实现矢量中文标注下的乱码和可用字体解析

发布于:2025-04-01 ⋅ 阅读:(24) ⋅ 点赞:(0)

目录

前言

一、需求溯源

1、原始的SLD渲染

2、最初的效果

二、问题修复

1、还是字符编码

2、如何选择可用的字体

 3、如何查看支持的字体库

三、总结


前言

        随着地理信息系统(GIS)技术的不断发展,矢量数据的可视化和标注成为了地理信息展示的重要环节。矢量数据标注不仅能够增强地图的可读性,还能为用户提供更多直观的信息。然而,在实际应用中,矢量数据的中文标注往往面临乱码问题,尤其是在跨平台、跨系统环境下,字体的兼容性和可用性问题尤为突出。本文将探讨如何利用Geotools结合SLD(Styled Layer Descriptor)技术,解决矢量中文标注中的乱码问题,并解析可用字体,以实现高效、准确的矢量数据可视化。

        1. 矢量数据标注的重要性

        矢量数据标注是地理信息系统中不可或缺的一部分。通过标注,用户可以快速获取地理实体的名称、属性等信息,从而更好地理解地图内容。在城市规划、资源管理、环境保护等领域,矢量数据标注的应用尤为广泛。然而,随着应用场景的多样化,矢量数据标注面临着越来越多的挑战,尤其是在中文标注方面。

        2. 中文标注的乱码问题

        中文标注的乱码问题主要源于以下几个方面:

  1. 编码问题:不同系统或平台对字符编码的支持可能存在差异,导致字符无法正确显示。

  2. 字体问题:某些字体在特定系统或环境中可能不可用,或者字体本身不支持中文字符。

  3. 渲染问题:矢量数据的渲染过程可能涉及多种技术栈,不同技术栈对字体和字符的支持程度不同。

        这些问题在实际应用中可能导致标注内容无法正确显示,影响地图的可读性和用户体验。

        3. 可用字体解析

        在实际应用中,确保标注字体的可用性是解决乱码问题的关键。Geotools提供了字体解析功能,可以动态检测系统中可用的字体,并根据SLD文件中的配置选择合适的字体进行渲染。通过解析系统字体,可以确保标注内容在不同环境下的兼容性和一致性。

        本文的目标是通过Geotools和SLD技术,解决矢量中文标注中的乱码问题,并解析可用字体,以实现高效、准确的矢量数据可视化。研究方法包括:

  1. 分析矢量数据标注的常见问题:通过实际案例分析中文标注乱码的原因。

  2. 探索Geotools和SLD的结合应用:研究如何利用Geotools的字体管理和SLD的样式定义解决乱码问题。

  3. 验证解决方案的有效性:通过实验验证解决方案在不同环境下的适用性和稳定性。

一、需求溯源

        Geotools是一个开源的Java GIS工具库,广泛应用于地理信息数据的处理和可视化。SLD(Styled Layer Descriptor)是一种基于XML的标准,用于定义地理数据的样式和渲染规则。通过结合Geotools和SLD技术,可以实现对矢量数据的高效管理和可视化。在解决中文标注乱码问题时,Geotools提供了强大的字体管理和字符编码支持,而SLD则可以通过样式定义确保标注内容的正确显示。通过合理配置SLD文件,可以指定字体、颜色、大小等样式属性,从而避免因字体或编码问题导致的乱码。原来在做一个矢量文件渲染时,使用代码加载了SLD文件后,出现文字注记没有正确的加载展示的情况,虽然图形的轮廓是展示出来了,但是表示是乱码的,所以整体效果比较差。如下图:

        通过在网络上查询一些资料,讲解Geotools中如何进行SLD渲染的内容不少,讲解注记的也挺多。但是一些博主在讲解中文注记时,没有很好的进行深入,本文这里就是主要用来弥补相关信息的不足,为遇到问题的各位提供一个问题排查的思路。 

1、原始的SLD渲染

        首先我们可以使用Qgis软件来展示和编辑相关的矢量文件,在编辑预览的同时可以设置矢量数据的样式,比如渲染的边界颜色等信息。关于如何在Qgis中进行SLD样式的设置知识,这里不进行赘述,大家可以翻阅之前的系列博客进行学习。这里以一个湖南省的乡镇的面数据为例,主要讲解的一个面数据的简单标绘。在Qgis中生成的SLD文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<StyledLayerDescriptor xmlns="http://www.opengis.net/sld" xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:se="http://www.opengis.net/se" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1.0" xmlns:ogc="http://www.opengis.net/ogc">
  <NamedLayer>
    <se:Name>湖南-乡镇utf8</se:Name>
    <UserStyle>
      <se:Name>湖南-乡镇utf8</se:Name>
      <se:FeatureTypeStyle>
        <se:Rule>
          <se:Name>Single symbol</se:Name>
          <se:PolygonSymbolizer>
            <se:Fill>
              <se:SvgParameter name="fill">#f4f4f4</se:SvgParameter>
            </se:Fill>
            <se:Stroke>
              <se:SvgParameter name="stroke">#e31a1c</se:SvgParameter>
              <se:SvgParameter name="stroke-width">1</se:SvgParameter>
              <se:SvgParameter name="stroke-linejoin">bevel</se:SvgParameter>
              <se:SvgParameter name="stroke-dasharray">4 2</se:SvgParameter>
            </se:Stroke>
          </se:PolygonSymbolizer>
        </se:Rule>
        <se:Rule>
          <se:TextSymbolizer>
            <se:Label>
              <ogc:PropertyName>Name</ogc:PropertyName>
            </se:Label>
            <se:Font>
              <se:SvgParameter name="font-family">宋体</se:SvgParameter>
              <se:SvgParameter name="font-size">13</se:SvgParameter>
            </se:Font>
            <se:LabelPlacement>
              <se:PointPlacement>
                <se:AnchorPoint>
                  <se:AnchorPointX>0</se:AnchorPointX>
                  <se:AnchorPointY>0.5</se:AnchorPointY>
                </se:AnchorPoint>
              </se:PointPlacement>
            </se:LabelPlacement>
            <se:Fill>
              <se:SvgParameter name="fill">#000000</se:SvgParameter>
            </se:Fill>
            <se:VendorOption name="maxDisplacement">1</se:VendorOption>
          </se:TextSymbolizer>
        </se:Rule>
      </se:FeatureTypeStyle>
    </UserStyle>
  </NamedLayer>
</StyledLayerDescriptor>

        该SLD文件定义了一个矢量图层的样式规则,主要用于多边形数据的符号化和文本标注。文件的结构遵循OGC(Open Geospatial Consortium)的SLD规范,版本为1.1.0。 

 2.核心内容解析

2.1 命名层(NamedLayer

  • <se:Name>:定义图层的名称为“湖南-乡镇utf8”,表示该样式适用于名为“湖南-乡镇utf8”的矢量图层。

2.2 用户样式(UserStyle

  • <se:Name>:定义样式的名称为“湖南-乡镇utf8”,与命名层的名称一致。

  • <se:FeatureTypeStyle>:定义了适用于该图层的样式规则。

2.3 多边形符号化(PolygonSymbolizer

  • <se:Fill>:定义多边形的填充样式。

    • <se:SvgParameter name="fill">:填充颜色为浅灰色(#f4f4f4)。

  • <se:Stroke>:定义多边形边框的样式。

    • <se:SvgParameter name="stroke">:边框颜色为红色(#e31a1c)。

    • <se:SvgParameter name="stroke-width">:边框宽度为1像素。

    • <se:SvgParameter name="stroke-linejoin">:边框连接方式为“bevel”(斜接)。

    • <se:SvgParameter name="stroke-dasharray">:边框为虚线,虚线模式为“4 2”(4像素实线,2像素间隔)。

2.4 文本符号化(TextSymbolizer

  • <se:Label>:定义标注内容为矢量数据的“Name”字段。

  • <se:Font>:定义标注字体样式。

    • <se:SvgParameter name="font-family">:字体为“宋体”。

    • <se:SvgParameter name="font-size">:字体大小为13像素。

  • <se:LabelPlacement>:定义标注的定位方式。

    • <se:PointPlacement>:标注定位为点。

    • <se:AnchorPoint>:定义标注的锚点。

      • <se:AnchorPointX>:锚点X坐标为0。

      • <se:AnchorPointY>:锚点Y坐标为0.5。

  • <se:Fill>:定义标注文本的颜色。

    • <se:SvgParameter name="fill">:文本颜色为黑色(#000000)。

  • <se:VendorOption name="maxDisplacement">:定义标注的最大偏移量为1像素,用于避免标注重叠。

    3. 关键点分析

    3.1 多边形样式

  • 多边形填充为浅灰色,边框为红色虚线,这种样式通常用于突出显示区域边界。

  • 虚线模式“4 2”表示边框由4像素的实线和2像素的间隔交替组成。

  • 标注内容为矢量数据的“Name”字段,字体为“宋体”,大小为13像素,颜色为黑色。

  • 文件中明确指定了字体为“宋体”,这是常见的中文字体,但在某些系统或环境中可能不可用。如果字体不可用,可能会导致标注乱码。

  • 标注的锚点设置为(0, 0.5),表示标注文本的左中点对齐。

  • 最大偏移量为1像素,用于避免标注重叠。

2、最初的效果

        该SLD文件定义了一个矢量图层的样式规则,包括多边形的填充和边框样式,以及文本标注的字体、大小、颜色和定位方式。文件中特别指定了“宋体”作为标注字体,但需要注意字体的可用性问题,以避免中文标注乱码。通过合理配置SLD文件和利用Geotools的字体解析功能,可以确保标注内容在不同环境下的正确显示。正常情况,我们将这个sld文件加载到程序中对矢量数据进行渲染,你会发现问题还是出现了,在生成的图片中我们预期的乡镇名称并没有成功的加载,只是如下图所示:

        那么究竟是什么原因导致了上述的问题呢?在本文的下一个小节中会进行具体的讲解。 

二、问题修复

        本节将对上一节出现的中文标注在SLD样式渲染下无法正常展示的问题进行解决。以及讲解在中文标注下有哪些字体可以选择。导致上图中出现中文字体无法展示的原因就是字体的原因,所以在渲染时无法正常展示。跟我们常见的服务器端乱码的结果差不多。

1、还是字符编码

        首先来看下原来的字符编码是如何指定的,在之前的添加矢量图层的方法中。关键代码如下,在代码中,我们使用申明的方式直接指定了字符集编码为UTF-8:

/**
* 添加shp文件
* @param shpPath
*/
@SuppressWarnings("deprecation")
public void addShapeLayer(String shpPath, String sldPath) {
    try {
		File file = new File(shpPath);
		ShapefileDataStore shpDataStore = null;
		shpDataStore = new ShapefileDataStore(file.toURL());
		Charset charset = Charset.forName("UTF-8");
		shpDataStore.setCharset(charset);
		//xxx 加载SLD样式
		this.map.addLayer(layer);
	} catch (Exception e) {
		e.printStackTrace();
	}
}

        在创建shp文件时,通常我们会创建dbf文件用来保存属性文件。同时在属性文件中,我们会指定属性字段的字符集。 通常发生中文无法解析的情况就是设置的字符集编码不对。我们可以在QGIS或者Arcgis中来查看当前矢量文件的字符集。可以发现,真实文件的字符集是GB2312,因此基本可以断定是字符集的问题,在知晓了原理之后,就只需要设置新的字符集编码即可:

// 设置编码,这里格外要注意,否则会造成中文标注失败的情况
//Charset charset = Charset.forName("UTF-8");
Charset charset = Charset.forName("GB2312");

        重新生成,发现乡镇的名称可以正常展示,如下图所示:

 

        局部放大后给大家展示:

        可以直观的看到,中文标注正常。可以正确的展示。 

2、如何选择可用的字体

        除了字符编码可能会引起这种问题,还有一种情况是大家都能够想到的,就是操作系统的字体编码问题。如果设置的字体不是系统支持的,那肯定也是有问题,在本文的第一部分就说明了文章采用的字体是宋体,接下来我们来试试其它的字体,比如:华文行楷,sld中的样式标注部分调整为:

<se:Font>
    <se:SvgParameter name="font-family">华文行楷</se:SvgParameter>
    <se:SvgParameter name="font-size">13</se:SvgParameter>
</se:Font>

        在此运行程序,在控制台中它会报错,如下所示,表示无法加载字体库:

三月 31, 2025 11:28:18 下午 org.geotools.renderer.style.FontCache loadFromUrl
信息: null input stream, could not load the font

        在中文情况下,虽然无法加载,但是还是正常展示,如果切换成另外一种字符,如:

<se:SvgParameter name="font-family">MoolBoran</se:SvgParameter>

        此时的效果就完全是乱码了,如下图:

        所以字体的选择至关重要。 

 3、如何查看支持的字体库

        要想在程序中查看系统中支持的字体库,可以使用下面的方法,代码如下:

System.out.println("******************************");
Set<String> availableFonts = FontCache.getDefaultInstance().getAvailableFonts();
System.out.println(availableFonts.size());
for (String font : availableFonts) {
	System.out.println(font);
}

        其中FontCache类是org.geotools.renderer.style.FontCache这个类。在应用程序中输出以下信息:

         通过以上的输出就能确定当前系统环境支持哪些字体库。

三、总结

        以上就是本文的主要内容, 本文的目标是通过Geotools和SLD技术,解决矢量中文标注中的乱码问题,并解析可用字体,以实现高效、准确的矢量数据可视化。

        通过Geotools结合SLD技术,可以有效解决矢量中文标注中的乱码问题,并解析可用字体,确保标注内容的正确显示。这一解决方案不仅提高了矢量数据的可视化效果,还增强了系统的兼容性和用户体验。未来,随着GIS技术的不断发展,矢量数据标注技术也将不断创新,为地理信息的展示和应用提供更强大的支持。行文仓促,难免有许多不足之处,如有不足,在此恳请各位专家博主在评论区不吝留言指出,不胜感激。


网站公告

今日签到

点亮在社区的每一天
去签到