Martin 动态 Sprite 生成教程:从 SVG 到地图精灵图

在 MapLibre 生态中,Sprite(精灵图) 是地图样式中图标渲染的核心资源。传统工作流需要预先使用工具(如 spritezero)将 SVG 合成为 PNG 精灵图和 JSON 索引文件,每次图标变更都要重新生成。Martin 的亮点在于完全自动化------只需提供一个 SVG 目录,它就能按需生成符合 MapLibre 规范的精灵图资源。


一、Sprite 在地图中的作用

MapLibre 样式文件(style.json)中,sprite 字段指向精灵图服务:

json 复制代码
{
  "sprite": "https://tiles.example.com/sprite/my_icons",
  "glyphs": "https://tiles.example.com/font/{fontstack}/{range}.pbf",
  "layers": [
    {
      "id": "poi-bicycle",
      "type": "symbol",
      "source": "my_source",
      "layout": {
        "icon-image": "bicycle"
      }
    }
  ]
}

客户端会同时请求:

  • sprite/my_icons.png --- 包含所有图标的 PNG 精灵图
  • sprite/my_icons.json --- 描述每个图标在精灵图中位置和尺寸的索引

Martin 的 Sprite 模块会实时读取 SVG 文件、渲染为 PNG、生成索引,无需预构建步骤。


二、配置 Sprite 源

2.1 配置文件方式(推荐)

config.yaml 中添加 sprites 配置:

yaml 复制代码
# yaml-language-server: $schema=https://raw.githubusercontent.com/maplibre/martin/main/schemas/config.json

sprites:
  # 方式一:扫描目录,目录名自动作为 sprite_id
  paths:
    - /path/to/my_icons          # 生成 sprite_id: my_icons
  
  # 方式二:显式命名映射
  sources:
    transport_icons: /path/to/transport
    poi_icons: /path/to/poi

  # 缓存配置(可选)
  cache:
    size_mb: 64                 # 精灵图缓存大小,默认继承全局 cache 的 12.5%
    expiry: 1h                    # 缓存过期时间
    idle_timeout: 30m

目录结构约定:

复制代码
/path/to/my_icons/
├── bicycle.svg
├── bus.svg
├── restaurant.svg
└── icons/
    ├── hospital.svg
    └── school.svg

Martin 会递归扫描目录,子目录名作为前缀:

  • bicycle.svg → sprite ID: bicycle
  • icons/hospital.svg → sprite ID: icons/hospital

2.2 命令行方式

bash 复制代码
martin --sprite /path/to/my_icons --sprite poi=/path/to/poi

三、API 端点与请求

配置完成后,Martin 暴露以下端点:

端点 说明
GET /sprite/<sprite_id>.png 标准分辨率 PNG 精灵图
GET /sprite/<sprite_id>@2x.png 高 DPI(Retina)PNG 精灵图
GET /sprite/<sprite_id>.json 图标索引(含位置、尺寸)
GET /sprite/<sprite_id>@2x.json 高 DPI 索引(坐标自动翻倍)
GET /catalog 查看所有可用的 sprite、font、style 源

3.1 JSON 索引示例

请求 GET /sprite/my_icons.json 返回:

json 复制代码
{
  "bicycle": {
    "height": 15,
    "pixelRatio": 1,
    "width": 15,
    "x": 20,
    "y": 16
  },
  "bus": {
    "height": 18,
    "pixelRatio": 1,
    "width": 18,
    "x": 40,
    "y": 16
  },
  "icons/hospital": {
    "height": 20,
    "pixelRatio": 1,
    "width": 20,
    "x": 60,
    "y": 16
  }
}

@2x 版本会自动将 pixelRatio 设为 2,坐标和尺寸翻倍。


四、多源合并:动态组合精灵图

Martin 支持将多个 Sprite 源实时合并为一个精灵图,语法与瓦片多源合并一致:

bash 复制代码
# 合并 transport_icons 和 poi_icons
GET /sprite/transport_icons,poi_icons.png
GET /sprite/transport_icons,poi_icons.json

注意事项:

  • 不执行 ID 重命名,同名图标会被后者覆盖
  • 合并后的精灵图尺寸为各源图标的并集
  • 适合将"基础图标"和"业务图标"分层管理

也可在配置中定义别名(Alias)

yaml 复制代码
sprites:
  aliases:
    all_icons:
      sources:
        - transport_icons
        - poi_icons
  paths:
    - /path/to/transport
    - /path/to/poi

然后直接访问 /sprite/all_icons.png


五、SDF 精灵图:运行时着色

如果你的图标需要在地图样式中动态变色(如通过 icon-color 属性),需要使用 Signed Distance Field(SDF) 精灵图。SDF 将图标编码为距离场,支持运行时着色,但只能显示单色

端点:

端点 说明
GET /sdf_sprite/<sprite_id>.png SDF 格式 PNG
GET /sdf_sprite/<sprite_id>.json SDF 索引
GET /sdf_sprite/<sprite_id>@2x.png 高 DPI SDF

