QGis下载天地图切片并合并成一张图片

820 阅读3分钟

threejs使用球体制作地球模型时没找到合适的贴图,那么就自己下载地图切片制作吧,记录下过程。

初始化设置

下载QGis

QGis下载地址

image-20240330235257389.png

QGis 设置为中文

QGis > Preferences > General > User interface translation > OK

设置完成重启QGis image-20240330235750780.png

添加天地图XYZ切片服务

  1. 注册天地图用户前往控制台申请访问密钥tk

    控制台访问地址

image-20240331000355722.png 2. 创建应用

应用名称和应用类型可以随意填写,但是要注意的是应用类型 。使用不同客户端会限制访问,例如 申请应用选择的是服务端,在浏览器端使用改 key 访问就会访问失败

image-20240331000515114.png

  1. QGis中添加天地图服务

image-20240331000858986.png

  • 天地图切片服务访问地址

    3857是指球面墨卡托投影,4326是指经纬度投影

    tk 为创建应用时生成的key

    • 地址规则如下:

      t0.tianditu.gov.cn/[图层服务访问前缀]/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=[图层类型]&STYLE=default&TILEMATRIXSET=[切片规则]&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=填写成应用的key

      图层服务访问前缀:

      image-20240331003735699.png 图层类型+切片规则:

      let [图层类型,切片规则] = 图层服务访问前缀.split("_");

      // 矢量底图 http://t0.tianditu.gov.cn/vec_c/wmtslet [LAYER,TILEMATRIXSET]"vec_c".split("_");
      // 图层类型 LAYER = vec
      // 切片规则 TILEMATRIXSET = c
      
    • 常用服务地址

      1. 天地图影像图3857 :http://t0.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=填写成应用的key
      2. 天地图影像图3857注记:http://t0.tianditu.gov.cn/cia_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=填写成应用的key
      3. 天地图矢量图3857:http://t0.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=填写成应用的key
      4. 天地图矢量图3857注记:http://t0.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=填写成应用的key
      5. 天地图影像图4326:http://t0.tianditu.gov.cn/img_c/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=c&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=填写成应用的key
      6. 天地图影像图4326注记:http://t0.tianditu.gov.cn/cia_c/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=c&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=填写成应用的key
      7. 天地图矢量图4326:http://t0.tianditu.gov.cn/vec_c/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=c&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=填写成应用的key
      8. 天地图矢量图注记4326:http://t0.tianditu.gov.cn/cva_c/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=c&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=填写成应用的key
  • QGis 新建XYZ切片服务链接 image-20240331001030573.png image-20240331001730202.png

  • 切片服务预览 image-20240331001214411.png

  • 注意事项

    1. 当图层服务添加进去发现看不了图层,尝试切换下天地图服务的tk

安装 QTiles 切片下载插件

插件 > 管理并安装插件 > 搜索QTiles > 安装

image-20240331004857496.png

下载切片

打开QTiles插件下载

image-20240331005039893.png

切片下载设置

  1. Tileset name 配置输出名称

  2. Output 配置输出目录

  3. Extent 设置切片下载边界

  4. Zoom 设置切片下载层级

  5. Parameters 参数默认就好

    image-20240331005626333.png

    image-20240331005610238.png

image-20240331010038108.png

image-20240331010053529.png

注意事项

  1. 切片下载前先将天地图切片服务加入图层预览
  2. 下载的图层不对,检查下 Extent 边界设置
  3. 设置层级过大会非常耗时
  4. 下载的规则是 z/x/y,层级/列/行

合并切片

基于Node.js + jimp 简单实现某个层级下的切片合并

const { readdirSync, statSync, readFileSync } = require('fs');
const { join, basename, extname } = require('path');
const Jimp = require('jimp');
​
// 合并某个层级下的图片
const folderPath = 'Mapnik22/5/';
​
// 要忽略的文件夹/文件名
const excludedNames = ['.DS_Store'];
​
function getFilesAndFolders(filePath) {
  const items = readdirSync(filePath);
  return items
    .filter(item => !excludedNames.includes(item))
    .map(item => {
      const itemPath = join(filePath, item);
      return {
        path: itemPath,
        isFile: statSync(itemPath).isFile()
      };
    })
    .sort((a, b) => {
      if (a.isFile && b.isFile) {
        return (
          basename(a.path, extname(a.path)) - basename(b.path, extname(b.path))
        );
      }
      if (!a.isFile && !b.isFile) {
        return basename(a.path) - basename(b.path);
      }
      return 0;
    });
}
​
const imageGroups = [];
const folders = getFilesAndFolders(folderPath);
​
folders.forEach((folderInfo, index) => {
  if (!folderInfo.isFile) {
    const imagesInFolder = [];
    getFilesAndFolders(folderInfo.path).forEach(fileInfo => {
      if (fileInfo.isFile) {
        imagesInFolder.push(fileInfo.path);
      }
    });
    imageGroups[index] = imagesInFolder;
  }
});
​
Promise.all(
  imageGroups.map(col => Promise.all(col.map(path => Jimp.read(path))))
)
  .then(cols => {
    // 计算合并图片的宽度
    const width = cols.reduce(
      (acc, col) => acc + Math.max(...col.map(image => image.bitmap.width)),
      0
    );
    // 计算合并图片的高度
    const height = Math.max(
      ...cols.map(col =>
        col.reduce((acc, image) => acc + image.bitmap.height, 0)
      )
    );
​
    // 创建一个新的 Jimp 对象
    const mergedImage = new Jimp(width, height);
​
    // 合并图片
    let x = 0;
    cols.forEach((col, index) => {
      let y = 0;
      col.forEach((image, row) => {
        mergedImage.composite(image, x, y);
        y += image.bitmap.height;
        console.log(`第${index}列,第${row}行,${imageGroups[index][row]}`);
      });
      x += Math.max(...col.map(image => image.bitmap.width));
    });
​
    // 保存合并后的图片
    return mergedImage.writeAsync('output.png');
  })
  .then(() => {
    console.log('图片合并完成');
  })
  .catch(err => {
    console.error('图片合并失败:', err);
  });

成果预览

image.png