您的位置:首页 > 其它

利用Arcpy发布地图服务,制作切片

2016-05-18 21:38 676 查看
  因为工作需求,我需要把管理员上传的图片进行切片,供用户下载切片离线浏览。后台切片功能主要分为以下几个步骤:

1. 制作地图文档(*.mxd);
2. 发布地图文档;
3. 制作服务器缓存;
4. 生成切片;
5. 打包成zip


  ArcGIS版本是10.2,下面这些代码应该在10.0上无法运行。生成mxd文档时不支持栅格数据,我的图片大都是jpeg格式的,所以最终我更换了ArcGIS版本,妥协了…

Arcpy制作地图文档

  我没有找打直接生成地图文档的示例代码,因此我使用了SaveAs的方法,就是利用已有的空白文档(我称之为“模板”),加载上jpg图片后再“另存为”。这样的一个好处就是我可以直接在模板中定义地理坐标系,后面再发布为地图服务时会用到的,否则报错。

# 创建map document
def CreateMxd(imagepath,mxdpath):
dirname=os.path.dirname(imagepath)
imagename=os.path.basename(imagepath)
dotindex=imagename.index('.')
name=imagename[0:dotindex]
new_mxd=os.path.abspath(dirname+"/"+name+".mxd")
rasterLayer="raster"

temp_mxd = arcpy.mapping.MapDocument(mxdpath)
df=arcpy.mapping.ListDataFrames(temp_mxd,"Layers")[0]
arcpy.MakeRasterLayer_management(imagepath,rasterLayer,"","","")
addLayer=arcpy.mapping.Layer(rasterLayer)
arcpy.mapping.AddLayer(df,addLayer,"TOP")
temp_mxd.saveACopy(new_mxd)
del temp_mxd
return new_mxd


  这个函数的参数是“图片的位置”和“模板的位置”,然后将图片的名称提取出来作为新mxd文件的名称。

  需要注意的是,直接添加jpg格式的图层在ArcGIS10.2中是允许的,但生成的mxd文档里面的图层样式是采用“拉伸(Stretched)”方式展示的,图片的样式直接成为灰色调了,而我需要的是“RGB合成(RGB Composite)”。因此我使用了这种“先创建临时栅格图层,再添加到mxd”的方式。

  


发布地图文档

  我们都知道,在ArcGIS10.1之后都是先将mxd文档转为sd文档,再进行发布的。这样做也是有好处的(听说是),不再赘述。官网文档给出两种方式发布地图,一是需要ArcGIS Server服务器名、用户名和密码方式验证登录,二是采用arcgis server连接文件ags的方式直接验证。我采用了后者,比如我的连接文件位置在“C:\Users\Administrator\AppData\Roaming\ESRI\Desktop10.2\ArcCatalog\arcgis on WIN-20150327EEH_6080 (admin).ags”。直接引用这个地址作为参数传入下面这个函数就行。

# 发布服务
def PublishService(mxdpath,agspath):
new_mxd = arcpy.mapping.MapDocument(mxdpath)
dirname=os.path.dirname(mxdpath)
mxdname=os.path.basename(mxdpath)
dotindex=mxdname.index('.')
servicename=mxdname[0:dotindex]

sddraft = os.path.abspath(servicename + '.sddraft')
sd = os.path.abspath(servicename + '.sd')
if os.path.exists(sd):
os.remove(sd)
#创建服务定义草稿draft
arcpy.CreateImageSDDraft(new_mxd, sddraft, servicename, 'ARCGIS_SERVER', agspath,False,None, "Ortho Images", "ortho images,image service")

#分析草稿draft
analysis = arcpy.mapping.AnalyzeForSD(sddraft)
#打印分析结果
print "The following information was returned during analysis of the MXD:"
for key in ('messages', 'warnings', 'errors'):
print '----' + key.upper() + '---'
vars = analysis[key]
for ((message, code), layerlist) in vars.iteritems():
print '', message, ' (CODE %i)' % code
print '   applies to:',
for layer in layerlist:
print layer.name,
print

