背景
地图功能是每个系统必备的功能之一,通常可以使用百度地图和高德地图来实现在线地图展示。
但是将展示的地图下载到本地则是一件有挑战的事情。
运行环境
mac系统
java 1.8
其中标注的坐标原始数据是百度坐标,因此代码中进行了转换。
参考代码
需求
某一天领导找我,说客户提出需要将系统里的在线地图下载到本地浏览。利用搜索引擎,找到一些思路,
前端思路: 在线地图是canvas绘制的,可以将canvas转图片存储到本地。
后端思路: 高德和百度均提供静态地图接口,但是存在尺寸限制、标注限制。因此需要程序自己切割下载,拼接地图。
作为一名java后端开发,当然是选择后端解决方案。
这里先说下我的需求:我需要一份地图,是杭州滨江地区的,地图需要标注一些位置。这些位置超过10个。因此无法直接使用高德地图接口下载。
实现过程
以高德地图为例,
首先请注册高德开发者,申请密钥,如此才可以调用接口
使用到的接口地址 https://lbs.amap.com/api/webservice/guide/api/staticmaps
public final static String uurl = "http://restapi.amap.com/v3/staticmap?zoom=16&size=1024*1024&scale=1";// 高德地图api
key = "你的密钥";
解释下这个接口的参数。
zoom 地图的缩放比。
size 地图的尺寸
scale 地图清晰度 1表示非高清。2表示高清。如果设定值为2 则 zoom将自动成为17 size将变成 2048
由于下载高清地图,非常慢,以及内存容易溢出,因此这里修改非高清的参数。
直接想要结果的,可以下载一份代码,自己跑一次
这里先解释下思路:
1、经纬度切割。 先确定你需要下载地图的经纬度范围。需要2个点即可。
地图左上角、地图右下角。
例如这里我的坐标是杭州滨江区。
String top = "120.123754,30.232441";
String end = "120.243745,30.141632";
你需要决定将你的地图切割成多少块。
这里我设定步长是
// 按照0.01为步长,循环计算出所需获得的图片中心位置坐标
int countX = (int) ((ex - sx) / 0.010999);// 如果ex - sx = 0,说明只有一列
int countY = (int) ((sy - ey) / 0.00955);// 如果sy - ey = 0,说明只有一行
其中0.010999 表示 横向的地图中心距离 0.00955 表示竖向的地图中心距离。
这2个值 不能随意修改。和缩放比、清晰度存在关联。
2、下载地图
设定了步长后即可运行程序,下载地图碎片。下载有可能失败,请多次执行,直到数目完整。
3、横向切割图片
下载的地图碎片,多数情况存在重叠部分,因此需要切割。切割的规则是 第一张图片保持完整,从第二张图片开始切割重叠的部分,只保留不重叠的图片。因此需要确定起点是关键。
for (int i = 1, j = 0; i <= allPng; i++) {
System.out.println("正在截取");
if (i == (j * count[1] + 1)) {
cutImage(path + "/getMaps/" + i + ".png", path + "/cuttedMaps/" + i + ".png", 0, 0, 1024, 1024);
j++;
} else {
cutImage(path + "/getMaps/" + i + ".png", path + "/cuttedMaps/" + i + ".png", 1024 - 1024, 0, 1024,
1024);
}
}
上图中的 1024-1024 表示计算切割的起点位置。
这个重叠值如何确定,拿 1.png和2.png 对比确定。在打开ps工具手动数数偏差。 如果你重叠的像素是10 则这里应当是 10
这里因为我给的步长十分精确,重叠为0 因此切割的起点位置从0开始。
3、竖向切割
和横向是同理的。需要人工通过ps确定 重叠的像素是多少.
横向是比较第一张和第二张图片,但是竖向则需要 比较 第一列的第一张和 第二列的第一张图片。
System.out.println("开始对图片进行第二次截取...");
File f1 = new File(path + File.separator+"mergedMaps");
String[] mergedImgs = f1.list();
for (int i = 1; i <= mergedImgs.length; i++) {
if (i != mergedImgs.length) {
cutImage(path + File.separator+"mergedMaps"+File.separator + i + ".png", path + "/cutteddMaps/" + i + ".png", 0, 0,
(count[1] - 1) * 1024 + 1024, 1024);
} else {
cutImage(path + File.separator+"mergedMaps"+File.separator + i + ".png", path + "/cutteddMaps/" + i + ".png", 0, 0,
(count[1] - 1) * 1024 + 1024, 1024);
}
}
4、合成
正确设定步长、横竖的切割起点,即可正确拼接出想要的图片了。
下载图片可能不完整,可以重复多次执行,
以下是程序执行的效果。由于是16的缩放比,所以图是很大的。大小是 28MB
问题
1、拼接的图片,出现错位?
重叠值错误。请重新设定。
2、图片没有重叠?
步长太大,请重新设定。
3、标注不完整,破碎
这个问题非常常见,本人也卡在这里。主要原因是标注的点,正好处于分割线上,然后分割线存在重叠部分,切割的时候导致标注不完整。
这里解决方案主要是,不断改变步长,确保地图水平恰好无缝可以拼接。也就是0重叠,但是线条吻合。传说中的完美分割,本人采用的就是该方案。
另外一个就是 ,位于标注上的点,坐标进行偏移,确保位于重叠的右侧。这样不会被切割。也需要多次人工尝试。
4、高清版本
高清版本的参数和非高清的差异较大。主要是确保是 高清版本的地图碎片尺寸是固定的 2048
而非高清的是 1024 因此需要注意修改参数。
5、切割和合并提示文件不存在
下载的地图不完整,多次运行程序即可。因为高德的该接口似乎很奇怪,经常会失败。
代码下载
提供2份代码
滨江非高清版本
https://download.csdn.net/download/douniwan123654/12838090
滨江高清版本
稍后发布,