概述:
Arcgis Server的切片得要有Arcgis Server的支持才能使用,这样就显得比较麻烦,如果对于已经切好的切片怎么样通过自己写的程序来调用展示呢,本文讲解的内容就是这些。
Arcgis 切片简介:
Arcgis Server的切片分为两种:松散型和紧凑型。松散型,就是以单个的jpg或者png文件形式存储;紧凑型,是将多个切片文件制作成一组bundle和bundlx文件,其中bundlx存储的是切片的索引,bundle存储的是切片本身。在10的版本之前,Arcgis只支持松散型的切片方式,紧凑型是在Arcgis10的版本之后才出现的。
实现方式:
1、后台读取
后台写了一个比较简单的servlet来实现切片的读取,其中实现参考了下两篇文章中的内容,最终的实现代码如下:
package com.lzugis.servlet;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.codec.binary.Base64;
import com.lzugis.tile.helper.CommonConfig;
/**
* Servlet implementation class TileServlet
*/
@WebServlet(description = "get arcgis offline tile", urlPatterns = {"/agstile"})
public class AgsOffTilesServiceServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private String rootPath = "";
private static String base64Blank = "iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NkZFQUUzNjgyRjJBMTFFNEFBQ0JGMEMyRjFFNUE0MUYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NkZFQUUzNjkyRjJBMTFFNEFBQ0JGMEMyRjFFNUE0MUYiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo2RkVBRTM2NjJGMkExMUU0QUFDQkYwQzJGMUU1QTQxRiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo2RkVBRTM2NzJGMkExMUU0QUFDQkYwQzJGMUU1QTQxRiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pij7ZYAAAAJdSURBVHja7NQxAQAACMMwwL/nYQAHJBJ6tJMU8NNIAAYAGABgAIABAAYAGABgAIABAAYAGABgAIABAAYAGABgAIABAAYAGABgAIABAAYAGABgAIABAAYAGABgAIABAAYAGABgAIABAAYAGABgAIABgAEABgAYAGAAgAEABgAYAGAAgAEABgAYAGAAgAEABgAYAGAAgAEABgAYAGAAgAEABgAYAGAAgAEABgAYAGAAgAEABgAYAGAAgAEABgAYAGAAgAGAAQAGABgAYACAAQAGABgAYACAAQAGABgAYACAAQAGABgAYACAAQAGABgAYACAAQAGABgAYACAAQAGABgAYACAAQAGABgAYACAAQAGABgAYACAAYABAAYAGABgAIABAAYAGABgAIABAAYAGABgAIABAAYAGABgAIABAAYAGABgAIABAAYAGABgAIABAAYAGABgAIABAAYAGABgAIABAAYAGABgAIABgAEABgAYAGAAgAEABgAYAGAAgAEABgAYAGAAgAEABgAYAGAAgAEABgAYAGAAgAEABgAYAGAAgAEABgAYAGAAgAEABgAYAGAAgAEABgAYAGAAgAGAAQAGABgAYACAAQAGABgAYACAAQAGABgAYACAAQAGABgAYACAAQAGABgAYACAAQAGABgAYACAAQAGABgAYACAAQAGABgAYACAAQAGABgAYACAAYABAAYAGABgAIABAAYAGABgAIABAAYAGABgAIABAAYAGABgAIABAAYAGABgAIABAAYAGABgAIABAAYAGABgAIABAAYAGABgAIABAJcVYADnygT9CIf4ngAAAABJRU5ErkJggg==";
/**
* @see HttpServlet#HttpServlet()
*/
public AgsOffTilesServiceServlet() {
super();
// TODO Auto-generated constructor stub
try{
//切片存储路径
rootPath = CommonConfig.getVal("tile.agspath")+File.separator;
}
catch(Exception e){
e.printStackTrace();
}
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
this.doPost(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
@SuppressWarnings("resource")
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String x= request.getParameter("x");
String y= request.getParameter("y");
String z= request.getParameter("z");
String layer= request.getParameter("layer");
String type= request.getParameter("type");//file为紧凑型,image为松散型
String tilePath = rootPath+layer+"/Layers/_alllayers";
int level = Integer.parseInt(z);
int row = Integer.parseInt(x);
int col = Integer.parseInt(y);
try {
OutputStream os = response.getOutputStream();
byte[] output = null;
int outlength = 0;
if(type.equals("file")){//紧凑型
String l = "L" + getZero(2,z.length()) + level;
int rGroup = 128 * (row / 128);
String rTail = Integer.toHexString(rGroup);
String r = "R" + getZero(4,rTail.length()) +rTail ;
int cGroup = 128 * (col / 128);
String cTail = Integer.toHexString(cGroup);
String c = "C" + getZero(4,cTail.length()) + cTail;
String bundleBase = String.format("%s/%s/%s%s", tilePath, l, r, c);
String bundleFileName = bundleBase + ".bundle";
String bundlxFileName = bundleBase + ".bundlx";
File file = new File(bundleFileName);
if(file.exists()){
int index = 128 * (col - cGroup) + (row - rGroup);
FileInputStream isBundlx = new FileInputStream(bundlxFileName);
isBundlx.skip(16 + 5 * index);
byte[] buffer = new byte[5];
isBundlx.read(buffer);
long offset = (long)(buffer[0]&0xff) + (long)(buffer[1]&0xff)*256 + (long)(buffer[2]&0xff)*65536 + (long)(buffer[3]&0xff)*16777216+ (long)(buffer[4]&0xff)*4294967296L;
FileInputStream isBundle = new FileInputStream(bundleFileName);
isBundle.skip(offset);
byte[] lengthBytes = new byte[4];
isBundle.read(lengthBytes);
int length = (int)(lengthBytes[0]&0xff)+ (int)(lengthBytes[1]&0xff)*256 + (int)(lengthBytes[2]&0xff)*65536+ (int)(lengthBytes[3]&0xff)*16777216;
byte [] result = new byte[length];
isBundle.read(result);
if(result.length>0){
output = result;
outlength = length;
}
}
else{
byte[] blankImg = Base64.decodeBase64(base64Blank);
InputStream is = new ByteArrayInputStream(blankImg);
int count=0;
while ((count = is.read(blankImg)) != -1) {
output = blankImg;
outlength = count;
}
}
}
else{//松散型
String l = "L" + getZero(2,z.length()) + level;
String strRow = Integer.toHexString(row);
String r = "R" +getZero(8,strRow.length())+ strRow;
String strCol = Integer.toHexString(col);
String c = "C"+getZero(8,strCol.length()) + strCol;
String imgfile = tilePath+l+"/"+r+"/"+c+".png";
InputStream is = null;
File file = new File(imgfile);
if(!file.exists()){
imgfile = tilePath+l+"/"+r+"/"+c+".jpg";
file = new File(imgfile);
if(!file.exists()){
byte[] blankImg = Base64.decodeBase64(base64Blank);
is=new ByteArrayInputStream(blankImg);
}
else{
is = new FileInputStream(imgfile);
}
}
else{
is = new FileInputStream(imgfile);
}
int count = 0;
byte[] buffer = new byte[1024 * 1024];
while ((count = is.read(buffer)) != -1) {
output = buffer;
outlength = count;
}
}
os.write(output, 0, outlength);
os.flush();
os.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
private String getZero(int length,int strLength){
int zeroLength = length-strLength;
String strZero = "";
for(int i=0;i<zeroLength;i++){
strZero+="0";
}
return strZero;
}
}
2、前台调用(Openlayers2)
为方便调用展示,扩展了一个Openlayers的图层类,代码如下:
OpenLayers.Layer.AgsTileLayer = OpenLayers.Class(OpenLayers.Layer.XYZ, {
url: null,
tileOrigin: null,
tileSize: new OpenLayers.Size(256, 256),
type: 'png',
useScales: false,
overrideDPI: false,
useArcgisServer:false,
cachetype:"file",//file为紧凑型,image为松散型
initialize: function(name, url, options) {
OpenLayers.Layer.XYZ.prototype.initialize.apply(this, arguments);
},
getURL: function (bounds) {
var res = this.getResolution();
var originTileX = (this.tileOrigin.lon + (res * this.tileSize.w/2));
var originTileY = (this.tileOrigin.lat - (res * this.tileSize.h/2));
var center = bounds.getCenterLonLat();
var y = (Math.round(Math.abs((center.lon - originTileX) / (res * this.tileSize.w))));
var x = (Math.round(Math.abs((originTileY - center.lat) / (res * this.tileSize.h))));
var z = this.map.getZoom();
var url = this.url;
var s = '' + x + y + z;
if (OpenLayers.Util.isArray(url)) {
url = this.selectUrl(s, url);
}
url = url + '?layer=${layer}&type=${type}&x=${x}&y=${y}&z=${z}';
url = OpenLayers.String.format(url, {'layer': this.name,'type': this.cachetype,'x': x, 'y': y, 'z': z});
return OpenLayers.Util.urlAppend(
url, OpenLayers.Util.getParameterString(this.params)
);
},
CLASS_NAME: 'OpenLayers.Layer.AgsTileLayer'
});
前台页面中的调用代码如下:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>openlayers map</title>
<link rel="stylesheet" href="../../../plugin/OpenLayers-2.13.1/theme/default/style.css" type="text/css">
<style>
html, body,#map{
padding:0;
margin:0;
height:100%;
width: 100%;
overflow: hidden;
}
</style>
<script src="../../../plugin/OpenLayers-2.13.1/OpenLayers.js"></script>
<script src="../../../plugin/jquery/jquery-1.8.3.js"></script>
<script src="extend/AgsOffTileLayer.js"></script>
<script>
var map;
var tiled;
$(window).load(function() {
var bounds = new OpenLayers.Bounds(
73.45100463562233, 18.16324718764174,
134.97679764650596, 53.531943152223576
);
var options = {
controls: [],
maxExtent: bounds,
maxResolution: 0.2403351289487642,
projection: "EPSG:4326",
units: 'degrees'
};
map = new OpenLayers.Map('map', options);
OpenLayers.INCHES_PER_UNIT["千米"] = OpenLayers.INCHES_PER_UNIT["km"];
OpenLayers.INCHES_PER_UNIT["米"] = OpenLayers.INCHES_PER_UNIT["m"];
OpenLayers.INCHES_PER_UNIT["英里"] = OpenLayers.INCHES_PER_UNIT["mi"];
OpenLayers.INCHES_PER_UNIT["英寸"] = OpenLayers.INCHES_PER_UNIT["ft"];
//比例尺
map.addControl(new OpenLayers.Control.ScaleLine({topOutUnits:"米",topOutUnits:"千米"}));
$(".olControlScaleLineBottom").hide();
map.addControl(new OpenLayers.Control.Zoom());
map.addControl(new OpenLayers.Control.Navigation());
tiled = new OpenLayers.Layer.AgsTileLayer( "chinashp",
"http://localhost:8081/tile/agstile", {
isBaseLayer: true,
tileSize: new OpenLayers.Size(256, 256),
resolutions: [
0.15228550437313793,
0.07614275218656896,
0.03807137609328448,
0.01903568804664224,
0.00951784402332112,
0.00475892201166056,
0.00237946100583028
],
tileOrigin: new OpenLayers.LonLat(-400 , 400),
maxExtent: bounds,
projection: 'EPSG:4326'
});
map.addLayers([tiled]);
map.zoomToExtent(bounds);
});
</script>
</head>
<body>
<div id="map" style="width: 100%;"></div>
</body>
</html>`
注意:在前台页面调用的时候,有两个参数:分辨率组(resolutions)和切片原点(tileOrigin)。这两个参数是从服务的配置中获取的,你可以从服务配置文件Conf.xml中读取,Conf.xml文件位于“切片路径\Layers\”文件夹下,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<CacheInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:typens="http://www.esri.com/schemas/ArcGIS/10.1" xsi:type="typens:CacheInfo">
<TileCacheInfo xsi:type="typens:TileCacheInfo">
<SpatialReference xsi:type="typens:GeographicCoordinateSystem">
<WKT>GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433],AUTHORITY["EPSG",4326]]</WKT>
<XOrigin>-400</XOrigin>
<YOrigin>-400</YOrigin>
<XYScale>11258999068426.24</XYScale>
<ZOrigin>-100000</ZOrigin>
<ZScale>10000</ZScale>
<MOrigin>-100000</MOrigin>
<MScale>10000</MScale>
<XYTolerance>8.983152841195215e-009</XYTolerance>
<ZTolerance>0.001</ZTolerance>
<MTolerance>0.001</MTolerance>
<HighPrecision>true</HighPrecision>
<LeftLongitude>-180</LeftLongitude>
<WKID>4326</WKID>
<LatestWKID>4326</LatestWKID>
</SpatialReference>
<TileOrigin xsi:type="typens:PointN">
<X>-400</X>
<Y>399.99999999999977</Y>
</TileOrigin>
<TileCols>256</TileCols>
<TileRows>256</TileRows>
<DPI>96</DPI>
<PreciseDPI>96</PreciseDPI>
<LODInfos xsi:type="typens:ArrayOfLODInfo">
<LODInfo xsi:type="typens:LODInfo">
<LevelID>0</LevelID>
<Scale>64000000</Scale>
<Resolution>0.15228550437313793</Resolution>
</LODInfo>
<LODInfo xsi:type="typens:LODInfo">
<LevelID>1</LevelID>
<Scale>32000000</Scale>
<Resolution>0.076142752186568963</Resolution>
</LODInfo>
<LODInfo xsi:type="typens:LODInfo">
<LevelID>2</LevelID>
<Scale>16000000</Scale>
<Resolution>0.038071376093284481</Resolution>
</LODInfo>
<LODInfo xsi:type="typens:LODInfo">
<LevelID>3</LevelID>
<Scale>8000000</Scale>
<Resolution>0.019035688046642241</Resolution>
</LODInfo>
<LODInfo xsi:type="typens:LODInfo">
<LevelID>4</LevelID>
<Scale>4000000</Scale>
<Resolution>0.0095178440233211203</Resolution>
</LODInfo>
<LODInfo xsi:type="typens:LODInfo">
<LevelID>5</LevelID>
<Scale>2000000</Scale>
<Resolution>0.0047589220116605602</Resolution>
</LODInfo>
<LODInfo xsi:type="typens:LODInfo">
<LevelID>6</LevelID>
<Scale>1000000</Scale>
<Resolution>0.0023794610058302801</Resolution>
</LODInfo>
</LODInfos>
</TileCacheInfo>
<TileImageInfo xsi:type="typens:TileImageInfo">
<CacheTileFormat>PNG</CacheTileFormat>
<CompressionQuality>0</CompressionQuality>
<Antialiasing>false</Antialiasing>
</TileImageInfo>
<CacheStorageInfo xsi:type="typens:CacheStorageInfo">
<StorageFormat>esriMapCacheStorageModeCompact</StorageFormat>
<PacketSize>128</PacketSize>
</CacheStorageInfo>
</CacheInfo>
实现效果:
参考文献:
http://www.cnblogs.com/yuantf/p/3320876.html
http://blog.csdn.net/wankehui165/article/details/49489703