Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

使用imagemagic制作瓦片地图 #5

Open
gwl002 opened this issue Jun 15, 2021 · 0 comments
Open

使用imagemagic制作瓦片地图 #5

gwl002 opened this issue Jun 15, 2021 · 0 comments

Comments

@gwl002
Copy link
Owner

gwl002 commented Jun 15, 2021

之前有个项目客户给一张精度很高的图让做成那种能够缩放的地图的效果。一开始的想法是直接加载大图,然后通过手势去控制图片的scale来实现,后来觉得不妥,高精度图片的体积实在太大,加载时间太长,效果很不好。通过研究发现openlayers这种专门用来加载地图的库才是更好的选择。但是怎么把图片制作成那种瓦片地图是个问题。

瓦片地图金字塔模型是一种多分辨率层次模型,从瓦片金字塔的底层到顶层,分辨率越来越低,但表示的地理范围不变。首先确定地图服务平台所要提供的缩放级别的数量N,把缩放级别最高、地图比例尺最大的地图图片作为金字塔的底层,即第0层,并对其进行分块,从地图图片的左上角开始,从左至右、从上到下进行切割,分割成相同大小(比如256x256像素)的正方形地图瓦片,形成第0层瓦片矩阵;在第0层地图图片的基础上,按每像素分割为2×2个像素的方法生成第1层地图图片,并对其进行分块,分割成与下一层相同大小的正方形地图瓦片,形成第1层瓦片矩阵;采用同样的方法生成第2层瓦片矩阵;…;如此下去,直到第N一1层,构成整个瓦片金字塔。

原理

瓦片地图的原理很简单。假设客户给的原图为(5124,5124),这是我们地图能够达到的最高分辨率,但是假设我们的视窗只有512512,此时我们只能看到左上角1/16的部分。假设用户最开始看到的图包含整个地图,也就是512512,此时地图被缩放了16倍,宽高个4倍,此时设level为1,那么当放大一倍时,此时地图实际图片大小为(5122,5122),此时level为2,当再放大一倍时,此时level为3,刚好为原图,分辨率最高。那么我们只要想办法把原图按不同level缩放切割就行。level1就是直接宽高各缩放4倍,level2各缩放2倍,再把它切成4张,每张大小为512512,level3的时候不用缩放,直接切成16张,同样每张512512.我们把
不同level的图片放在不同的文件夹下,然后用能够加载瓦片地图的库就能加载,例如openlayers。所以我们剩下的问题就是怎么切图了。

import 'ol/ol.css';
import Map from 'ol/Map';
import TileLayer from 'ol/layer/Tile';
import View from 'ol/View';
import XYZ from 'ol/source/XYZ';

var map = new Map({
  target: 'map',
  layers: [
    new TileLayer({
      source: new XYZ({
        url:
          'https://localhost:9080/tiles/{z}-{x}-{y}.png'    //因为我的图片是 1-1-1这种形式组成所以这里是这样,如果你的图片是按等级放在不同文件夹要写成 https://localhost:9080/tiles/{z}/{x}/{y}.png 具体怎么放要看你如何组织的tiles结构
      }),
    }) ],
  view: new View({
    center: [-472202, 7530279],
    zoom: 12,
  }),
});

QQ20210615-225842@2x

使用imagemagic处理图片

Use ImageMagick® to create, edit, compose, or convert digital images. It can read and write images in a variety of formats (over 200) including PNG, JPEG, GIF, WebP, HEIC, SVG, PDF, DPX, EXR and TIFF. ImageMagick can resize, flip, mirror, rotate, distort, shear and transform images, adjust image colors, apply various special effects, or draw text, lines, polygons, ellipses and Bézier curves.

imagemagic是一个强大的图片处理工具,可以用命令行直接处理图片,可以很方便的实现各种图片处理操作。虽然很强大但不得不说文档很晦涩难懂,我也只是为了完成这个任务熟悉了几个命令而已,完全谈不上精通。
[我们的切图工具分2个步骤,第一步就是按不同level切图,但是因为并不是刚好如原理分析里讲的那么刚好就是整数倍,地图原图往往不是刚好是正方形,比如切的瓦片每个为512512,切到边上的时候可能只有360400这样的,这时需要把它补成512*512,不然会有奇怪的现象发生。注意,脚本里有些参数要根据你的实际情况自己设置。源码地址

#! /bin/bash
#cropFile.sh
INDEX=1
IMAGE_WIDTH=10752   #原图宽度
IMAGE_HEIGHT=21504  #原图高度

for file in `ls "originImages"`;do #将原图放在orginalImages文件夹下
	echo "processing ${file}"
	file_base=$(basename $file .png) #拿到原图名称
	tiles_dir="${file_base}_tiles"   #碰到有无目标文件夹,有则直接下一步,没有就建立文件夹
	if [ -e "${tiles_dir}" ] && [ -d "${tiles_dir}" ];then 
		echo "${tiles_dir} exisit"
	else
		echo "mkdir ${tiles_dir}"
		mkdir "${tiles_dir}"
		echo "mkdir ${tiles_dir} completed"
	fi
	for (( i=1; i<=7; i++));do    #根据你自己的需求调节所需的等级
		echo "processing ${file} scale ${i}"
		((level= 7 - i))
		((scale= 2 ** (i-1)))
		((width= $IMAGE_WIDTH / $scale))
		((height= $IMAGE_HEIGHT / $scale))
		resizeFormat="${width}x${height}"
		echo $resizeFormat
		convert "originImages/${file}" -resize $resizeFormat -crop 512x512 -set filename:tile ./${tiles_dir}/${level}-%[fx:page.x/512]-%[fx:page.y/512] %[filename:tile].png
		echo "complete ${file} scale ${i}"
	done
	echo "complete ${file}"
	let INDEX=${INDEX}+1
done
#! /bin/bash
#fillSize.sh
START=`date +%s%N`;
for folder in `ls | grep "H*tiles"`;do  #找到所有之前切片生成的文件夹,遍历其中找到其中尺寸不对的,将其放置在512*512透明图的左上角
	echo $folder
	for image in `ls $folder`;do
		echo $image
		ratio=`identify "${folder}/${image}" | cut -d " " -f 3`
		if [ "$ratio" != "128x128" ];then
			echo $ratio
			convert "${folder}/${image}" -background transparent -gravity NorthWest -extent 512x512 "${folder}/${image}"
		fi 
	done
done
END=`date +%s%N`;
time=$((END-START))
time=`expr $time / 1000000`
echo "totally spend time ${time}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant