[GIS] Convert TIF to PNG for Leaflet map

convertgeotiff-tiffleafletpng

I have a single-band, georeferenced .tif file that I would like to display on top of a Leaflet.js map, using the ImageOverlay function. Unfortunately, Leaflet seems only to accept PNG or JPG files, and I haven't been able to produce a PNG file that Leaflet will display.

The original .tif file is in EPSG:102022 and the pixel values are represented by floating-point 64-bit numbers (Float64). Here is a snippet from gdalinfo:

Origin = (-1253000.000000000000000,-3095000.000000000000000)
Pixel Size = (1000.000000000000000,-1000.000000000000000)
Metadata:
  AREA_OR_POINT=Area
Image Structure Metadata:
  COMPRESSION=LZW
  INTERLEAVE=BAND
Band 1 Block=2433x1 Type=Float64, ColorInterp=Gray
  Min=0.000 Max=28.907 
  Minimum=0.000, Maximum=28.907, Mean=0.574, StdDev=1.419
  NoData Value=-1.69999999999999994e+308
  Metadata:
    STATISTICS_MAXIMUM=28.906996389906
    STATISTICS_MEAN=0.57436288189673
    STATISTICS_MINIMUM=0.0004002906752851
    STATISTICS_STDDEV=1.4194311264403

I transformed the original image from EPSG:102022 to EPSG:4326 using gdalwarp, and that seems to have worked fine. However, when I try to convert the reprojected tif image to a PNG image, I get an error message that the data type has to be changed from Float64 to an unsigned 8 or 16-bit integer. I tried

gdal_translate -ot UInt16 -of PNG <infile> <outfile>

but for some reason it appears to lose a lot of resolution (when I look at in in QGIS) and the resulting PNG file will not display in Leaflet. I also tried an online converter which produced a PNG image that looked good in QGIS but wouldn't display in Leaflet. I can see the bounding box in the correct position on the Leaflet map, but there is just a question mark inside. My Leaflet code is standard, except for substituting a local file path for the URL:

var southWest = L.latLng(-37.0328788,12.7036709),
  northEast = L.latLng( -26.8167313,36.5804906),
  imageBounds = L.latLngBounds(southWest, northEast);
var imageUrl = '/<local_path_on_my_computer>/image.png';

L.imageOverlay(imageUrl, imageBounds).addTo(map);

I've tried lots of variations. I'd also like to be able to control the color scale in the png file and I'm not sure how to do that. I've seen some complicated suggestions using other software to produce tiled layers, but I'm hoping that there's a simpler solution, since this is just a single image.

I'd be grateful for any strategy suggestions.

Best Answer

For tricky (and scriptable) image manipulation, my tool of choice is ImageMagick.

It's not a particularly easy-to-learn tool, but it can do things like changing the bit depth of images, or convert from grayscale to a colour ramp, control the number of channels of the output file (RGB/greyscale/etc), or anything, really. With a bit of work, it should be able to do things like automatically trim the range of values from the GeoTIFF and map that to 8-bit channels.

Please note that ImageMagick (and GIMP, for this matter) strip the GeoTIFF information off the files. Use listgeo and geotifcp if you need to preserve that information.

Also, you mention

...and the resulting PNG file will not display in Leaflet

What happens if you try to load that file directly in your web browser? Also, double-check uppercase/lowercase filenames!