KML 里的图标写相对路径,加载后全是碎图
KML 在 Google Earth 里正常,放进网页地图后每个点都变成一个破碎的小图标。
现象
一份标注文件 poi.kml,图标写的是
<href>images/pin.png</href>。
在 Google Earth 中打开正常;用 omnivore.kml('poi.kml')
加载到 Leaflet 后,所有点位显示为浏览器默认的破图占位符,
网络面板里出现 GET /cookbook/images/pin.png 404。
原因
KML 规范规定,href 为相对路径时,基准是 KML 文件本身的 URL,
而不是当前页面的 URL。解析库通常按页面地址去拼,
或者把 href 原样塞给 L.icon。
上面的例子里,页面在 /cookbook/ 下,KML 在 /data/poi.kml,
正确的图标地址应是 /data/images/pin.png,
实际请求了 /cookbook/images/pin.png,自然 404。
排查过程
- 打开网络面板,筛选
png,看 404 的完整路径。 - 把该路径与 KML 的实际地址比对,看基准目录是否一致。
- 在 KML 里搜
<href>,看是绝对 URL、相对路径还是file://。 - 把 KML 用文本编辑器打开,确认
<IconStyle>是否真的存在,有些导出工具根本不写图标。
<Style id="s1">
<IconStyle>
<scale>1.0</scale>
<Icon><href>images/pin.png</href></Icon>
</IconStyle>
</Style>
解决方案
把 href 改成绝对路径,或在解析后统一重写图标地址。
跨域加载 KML 时相对路径几乎必然失败,绝对路径最省事。
<!-- 改成绝对路径(同源) -->
<Icon><href>/data/images/pin.png</href></Icon>
<!-- 或者内联成 data URI,彻底摆脱路径问题 -->
<Icon><href>data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQ...</href></Icon>
解析端也可以拦截,把相对路径按 KML 的 URL 重新拼一次。
const kmlUrl = new URL('/data/poi.kml', location.origin);
omnivore.kml(kmlUrl.href, null, L.geoJSON(null, {
pointToLayer: (f, ll) => {
const href = f.properties.styleUrl || 'images/pin.png';
const iconUrl = new URL(href, kmlUrl).href; // 以 KML 地址为基准
return L.marker(ll, { icon: L.icon({ iconUrl, iconSize: [24, 24] }) });
}
})).addTo(map);
验证
网络面板中图标请求返回 200,路径以 /data/images/ 开头;
地图上所有点位显示正常图标,不再是破图。
console.assert(new URL('images/pin.png', 'http://localhost/data/poi.kml').href
=== 'http://localhost/data/images/pin.png', '基准目录仍不对');
适用版本
| 组件 | 版本 | 说明 |
|---|---|---|
| KML / OGC | 2.2 | 相对 href 以 KML 文件 URL 为基准 |
| Leaflet.omnivore | 1.0.0 | 不自动改写 href |
| OpenLayers | 9.x | KML format 解析后仍需处理图标 |
| Google Earth | 桌面版 / 网页版 | 按文件位置解析,所以本地正常 |
经纬志(2026)。《KML 里的图标写相对路径,加载后全是碎图》。https://www.jingweizhi.com/cookbook/kml-relative-icon.html(访问日期 2026-11-03)。