Recently a colleague asked if we could embed maps into Documaker output. Being a tech person, I naturally replied, "Of course!" and then I thought about that for a moment and followed that up with, "Wait, what do you mean 'maps'?" What followed was a mini-requirements definition discussion in which we determined that the what we want is:
We also discuss some additional use cases that I won’t cover in this post, but will in the future:
After understanding my particular requirements, the first thing I needed to do was determine which third party service I would use, which prompted another delve into requirements. Such a service would need to:
I settled on a popular mapping API provided by Google. It’s feature-rich, and easy to implement. All you need is a Google API key which is tied to your Google account… and that’s where this experiment goes a little wonky. Why? Well, because my Google account is my personal account and I don’t have a corporate Google account. If you keep your API usage below a certain threshold, your queries will remain free, so this is good for extremely limited development testing. If you decide to go this route, you’ll definitely want to have a corporate Google account for using this feature. I’ve learned that Oracle has a similar maps API that uses a wholly different licensing model, so I’ll explore that in a future post.
To use the Google Maps API:
Next, you’ll create a data enrichment program. For my “less than 20 lines of code” requirement, I chose to implement this in PowerShell (yes, PowerShell!) I created this script:
Add-Type -AssemblyName System.Web [xml]$ef = Get-Content $args $addr = "$($ef.DocumentRequest.Addressees.Addressee.AddrLine1) $($ef.DocumentRequest.Addressees.Addressee.AddrLine2), $($ef.DocumentRequest.Addressees.Addressee.City), ($ef.DocumentRequest.Addressees.Addressee.State) $($ef.DocumentRequest.Addressees.Addressee.PostalCode) $($ef.DocumentRequest.Addressees.Addressee.Country)" $addr = [System.Web.HttpUtility]::UrlEncode($addr) $key = $args $out = $args $url = "https://maps.googleapis.com/maps/api/staticmap?center=$addr&zoom=13&size=300x300&maptype=roadmap&format=jpg&key=$key" $wc = New-Object System.Net.WebClient $wc.DownloadFile($url, $out)
That’s 10 lines of code, not including whitespace. Two things are important to note here: the call to this program expects three arguments:
In my code above, you can see where I have concatenated the address lines in the extract data into a non-geocoded address variable $addr, which I use later when I call the Google API. This call is on the line in bold, where I have specified a size for my map as 300x300, and a format of jpg. I have also included the API key as a variable, which should be passed as the second argument. Finally, the response to this web call is downloaded into the file specified in the third argument. I ran a quick test and can see my image is being downloaded as a JPG:
Now, depending on what your map service provides, you may need to convert the image from one format to another. ImageMagick is a multi-platform, open source image processing application that we can download and install, and will give us a simple command we can call to perform the necessary conversion based on the file extension (e.g. input.jpg output.tif). However, since the Google API returns a JPG, and we can import that directly, we don’t need to do this — I’m just leaving this info here in case it’s needed:
convert <input file> <output file>
What remains at this point is to get the map image into Documaker’s output. There are a number of ways to do this, but the way I’ve done it in my example is a simple process.
Finally, we need to string together the workflow, which for Standard Edition is normally done in a shell script (e.g. a BAT or CMD file):
@echo off setlocal @rem Please set your Google Maps API key set KEY="" set MRLDIR="c:\fap\mstrres\dmres" set EXTRFILE=%MRLDIR%\INPUT\map.xml set OUT=%MRLDIR%\forms\embedmap.jpg" cd %MRLDIR% del data\*.* /q powershell.exe -file ".\GetMap.ps1" %EXTRFILE% %KEY% %OUT% @REM convert %OUT% %MRLDIR%\forms\embedmap.jpg @REM assumes FSIUSER.INI is used, and JDT is configured for single-step to run @REM GENTRAN, GENDATA, and GENPRINT. gendaw32
In the lines above, I call the PowerShell script, and pass three arguments to obtain the JPG of the map (remember to add your API key). I have commented out the call to convert since we don’t need. I’m going to say that the above does not constitute lines of code, since we’re just calling a program, but let’s say we have one additional line of code since we are having to call PowerShell. At the end of the shell script Documaker executes in single-step mode (which combines GENTRAN, GENDATA and one or more subsequent Documaker components such as GENPRINT). The PostTransDAL script is called by the JDT command, which swaps the map. In the output PDF we can see the results, all in 13 lines of code:
Now, it should be noted that what I have demonstrated above relies on statically-named intermediary files. If you were operating strictly in a single batch process environment, it would be fine as-is. But if you are running multiple Gendata processes, or using IDS to front any processes, you would need to have dynamically-named intermediary files that ideally use information from the extract data to uniquely name the map JPG file. I hope you’ve found this informative and useful, as it shows how you can take an older system and add new functionality to it to support your business requirements.
Stay tuned for a post where I get into Oracle’s Map API!