MapLibre 样式中使用:

json 复制代码
{
  "layout": {
    "icon-image": "bicycle",
    "icon-color": "#ff0000",
    "icon-halo-color": "#ffffff",
    "icon-halo-width": 2
  }
}

限制: 如需多色图标,必须将多个单色图标叠加渲染。


六、完整配置示例

yaml 复制代码
# config.yaml
listen_addresses: "0.0.0.0:3000"

# 瓦片源(PostGIS / MBTiles / PMTiles)
postgres:
  connection_string: postgres://user:pass@localhost/db
  auto_publish: true

# 精灵图配置
sprites:
  paths:
    - ./assets/sprites/default
    - ./assets/sprites/transport
  sources:
    custom_poi: ./assets/sprites/poi
  aliases:
    full_set:
      sources:
        - default
        - transport
        - custom_poi
  cache:
    size_mb: 32
    expiry: 30m

# 字体配置
fonts:
  paths:
    - ./assets/fonts

# 样式配置
styles:
  paths:
    - ./styles

启动后验证:

bash 复制代码
# 查看所有资源
curl http://localhost:3000/catalog | jq '.sprites'

# 获取精灵图
curl -o sprite.png http://localhost:3000/sprite/full_set.png
curl -o sprite.json http://localhost:3000/sprite/full_set.json

七、性能与缓存

Martin 的 Sprite 生成是计算密集型操作(SVG 解析 → 栅格化 → PNG 编码),因此内置了基于 Moka 的 LRU 缓存:

  • 默认缓存大小:全局 cache.size_mb12.5%(如全局 512MB,则 Sprite 缓存约 64MB)
  • 可独立配置 sprites.cache.size_mb
  • 缓存键包含文件修改时间,目录更新后自动失效

优化建议:

  1. SVG 文件尽量精简,避免复杂路径
  2. 图标尺寸统一(推荐 15×15、20×20、24×24 等标准尺寸)
  3. 高并发场景增大缓存,或前置 CDN 缓存 @2x 版本

八、与样式系统的联动

Martin 的 Sprite 服务天然与 Style 服务配合。你可以在 style.json 中直接引用 Martin 提供的 Sprite 端点:

json 复制代码
{
  "version": 8,
  "name": "My Map Style",
  "sprite": "http://localhost:3000/sprite/full_set",
  "glyphs": "http://localhost:3000/font/{fontstack}/{range}.pbf",
  "sources": {
    "basemap": {
      "type": "vector",
      "url": "http://localhost:3000/basemap.json"
    }
  },
  "layers": [
    {
      "id": "poi-restaurant",
      "type": "symbol",
      "source": "basemap",
      "source-layer": "poi",
      "layout": {
        "icon-image": "restaurant",
        "icon-size": 1,
        "text-field": "{name}",
        "text-font": ["Noto Sans Regular"]
      },
      "paint": {
        "icon-color": "#c62828",
        "text-color": "#333333"
      }
    }
  ]
}

将样式文件放入 styles/ 目录,Martin 会自动通过 /style/<style_id> 端点提供,形成瓦片 + 精灵图 + 字体 + 样式的完整自托管地图服务。


九、总结

特性 说明
零预构建 直接读取 SVG 目录,无需手动合成精灵图
递归扫描 子目录自动作为 ID 前缀
多源合并 支持逗号分隔组合多个 Sprite 源
SDF 支持 运行时动态着色,适合主题切换
实时更新 文件变更后自动反映(有缓存失效)
缓存优化 独立缓存配置,支持高并发场景

Martin 的 Sprite 生成能力消除了地图图标管理中的"构建步骤",让图标迭代与地图样式开发同步进行,是构建自托管 MapLibre 地图服务时不可或缺的组件。

相关推荐
GDAL2 天前
mbserver(mbtiles‑server) vs Martin 全面对比
martin·mbserver
GDAL2 天前
Martin:基于 Rust 的高性能矢量瓦片服务器
mapbox·martin
tzy2331 个月前
Web GIS 矢量瓦片(MVT)入门:一文读懂栅格与矢量的核心差异
gis·地图·mvt·mapbox·瓦片
GDAL2 个月前
Martin 瓦片服务器极简实用教程
矢量切片·mbtiles·martin
LEILEI18A3 个月前
maplibre-gl mapbox-gl精灵图 雪碧图制作(python代码)
python·mapbox·精灵图·maplibre·雪碧图
duansamve4 个月前
Mapbox中点击按钮在多条线其中一条线上生成一条新的可编辑的线
mapbox
WebGIS开发4 个月前
新中地系统学习3个月能做出什么效果?
openlayers·mapbox·webgis
duansamve4 个月前
Mapbox中如何对已经加载的线段进行编辑?
mapbox
duansamve4 个月前
Mapbox中如何需改线的样式?
mapbox