# 发送草稿至服务器
if analysis['errors'] == {}:
# Execute StageService. This creates the service definition.
arcpy.StageService_server(sddraft, sd)
# Execute UploadServiceDefinition. This uploads the service definition and publishes the service.
arcpy.UploadServiceDefinition_server(sd, agspath)
print "Service successfully published"
else:
print "Service could not be published because errors were found during analysis."

print arcpy.GetMessages()
return agspath.replace(".ags","/"+servicename+".MapServer")


  同样两个参数,这个函数需要mxd文档路径和ags文件路径作为参数。中间需要先生成服务定义文件(.sd)和服务定义草稿文件(.sddraft),然后对sddraft文件进行分析,若中间没有出现错误,现将其发送至服务器。然后再将sd文件,通过ags文件发送至服务器,更新服务。

  这段代码最后我返回了刚刚发布的服务地址,后面将会用到。

制作服务器缓存

  注意哟,这里是定义服务器缓存,不是生成切片地方。这里是定义,下一步才是生成。就好比“打开存有《名侦探柯南》的云盘文件夹”,下一步才是“点击播放按钮”。

#制作地图服务器缓存
def CreateCache(inputService,cachepath):
# List of input variables for map service properties
tilingSchemeType = "NEW"
scalesType = "CUSTOM"
numOfScales = "5"#此参数无效
scales = [500000000,250000000,125000000,64000000,32000000]
dotsPerInch = "96"
tileOrigin = "0 0"
tileSize = "256 x 256"
cacheTileFormat = "PNG8"
tileCompressionQuality = ""
storageFormat = "COMPACT"
predefinedTilingScheme = ""

try:
starttime = time.clock()
result = arcpy.CreateMapServerCache_server(inputService,cachepath,tilingSchemeType, scalesType, numOfScales, dotsPerInch,tileSize, predefinedTilingScheme,tileOrigin, scales,cacheTileFormat,tileCompressionQuality,storageFormat)

# print messages to a file
while result.status < 4:
time.sleep(0.2)
resultValue = result.getMessages()
print "completed " + str(resultValue)

except Exception, e:
# If an error occurred, print line number and error message
tb = sys.exc_info()[2]
print "Failed at step 1 \n" "Line %i" % tb.tb_lineno
print e.message

print "Executed creation of Map server Cache schema "


  这里主要用了
CreateMapServerCache_server
这个函数,具体函数的意义这里就不再多说了,完全可以自己去查看ArcGIS文档。我是使用了自定义的方式切片,可以采用STANDARD方式切片,然后设置numOfScales的值就可以了。

生成切片

  这里才是生成切片的地方,用到的是Arcpy的
ManageMapServerCacheTiles_server
函数,同样具体的参数还是需要自己去查官方文档。帮助文档上面说参数
waitForJobCompletion
的值为“WAIT”时,可以从其他地方查到具体的切片进度,这里我还没去做,看以后的需求吧。

#生成瓦片
def CreateTiles(inputService):
scales = ""
numOfCachingServiceInstances = 2
updateMode = "RECREATE_ALL_TILES"
areaOfInterest = ""
waitForJobCompletion = "WAIT"
updateExtents = ""

try:
result = arcpy.ManageMapServerCacheTiles_server(inputService, scales,updateMode,numOfCachingServiceInstances,areaOfInterest, updateExtents,waitForJobCompletion)
#print messages to a file
while result.status < 4:
time.sleep(0.2)
resultValue = result.getMessages()
print "completed " + str(resultValue)
print "Created cache tiles for given schema successfully"
except Exception, e:
# If an error occurred, print line number and error message
tb = sys.exc_info()[2]
print "Failed at step 1 \n" "Line %i" % tb.tb_lineno
print e.message

print "Created Map server Cache Tiles "


  这个函数需要上一步返回的参数,就是那个以“*.MapServer”结尾的全路径。

压缩切片文件

  将切片打包主要是为了便于用户下载,在线预览的话就不需要这一步了。下面的代码是参考了linda1000的博文,有兴趣的可以自己前去看看。

  这里的两个参数分别是要压缩的切片路径,然后是压缩后的输出路径(注意这里要以*.zip结尾,包括压缩文件名).

