A few weeks ago, I was working on a project to create a Leaflet map with a custom GeoTIFF file. I did some research on how to integrate GeoTIFF into Leaflet, but it was challenging to find resources on this topic. After several days of searching, I finally discovered a solution. I decided to write this blog post to help others who want to use GeoTIFF files with Leaflet.
What is a GeoTIFF file?
Let’s start with an explanation of what a GeoTIFF file is. A GeoTIFF is a type of raster image file that contains geospatial information embedded within the file. It is a standard image file, but with added geolocation information, allowing it to be accurately placed on a map.
We can display GeoTIFF file information using Python libraries. I installed GDAL using Conda on Ubuntu 22.04 with the following command:
conda install -c conda-forge gdal
To verify the installation, run:
gdal --version
I downloaded an GeoTIFF file on geotiff samples.
When I run gdalinfo cea.tif
command on terminal, you should see following output:
Driver: GTiff/GeoTIFF
Files: cea.tif
Size is 514, 515
Coordinate System is:
PROJCRS["unnamed",
BASEGEOGCRS["NAD27",
DATUM["North American Datum 1927",
ELLIPSOID["Clarke 1866",6378206.4,294.978698213898,
LENGTHUNIT["metre",1]]],
PRIMEM["Greenwich",0,
ANGLEUNIT["degree",0.0174532925199433]],
ID["EPSG",4267]],
CONVERSION["Lambert Cylindrical Equal Area",
METHOD["Lambert Cylindrical Equal Area",
ID["EPSG",9835]],
PARAMETER["Latitude of 1st standard parallel",33.75,
ANGLEUNIT["degree",0.0174532925199433],
ID["EPSG",8823]],
PARAMETER["Longitude of natural origin",-117.333333333333,
ANGLEUNIT["degree",0.0174532925199433],
ID["EPSG",8802]],
PARAMETER["False easting",0,
LENGTHUNIT["metre",1],
ID["EPSG",8806]],
PARAMETER["False northing",0,
LENGTHUNIT["metre",1],
ID["EPSG",8807]]],
CS[Cartesian,2],
AXIS["easting",east,
ORDER[1],
LENGTHUNIT["metre",1,
ID["EPSG",9001]]],
AXIS["northing",north,
ORDER[2],
LENGTHUNIT["metre",1,
ID["EPSG",9001]]]]
Data axis to CRS axis mapping: 1,2
Origin = (-28493.166784412522247,4255884.543802191503346)
Pixel Size = (60.022136983193739,-60.022136983193739)
Metadata:
AREA_OR_POINT=Area
Image Structure Metadata:
INTERLEAVE=BAND
Corner Coordinates:
Upper Left ( -28493.167, 4255884.544) (117d38'27.05"W, 33d56'37.74"N)
Lower Left ( -28493.167, 4224973.143) (117d38'27.05"W, 33d39'53.81"N)
Upper Right ( 2358.212, 4255884.544) (117d18'28.38"W, 33d56'37.74"N)
Lower Right ( 2358.212, 4224973.143) (117d18'28.38"W, 33d39'53.81"N)
Center ( -13067.478, 4240428.844) (117d28'27.71"W, 33d48'15.38"N)
Band 1 Block=514x15 Type=Byte, ColorInterp=Gray
As you can see, there are lots of useful information.
Converting GeoTIFF to Map Tiles
Tiles are small, square images that represent a portion of a larger map. These tiles are typically organized in a grid pattern and are used to display maps at various zoom levels.
GeoTIFF files, especially large ones, can be very heavy and slow to load on the web. By converting a GeoTIFF to map tiles, the data is broken down into smaller, manageable pieces. This results in faster loading times and a more responsive map experience.
We can use a gdal2tiles.py
Python script to convert our GeoTIFF to map tiles. The script is part of the GDAL library.
gdal2tiles.py -z 0-22 -w leaflet cea.tif ./tiles/
-z 0-22
: It will create for zoom levels 0 through 22. Zoom level 0 is the entire world in a single tile, and higher zoom levels provide more detailed, smaller-area tiles. Zoom level 22 is very detailed, typically used for street-level maps.
-w leaflet
: This option specifies the type of web viewer for which the tiles are being generated.
cea.tif
: This is the input file.
./tiles/
: This is the output directory where the generated tiles will be stored.
Overlaying custom tiles onto Leaflet Map
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Adding Tiles Layer on Leaflet</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<style>
#map {
height: 100vh;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script>
// Initialize the map
var map = L.map('map', {
center: [33.80427100088687, -117.4753998353766],
zoom: 10,
minZoom: 0,
maxZoom: 15,
});
// Add a tile layer to the map (OpenStreetMap)
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution:
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
}).addTo(map);
// Overlay custom tiles (TMS)
var lyr = L.tileLayer("./tiles/{z}/{x}/{y}.png", {
tms: 1,
opacity: 0.7,
attribution: "",
minZoom: 0,
maxZoom: 15,
}).addTo(map);
</script>
</body>
</html>
This code sets up a basic Leaflet map that uses OpenStreetMap as a base layer and overlays custom tiles generated from cea.tif file. The custom tiles are semi-transparent, allowing the user to see both the base map and the overlay. ./tiles/{z}/{x}/{y}.png
points to the directory where the tiles are stored, with {z}
, {x}
, and {y}
representing the zoom level, and x and y coordinates of the tiles.
Here is the result:
Conclusion
It’s amazing how something that seems difficult at first can become easy with a little learning, isn’t it :)? I hope this post helps you overcome a small hurdle on your way to creating amazing maps.
Thank you for reading!