Build a geolocation image watermarker with Transloadit
While we are proud how versatile our API is, obviously there are always more things, that it cannot do just yet. Fortunately it is easy to integrate it with third-party libraries and APIs.
In this post we're going to demonstrate this in a Node program using the external library Node Geocoder to extract geo metadata from images before watermarking this data onto our input image with Transloadit.
Before we start
As previously stated, you will need to use some external tools and an input file. We'll be using the following libraries for this blog:
- Mdls — A file inspection utility that is only available for Macs (alternative for non-Mac users can be found here)
- Node Geocoder — Based on the information in our found files, it performs geocoding and reverse geocoding
- Transloadit — Used to produce our watermarked result
Go ahead and create a new directory to work from and a js file. Once done access your working directory from the console and run the following command:
yarn add mdls transloadit node-geocoder
With setup complete let's get onto the code.
Code
First off, we need to import our used libraries. Easy enough.
const nodeGeocoder = require('node-geocoder')
const mdls = require('mdls')
const Transloadit = require('transloadit')
Info extraction
Now we can get onto the main body of our code and extract our metadata. While we could import our file from an external vendor and extract our file info using two Assemblies tethered together as shown in this blog, that would add to file consumption costs, and well, we've shown that before. However, if you prefer, you are free to use that method.
(async () => {
const metaData = await mdls(`./blog/${process.env.PHOTO}`)
const lat = metaData.ItemLatitude
const lon = metaData.ItemLongitude
Here in our program, we extract our file info using mdls and declare two variables to hold our latitude and longitude values. We use the process.env functionality so we can update our processed file from the command line.
Geo encoding
Now we have our latitude and longitude values in place, let's look at how we accomplish our geo encoding.
const geoCoder = nodeGeocoder({
provider: 'openstreetmap',
})
const res = await geoCoder.reverse({ lat, lon })
const [place] = res
const parts = []
if (place.streetNumber) parts.push(place.streetNumber)
if (place.streetName) parts.push(place.streetName)
if (place.city) parts.push(place.city)
if (place.country) parts.push(place.country)
const address = parts.join(', ')
Node Geocoder comes equipped with many provider options to choose between several APIs for your geo encoding. We've opted to use OpenStreetMap as it doesn't require any external API keys to be set up; however, take a look at the other available providers as they come with additional configurable options if you wish to expand on this blogs program.
With our options in place, we've initialized an instance of our geo encoder and set a response using
the .reverse
property so we can search with predefined geolocation information. By default, Node
Geocoder looks for geo info without that property, but that's not much use to us as we already have
the information.
The final part of this snippet takes the extracted geo info and parses it, so it's suitable for our
text watermarking. To avoid any "undefined"
, we only push non-empty values onto the parts
array,
and then join it together with commas.
Encoding final result
With all our geolocation data processed, we can send it off for encoding using the Transloadit API. Head over to your Transloadit console and note both your Auth Key and Secret Key so you can follow along.
const transloadit = new Transloadit({
authKey : process.data.env.TRANSLOADIT_AUTH_KEY,
authSecret: process.data.env.TRANSLOADIT_SECRET_KEY,
});
const assemblyStatus = await transloadit.createAssembly({
waitForCompletion: true,
files: {
file1: `./blog/${process.env.PHOTO}`,
},
params: {
steps: {
':original': {
robot: '/upload/handle',
},
watermarked: {
use: ':original',
robot: '/image/resize',
result: true,
text: [
{
text: '${fields.address}',
size: 30,
font: 'Ubuntu',
color: '#eeeeee',
valign: 'bottom',
align: 'right',
x_offset: 16,
y_offset: -10,
},
],
imagemagick_stack: 'v3.0.1',
},
},
fields: { address: address },
},
})
const resultUrl = assemblyStatus.results.watermarked[0].ssl_url
console.log(`Here is your result url - ${resultUrl}`)
})().catch((err) => {
console.log(err)
process.exit(1)
})
From here, we can create our Transloadit API instance. We set up our credentials to pass them in via the command line, then use that instance to create our Assembly.
We use the file parameter to select which file we want to upload. In this case, since we are using the same file we used for processing geolocation info, we recycle the before used method for selecting our file.
Following that, we setup the Steps for our Assembly to use. Apart from our
uploading Step, this Assembly only makes use of one Robot,
/image/resize. The watermarking setup is simple, and we use the
Assembly Variables field functionality for the text
parameter to pass our previously
processed text value. You'll notice that the variable in the fields parameter object stating the
address variable is shared by the field value for text. Upon upload, this is what sends our
processed geolocation text value to our Transloadit Assembly instance.
It's worth noting we've set waitForCompletion
to true
. This is done so that our program knows to
wait for a response from Transloadits Assembly before completing the program's cycle.
With our Steps in place, all that remains is to configure a response from our Assembly. We create a new variable to hold our Assembly result and assign it using our Assemblies results property; if everything goes well, the result will be posted to our console; otherwise, an error message will be displayed.
Results
Let's now run our program using the below commands.
# I got these credentials from: https://transloadit.com/c/my-app/template-credentials
export TRANSLOADIT_AUTH_KEY=********
export TRANSLOADIT_AUTH_SECRET=********
export PHOTO=my_image.HEIC
node geo-watermarker.js
Assuming all is well, we're left with the below result in your console which will link to a result similar to the proceeding image:
Here is your result url - YOUR_IMAGE_URL
And with that, we've come to an end. We hope you enjoyed this brief walkthrough and learned how to integrate Transloadit into your projects with external tools to achieve impressive results. We'd love to hear your thoughts and suggestions for how to improve this project. If so, please feel free to reach out!