草庐IT

webgis —— geoserver 更优秀的瓦片格式

纯爱枫若情 2023-03-28 原文

前言

刚进目前所在的这家公司之前,其实我没有做过 webgis 方面的开发工作的,所以对于 gis 开发,我算是个完完全全的新手。

那时候,我甚至连 wmts、wms 服务都不太能分得清。更不要说什么 openlayers、cesium、geoserver 这些了,统统都没怎么用过。

想想,人对于未知的东西,就会产生恐惧。

而客服恐惧的最好方式,就是不停的学习。

很多时候,有了好的学习资料,有了好的学习方式,甚至于有了好的老师,完全可以让你事半功倍。

相反,如果这些都没有,也只能让你事倍功半了。

回过头来想想,对于 webgis 方面的学习,真可谓是一路坎坷,甚至于比自学前端的经历更让人难忘。

虽然很多人都说前端简单,但是如果你只是写写 html、css,而且只满足于应付日常的工作,确实简单。

但是,在众多的前端领域中,如果你选择的是我之前做过的数据可视化方向,以及现在做的 webgis 方向,你会真真切切的感受到,那些口口声声说简单的人简直是睁着眼睛说瞎话。

对于前端数据可视化工程师和 webgis 工程师来说,首先,你得是个优秀的前端工程师,也就是说,大部分前端的会的东西,你都要会,并且需要你掌握的游刃有余,这样才能不至于与前端这个岗位脱节。

除了这些以外,你还要学习掌握一些 canvas、webgl 等知识,如果你是做 webgis 方向,你还要了解 gis 方面的一些专业知识。

这几个方面的知识,除了 canvas 稍微简单好啃点,其他都是一些难啃的硬骨头。

初识 webgis

很多东西,你只有接触了,思考了?,并在实际的工作中运用了,才会开始慢慢掌握,了解其应用场景,否则,即使是学习了,也很难融会贯通。

就比如我今天要讲的这个话题,就让我深切的感受到了这一点。

通常情况下,在 web 端,加载影像图都是通过影像切片的方式进行的。

在这里,我不想引用一大段专业的术语,来枯燥的讲述什么是影像切片,因为这毫无意义。

我写并非科普文,只是想从一个外行的从业者,谈谈自己对 webgis 的理解,如果完全“照本宣科”,就背离了我写这篇文章的初衷了。

当然以下的内容,完全是我一家之言,如果有讲的不对的地方,希望更专业的童鞋能像我提出自己的意见,大家一起讨论讨论。

个人理解,之所以出现影像切片,纯粹是由于,对于 web 端来说,需要一个更加合适的方式,来展示影像图。

那么为什么不能直接展示影像图呢?原因显而易见,数据量太大,没法直接在 web 端展示。

一般按照我们通俗的理解来说,一张照片要想越清晰,分辨率就得越高,分辨率越高同时也意味照片越大。

这个道理放在影像图,也就是 geotiff 上,同样适用。

通常情况下,一景数据(也就是卫星拍摄的一张影像),所包含的面积,少则几千平方公里,多则上万平方公里。

试想想,范围这么大,又想看得清晰,geotiff 文件大也可以了理解了。

更别说,我们通常用的影像图,都是用好多景的数据拼凑而成,形成某个区域或地方的某一时期的影像图。

这么大的文件,不可能通过网络直接传输,进而显示到用户的浏览器上的。

那么就有了一些别的方法,可以帮助我们,实现直接远程通过浏览器来查看影像图的目的。

其中 OSGeo 制定的 Web地图服务(WMS) — OGC e-Learning 2.0.0 文档Web地图平铺服务(WMTS) — OGC e-Learning 2.0.0 文档 等地图可视化服务标准,就是通过一定的分层规则和投影方式,对影像进行分层切割。

使用的时候再按照对应的规则,根据层级请求瓦片资源,进行地图还原。

详细的定义和使用方式,在这里,我就不想过多的赘述了。我想能阅读这篇文章的人,多半对这些知识有过一些了解。

当然,据我了解,也还有一些别的影像使用方式,比如谷歌的 xyz 方式、bing 地图的 QuadTree 方式,甚至于还有不切片的 Cloud Optimized GeoTIFF 的方案。

这些不在我们这里的讨论范围之内,有兴趣的童鞋,可以自行了解下相关知识。

geoserver

谈到了 wmts、wms 以后,一个不能避开的一个话题就是 GeoServer 了。

geoserver 是一款开源的地图服务软件,允许用户共享和编辑地理空间数据。

对 geoserver 不了解的童鞋,可以去官网看下介绍:GeoServer Documentation。要是觉得英文阅读存在障碍的童鞋,还有对应的中文文档:GeoServer用户手册 — GeoServer 2.19.x User Manual

