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格式说明:
- geotiff的github链接:https://github.com/geotiffjs/geotiff.js/
官方文档:https://geotiffjs.github.io/geotiff.js/module-geotiff.html