I have found some examples but haven't managed yet to adapt them to my needs...

I have an image that is served as TMS (tiles already statically rendered): http://humadat.alwaysdata.net/tms/khorog/tiles

What would be the right syntax to display it in OpenLayers?

On this example: http://openlayers.org/dev/examples/tms.html It looks quite different, as if the tiles are dynamically rendered by a python script...

I tried something like this

layer = new OpenLayers.Layer.TMS( "TMS",
    "http://humadat.alwaysdata.net/tms/khorog/", {layername: 'tiles', type:'jpg'} 

But no success so far

1 Answer 1


What you serve is not a TMS service acording to Openlayers specification. They expect a service which can be questioned for tiles similar to WMS.

Unfortunately, your tiles follw the OGC naming convention, and not OSM-like. See my answer here to number the tiles correctly:

GDAL2Tiles: MapTiles from BSB/KAP are Switched


I finally managed to load the data into QGIS using the TileLayer Plugin. That allows to switch the layer numbering between OGC and OSM.

This is my entry in the config file:

khorog  khorog  http://humadat.alwaysdata.net/tms/khorog/tiles/{z}/{x}/{y}.jpg  0   12  16  -180    -85.0   180.0   85.0

Note that tabs have to be used as delimiters. And this is the result:

enter image description here

with OSM in the background and your tiles transparently overlayed (which Openlayers plugin will do not either).

Last Edit

I finally got success with your Maptiler tiles by using the Openlayers page that was created by Maptiler. They hacked the getURL to respect the inverse numbering:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
        <html xmlns="http://www.w3.org/1999/xhtml>"
            <meta http-equiv='imagetoolbar' content='no'/>
            <style type="text/css"> v\:* {behavior:url(#default#VML);}
                html, body { overflow: hidden; padding: 0; height: 100%; width: 100%; font-family: 'Lucida Grande',Geneva,Arial,Verdana,sans-serif; }
                body { margin: 10px; background: #fff; }
                h1 { margin: 0; padding: 6px; border:0; font-size: 20pt; }
                #header { height: 43px; padding: 0; background-color: #eee; border: 1px solid #888; }
                #subheader { height: 12px; text-align: right; font-size: 10px; color: #555;}
                #map { height: 95%; border: 1px solid #888; }
            <script src="OpenLayers.js" type="text/javascript"></script>
            <script type="text/javascript">
                var map;
                var mapBounds = new OpenLayers.Bounds( 71.5, 37.4, 71.6, 37.5);
                var mapMinZoom = 12;
                var mapMaxZoom = 20;

                // avoid pink tiles
                OpenLayers.IMAGE_RELOAD_ATTEMPTS = 3;
                OpenLayers.Util.onImageLoadErrorColor = "transparent";

                function init(){
                var options = {
                    controls: [],
                    projection: new OpenLayers.Projection("EPSG:900913"),
                    displayProjection: new OpenLayers.Projection("EPSG:4326"),
                    units: "m",
                    maxResolution: 156543.0339,
                    maxExtent: new OpenLayers.Bounds(-20037508, -20037508, 20037508, 20037508.34)
                map = new OpenLayers.Map('map', options);

                // create OSM/OAM layer
                var osm = new OpenLayers.Layer.TMS( "OpenStreetMap",
                    { type: 'png', getURL: osm_getTileURL, displayOutsideMaxExtent: true, 
                      attribution: '<a href="http://www.openstreetmap.org/">OpenStreetMap</a>'} );

                // create TMS Overlay layer
                var tmsoverlay = new OpenLayers.Layer.TMS( "TMS Overlay", "http://humadat.alwaysdata.net/tms/khorog/tiles/",
                    {   // url: '', serviceVersion: '.', layername: '.',
                        type: 'jpg', getURL: overlay_getTileURL, alpha: true, 
                        isBaseLayer: false
                if (OpenLayers.Util.alphaHack() == false) { tmsoverlay.setOpacity(0.7); }

                map.addLayers([osm, tmsoverlay]);

                var switcherControl = new OpenLayers.Control.LayerSwitcher();

                map.zoomToExtent( mapBounds.transform(map.displayProjection, map.projection ) );

                map.addControl(new OpenLayers.Control.PanZoomBar());
                map.addControl(new OpenLayers.Control.MousePosition());
                map.addControl(new OpenLayers.Control.MouseDefaults());
                map.addControl(new OpenLayers.Control.KeyboardDefaults());

            function osm_getTileURL(bounds) {
                var res = this.map.getResolution();
                var x = Math.round((bounds.left - this.maxExtent.left) / (res * this.tileSize.w));
                var y = Math.round((this.maxExtent.top - bounds.top) / (res * this.tileSize.h));
                var z = this.map.getZoom();
                var limit = Math.pow(2, z);

                if (y < 0 || y >= limit) {
                    return "http://www.maptiler.org/img/none.png";
                } else {
                    x = ((x % limit) + limit) % limit;
                    return this.url + z + "/" + x + "/" + y + "." + this.type;

            function overlay_getTileURL(bounds) {
                var res = this.map.getResolution();
                var x = Math.round((bounds.left - this.maxExtent.left) / (res * this.tileSize.w));
                var y = Math.round((bounds.bottom - this.tileOrigin.lat) / (res * this.tileSize.h));
                var z = this.map.getZoom();
                if (mapBounds.intersectsBounds( bounds ) && z >= mapMinZoom && z <= mapMaxZoom ) {
                   //console.log( this.url + z + "/" + x + "/" + y + "." + this.type);
                   return this.url + z + "/" + x + "/" + y + "." + this.type;
                } else {
                   return "http://www.maptiler.org/img/none.png";

           function getWindowHeight() {
                if (self.innerHeight) return self.innerHeight;
                if (document.documentElement && document.documentElement.clientHeight)
                    return document.documentElement.clientHeight;
                if (document.body) return document.body.clientHeight;
                    return 0;

            function getWindowWidth() {
                if (self.innerWidth) return self.innerWidth;
                if (document.documentElement && document.documentElement.clientWidth)
                    return document.documentElement.clientWidth;
                if (document.body) return document.body.clientWidth;
                    return 0;

            function resize() {  
                var map = document.getElementById("map");  
                var header = document.getElementById("header");  
                var subheader = document.getElementById("subheader");  
                map.style.height = (getWindowHeight()-80) + "px";
                map.style.width = (getWindowWidth()-20) + "px";
                header.style.width = (getWindowWidth()-20) + "px";
                subheader.style.width = (getWindowWidth()-20) + "px";
                if (map.updateSize) { map.updateSize(); };

            onresize=function(){ resize(); };

          <body onload="init()">
            <div id="subheader">Generated by <a href="http://www.maptiler.org/">MapTiler</a>/<a href="http://www.klokan.cz/projects/gdal2tiles/">GDAL2Tiles</a>, Copyright &copy; 2008 <a href="http://www.klokan.cz/">Klokan Petr Pridal</a>,  <a href="http://www.gdal.org/">GDAL</a> &amp; <a href="http://www.osgeo.org/">OSGeo</a> <a href="http://code.google.com/soc/">GSoC</a>
            <div id="map"></div>
            <script type="text/javascript" >resize()</script>

This works with all browsers.

  • You can find the structure here: humadat.alwaysdata.net/tms/khorog/tiles I used Maptiler (maptiler.org) to create the tiles. In JOSM, I can display it with humadat.alwaysdata.net/tms/khorog/tiles{zoom}/{x}/{-y}.jpg I think the problem comes from the "y" coordinate: for some reason, I have to use "-y" in JOSM. So with "y" in OpenLayers, incorrect tile names are requested. But I don't get it to work, neither with "${-y}" nor with "-${y}" Feb 14, 2014 at 18:04
  • In JOSM, I have managed to see the tiles at the right place with {-y}, but that syntax is not valid for Openlayers. Maptiler should have a switch to number the tiles correctly (that is OSM-like). I prefer to hack gdal2tiles for it. See my extended answer.
    – AndreJ
    Feb 14, 2014 at 18:35
  • I see... I would actually be quite happy if I don't have to recreate the tiles... According to what you say, I would assume that using OpenLayers.Layer.TMS() instead of OpenLayers.Layer.OSM() might do the job, because it would use the OGC system instead of the OSM one? But the parameters are obviously different Feb 14, 2014 at 18:53
  • No, Layer.TMS() expects a service like WMS, which you do not have. Openlayers can not handle your tile naming, but leaflet does: gis.stackexchange.com/questions/66986/…
    – AndreJ
    Feb 14, 2014 at 19:08
  • Ok, I have modified GDAL2tiles.py, regenerated the tiles (available here: humadat.alwaysdata.net/tms/khorog/tiles_osm )and it works correctly in JOSM without the "y flip". But for some reason it doesn't display in OpenLayers henriod.info/khub2/khub2_new.html (base layer "Khorog high-res") What is weird is that Firebug seems to receive the tiles... Feb 15, 2014 at 7:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.