Combining ArcGIS Server Images - Serverside

Printing aint what it used to be. The days of sending that request off to ArcIMS and getting back a print - ready image are long gone. In fact, I can safely say that one of the few things that ArcIMS does much better than ArcGIS Server is printing.

These days, we have multiple services, markup, etc all on different layers being combined (layered), client side to create the illusion of a nice neat merged image. That illusion doesn't translate very well when it comes to printing. There have been a few hackish (in my opinion) attempts working around this by combining these different layers of images serverside. Personally, I it looked like a mess, and it was difficult to configure. I set out a few months back to try and figure out an easy way to combine these images using my serverside language of choice, Coldfusion. I was extremely surprised to find out that I couldn't not do it. I tried about everything in Coldfusion's image processing function library, and I was just stumped. I asked around and I could get anyone that could get this to work either. Until today.

The other day, I got an email from Ann, and she was looking for some advice on using REST calls to ArcGIS server from serverside. Then more specifically, she asked about combining images from a cached service and a dynamic service (or really any two services):

"Is it possible to use arcGIS to produce static images which consist of one base layer (cached) and an overlay? "

I, having tried this already, quickly replied no way. To my surprise, this morning, she sent over the following code (modified slightly for example purposes) that's using the Coldfusion ImagePaste function:



<!--- Create the envelope --->
<cfset MaxX = '-81.202'>
<cfset MaxY = '29.483'>
<cfset MinX = '-81.239'>
<cfset MinY = '29.461'>
<cfoutput>
    
<!--- make a call for the base map image --->
<cfimage name="baseimg" source="http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer/export?bbox=#MinX#,#MinY#,#MaxX#,#MaxY#&size=400,400&imageSR=&format=jpg&transparent=false&dpi=&f=image">

<!--- make a call for the overlay map image --->
<cfimage name="flagler" source="http://arcgis.roktech.net/ArcGIS/rest/services/Flagler/FlaglerDefault/MapServer/export?bbox=#MinX#,#MinY#,#MaxX#,#MaxY#&size=400,400&imageSR=&format=png8&transparent=true&dpi=&f=image">
</cfoutput>

<!--- use the elusive Imagepaste function to combine them --->
<cfset ImagePaste(baseimg,flagler,0,0)>


<!-- Send it out to the browser -->
<cfimage source="#baseimg#" action="writeToBrowser">


I cant believe that I missed something that easy. Here is the example: Image Merge Demo

Thanks Ann!

Coldfusion 9 Launched

Wow...Adobe just keeps wowing me with what they are doing with Coldfusion. Coldfusion 9 was released today. Check it out: Coldfusion 9

What a great time to be a Coldfusion developer...especially with the tight Flex integration...this make my ArcGIS Server development a breeze.

I tend to do most of my searching via Coldfusion cfcs with front ends in Flex. Using serverside cfc's to construct straight REST calls to ArcGIS Server has also proved to be dead simple and powerful.

Part 1 - Whats Is A Geoprocessing Task And Why Should I Care?

So, lets begin this discussion of Geoprocessing with ArcGIS Server that I promised. I guess the first question is what is geoprocessing and why should I even care?

The big promise of ArcGIS Server has always been this: "Whatever you can do in ArcMap and ArcCatalog, you can now do with ArcGIS Server". I have often heard ESRI reps say 'You can even rebuild ArcMap if you want to'. Of course, no one would ever want to do such a thing, but wouldn't it be nice to have all that functionality available to you in a web based application?

In the old days of ArcIMS and MapObjects IMS we were pretty limited in what types of geoprocessing we could do on the web. I can recall all sorts of crazy tricks with buffers that we used to write to really push ArcIMS to its limits. But, at the end of the day, it was still just a buffer, and there is only so far it will take you. How about a select by location, or a union, or a clip? Sorry folks, you were out of luck if you needed to do that on the web. But then, ArcGIS Server came around, and suddenly doing real geoprocessing became a reality.

So, what is a geoprocessing task? In short, it is a set of server side tools called from a web based client. Users create a model using Model builder, and then publish that model to the web as a geoprocessing task. The output parameters of the model are then streamlined to your web application.

Lets take for example a recent Flex application that I wrote (Check it out here). The purpose of this application is to help citizens locate their property and then return information about the zoning on that property. It sounds easy enough, right? I'll bet you are thinking, why not just do an Identify, and return results from the zoning layer? Ah, if it were only that easy.

There can be many, multiple types of zoning found on a single parcel, so a simple identify by point will not work. We need to do a spatial analysis to get the property boundary that the map click point or address point resides in. Once we get the property boundary, we need to do a second spatial analysis to determine which zoning layers intersect that property boundary.

So, how can we use a geoprocessing task to help solve this problem? I started by simply going into ArcMap and writing down the steps that it takes to get the results I need. Then, I used model builder to string together these tasks into a single workflow. Finally, I published this model to ArcGIS Server so I could access it from the web.

