百度地图自定义图层----BMapTileCutter(Java切图工具网络版)
最近做百度地图API相关应用,需要将自己的地图叠加到百度地图上面,查看了百度官方的API说明Javascript部分,不没有很好的解释如何覆盖接口。
在网上找了相关的文章看了下,(http://www.cnblogs.com/jz1108/archive/2011/10/08/2202239.html)这篇文章实现了这个切图的功能,但是最新的百度最高缩放等级达到19级,项目需要,无奈只能自己写个切图工具。
参考了同样作者的另一篇文章(http://www.cnblogs.com/jz1108/archive/2011/07/02/2095376.html),专门讲百度坐标系统的。
程序是用Java Web实现, struts2文件标签和简单Js调用。
实现核心代码
1.TileUtils.java
1 package com.xiefei.core; 2 3 import java.awt.Graphics2D; 4 import java.awt.Image; 5 import java.awt.Toolkit; 6 import java.awt.Transparency; 7 import java.awt.image.BufferedImage; 8 import java.awt.image.CropImageFilter; 9 import java.awt.image.FilteredImageSource; 10 import java.awt.image.ImageFilter; 11 import java.io.File; 12 13 import javax.imageio.ImageIO; 14 15 public class TileUtils { 16 private int minLevel; 17 private int maxLevel; 18 private int picLevel; 19 private double mercatorX; 20 private double mercatorY; 21 private String pic; 22 private String savePath; 23 24 public TileUtils(String pic, double mercatorX, double mercatorY, 25 String savePath) { 26 this.pic = pic; 27 this.mercatorX = mercatorX; 28 this.mercatorY = mercatorY; 29 this.savePath = savePath; 30 } 31 32 public TileUtils(String pic, int minLevel, int maxLevel, int picLevel, double mercatorX, 33 double mercatorY, String savePath) { 34 this.pic = pic; 35 this.minLevel = minLevel; 36 this.maxLevel = maxLevel; 37 this.mercatorX = mercatorX; 38 this.mercatorY = mercatorY; 39 this.savePath = savePath; 40 this.picLevel = picLevel; 41 } 42 43 public void cutterAll() throws Exception { 44 for (int i = minLevel; i <= maxLevel; i++) { 45 cutterOne(i); 46 } 47 } 48 49 public void cutterOne(int level) throws Exception { 50 //图片中心的像素坐标(pixelX,pixelY),图片中心的平面坐标即魔卡托坐标(mercatorX, mercatorY) 51 //像素坐标 = 平面坐标 * Math.pow(2, level - 18) 52 double pixelX = mercatorX * Math.pow(2, level - 18); 53 double pixelY = mercatorY * Math.pow(2, level - 18); 54 System.out.println("pixelX : " + pixelX); 55 System.out.println("pixelY : " + pixelY); 56 BufferedImage bi = ImageIO.read(new File(pic)); 57 int width = bi.getWidth(); 58 int height = bi.getHeight(); 59 //图片遵循原则:当前图片所属级别picLevel不缩放即像素级别相等。 60 //按照公式缩放:当前级别图片长度 = 原图片长度 * Math.pow(2, level - picLevel) 61 //minX: 图片左下角X坐标 62 //minY: 图片左下角Y坐标 63 //maxX: 图片右上角X坐标 64 //maxY: 图片右上角Y坐标 65 double minX = pixelX - width * Math.pow(2, level - picLevel) / 2; 66 double minY = pixelY - height * Math.pow(2, level - picLevel) / 2; 67 double maxX = pixelX + width * Math.pow(2, level - picLevel) / 2; 68 double maxY = pixelY + height * Math.pow(2, level - picLevel) / 2; 69 System.out.println("(minX,minY) = (" + minX + ", " + minY + ")" ); 70 System.out.println("(maxX,maxY) = (" + maxX + ", " + maxY + ")" ); 71 int neatMinX = (int) minX / 256; 72 int remMinX = (int) minX % 256; 73 int neatMinY = (int) minY / 256; 74 int remMinY = (int) minY % 256 ; 75 76 int neatMaxX = (int) maxX / 256; 77 int remMaxX = 256 - (int) maxX % 256; 78 int neatMaxY = (int) maxY / 256; 79 int remMaxY = 256 - (int) maxY % 256; 80 //(neatMinX,neatMinY)为图片左下角最近的整数图块坐标,neatMinX到neatMaxX即当前级别下切割图块的图块坐标x 81 //(neatMaxX,neatMaxY)为图片右上角最近的整数图块坐标,neatMinY到neatMaxY即当前级别下切割图块的图块坐标y 82 System.out.println("neatMinX: " + neatMinX); 83 System.out.println("neatMaxX: " + neatMaxX); 84 System.out.println("neatMinY: " + neatMinY); 85 System.out.println("neatMaxY: " + neatMaxY); 86 System.out.println("remMinX width remMaxX : " + remMinX + " "+ width + " "+ remMaxX ); 87 System.out.println("remMinY height remMaxY : " + remMinY + " " + height +" " + remMaxY ); 88 89 // 扩充原图片为width * height --- > (remMinX + width + remMaxX ) * (remMinY + 90 // height +remMaxY) 91 int extendWidth = (neatMaxX - neatMinX + 1 ) * 256; 92 int extendHeight = (neatMaxY - neatMinY + 1 ) * 256; 93 System.out.println("extendWidth: " + extendWidth); 94 System.out.println("extendHeight: " + extendHeight); 95 96 BufferedImage outputImage = null; 97 Graphics2D g = bi.createGraphics(); 98 BufferedImage extend = g.getDeviceConfiguration().createCompatibleImage(extendWidth, extendHeight, Transparency.TRANSLUCENT); 99 g.dispose(); 100 g = extend.createGraphics(); 101 g.drawImage(extend, 0, 0, extendWidth, extendHeight, null); 102 g.drawImage(bi, remMinX, remMaxY, (int) (width * Math.pow(2, level - picLevel)), (int)(height * Math.pow(2, level - picLevel)), null); 103 outputImage = extend; 104 105 //切割图片,共( neatMaxX - neatMinX + 1) * (neatMaxY - neatMinY + 1)份 256*256图片 106 String dirName = savePath.substring(0, savePath.lastIndexOf("\\")) + "\\tiles\\" + level; 107 System.out.println("dirName : " + dirName); 108 109 110 File dir = new File(dirName); 111 Image image = extend.getScaledInstance(extendWidth, extendHeight, Image.SCALE_DEFAULT); 112 if(dir.exists()) { 113 System.out.println("创建目录失败!, 目录已存在!"); 114 } else { 115 if(dir.mkdirs()) { 116 ImageIO.write(extend, "png", new File(dirName + savePath.substring(savePath.lastIndexOf("\\")))); 117 System.out.println("savePath : " + dirName + savePath.substring(savePath.lastIndexOf("\\"))); 118 System.out.println("Extend success!"); 119 int w = neatMaxX - neatMinX + 1; 120 int h = neatMaxY - neatMinY + 1; 121 for(int i = 0; i < w; i++) { 122 for(int j = 1; j <= h; j++) { 123 ImageFilter cropFilter = new CropImageFilter(256 * i, 256* (h - j), 256, 256); 124 Image img = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(image.getSource(),cropFilter)); 125 BufferedImage tag = new BufferedImage(256, 256 , BufferedImage.TYPE_INT_BGR); 126 Graphics2D gs = tag.createGraphics(); 127 tag = gs.getDeviceConfiguration().createCompatibleImage(256, 256, Transparency.TRANSLUCENT); 128 gs.dispose(); 129 gs = tag.createGraphics(); 130 gs.drawImage(img, 0, 0, null); 131 g.dispose(); 132 String cropPicName = dirName + "\\tile" + (neatMinX + i) + "_" + (neatMinY + j - 1) + ".png"; 133 ImageIO.write(tag, "png", new File(cropPicName)); 134 } 135 } 136 System.out.println("切割图片成功!"); 137 } else { 138 System.out.println("创建目录失败!"); 139 } 140 } 141 } 142 143 }
代码的核心思想是将原图片外围拓展成256整数倍长度(最小包围),即源代码中的extendWidth * extendHeight图片长度,然后再横竖切割成多个256*256的瓦片图块。
2.index.jsp(切割图片主页)
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <% 3 String path = request.getContextPath(); 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 5 %> 6 <%@ taglib prefix="s" uri="/struts-tags" %> 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 8 <html> 9 <head> 10 <base href="<%=basePath%>"> 11 12 <title>百度地图切图工具</title> 13 <meta http-equiv="pragma" content="no-cache"> 14 <meta http-equiv="cache-control" content="no-cache"> 15 <meta http-equiv="expires" content="0"> 16 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 17 <meta http-equiv="description" content="This is my page"> 18 <script type="text/javascript" src="http://api.map.baidu.com/api?v=1.3"></script> 19 <script type="text/javascript"> 20 function getData(){ 21 //var map = new BMap.Map("baiduMap"); 22 var centerX = document.form1.centerX.value; 23 var centerY = document.form1.centerY.value; 24 //alert(centerX); 25 //alert(centerY); 26 var center = new BMap.Point(centerX, centerY); 27 /*获取中心点的魔卡托坐标*/ 28 var projection = new BMap.MercatorProjection(); 29 var mercatorPoint = projection.lngLatToPoint(center); 30 document.form1.mercatorX.value = mercatorPoint.x; 31 document.form1.mercatorY.value = mercatorPoint.y; 32 document.form1.submit(); 33 //alert(mercatorPoint.x+","+mercatorPoint.y); 34 } 35 function chooseDir(){ 36 var savePath; 37 var objSrc = new ActiveXObject("Shell.Application").BrowseForFolder(0,"请选择输出文件夹路径",0,""); 38 if(objSrc!=null){ 39 savePath = objSrc.Items().Item().Path; 40 document.form1.savePath.value = savePath; 41 //alert(savePath); 42 } 43 } 44 </script> 45 </head> 46 47 <body> 48 <!-- 49 <div id="baiduMap" style="width:600px,height:800px"></div> 50 --> 51 52 <form action="cutter" method="post" name="form1" id="form1" enctype="multipart/form-data"> 53 请选择需要切图的图片来源<s:file name="pic" label="Picture"/><br/> 54 图片中心的经度坐标<input type="text" name="centerX" id="centerX" value="120.27628"/><br> 55 图片中心的纬度坐标<input type="text" name="centerY"/ id="centerY" value="30.27554"><br> 56 <input type="text" name="mercatorX" id="mercatorX" value="" style="display:none"/> 57 <input type="text" name="mercatorY"/ id="mercatorY" value="" style="display:none"> 58 最小级别 59 <select name="minLevel"> 60 <option selected>16</option> 61 <option>17</option> 62 <option>18</option> 63 <option>19</option> 64 </select><br> 65 最大级别 66 <select name="maxLevel"> 67 <option>16</option> 68 <option>17</option> 69 <option>18</option> 70 <option selected>19</option> 71 </select><br> 72 图片所在级别 73 <select name="picLevel"> 74 <option>16</option> 75 <option>17</option> 76 <option>18</option> 77 <option selected>19</option> 78 </select><br> 79 请选择输出目录 80 <input type="text" name="savePath"/> 81 <input type="button" name="selectDir" onClick="chooseDir()" value="浏览"/><br/> 82 <input type="button" value="提交" onClick="getData()"/> 83 </form> 84 </body> 85 </html>
3.实现截图
4.选择输出目录,是查看本地目录,用javascript调用ActiveX实现,只能在IE下运行,且需要把IE-->Internet选项-->安全中运行ActiveX控件运行才可以查看本地文件夹目录。
源码下载链接:https://files.cnblogs.com/thly1990/BaiduMapTileCutter.rar