Vishful thinking…

Issues encountered and solved while building a comprehensive web-based map printing solution

Posted in ArcGIS, ESRI, GIS by viswaug on March 30, 2010

Web-based map printing has been one of those problems that, so far, doesn’t have a COMPLETE solution that meets all the needs of the different users out there. We had created various solutions in the past to meet web-based printing needs on a per-project basis. But, we didn’t have one single comprehensive solution that was capable enough to meet all requirements regardless of the unique complexities involved in each of them. A little while ago, we set out to build one such comprehensive web-based map printing solution and ran into some issues along the way that I thought might be worth sharing here. I am not going to go into what we built here, but just the issues/oddities we encountered…

Here are the issues we faced while developing the printing component and some details into how we worked-around them.

  • Printing token secure layers – This is a problem that we initially didn’t see coming because we were using the Silverlight client api to print. When using token layers, the client (which is the browser) requests a token from the GIS server using it’s IP address (or a web address) as the optional ClientID. When using a token generated with a ClientID, the AGS server checks for the origin of the request to confirm identity. So, when we tried to use the token generated by the client browser with it’s IP address as the ClientID in the server-side printing component, the requests were denied by AGS as it rightfully should since the server’s IP address doesn’t match the one in the token. We did not initially see this problem with Silverlight clients because, Silverlight clients currently request tokens without the optional ClientID. To work around this, we had to request token without the ClientID or had to spoof the Referrer in the HTTP request for the image.
  • Max Image Size constraints – The size of map image requests that need to be made can get quite large depending on the size of the map on the print layout and also on the DPI required on the map print output. AGS has default max image size limits set to 2048 X 2048. Bing maps maximum image size is around ~800. Increasing the maximum image size limit in AGS will only take you so far. Eventually, your image size requests can be big enough (think plotter size) to either cause AGS to crash or just take an unacceptably long time to return. So, to work around this limitation, we had to resort to cutting the big image requests into a series reasonably sized tile requests. Once all the tiles to cover the big area arrive, the tiles can be stitched back together using GDI+ to produce a seamless big image that the map print layout needs.
  • Bing logo – The above solution to split big image requests into works for AGS MapServices and WMS services, but Bing map layers add another twist to the problem. Image responses from Bing contain the Bing logo on the bottom right corner of the image. This caused the Bing logo to appear multiple times on the map when the numerous smaller tile images were stitched together. To solve this issue, we had to get special permission from Bing to access their tile images directly which do not have the Bing logo on them and stitch those together to produce the seamless image required.
  • Custom legends – The swatches for legend image for an AGS MapService can be obtained pretty easily using the AGS SOAP API. But more custom work is needed to stitch together the swatch and legend text information from multiple map services. Also, to add to it, there was no easy way to generate swatches for graphics layers. So, we ended up writing a custom Server Object Extension (we call it LegendServer) exposed over SOAP that takes in the information needed to produce swatches for the graphics layers and produces swatch images. The legend service consumed the swatches information from the AGS MapService and the custom SOE and stitched them together into one legend image handling the font styles etc and wrapping as necessary. We still have the issues here that ArcObjects is not able to generate the swatches at the required DPI. For e.g. we can’t request for swatches in 300 DPI etc.
  • Missing legend symbol markers in AGS – When writing the custom Server Object Extension described above to produce legend swatches, we discovered that ArcObjects doesn’t support triangle markers. But triangle markers were supported on the client-side APIs. So, to overcome that limitation, we can handle just the triangle markers as picture marker symbols and handle it with a special image service that produces a triangle image in the required dimensions, fill and border color.
  • Overflowing legends – Sometimes the legend for a map just can’t fit on a single page. In those cases, we had to make sure that we build the legend in parts that can fit on the page and stick the overflowing legend into new pages as needed. The trick here is to not build one single legend image and chop it to overflow to the next page. Because, we decide to chop off the legend at an arbitrary height, we might end up chopping the text or swatch on the legend. So, we will have to build the legend in parts and then assemble them into the different pages.
  • Printing Graphics layers – Printing graphics layers on the map turned out to be a little tricker than expected. We went down the path of rendering the graphic layers as PDF graphics on top of the map. It seemed to do everything we needed until we had to print polygons with holes in it. Then we used the AGS SOAP API to generate an image for the graphics on the map and overlay it on top of the map. We ended up pulling back that solution because that technique did not support transparency in graphics. So, eventually, we ended up writing a custom Server Object Extension (we call it GraphicsServer) that produces images from the graphics layer geometries and symbology respecting their transparency.
  • Overview Map – Printing overview map doesn’t sound too complicated until you consider the fact that we might have a totally different set of layers on the overview map than we do on the map itself. Also, the overview map can be static or dynamic, meaning it can always be at the same extent (world extent for example) or it may have it’s extent set at levels that closely follow the extent of the map itself. Also, keep in mind that the overview map will also need to have a small rectangle graphic inside it that highlights to current extent of the map.
  • Print Rendering – In most cases, we will want to have the option of being able to render to PDF or an image as the user requires. When implementing these renderers, please keep in mind that the co-ordinates axis for the PDF and the image GDI graphics are reversed. PDF is bottom-up and image GDI graphics is top-down.

