GeoPDF Publisher for ArcGIS Server is all about creating GeoPDFs with your maps, imagery and GIS data for your customers and internal workflows. Publisher for desktop has a lovely user interface integrated into ArcGIS desktop products. Publisher for Server doesn't have that luxury; it relies on Python and Esri map documents to automate your creation of GeoPDF files. Optionally, C++ libraries can be used for specialized applications.
Here we'll explore creating GeoPDFs with Python, publishing them in your geoprocessing services, and integrating them into your web applications.
In this section:
Exploring PubPy with the Python command line
To get our first look at what Publisher for Server can do, let's fire up the Python interpreter on your machine.
C:\>\Python27\ArcGISx6410.3\python.exe Python 2.7.8 (default, Jun 30 2014, 16:08:48) [MSC v.1500 64 bit (AMD64)] on win32 Type 'help', 'copyright', 'credits' or 'license' for more information.
>>>
In this example, we are using the Python executable that ships with ArcGIS for Server 10.3. The path may be different on your server. If you'd like to follow along using Publisher and ArcGIS on the desktop, you'll need to have those two installed and use the 32bit version of Python, something like C:\Python27\ArcGIS10.3\python.exe.
To load the Publisher for Server tools necessary for publishing a GeoPDF we'll use Python's import command with the name of our Python library, PubPy. In the first line, we are using the import command to drill down through PubPy directly to the functions and classes that do the actual publishing, and then defining a namespace so that we can save ourselves some typing.
>>> import pubpy.geopdf_export.api as pubpy_ex >>> dir(pubpy_ex) ['ExportGeoPDFConfig', 'ExportMXDToGeoPDF', 'ExportToGeoPDF', 'ExportToGeoPDFWithConfig', '__builtins__', '__doc__', '__file__', '__name__', '__package__'] >>>
In that second line, we're doing a quick dump to see what functions and classes were just loaded. We'll come back to that first item, 'ExportGeoPDFConfig'. The next three items are different flavors of the functions that will be doing our exporting (aka publishing). The rest of the members of this class are typical housekeeping items used by Python.
To figure out how we can actually use one of these functions to produce a GeoPDF from the GIS data available to ArcGIS Server, we'll use one of Python's built-in documentation tricks.
>>> print pubpy_ex.ExportMXDToGeoPDF.__doc__ ExportMXDToGeoPDF(mxd_path, geopdf_path) Export a pre-configured MXD to GeoPDF file format. Export configuration is stored in the MXD. mxd_path(String): A string that represents the path and filename of the MXD to export. geopdf_path(String): A string that represents the path and filename of the GeoPDF to create. >>>
Here we see the arguments we need to provide to this function and what value it could return [in this case nothing].
Creating your first GeoPDF
So now we have almost everything we need to write our first script to create a GeoPDF--we only need an MXD and a path for the created GeoPDF.
On ArcGIS Server, there are some complications when reading and writing files, so let's first look at what the most basic creation of a GeoPDF using the desktop versions of Publisher and ArcGIS.
C:\>\Python27\ArcGIS10.3\python.exe Python 2.7.8 (default, Jun 30 2014, 16:03:49) [MSC v.1500 32 bit (Intel)] on win32 Type 'help', 'copyright', 'credits' or 'license' for more information. >>> import arcpy >>> import pubpy.geopdf_export.api as pubpy_ex >>> pubpy_ex.ExportMXDToGeoPDF(r'C:\tmp\USA_Sample.mxd', r'C:\tmp\MyFirstGeo.pdf') >>>
Here we simply imported ArcPy and the export functions for PubPy, then called the ExportMXDToGeoPDF function with an existing MXD as input and a path to where we want to GeoPDF as output. Note: the output path cannot be relative, it must be absolute. You will have to provide your own MXD for C:\tmp\USA_Sample.mxd. Afterward, you can examine the output using Adobe Reader and the TerraGo Toolbar.
Making this work on server adds some complexity because ArcGIS Server requires the input MXD to be stored in a registered folder and the output GeoPDF file to be written to a folder that it has write privileges.
Since this is going to require a few more lines of code, instead of typing everything in at the Python command line, let's create a Python script that brings all these considerations together:
import arcserver, arcpy, os.path import pubpy.geopdf_export.api as pubpy_ex mxdPath = r'C:\arcgisserver\directories\TerraGo_Samples\USA_Sample.mxd' pdfPath = os.path.join(arcpy.env.scratchFolder, 'sampleGeo.pdf') print '\nAbout to call:' print 'ExportMXDToGeoPDF({0}, {1})'.format(mxdPath, pdfPath) pubpy_ex.ExportMXDToGeoPDF(mxdPath, pdfPath) print '\nYou can find output here:' print pdfPath
Notice that to handle the input file access we moved our MXD to a folder registered with ArcGIS server (as seen on the line starting with 'mxdPath'). There is a different strategy for the path for the output GeoPDF. Here we take advantage of ArcPy's environment and write our output to ArcPy's scratch folder (as seen on the line starting with 'pdfPath').
If you were to save the script above to something like C:\tmp\MyFirstGeoPDF.py, you can run the script like this:
C:\>\Python27\ArcGISx6410.3\python.exe C:\tmp\MyFirstGeoPDF.py About to call: ExportMXDToGeoPDF(C:\arcgisserver\directories\TerraGo_Samples\USA_Sample.mxd, C:\Users\HAPPYU~1\AppData\Local\Temp\2\scratch\sampleGeo.pdf) You can find output here: C:\Users\HAPPYU~1\AppData\Local\Temp\2\scratch\sampleGeo.pdf C:\>
Creating a script for a GeoPDF geoprocessing service
Here the goal is to create a geoprocessing service that will create a GeoPDF from the web map from a typical Esri web application. To do this, our new GP service will leverage the PrintingTools service that is built into your ArcGIS server software.
Creating a Geoprocessing service that utilizes Publisher for Server to create a GeoPDF has several steps:
-
Write the python script
-
Create a GP toolbox in ArcMap
-
Create and set up the tool itself
-
Test tool
-
Publish the tool as a service
The first step is easy but interesting. We're going to leverage what we learned above and create a Python script like this:
import arcpy import os import uuid import pubpy.geopdf_export.api as pubpy_ex # Input WebMap json Web_Map_as_JSON = arcpy.GetParameterAsText(0) # The template location in the server data store ##templatePath = r'C:\Program Files\ArcGIS\Server\Templates\ExportWebMapTemplates' templatePath = r'C:\arcgisserver\TerraGo_Samples' templateName = r'USA_Sample' templateMxd = os.path.join(templatePath, (templateName + '.mxd')) # Convert the WebMap to a map document result = arcpy.mapping.ConvertWebMapToMapDocument(Web_Map_as_JSON, templateMxd) mapDoc = result.mapDocument # Use the uuid module to generate a GUID as part of the output name # This will ensure a unique output name output = 'WebMap_{}.pdf'.format(str(uuid.uuid1())) Output_File = os.path.join(arcpy.env.scratchFolder, output) # Export the WebMap ##arcpy.mapping.ExportToPDF(mapDoc, Output_File) pubpy_ex.ExportToGeoPDF(mapDoc, Output_File) # Set the output parameter to be the output file of the server job arcpy.SetParameterAsText(1, Output_File) # Clean up - delete the map document reference filePath = mapDoc.filePath del mapDoc, result os.remove(filePath)
Be sure to save your script to your server with a name like WebMap2GeoPDF.py.
There are a couple of new things in this script.
First of all, the GP tool we are creating is going to take advantage of the PrintingTools service that is built into your ArcGIS server software. To do this, two specific parameters must be used: 1) the description of the web map and 2) the path of the created GeoPDF file. In the script, you can see the web map description loaded in the first highlighted text. Then the last highlighted text sets the GeoPDF path so that it can be returned to the requester.
We need an MXD or a map document for creating a GeoPDF. There is a function, arcpy.mapping.ConvertWebMapToMapDocument(), that converts the web map description passed to us into a map document object with the help of a template MXD. You can see the conversion towards the middle of the script.
The next highlight in the script is some code that will create a path to store the GeoPDF output in a scratch folder.
After that, you'll see we're using a slightly different pubpy function to create the GeoPDF, pubpy_ex.ExportToGeoPDF(). It uses the map document object and path that we just created.
Going from Your Python Script to a geoprocessing service
There are quite a number of steps needed to get your script published as a geoprocessing server on your server. Please refer to the Web Map to GeoPDF sample in the Sample GP Services and Web Applications chapter to get your GP service running.
When you are done you should have a GP service named WebMap2GepPDF on your local ArcGIS server.
Another good tutorial that covers the creation of a geoprocessing service for printing web maps can be found on the Esri support site Tutorial: Basic web map printing and exporting using arcpy.mapping.
Adding GeoPDF exports to an existing web application
If you create your geoprocessing service that conforms with the Export Web Map interface (as we did in the example above), creating GeoPDFs can be as easy as printing using an Esri PrintTask object.
Here is a quick example that shows the HTML for a web page that displays a simple web map and a Print button. When the print button is clicked, the page calls the GP service on your server to create a GeoPDF and displays the results in a new window:
<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01//EN' 'http://www.w3.org/TR/html4/strict.dtd'> <html> <head> <title>Web Map to GeoPDF</title> <link rel='stylesheet' type='text/css' href='http://serverapi.arcgisonline.com/jsapi/arcgis/3.0/js/dojo/dijit/themes/tundra/tundra.css'> <script src='http://serverapi.arcgisonline.com/jsapi/arcgis/?v=3.0'></script> <script type='text/javascript' language='Javascript'> dojo.require('esri.map'); dojo.require('esri.tasks.PrintTask'); var printTask, params; function init() { // when loading page, setup our web map and print task // create web map and add tiled map service var map = new esri.Map('map'); var tiledUrl = 'http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer' var tiledLayer = new esri.layers.ArcGISTiledMapServiceLayer(tiledUrl); map.addLayer(tiledLayer); // setup print task and PrintParameters // If your GIS server is public, replace 'localhost:6080' with your own domain var printUrl = 'http://localhost:6080/arcgis/rest/services/WebMap2GepPDF/GPServer/WebMap2GepPDF'; printTask = new esri.tasks.PrintTask(printUrl, {async: true}); params = new esri.tasks.PrintParameters(); params.map = map; } function print() { // when Print button is clicked, setup template and call print task var printTemplate = new esri.tasks.PrintTemplate(); // use the extent of the webmap in the output PDF printTemplate.preserveScale = false; params.template = printTemplate; printTask.execute(params, printComplete); } function printComplete(result) { // when print task is done, show results window.open(result.url); } dojo.addOnLoad(init); </script> </head> <body class='tundra'> <input type='button' id='print' value='Print' onclick='print();'/> <div id='map' style='width:1000px; height:600px;'></div> </body> </html>
The highlighted text shows setting up the PrintTask. First, it specifies the GP service on your server that will be called, then creates the PrintTask, and points the PrintParameters to the web page's map.
Note: this web page can be served locally or from any web server, but must be opened in a browser on your GIS server. The domain of the printUrl is 'localhost:6080' which is the special domain name for the local machine and the default port number for ArcGIS server, but is only visible on the server. To see the example in a browser on other machines, you will have to substitute the public domain name of your ArcGIS server.
The next function after the highlighting is the print() callback function. When the Print button is pressed by the user, it is called to create an HTTP request to your GP service.
The next function printCompleted() is another callback function that is called when the GP task is complete, and it opens a new window with the GeoPDF in it.
Further exploring GeoPDF creation options
Using the export config options allows you to optimize the format of your GeoPDF creation. Some of your customers may want a flattened, lightweight version of your map for their mobile device. Others might want multiple layers, full-resolution rasters and GIS data bundled for data exchange and offline searches.
So far all the examples we've looked at have used ExportMXDToGeoPDF() to create our GeoPDF output. All the export options were set to the defaults that were set when you installed the software. Let's look into how we can customize those options for your applications and customers.
There are three flavors of the export function in the pubpy.geopdf_export.api:
-
ExportMXDToGeoPDF - This function only takes an input path to an MXD and an output path as arguments. Any customized export options can only come from the MXD, and the only way the Publisher export options can be set in the MXD is if it is modified by Publisher for ArcGIS desktop.
-
ExportToGeoPDF - This function was designed to be a drop-in replacement for arcpy.mapping.ExportToPDF(). It takes a mapDocument object, an output path, and a whole bunch of optional named export options. These export options will override any Publisher export options stored in the MXD file used to create the mapDocument object.
-
ExportToGeoPDFWithConfig - This function is like ExportToGeoPDF except that all the named export options are replaced with a single ExportGeoPDFConfig object that lets you specify the much larger set of export options available to GeoPDFs.
And there is also a class:
-
ExportGeoPDFConfig - This class lets you specify the export options when creating a GeoPDF. To see the most current list of options available, fire up the Python command line and type import pubpy.geopdf_export.api as pubpy_ex; print pubpy_ex.ExportGeoPDFConfig.__doc__.
So you have two avenues to setting your export options:
-
Use the desktop version of Publisher to edit the MXD that is referenced by the file path or mapDocument object . For the steps to do this, go to the Configuring Export Settings for a GeoPDF File section of the Publisher for ArcGIS Help. The advantage of going this route is that a non-programmer can set export options using a nice UI. The downside is that you can't programmatically control the options at runtime.
-
Use ExportToGeoPDFWithConfig() function to set the export options when it is called. The advantage here is that your options can be determined by your business logic and/or the customer's preferences. This method is also useful for managing the export options when you have multiple template MXDs used by your application.
Using ExportToGeoPDFWithConfig() to ceate a GeoPDF with an embedded GeoPackage
A GeoPDF that has a GeoPackage database embedded in it allows you to include the source GIS data for selected layers in addition to the visible map. Your customers can then use the GeoPDF Toolbar to search the GIS data while not connected to the internet and/or save the attached database as input to other workflows.
In this example, we want to include the feature data associated with the Cities layer of our map.
With that in mind, let's take the earlier Python script MyFirstGeoPDF.py and extend it so that it creates an OpenGeoPDF. In the script, we will set a flag that we want to attach a GeoPackage database to the PDF and then define which layers (feature sets) should be included:
import arcserver, arcpy, os.path import pubpy.geopdf_export.api as pubpy_ex # collecting our arguments for ExportToGeoPDFWithConfig mxdPath = r'C:\arcgisserver\directories\TerraGo_Samples\USA_Sample.mxd' mapDoc = arcpy.mapping.MapDocument(mxdPath) pdfPath = os.path.join(arcpy.env.scratchFolder, 'sampleOpenGeo.pdf') exportConfig = pubpy_ex.ExportGeoPDFConfig() exportConfig.attributeFormat = 'GEOPACKAGE' exportConfig.attributeLayers = [('Layers', ['Cities'])] print '\nAbout to call:' print 'ExportToGeoPDFWithConfig({0}, {1}, {{'attributeFormat':'{2}', 'attributeLayers':{3}, ... }})'.format( mxdPath, pdfPath, exportConfig.attributeFormat, str(exportConfig.attributeLayers)) pubpy_ex.ExportToGeoPDFWithConfig(mapDoc, pdfPath, exportConfig) print '\nYou can find output here:' print pdfPath
In the highlighted text above you'll see where we are creating a mapDocument object using the MXD path. Next, we're creating an ExportGeoPDFConfig object and setting the option to include a GeoPackage database. We then are specifying the layers we want to include using a list. Each item in the list contains a tuple with the data frame name and a list of the names in the path to the layer we want to export. Finally we are calling ExportToGeoPDFWithConfig() instead of ExportMXDToGeoPDF().
Comments
0 comments
Please sign in to leave a comment.