OpenLayers.js + geotiff.js实现tiff格式图片导出
引言
OpenLayers是一个开源的JavaScript库,用于在Web浏览器中呈现交互式地图。它本身并不提供导出地图为TIFF图片的功能,但可以结合其他库或服务来实现这个功能。一种可能的解决方案是使用Canvas和FileSaver.js库。Canvas可以将网页上的内容渲染为图像,而FileSaver.js库可以将生成的图像保存到本地。在生成TIFF文件上我选择geotiff.js这个库,GeoTIFF.js可以在TIFF图像中嵌入地理元数据,并且支持多种地图投影坐标系。
步骤
-
下载所需要的库
npm install geotiff npm install file-saver
-
获取canvas信息
这一步可以参考openlayers导出PNG的官方示例:https://openlayers.org/en/v6.15.1/examples/export-map.html
具体思路就是获取地图所在的元素,转化为画布绘制,这里主要提供思路,所以只针对整个显示区域做导出,需要自定义导出范围的朋友可以私信或者评论,我再补充对应的例子,这里以tiff制做为主。
-
创建地图
let map = new Map({ target: 'olMap', layers: [layers], controls: defaults({ attributionOptions: { collapsible: false, } }), view: new View({ center: fromLonLat([0,0]), zoom: 15 }) })
-
获取地图范围
// 获取地图范围信息 let extent = map.getView().calculateExtent(this.map.getSize()) let bottomLeft = [extent[0], extent[1]] let topRight = [extent[2], extent[3]] let bbox = [bottomLeft[0], bottomLeft[1], topRight[0], topRight[1]]
-
获取投影和分辨率
let resolution = map.getView().getResolution() let projection = map.getView().getProjection().getCode()
-
将地图转换为canvas
map.once('postcompose', function (event) { let canvas = event.context.canvas; let imageData = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height).data })
-
至此,我们得到了需要导出范围的地图canvas及图像数据,接下来,我们需要将数据写入tiff文件中,即需要用到geotiff中的writeArrayBuffer方法。
-
创建tiff文件实例
-
导入所需方法
import {writeArrayBuffer} from 'geotiff'
-
编写元数据
// 将图像数据写入GeoTIFF文件 let tifImage = writeArrayBuffer(imageData, { width: canvas.width, height: canvas.height, GeographicTypeGeoKey: projection, ModelTiepoint: [0, 0, 0, bbox[0], bbox[3], 0], ModelPixelScale: [resolution, resolution, 0], GTModelTypeGeoKey: 2, })
这里将步骤3中得到的地图元素写入tiff文件,{}中为元数据,这里我依次定义了图片的长宽、投影类型、模型点配准(这里我理解为canvas坐标和地理坐标的配准)、模型像素比例尺、模型类型(0表示未定义或未知;1表示2D投影坐标参考系;2表示地理二维坐标参考系;3表示3D坐标参考系;32767表示自定义)。
这些参数可以查询GEOTIFF文件规范,根据需要添加,我这里只需要图片能导入ArcGIS能显示具体坐标信息即可。
-
geotiff.js源代码展示的属性信息
[ 'Compression', 'ExtraSamples', 'GeographicTypeGeoKey', 'GTModelTypeGeoKey', 'GTRasterTypeGeoKey', 'ImageLength', // synonym of ImageHeight 'ImageWidth', 'Orientation', 'PhotometricInterpretation', 'ProjectedCSTypeGeoKey', 'PlanarConfiguration', 'ResolutionUnit', 'SamplesPerPixel', 'XPosition', 'YPosition', ]
-
-
导出图片
-
导入方法
import { saveAs } from 'file-saver'
-
转blob格式
let tiffBlob = new Blob([tifImage])
-
导出
saveAs(tiffBlob, 'map.tiff')
-
-
全部代码
import {writeArrayBuffer} from 'geotiff' import { saveAs } from 'file-saver' let map = new Map({ target: 'olMap', layers: [layers], controls: defaults({ attributionOptions: { collapsible: false, } }), view: new View({ center: fromLonLat([0,0]), zoom: 15 }) }) // 获取地图范围信息 let extent = map.getView().calculateExtent(this.map.getSize()) let bottomLeft = [extent[0], extent[1]] let topRight = [extent[2], extent[3]] let bbox = [bottomLeft[0], bottomLeft[1], topRight[0], topRight[1]] let resolution = map.getView().getResolution() let projection = map.getView().getProjection().getCode() map.once('postcompose', function (event) { let canvas = event.context.canvas; let imageData = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height).data // 将图像数据写入GeoTIFF文件 let tifImage = writeArrayBuffer(imageData, { width: canvas.width, height: canvas.height, GeographicTypeGeoKey: projection, ModelTiepoint: [0, 0, 0, bbox[0], bbox[3], 0], ModelPixelScale: [resolution, resolution, 0], GTModelTypeGeoKey: 2, }) let tiffBlob = new Blob([tifImage]) saveAs(tiffBlob, 'map.tiff') })
参考资料
-
GeoTiff格式说明:
- https://blog.csdn.net/oYinHeZhiGuang/article/details/121904325
- https://www.mathworks.com/help/map/ref/geotiffwrite.html
- https://blog.csdn.net/DLW__/article/details/124024718
-
geotiff的github链接:https://github.com/geotiffjs/geotiff.js/
官方文档:https://geotiffjs.github.io/geotiff.js/module-geotiff.html