The, the final product takes in a point, selects the containing parcel for the point, and returns the zoning types that are present in the parcel.

Now, this is a pretty straightforward example. We could take this example much further. We could actually clip that zoning layer and determine precise percentages of each zoning type on that parcel. For parcels with multiple structures, we could determine the zoning district for each structure. List goes on.

This scenario, while certainly not impossible to do by conventional means (thinking FIND, QUERY, and IDENTIFY tasks), becomes much, much easier to solve by using a geoprocessing task. It also combines all the steps into one task. Instead of writing a complex combination of code to perform these steps in javascript or actionscript (flex) on the client, I have created a new, reusable tool that does all of these steps for me, serverside.

I hope this clears up what a geoprocessing task actually is and why you should care. Next up in the series, we'll tackle the technical aspects of actually creating and executing one from your web application.

New ArcGIS Server 9.3 Js API site to share

We have a new site that we would like to share with everyone. Its targeted towards the public for county/city governments. Its a work in progress of course, but we are well on our way with it. It was also recently showcased by ESRI on their Live User Sites showcase page.

There are several interesting technical details going on with the site that Trent will touch on in a upcoming blog post. However, I'll give you a brief overview now:

-Its built with the new 9.3 Javascript api
-Initially, we attempted to perform parcel attribute searches such as parcel number and owner name via the Javascript API QueryTask. Although, turning off the geometry in the query parameters improved performance, we found that using Coldfusion to query the database directly was much faster.
-Its also using our new Map Cache Hosting service to serve up the 'Flagler Aerials' layer.

Creating a Simple Layer List With The ArcGIS Server Javascript / REST api

I thought it was time to put my money where my mouth has been these past couple of months. I have been yapping about how easy the new ArcGIS javascript api is to work with, so I thought I'd share a very simple example. This example will show how to create a simple layer list for a DYNAMIC map service and give you the ability to turn layers on and off. Maybe I'll follow this post up with one for a tiled service.

In my example, I use Coldfusion, but you could easily adapt this to your langauge of choice. Actually, you could do this with pure javascript, but using something like Coldfusion just makes sense to me - as you will see from this example. Also, lets be clear - I am terrible with javascript - and I'll be the first to admit that. However, there are thousands and thousands of examples out there to help you along.

I'll show you the important parts here, but essentially its broken down into 3 parts. 1. Make a simple REST call to get a list of all the layers in the map service 2. Loop over the results to display the Layer name and a simple check box (with a onclick event) 3. Create the javascript that turns on and off the layers and then refreshes the map

The simple REST call:


    <!--- Create the cfc object and make a simple REST call. You can use any language that you
    are comfortable with. Coldfusion I find to be the most straightforward. --->

    <cfset esri = createObject("component","esri")>        
    <cfset LayerInfo = esri.ServiceInfo('http://snake/ArcGIS/rest/services/pickenscounty/MapServer?f=json')>


<!--- Create the initial list of layers that should be turned on --->
     <cfset LayerVisible = ''>
     <cfloop query="LayerInfo">
        <cfif DEFAULTVISIBILITY eq 'YES'>
            <cfset LayerVisible = listAppend(LayerVisible,#ID#)>
        </cfif>
    </cfloop>

Now display the results of the REST call:


<cfoutput query="LayerInfo">
<input type="checkbox" id="#id#" onclick="toggleDynamicVisibility(#id#);"<cfif DEFAULTVISIBILITY eq 'YES'>checked</cfif>>#Name#<br>
</cfoutput>

Lastly, add some javascript functions that will keep track of the layers to turn on and off and then refresh the map:


<script>
//I am using a coldfusion variable to populate this array. again, any language can be used here.
    var dynamiclayerlist = new Array(#LayerVisible#);
    function removeItems(array, item) {
    var i = 0;
    while (i < array.length) {
    if (array[i] == item) {
    array.splice(i, 1);
    } else {
    i++;
    }
    }
    return array;
    }
    
    function addItems(array, item) {
    array.push(item);
    }
    function toggleDynamicVisibility(layerid) {
    if     (dynamiclayerlist.indexOf(layerid) != -1){
        removeItems(dynamiclayerlist,layerid);
    }else{
        addItems(dynamiclayerlist,layerid);
        }
    dynamiclayer.setVisibleLayers([dynamiclayerlist]);
    }
    </script>

Note that when I make the REST call, I am using a Coldfusion component (CFC). I have included that cfc in the code download (see below for the link or get it here). So, hopefully when you see the finished code you see just how easy it really is.

This simple demo is available to actually try and view here: http://maps.roktech.net/demo/layerlist.cfm. Hopefully I can get some kind of regular series of simple ArcGIS Server javascript and REST api demos going...

BlogCFC was created by Raymond Camden. This blog is running version 5.9.1.002. Contact Blog Owner