I am pretty sure that I am leaving out some more. I will add them to the list above as and when I remember them. But I am happy to say that we did solve/work-around all the problems that came our way and have been re-using the printing component in various projects with great success. The printing component is also being used by all Silverlight, Flex and Javascript clients.

Please let me know, if you ran across other issues when you implemented your print feature or if you solved any of the issues above in a different way.

6 Responses

Subscribe to comments with RSS.

  1. Phil Penn said, on March 31, 2010 at 7:59 pm

    Excellent article.

    One thing that we did was allow the user to publish templates through ArcMap. How else are you doing things like scalebars/scaletext on your maps? And how else to allow the client to publish map look & feel after you’ve gone? We would export a wireframe (empty map service) of a given template and sort of glue things in from there.

    When are ESRI going to deal with this thorny issue?

  2. Bernd Nierula said, on April 1, 2010 at 1:44 pm

    Very interesting arcticle.

    We also want to implement some server based printing (200 – 300 dpi, about letter format) for a silverlight API (ESRI) based web app. It turned out to be more complicated than expected…

    Now we are thinking about using the ESRI Silverlilght MapControl (WPF) at serverside and

    . load all the maplayers and graphics for the given extent as on the client and
    . render the mapcontrol to an image
    . include the image in a pdf-report (active report)
    . send the pdf to the client

    Have you any experience with this approach?

    Best regards

    Bernd

    • viswaug said, on April 1, 2010 at 2:06 pm

      Hi Bernd,

      I have heard somethings about other people attempting the same kind of thing too. That might get you out of the pain of printing the map alone and not some other things like the legend etc. Also, I would be really wary of SynchronizationContext issues here since you might be attempting to load a UI control in a web application thread. It remains to be seen as to if your UI control would load properly without a UI Dispatcher SynchronizationContext. And what might happen if two UI control instances are loaded onto 2 threads in the web app. I wouldn’t build a server like that, but that said, if you or somebody can get it to work, then why not? Let me know how it works out for ya. I would be real interested in it. What other complex map printing requirements do you have?

      Thank You,
      Vish

  3. Lakshmanan said, on April 15, 2010 at 6:35 am

    Hi Vish,

    Really interesting article. Yes, am also doing same printing for SL web API. Luckily I have read your articel before I start. I am just sending visible layer, extents, graphics as string to WCF service where I am creating map, graphics layer, legend, scale bar, title etc and generating Layout using ArcObjects. Though this is bit complex, but works well atleast for my requirement. I dont have transparency symbols to be worried out.

    But I would like to custom SOE for this like yours.

    Lakshmanan

  4. Patrick said, on July 13, 2010 at 10:40 am

    Hi Vish,

    I had to tackle this task for a previous client last year in Flex and ended up with an “acceptable” print solution (though there were still complaints about resolution). For that, I brought in all my print elements (scale bar, legend, etc.) as UIComponents, hid any non print elements, resized the browser window to fit A4 landscape dimensions and launched a print function.

    I explored a number of ways of doing the print, however had to settle on that one due to certain constraints. At the time, I merged ArcGIS Server and Google Maps together (as two separate, yet synchronized services). Google would throw security errors when I’d try any programmatic print methods (they hadn’t implemented any cross domain policies on their end to protect their services [which made people who paid to license their services rather angry]). They’ve since implemented a crossdomain.xml, but I haven’t personally tried it again so I can’t say whether it’s solved that old problem or not.

    I’m back to this task for my current client (again in Flex). Instead of Google Maps, I’m working with Bing Maps now, and thankfully there’re no security issues. However, resolution needs to be maximized as much as possible this time around.

    I’m currently using a combination of Flex and AlivePDF. I output the map as a 300 dpi image, which is actually still a 96 dpi image – just a big one – and then shrink it down to fit the page. The output image’s background imagery of Bing Maps is quite good, but the custom Map Service layers that are on top are a bit pixelated. Boosting the Map Service dpi did nothing, and setting the layer’s dpi programmatically does the same thing as outputting the map to 300 dpi – I just end up with really big symbols.

    Reading over the problems you encountered and how you worked around them was very helpful. I avoided the SOE and GDI routes out of concern over their complexity, but I probably created more headaches for myself in doing so. Did you encounter resolution issues with the solution you had implemented? Do you have any suggestions on how to maximize Map Service display/print quality?

    Thanks!

    • viswaug said, on July 13, 2010 at 11:26 am

      Hi Patrick,

      To workaround the problem you had mentioned, we request the images at 300 DPI from the GIS Server but we tile the requests into smaller blocks and stitch them together. So, the output quality for mapservices are pretty good.

      Thank You,
      Vish


Leave a comment