Skip to main content

Are there any specific coordinate strings or bounding boxes to be created for the ImageFetcher to understand where to fetch from a URL? I.e. I tried to fetch from a XYZ tile server and it works flawless in QGIS. The same URL doesn't work with the ImageFetcher for some reason.

The image fetcher only works for images - essentially the ImageFetcher is an HTTPCaller with a building in FeatureReader pointing to the downloaded image.

 

For example if i point the URL to the random image I found via google images: 

https://www.thedesignwork.com/wp-content/uploads/2011/10/Random-Pictures-of-Conceptual-and-Creative-Ideas-02.jpg

imageFME will download the image and read it in with the JPEGReader - you can see evidence of the JPEG reader in the log fie  e.g.,

JPEG reader: Directive '_DELETE_SOURCE_ON_CLOSE' has the value 'yes'

There is also the Content-Type which you can either set to Auto or you can specify it manually.

 

If the headers are not set correctly then you will need to specify it manually. 

 

the image fetcher will not with with vector features like point, lines, etc

 

What is the URL you are trying to read from? 


Pluss one for the reply from @virtualcitymatt​ .

Could you perhaps try with the "OGC WMTS (Web Map Tile Service)" format in a FeatureReader? It will let you pass polygon as bounding boxes and format the request URL accordingly.


Here's the URL https://tile.opentopomap.org/{z}/{x}/{y}.png and attached is a sample area for which I would want to load tile through ImageFetcher.


Here's the URL https://tile.opentopomap.org/{z}/{x}/{y}.png and attached is a sample area for which I would want to load tile through ImageFetcher.

You can, but it is not out of the box.

For example, you can use https://a.tile.openstreetmap.org/5/9/12.png in the dataset, but you will need to calculate x and y from the coordinates. And the returned pdf's are not georeferenced, so you will need to do that as well, using a RasterGeoreferencer.


Here's the URL https://tile.opentopomap.org/{z}/{x}/{y}.png and attached is a sample area for which I would want to load tile through ImageFetcher.

this is the setup in FME 2023.0 image


You can, but it is not out of the box.

For example, you can use https://a.tile.openstreetmap.org/5/9/12.png in the dataset, but you will need to calculate x and y from the coordinates. And the returned pdf's are not georeferenced, so you will need to do that as well, using a RasterGeoreferencer.

hm, I thought to be able to download tiles (.png) from the given area of interest. So that doesn't work? Is ImageFetcher the wrong Transformer?


Pluss one for the reply from @virtualcitymatt​ .

Could you perhaps try with the "OGC WMTS (Web Map Tile Service)" format in a FeatureReader? It will let you pass polygon as bounding boxes and format the request URL accordingly.

I need to download from an XYZ tile server..


You can, but it is not out of the box.

For example, you can use https://a.tile.openstreetmap.org/5/9/12.png in the dataset, but you will need to calculate x and y from the coordinates. And the returned pdf's are not georeferenced, so you will need to do that as well, using a RasterGeoreferencer.

No, Safe did not implement XYZ tiles, as far as I know. They did implement WMTS and, as @david_r​ pointed out, you can use this as expected with a FeatureReader.

 

As said, I think you can build this yourself, but it will take some effort.


You can, but it is not out of the box.

For example, you can use https://a.tile.openstreetmap.org/5/9/12.png in the dataset, but you will need to calculate x and y from the coordinates. And the returned pdf's are not georeferenced, so you will need to do that as well, using a RasterGeoreferencer.

Indeed, it shouldn't be too complicated. This article shows how to calculate the tile numbers based on a bounding box, with concrete examples in Python:

https://medium.com/@ty2/how-to-calculate-number-of-tiles-in-a-bounding-box-for-openstreetmaps-4bf8c3b767ac


You can, but it is not out of the box.

For example, you can use https://a.tile.openstreetmap.org/5/9/12.png in the dataset, but you will need to calculate x and y from the coordinates. And the returned pdf's are not georeferenced, so you will need to do that as well, using a RasterGeoreferencer.

got it, thank you for looking into it!


Here's some sample code for the PythonCaller that will accept a bounding box geometry (should be according to EPSG:4326) and will output one feature for each tile that is covered. You have to provide the zoom level as an attribute "z" to the PythonCaller. The output from the PythonCaller will contain the new attributes "x" and "y" (you'll have to expose them in the PythonCaller settings) which, together with the input "z", you can use to build the URL that is then passed to the ImageFetcher.

import fmeobjects
from itertools import chain
from math import log, tan, radians, cos, pi, floor
 
# Based on https://jimmyutterstrom.com/blog/2019/06/05/map-tiles-to-geotiff/
def sec(x):
    return(1/cos(x))
 
def latlon_to_xyz(lat, lon, z):
    tile_count = pow(2, z)
    x = (lon + 180) / 360
    y = (1 - log(tan(radians(lat)) + sec(radians(lat))) / pi) / 2
    return(tile_count*x, tile_count*y)
 
def bbox_to_xyz(lon_min, lon_max, lat_min, lat_max, z):
    x_min, y_max = latlon_to_xyz(lat_min, lon_min, z)
    x_max, y_min = latlon_to_xyz(lat_max, lon_max, z)
    return(floor(x_min), floor(x_max),
           floor(y_min), floor(y_max))
           
class GetXYZTilesByBbox(object):
    def __init__(self):
        pass
 
    def input(self, feature):
        fme_bbox = feature.getGeometry().boundingBox()
        zoom_level = int(feature.getAttribute('z'))
        bbox = tuple(chain.from_iterable(fme_bbox))
        tile_list = bbox_to_xyz(*bbox, zoom_level)
 
        for x in range(tile_list.0], tile_list<1]+1):
            for y in range(tile_listg2], tile_listz3]+1):
                tile_feature = feature.cloneAttributes()
                tile_feature.setAttribute('x', x)
                tile_feature.setAttribute('y', y)
                self.pyoutput(tile_feature)
                               
    def close(self):
        pass

The georeferencing is left as an exercise for the reader, but there's sample code to be found in this excellent article that I used as basis for the above: https://jimmyutterstrom.com/blog/2019/06/05/map-tiles-to-geotiff/


Reply