The QuickMapsServices and OpenLayers plugins, as described in the Loading BaseMaps with the QuickMapServices plugin and Loading BaseMaps with the OpenLayers plugin recipes in Chapter 4, Data Exploration, are awesome as they put a reference layer in your map session. The one downside, however, is that it is a hassle to add new layers. So, if you come across or build your own Tile service and want to use it in QGIS, this recipe will let you use almost any Tile service.
You will need a web browser, text editor, and the URL of a web-based XYZ (sometimes called TMS) service—one that allows you to make requests without an API key. We're going to use the maps at http://www.opencyclemap.org/.
Viewing the JavaScript source (a good tool for this is Firebug, or other web-developer tools for the browser), we can view the source URLs for the tiles.
map.js and you'll see the layer definition:var cycle = new OpenLayers.Layer.OSM("OpenCycleMap",
["https://a.tile.thunderforest.com/cycle/${z}/${x}/${y}.png",
"https://b.tile.thunderforest.com/cycle/${z}/${x}/${y}.png",
"https://c.tile.thunderforest.com/cycle/${z}/${x}/${y}.png"],
{ displayOutsideMaxExtent: true,
attribution: cycleattrib, transitionEffect: 'resize'}
);<server name>/<layer>/<zoom>/<tile index X>/<tile index X>.<image format>
In this particular case, the Tile Index pattern is the TMS style; refer to http://www.maptiler.org/google-maps-coordinates-tile-bounds-projection/.
z, x, and y as variables. Save the file as opencyclemap.xml:<GDAL_WMS>
<Service name="TMS">
<ServerUrl>http://c.tile.thunderforest.com/cycle/${z}/${x}/${y}.png</ServerUrl>
</Service>
<DataWindow>
<UpperLeftX>-20037508.34</UpperLeftX>
<UpperLeftY>20037508.34</UpperLeftY>
<LowerRightX>20037508.34</LowerRightX>
<LowerRightY>-20037508.34</LowerRightY>
<TileLevel>18</TileLevel>
<TileCountX>1</TileCountX>
<TileCountY>1</TileCountY>
<YOrigin>top</YOrigin>
</DataWindow>
<Projection>EPSG:3785</Projection>
<BlockSizeX>256</BlockSizeX>
<BlockSizeY>256</BlockSizeY>
<BandsCount>3</BandsCount>
<Cache />
</GDAL_WMS>
The XML file defines the parameters of the service; however, because XYZ-style servers don't follow a standard, the URL pattern varies slightly for each server and the servers do not have a GetCapabilities function that describes available layers. By telling GDAL how to handle the URL, you are wrapping a nonstandard format into a typical GDAL layer, which QGIS can easily be loaded as a raster.
One additional tip when using Spherical Mercator (EPSG:3785) is that you can set a custom list of scales (Zoom Levels) in QGIS. The following set of scales can be loaded per QGIS project, and will change the dropdown at the bottom right. These scales match the scales that most servers will provide, so you get the best viewing experience:
scales.xml file that is provided:
This technique is not limited to just tile services. Many other formats that GDAL works with can be wrapped for easier usage in QGIS. This is a similar method to Virtual Raster Tables (VRT) layers mentioned in the Creating raster overviews (pyramids) recipe in Chapter 2, Data Management.
Lastly, you may ask why a new plugin using this method doesn't replace the OpenLayers plugin. Such an idea has been under discussion for a while; the key sticking point is that accessing some layers, such as Google, Bing, and so on, with this method may violate the Terms of Service as they do not keep the Copyright, Trademark, and Logo in the correct place. Also, caching and printing such layers may not be legal. In general, avoid using proprietary data when possible to reduce licensing issues.