# MakeZipFile
def MakeZipFile(filepath,zippath):
filelist = []
#Check input ...
fulldirname = os.path.abspath(filepath)
fullzipfilename = os.path.abspath(zippath)
print "Start to zip %s to %s ..." % (fulldirname, fullzipfilename)
if not os.path.exists(fulldirname):
print "Dir/File %s is not exist" % fulldirname
return
if os.path.isdir(fullzipfilename):
tmpbasename = os.path.basename(filepath)
fullzipfilename = os.path.normpath(os.path.join(fullzipfilename, tmpbasename))

#Get file(s) to zip ...
if os.path.isfile(filepath):
filelist.append(filepath)
filepath = os.path.dirname(filepath)
else:
#get all file in directory
for root, dirlist, files in os.walk(filepath):
for filename in files:
filelist.append(os.path.join(root,filename))

#Start to zip file ...
destZip = zipfile.ZipFile(fullzipfilename, "w")
for eachfile in filelist:
destfile = eachfile[len(filepath):]
print "Zip file %s..." % destfile
destZip.write(eachfile, destfile)
destZip.close()
print "Zip folder succeed!"


调用

  这段代码我是使用Java runtime直接调用的,可以使用这种方式一套流程走下来。但也有不大合适的地方,比如瓦片被删掉了,我只想生成一下切片等等,这样就不合适了。 

#********************************************
#           主      函      数              *
#********************************************
# 程序运行所需参数:
# 1.图片所在位置(filepath+filename)
# 2.mxd模板位置(filepath+filename)
# 3.arcgis server连接文件(ags)位置
# 4.生成切片缓存位置(out_path)
# 5.生成压缩文件位置(out_path+zipname)
if __name__ == '__main__':
#验证路径是否正确
imagepath=sys.argv[1]
mxdpath=sys.argv[2]
agspath=sys.argv[3]
cachepath=sys.argv[4]
zippath=sys.argv[5]
if not os.path.isfile(imagepath):
print "图片文件不存在"
sys.exit()
if not os.path.isfile(mxdpath):
print "mxd模板不存在"
sys.exit()
if not os.path.isfile(agspath):
print "arcgis server连接文件不存在"
sys.exit()
if not os.path.isdir(cachepath):
print "缓存目录不存在"
sys.exit()
# 创建mxd
new_mxd=CreateMxd(imagepath,mxdpath)
print "Finished CreateMxd"
# 发布服务
inputService=PublishService(new_mxd,agspath)
print "Finished PublishService"
# 制作服务器缓存
CreateCache(inputService,cachepath)
print "Finished CreateCache"
# 生成瓦片
CreateTiles(inputService)
print "Finished CreateTiles"
# 压缩文件
tcachepath=os.path.abspath(cachepath+"/"+new_mxd[new_mxd.rindex("\\")+1:new_mxd.rindex(".")])
print tcachepath
MakeZipFile(tcachepath,zippath)
print "Finished MakeZipFile"


更新

  使用过程中,发现无法使得切出更小比例尺的切片,最小的切片也是1:500000000。但当用户上传的图片过大时,切出的图片无法在视图内完整的看到全貌。这显然不合理,最后终于找到了解决方法。草稿文件上传至服务器前对其进行修改,sddraft文件是指上是一个符号xml标准的文件。使用python直接可以进行操作,将里面的minScale改为更大

#修改草稿draft
# read sddraft xml
doc = DOM.parse(sddraft)

# turn on caching in the configuration properties
configProps = doc.getElementsByTagName('ConfigurationProperties')[0]
propArray = configProps.firstChild
propSets = propArray.childNodes
for propSet in propSets:
keyValues = propSet.childNodes
for keyValue in keyValues:
if keyValue.tagName == 'Key':
if keyValue.firstChild.data == "minScale":
# turn on caching
keyValue.nextSibling.firstChild.data = "32000000000"

# output to a new sddraft
if os.path.exists(sddraft): os.remove(sddraft)
f = open(sddraft, 'w')
doc.writexml( f )
f.close()


下载源码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  arcpy arcgis 切片