一般情况下,我们会用 geoserver 发布矢量和栅格图,然后通过调用其提供的 wmts 或者 wms 服务接口来加载地图。

具体如何发布以及如何使用发布的影像,可以查看相关文档进行了解。

最近在使用 geoserver 的时候,突然发现它支持一种很奇怪的 format:

20220706145136.png

当然,之前也并不是没发现,可以选择很多不同的格式来查看发布的数据,只不过以前没去探究原因而已。

这次,刚好需要对项目做一些优化工作,所以就开始注意到这个地方了。

我们知道,png 格式支持 alpha 通道,所以一般情况下,我们会用 png 格式来存储可能会存在透明区域的图。当然,还有 webp 等图片格式,支持 alpha 通道,但是由于 geoserver 默认不支持,就不再这里讨论了。

当改用 image/vnd.jpeg-png 这个方式的时候,wms 请求里,参数发生了一些变化:

20220706150752.png

为了了解清楚其作用,在官方文档 WMS output formats — GeoServer 2.21.x User Manual 找到如下描述。

20220706151325.png

简而言之,这个格式的作用的就是,如果影像中存在透明的区域,就会返回 png 图像;如果不存在,则返回 jpg 格式的图像。

可以说,这种方案,一举解决了,之前项目中的种种弊端。

  1. 影像图不能用 jpeg 格式,因为会存在透明区域,叠加在底图上效果会很难看。所以,以前默认情况下,都是用 png 格式的瓦片。
  2. 但是 png 由于编码的原因,单张瓦片占用内存太大,浪费存储空间。
  3. 一般我们都会用 gwc 的方式来访问影像切片,为了加速访问,我们一般会提前预切好到一定层级的影像瓦片。
  4. 正常情况下,一帮 256 * 256 大小的瓦片,如果内容丰富,jpeg 格式和 png 格式,所占存储空间大小相差十倍之多,导致如果全用 png 格式,对服务器来说,带宽压力很大;对客户端来说,表现的性能也要差的多。
  5. 改用 webp,默认 geosever 不支持该格式; openlayers、cesium 等前端 gis 框架的支持度也有待考证;某些系统的浏览器,默认对 webp 的支持度不高。

基于以上种种因素,这种自动决定使用 jpeg 或者 png 的瓦片方案,简直就是太优秀了。

实际应用

稍微研究了下,改改之前的加载方式,就能很平滑的应用到实际的项目中去了:

// 在 openlayers 中使用
new WMTS({
  name: option.name,
  url: `${config.wmtsPrefix}?transparent=TRUE`,
  layer: option.layerName,
  style: '',
  matrixSet: 'EPSG:4326',
  format: 'image/vnd.jpeg-png',
  wrapX: true,
  tileGrid: new WMTSTileGrid({
    tileSize: [tileSize, tileSize],
    extent: option.extent || [-180.0, -90.0, 180.0, 90.0], // 范围
    origin,
    resolutions,
    matrixIds,
  }),
})

//在 cesium 中使用
new WebMapTileServiceImageryProvider({
    url: `${url}?transparent=TRUE`,
    layer,
    style,
    format: 'image/vnd.jpeg-png',
    rectangle: Rectangle.fromDegrees(
      ...rectangle,
    ),
    tilingScheme: new GeographicTilingScheme({
      numberOfLevelZeroTilesX: 2,
      numberOfLevelZeroTilesY: 1,
    }),
    tileMatrixSetID: 'EPSG:4326',
    tileMatrixLabels: [...Array(zoomMax - zoomMin + 1)].map((_, index) => `EPSG:4326:${zoomMin + index}`),
    minimumLevel: zoomMin,
    maximumLevel: zoomMax,
});

当然,以上两段代码,都是没法正常运行的,需要结合实际的情况,补齐对应的变量方能正常的将 wmts 服务请求的瓦片格式设置为 image/vnd.jpeg-png

当然,如果你不是用 geoserver 作为地图服务器,就不能直接这么用了,这是 geoserver 特有的功能。

如果你也像我们一样,用 gwc 对瓦片做缓存,那么你需要开启对 vnd.jpeg-png 格式的支持,默认 gwc 是没开启对该格式的支持的。

20220706154406.png

结语

老实说,这篇文章,前前后后写了很多次,每次想一鼓作气地写完,却每每半途而废。

本想不落窠臼,却无奈对于 webgis 了解的并不是太透彻,最后难免还是落入了俗套。

不过好歹也是写完了,对自己也算是有了一个交代吧。

世上无难事,只怕有心人。

这句谚语,你越是品味,越是觉得其中蕴涵了丰富的人生经验。

现在回过头去看看,不知不觉,在很多以前看来是未知的领域,已经探索了很久了。

从陌生到熟悉,从畏惧到从容,从一知半解到现在的渐入佳境,这又何尝不是一种美妙的体验呢。

