This project has moved and is read-only. For the latest updates, please go here.

TMS tilesources

Apr 13, 2013 at 8:20 PM
Hi Clemens,

Let me start by saying this is a great control and saved me a lot of work.
I'm using local stored tiles that comply to the TMS format so I've modified the tilesource class and UriFormat to include:
    private Uri GetTMSUri(int x, int y, int zoomLevel)
        double ymax = 1 << zoomLevel;
        double ynew = ymax - y - 1;

        return new Uri(UriFormat.
            Replace("{tms}", "").
            Replace("{x}", x.ToString()).
            Replace("{y}", ynew.ToString()).
            Replace("{z}", zoomLevel.ToString()));
this is triggered by a TileSource DP having a "{tms]" string in it:

<map:TileLayer x:Key="Layer1" SourceName="OpenStreetMap" Description="TMS tile layer TileSource="file://c:/H50/{z}/{x}/{y}.png{tms}" Opacity="0.3"/>

I think this is not the best way to implement it since I can´t keep up with MapControl new releases right?
What do you think would be a better way? Should I derive a class from tilesource?

Apr 13, 2013 at 9:37 PM
Edited Apr 13, 2013 at 11:12 PM
Hi Fernando,

I must admit that I've never cared for the TMS standard before. I looks like if the only difference is that it reverses the direction of the y indices. If that would be the case I could easily add it to TileSource with a special format specifier like perhaps {v}.

However, when I test that with a reference (?) TMS service like{z}/{x}/{v}.png (found on, it doesn't work properly. The map shows Florida instead of Northern Germany. There seems to be more than just the reversed y-direction.

Anyway, you could easily add a derived TileSource class to your application, like this:
class TmsTileSource : TileSource
    public override Uri GetUri(int x, int y, int zoomLevel)
        return base.GetUri(x, (1 << zoomLevel) - y - 1, zoomLevel);
Now you would add a TileLayer in XAML like this:
<map:TileLayer SourceName="TMS">
    <local:TmsTileSource UriFormat="..."/>
You could also derive your TmsTileSource from ImageTileSource, which enables you to completely bypass the map tile loading and caching system in the Map Control.
class TmsTileSource : ImageTileSource
    public override ImageSource LoadImage(int x, int y, int zoomLevel)
        var uri = GetUri(x, (1 << zoomLevel) - y - 1, zoomLevel);
        // optimize image loading here
        return new BitmapImage(uri);
Apr 14, 2013 at 5:19 AM
Hi Clemens,

No worries, I've been using MapTiler to generate my own tiles and seems to be using that format.

The spec:

And this is were I´ve got the conversion:

As you state, it just reverses the index on the y axis.


Apr 14, 2013 at 8:03 AM
Thanks Clemens!

Deriving from TileSource worked perfectly on the tiles generated by MapTiler.
Apr 16, 2013 at 7:12 PM
Would be good to have TMS TileSource in the master as part of the standard TileSource code - I'm using Geoserver and its cache prefers access using TMS as using WMS and a bounding box is a bit hit and miss.

I suppose its going to get trickier to have one tilesource class that can parse all the different styles of uri. Might it be better to have some kind of tilesource factory and separate classes for each style. I would be happy to work on that ..
Apr 16, 2013 at 7:27 PM
Adding TMS functionality to the TileSource class would be quite easy. I would do that immediately if somebody would point me to a tile server on the web where I could test that functionality. The server mentioned earlier in the discussion uses a different map projection.

If there would be a real world service providing its tiles according to the TMS scheme, that may convice me that TMS is not an obsolete standard.
Apr 17, 2013 at 1:00 PM
Here is one example URI.. There are not a lot of public examples but for internal server purposes, i.e. my geoserver, I'm hoping the TMS service it provides will speed things up somewhat..
Apr 17, 2013 at 4:39 PM
That URL is just the one I mentioned above that gives me Florida where I expect Nortern Germany.

Somebody would have to explain the tiling scheme, it's not just reversing the y index.
Apr 19, 2013 at 2:47 PM
I just added in a similar built Uri formatter and tried it with my geoserver here at London Ambulance with a cache layer and it FAST! and works perfectly. I then tried it again with the link on osgeo and am now suspicious that the osgeo site is broken.

For those who use Geoserver a typical Uri is in this format below.. oh, and build the cache with EPSG:900913

... http://cad-hq-diba:8080/geoserver/gwc/service/tms/1.0.0/Wolf:LondonStreet@EPSG:900913@png/{Z}/{X}/{Y}.png
        public string UriFormat
                if (uriFormat.Contains("{X}") && uriFormat.Contains("{Y}") && uriFormat.Contains("{Z}"))
                    getUri = GetTMSUri;

        private Uri GetTMSUri(int x, int y, int zoomLevel)
            int newY = (1 << zoomLevel )-y-1 ; // reverse the Y coord
            return new Uri(UriFormat.
                Replace("{X}", x.ToString()).
                Replace("{Y}", newY.ToString()).
                Replace("{Z}", zoomLevel.ToString()));
Apr 19, 2013 at 4:01 PM
Edited Apr 19, 2013 at 4:02 PM
I guess I'll add a {v} format specifier for reversed y index to TileSource in the next release. If only somebody could point me to a publicly available TMS server...
Apr 22, 2013 at 10:09 AM
Try this one.. I built this Geoserver over the weekend and loaded some open maps for London.. Its still building the cache but should work ok if you look at London as a whole. Its not fast or pretty but will hopefully allow you to test your change.{z}/{x}/{v}.png

Apr 22, 2013 at 7:12 PM
Edited Apr 22, 2013 at 7:13 PM
That one works!
Apr 22, 2013 at 8:09 PM
good... there was nothing wrong with your code... :)

I have had to change the layer name from Vector to VMDistrict as many tiles were missing and I had to reconstruct it. So change your URL appropriately. The cache is rebuilding as we speak and should be down to zoom level 15 by tomorrow morning. I'll leave this available for the time being for further testing if required.

Apr 22, 2013 at 9:27 PM
It's not necessary to keep that service available. The code change was easy enough and I guess I don't need any further testing. I was just worrying if reversing the y index was all that needed to be done to support TMS.