默认采用:
zoom=17&size=1024*1024&scale=2
高德地图api参数.获取的是2048*2048大小的图片,修改参数之后需要调整图片截取和拼接的偏移量
程序中部分代码来自:
已知问题:
1.效率慢 2.有内存溢出风险,拼接大面积的地图会出现 3.在不同纬度时可能会出现地图没有拼接上的问题,需要调整偏移参数.
1.通过左上角和右下角的图片中心的坐标抓取待拼接图片.计算成图结构.
package com.getMaps;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
public class GetMaps {
public final static String uurl = "http://restapi.amap.com/v3/staticmap?zoom=17&size=1024*1024&scale=2";// 高德地图api
/**
* 批量爬取地图并保存
*
* @param url
* 接口地址集合
* @param path
* 文件保存位置
* @return 地图图片获取完成并保存成功返回true
*/
public static boolean getMaps(ArrayList<String> url, String path) {
try {
// 开始时间
Date begindate = new Date();
int i = 1;
for (String ImgSrc : url) {
// 开始时间
Date begindate2 = new Date();
// String imageName = ImgSrc.substring(url.lastIndexOf("/") + 1,
// ImgSrc.length());
String imageName = i + ".png";
do {
URL uri = new URL(ImgSrc);
InputStream in = uri.openStream();
FileOutputStream fo = new FileOutputStream(new File(path + "\\getMaps\\" + imageName));
byte[] buf = new byte[1024];
int length = 0;
// System.out.println("开始下载:" + ImgSrc);
while ((length = in.read(buf, 0, buf.length)) != -1) {
fo.write(buf, 0, length);
}
in.close();
fo.close();
}while(new File(path + "\\getMaps\\" + imageName).length() <= 2000); //文件小于2K说明下载失败,重新下载
i++;
System.out.println(imageName + "/" + url.size() + "下载完成");
// 结束时间
Date overdate2 = new Date();
double time = overdate2.getTime() - begindate2.getTime();
System.out.println("耗时:" + time / 1000 + "s");
}
Date overdate = new Date();
double time = overdate.getTime() - begindate.getTime();
System.out.println("总耗时:" + time / 1000 + "s");
return true;
} catch (Exception e) {
System.out.println("下载失败");
return false;
}
}
/**
* 计算图片构成信息
*
* @param startX
* @param startY
* @param endX
* @param endY
* @return
*/
public static int[] getCount(String startX, String startY, String endX, String endY) {
// 解析参数,转换成浮点数,以便后期计算
Double sx = Double.parseDouble(startX);
Double sy = Double.parseDouble(startY);
Double ex = Double.parseDouble(endX);
Double ey = Double.parseDouble(endY);
// 按照0.005为步长,循环计算出所需获得的图片中心位置坐标
int countX = (int) ((ex - sx) / 0.005);// 如果ex - sx = 0,说明只有一列
int countY = (int) ((sy - ey) / 0.005);// 如果sy - ey = 0,说明只有一行
int[] count = { countY + 1, countX + 1 };
return count;
}
/**
* 构造接口地址
*
* @param startX
* 地图左上角x坐标
* @param startY
* 地图左上角y坐标
* @param endX
* 地图右下角x坐标
* @param endY
* 地图右下角y坐标
* @param key
* 开发者账号的key
* @return
*/
@SuppressWarnings("deprecation")
public static ArrayList<String> MakeUrls(String startX, String startY, String endX, String endY, String key) {
// 解析参数,转换成浮点数,以便后期计算
Double sx = Double.parseDouble(startX);
Double sy = Double.parseDouble(startY);
Double ex = Double.parseDouble(endX);
Double ey = Double.parseDouble(endY);
// 按照0.005为步长,循环计算出所需获得的图片中心位置坐标
int countX = (int) ((ex - sx) / 0.005);// 如果ex - sx = 0,说明只有一列
int countY = (int) ((sy - ey) / 0.005);// 如果sy - ey = 0,说明只有一行
ArrayList<String> url = new ArrayList<String>();
System.out.println(
"一共需要获取" + (countY + 1) + "行图片,每行图片共" + (countX + 1) + "张.共" + ((countX + 1) * (countY + 1)) + "图片");
for (int j = 0; j <= countY; j++) {
for (int i = 0; i <= countX; i++) {
System.out.println("X:" + new BigDecimal(sx).setScale(3, BigDecimal.ROUND_HALF_UP) + " Y:"
+ new BigDecimal(sy).setScale(3, BigDecimal.ROUND_HALF_UP));
url.add(uurl + "&location=" + new BigDecimal(sx).setScale(3, BigDecimal.ROUND_HALF_UP) + ","
+ new BigDecimal(sy).setScale(3, BigDecimal.ROUND_HALF_UP) + "&key=" + key);
sx += 0.005;
}
sy -= 0.005;
sx = Double.parseDouble(startX);
}
return url;
}
}
2.处理图片,完成拼接
package com.dealWithImage;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
public class DealWithImage {
/**
* 图像处理: 1.截图 2.横向拼接 3.纵向拼接
*
* @param path
* 获取的地图的位置
* @param count
* 最后合成的图片的信息 int[0]行数 int[1]每行的图片数
* @throws Exception
*/
public static void DealWithPhotos(String path, int[] count) throws Exception {
File f = new File(path + "\\getMaps");
String[] SourceImageList = f.list();
/**
* 对列表内的图片进行切割 每行第一张图片截取整张图(获取图中的所有像素),本行的其他图片截取右半部分
*/
System.out.println("开始对图片进行第一次截取...");
for (int i = 1, j = 0; i <= SourceImageList.length; i++) {
if (i == (j * count[1] + 1)) {
cutImage(path + "\\getMaps\\" + i + ".png", path + "\\cuttedMaps\\" + i + ".png", 0, 0, 2048, 2048);
j++;
} else {
cutImage(path + "\\getMaps\\" + i + ".png", path + "\\cuttedMaps\\" + i + ".png", 2048 - 932, 0, 932,
2048);
}
}
/**
* 对切割后小图片进行拼接
*/
System.out.println("开始对图片进行第一次拼接...");
ArrayList<String> arrImgs = new ArrayList<String>();
for (int i = 1, j = 1; i <= SourceImageList.length; i++) {
if (i != (j * count[1])) {
arrImgs.add(path + "\\cuttedMaps\\" + i + ".png");
} else {
arrImgs.add(path + "\\cuttedMaps\\" + i + ".png");
String[] imgs = (String[]) arrImgs.toArray(new String[arrImgs.size()]);
mergeImage(imgs, 1, path + "\\mergedMaps\\" + j + ".png");
arrImgs.clear();
j++;
}
}
/**
* 对生成的长图进行截图 第一行截取 x:0 y:0 h:1141 中间行截取 x:0 y:0 h:1140 尾行全截取
*/
System.out.println("开始对图片进行第二次截取...");
File f1 = new File(path + "\\mergedMaps");
String[] mergedImgs = f1.list();
for (int i = 1; i <= mergedImgs.length; i++) {
if (i != mergedImgs.length) {
cutImage(path + "\\mergedMaps\\" + i + ".png", path + "\\cutteddMaps\\" + i + ".png", 0, 0,
(count[1] - 1) * 932 + 2048, 1140);
} else {
cutImage(path + "\\mergedMaps\\" + i + ".png", path + "\\cutteddMaps\\" + i + ".png", 0, 0,
(count[1] - 1) * 932 + 2048, 2048);
}
}
/**
* 对第二次切割后的长图进行拼接
*/
System.out.println("开始对图片进行第二次拼接...");
File f9 = new File(path + "\\cutteddMaps");
ArrayList<String> cutteddList = new ArrayList<String>();
for (int i = 1; i <= f9.list().length; i++) {
cutteddList.add(path + "\\cutteddMaps\\" + i + ".png");
}
String[] cuttedd = (String[]) cutteddList.toArray(new String[cutteddList.size()]);
mergeImage(cuttedd, 2, path + "\\map.png");
}
/**
* @Description:截图
* @author:liuyc
* @time:2016年5月27日 上午10:18:23
* @param srcFile源图片、targetFile截好后图片全名、startAcross
* 开始截取位置横坐标、StartEndlong开始截图位置纵坐标、width截取的长,hight截取的高
*/
public static void cutImage(String srcFile, String targetFile, int startAcross, int StartEndlong, int width,
int hight) throws Exception {
// 取得图片读入器
Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("png");
ImageReader reader = readers.next();
// 取得图片读入流
InputStream source = new FileInputStream(srcFile);
ImageInputStream iis = ImageIO.createImageInputStream(source);
reader.setInput(iis, true);
// 图片参数对象
ImageReadParam param = reader.getDefaultReadParam();
Rectangle rect = new Rectangle(startAcross, StartEndlong, width, hight);
param.setSourceRegion(rect);
BufferedImage bi = reader.read(0, param);
ImageIO.write(bi, targetFile.split("\\.")[1], new File(targetFile));
}
/**
* @Description:图片拼接 (注意:必须两张图片长宽一致哦)
* @author:liuyc
* @time:2016年5月27日 下午5:52:24
* @param files
* 要拼接的文件列表
* @param type
* 1横向拼接, 2 纵向拼接
*/
public static void mergeImage(String[] files, int type, String targetFile) {
int len = files.length;
if (len < 1) {
throw new RuntimeException("图片数量小于1");
}
File[] src = new File[len];
BufferedImage[] images = new BufferedImage[len];
int[][] ImageArrays = new int[len][];
for (int i = 0; i < len; i++) {
try {
src[i] = new File(files[i]);
images[i] = ImageIO.read(src[i]);
} catch (Exception e) {
throw new RuntimeException(e);
}
int width = images[i].getWidth();
int height = images[i].getHeight();
ImageArrays[i] = new int[width * height];
ImageArrays[i] = images[i].getRGB(0, 0, width, height, ImageArrays[i], 0, width);
}
int newHeight = 0;
int newWidth = 0;
for (int i = 0; i < images.length; i++) {
// 横向
if (type == 1) {
newHeight = newHeight > images[i].getHeight() ? newHeight : images[i].getHeight();
newWidth += images[i].getWidth();
} else if (type == 2) {// 纵向
newWidth = newWidth > images[i].getWidth() ? newWidth : images[i].getWidth();
newHeight += images[i].getHeight();
}
}
if (type == 1 && newWidth < 1) {
return;
}
if (type == 2 && newHeight < 1) {
return;
}
// 生成新图片
try {
BufferedImage ImageNew = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
int height_i = 0;
int width_i = 0;
for (int i = 0; i < images.length; i++) {
if (type == 1) {
ImageNew.setRGB(width_i, 0, images[i].getWidth(), newHeight, ImageArrays[i], 0,
images[i].getWidth());
width_i += images[i].getWidth();
} else if (type == 2) {
ImageNew.setRGB(0, height_i, newWidth, images[i].getHeight(), ImageArrays[i], 0, newWidth);
height_i += images[i].getHeight();
}
}
// 输出想要的图片
ImageIO.write(ImageNew, targetFile.split("\\.")[1], new File(targetFile));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
*
* @Description:小图片贴到大图片形成一张图(合成)
* @author:liuyc
* @time:2016年5月27日 下午5:51:20
*/
public static final void overlapImage(String bigPath, String smallPath, String outFile) {
try {
BufferedImage big = ImageIO.read(new File(bigPath));
BufferedImage small = ImageIO.read(new File(smallPath));
Graphics2D g = big.createGraphics();
int x = (big.getWidth() - small.getWidth()) / 2;
int y = (big.getHeight() - small.getHeight()) / 2;
g.drawImage(small, x, y, small.getWidth(), small.getHeight(), null);
g.dispose();
ImageIO.write(big, outFile.split("\\.")[1], new File(outFile));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
3.测试
package com.Test;
import java.io.File;
import java.util.ArrayList;
import java.util.Scanner;
import com.dealWithImage.DealWithImage;
import com.getMaps.GetMaps;
public class Test {
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
String path = null;
String key = null;
System.out.println("输入地图保存路径(例如:C:\\map): ");
path = sc.next();
File f0 = new File(path);
f0.mkdir();
f0 = new File(path + "\\cutteddMaps");
f0.mkdir();
f0 = new File(path + "\\cuttedMaps");
f0.mkdir();
f0 = new File(path + "\\getMaps");
f0.mkdir();
f0 = new File(path + "\\mergedMaps");
f0.mkdir();
System.out.println("开发者账号key:");
key = sc.next();
System.out.println("地图左上角坐标(aa.bbb,cc.ddd): ");
String top = sc.next();
System.out.println("地图右下角坐标(aa.bbb,cc.ddd): ");
String end = sc.next();
sc.close();
String[] tops = top.split(",");
String[] ends = end.split(",");
ArrayList<String> url = GetMaps.MakeUrls(tops[0], tops[1], ends[0], ends[1], key);
GetMaps.getMaps(url, path);
int[] count = GetMaps.getCount(tops[0], tops[1], ends[0], ends[1]);
System.out.println("开始处理图像...");
DealWithImage.DealWithPhotos(path, count);
System.out.println("图像处理完成!");
Runtime.getRuntime().exec("cmd /c start explorer " + path);
}
}