越是深入研究,就越是明白一个道理,其实技术不分高低贵贱,更不分对错,什么场景使用什么技术,也只不过是一种取舍而已。

有关webgis —— geoserver 更优秀的瓦片格式的更多相关文章

  1. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  2. ruby-on-rails - 将 Ruby 中的日期/时间格式化为 YYYY-MM-DD HH :MM:SS - 2

    这个问题在这里已经有了答案:Railsformattingdate(4个答案)关闭4年前。我想格式化Time.Now函数以显示YYYY-MM-DDHH:MM:SS而不是:“2018-03-0909:47:19+0000”该函数需要放在时间中.现在功能。require‘roo’require‘roo-xls’require‘byebug’file_name=ARGV.first||“Template.xlsx”excel_file=Roo::Spreadsheet.open(“./#{file_name}“,extension::xlsx)xml=Nokogiri::XML::Build

  3. ruby - 我可以将我的 README.textile 以正确的格式放入我的 RDoc 中吗? - 2

    我喜欢使用Textile或Markdown为我的项目编写自述文件,但是当我生成RDoc时,自述文件被解释为RDoc并且看起来非常糟糕。有没有办法让RDoc通过RedCloth或BlueCloth而不是它自己的格式化程序运行文件?它可以配置为自动检测文件后缀的格式吗?(例如README.textile通过RedCloth运行,但README.mdown通过BlueCloth运行) 最佳答案 使用YARD直接代替RDoc将允许您包含Textile或Markdown文件,只要它们的文件后缀是合理的。我经常使用类似于以下Rake任务的东西:

  4. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  5. ruby-on-rails - 事件管理员日期过滤器日期格式自定义 - 2

    是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s

  6. ruby-on-rails - 如何在 Rails 中设置路由的默认格式? - 2

    路由有如下代码:resources:orders,only:[:create],defaults:{format:'json'}resources:users,only:[:create,:update],defaults:{format:'json'}resources:delivery_types,only:[:index],defaults:{format:'json'}resources:time_corrections,only:[:index],defaults:{format:'json'}是否可以使用1个字符串为所有资源设置默认格式,每行不带“默认值”散列?谢谢。

  7. ruby-on-rails - Rails 4 WYSIWYG Bootsy 不显示格式 - 2

    我刚刚按照thebootsygempage上的安装说明进行操作在我保存并查看帖子内容之前,一切看起来都不错。这是输出在View中的样子:HeaderSubhead:似乎没有呈现任何html格式,因为它被引号或类似的东西转义了-其他人有这个问题吗?我没有在github页面或SO上看到任何问题来指出我正确的方向。除了遵循gem安装说明之外,我还没有做任何事情,但也许我错过了什么或者只是犯了一个愚蠢的错误。如果你还有什么想知道的,请尽管问。干杯 最佳答案 你需要有这样的东西,转义html: 关

  8. ruby - 在 Ruby 中将整数格式化为固定长度的字符串 - 2

    有没有一种简单的方法可以将给定的整数格式化为具有固定长度和前导零的字符串?#convertnumberstostringsoffixedlength3[1,12,123,1234].map{|e|???}=>["001","012","123","234"]我找到了解决方案,但也许还有更聪明的方法。format('%03d',e)[-3..-1] 最佳答案 如何使用%1000而不是进行字符串操作来获取最后三位数字?[1,12,123,1234].map{|e|format('%03d',e%1000)}更新:根据theTinMan的

  9. ruby-on-rails - 如何正确格式化字符串,如 'mccdougal' 到 'McDougal' - 2

    什么Ruby或RailsDSL会将字符串"mccdougal"格式化为"McDougal",同时留下字符串"McDougal"原样?将titleize传递给"McDougal"结果如下:"McDougal".titleize#=>"McDougal" 最佳答案 据我所知,没有可以处理这种情况的Rails助手。这是一个非标准的边缘案例,需要特殊处理。但是,您可以创建自定义字符串变形。您可以将这段代码放入初始化程序中:ActiveSupport::Inflector.inflections(:en)do|inflect|inflect.

  10. ruby-on-rails - Rails 格式验证——字母数字,但不是纯数字 - 2

    什么是测试格式验证的最佳方法让我们说一个用户名,使用字母数字的正则表达式,但不是纯数字?我一直在我的模型中使用以下验证validates:username,:format=>{:with=>/^[a-z0-9]+[-a-z0-9]*[a-z0-9]+$/i}数字用户名(例如“342”)通过了验证,这是我不想要的。 最佳答案 您想“向前看”一封信:/\A(?=.*[a-z])[a-z\d]+\Z/i 关于ruby-on-rails-Rails格式验证——字母数字,但不是纯数字,我们在Sta

随机推荐