GeoTIFF / georaster

Wrapper around Georeferenced Rasters like GeoTIFF and soon JPG and PNG that provides a standard interface
Apache License 2.0
81 stars 32 forks source link

Extract GeoTIFF metadata/tags in parseData #86

Open kandersolar opened 8 months ago

kandersolar commented 8 months ago

Is your feature request related to a problem? Please describe.

I am using code like this to construct Leaflet layers from GeoTIFF files:

    fetch(url)
      .then(response => response.arrayBuffer())
      .then(arrayBuffer => {
        parseGeoraster(arrayBuffer).then(georaster => {
          var layer = rasterToLayer(georaster);  // creates a GeoRasterLayer with color mapping
          layerControl.addOverlay(layer, name);
      });
    });

This works well. However, in addition to the raster data itself, I now want to access the metadata/tag key-value pairs embedded within GeoTIFF files. As far as I can tell, there is no way to access that information from the georaster object returned by parseGeoraster, except by re-parsing the original array buffer using geotiff.js. I'd rather not do that, to keep my code simpler and more efficient. It would be nice if I could just access it from what parseGeoraster returns instead.

Describe the solution you'd like Add a call to image.getGDALMetadata() somewhere in here: https://github.com/GeoTIFF/georaster/blob/master/src/parseData.js#L65

getGDALMetadata returns exactly the metadata I am trying to access, so I propose calling it and storing the value as a new field on parseData's result object.

I think the new field would then propagate out and be included in the object returned from parseGeoraster.

Describe alternatives you've considered I suppose instead of storing the results of image.getGDALMetadata(), the image itself could be stored, which might be more generally useful (all of its methods would then be available, instead of just getGDALMetadata).

Additional context In case I'm not using the correct terminology (I am new to GeoTIFFs), the key-value pairs I am talking about are shown in the Metadata section of gdalinfo's output. Here's an example, where I want to access the CREATION_DATE, AUTHOR etc fields:

$ gdalinfo example.tiff 
Driver: GTiff/GeoTIFF
Files: example.tiff
Size is 115, 48
Coordinate System is:
GEOGCRS["WGS 84",
    DATUM["World Geodetic System 1984",
        ELLIPSOID["WGS 84",6378137,298.257223563,
            LENGTHUNIT["metre",1]]],
    PRIMEM["Greenwich",0,
        ANGLEUNIT["degree",0.0174532925199433]],
    CS[ellipsoidal,2],
        AXIS["geodetic latitude (Lat)",north,
            ORDER[1],
            ANGLEUNIT["degree",0.0174532925199433]],
        AXIS["geodetic longitude (Lon)",east,
            ORDER[2],
            ANGLEUNIT["degree",0.0174532925199433]],
    USAGE[
        SCOPE["unknown"],
        AREA["World"],
        BBOX[-90,-180,90,180]],
    ID["EPSG",4326]]
Data axis to CRS axis mapping: 2,1
Origin = (-124.750000000000000,48.250000000000000)
Pixel Size = (0.500000000000000,-0.500000000000000)
Metadata:
  AREA_OR_POINT=Area
  CREATION_DATE=2023-12-21
  DESCRIPTION=A raster file representing some nifty geospatial dataset.
  AUTHOR=Abraham Lincoln
Image Structure Metadata:
  INTERLEAVE=BAND
Corner Coordinates:
Upper Left  (-124.7500000,  48.2500000) (124d45' 0.00"W, 48d15' 0.00"N)
Lower Left  (-124.7500000,  24.2500000) (124d45' 0.00"W, 24d15' 0.00"N)
Upper Right ( -67.2500000,  48.2500000) ( 67d15' 0.00"W, 48d15' 0.00"N)
Lower Right ( -67.2500000,  24.2500000) ( 67d15' 0.00"W, 24d15' 0.00"N)
Center      ( -96.0000000,  36.2500000) ( 96d 0' 0.00"W, 36d15' 0.00"N)
Band 1 Block=115x17 Type=Float32, ColorInterp=Gray
  NoData Value=-9999
DanielJDufour commented 8 months ago

hey, @kandersolar . Great question! I'll think on your proposal in the coming weeks, but wanted to let you know quick that you can access the geotiff via a "private" undocumented property on the GeoRaster object called "_geotiff", like

const georaster = parseGeoRaster(url);

const tiff = georaster._geotifff;
const img = await tiff.getImage();
img.getGDALMetadata();

I'd recommend locking your georaster version if you take this approach. I can't say if this property will exist on the next major release of georaster because it's an undocumented non-public property subject to change.

kandersolar commented 8 months ago

Thanks for pointing that out! I was loading from a pre-fetched ArrayBuffer, which I guess is why I didn't notice the _geotiff attribute (seems like it is only populated when parsing from URL?).

Using that approach does indeed work to get me the metadata I'm after. However, I then ran into other problems where the georaster object no longer had mins, maxs etc attributes, nor was I able to figure out how to calculate them myself with geoblaze. I also ran into trouble with using geoblaze.identify to extract pixel values.

Here is a slimmed-down version of what I am trying to run:

    const url = window.location.origin + "/geotiffs/" + filename;
    const georaster = await parseGeoraster(url, {}, true);
    const tiff = georaster._geotiff;
    const img = await tiff.getImage();

    console.log(img.getGDALMetadata());  // works
    console.log(georaster.mins); // undefined
    console.log(georaster.maxs); // undefined
    console.log(georaster.ranges); // undefined

Any hints what I am doing wrong?

DanielJDufour commented 8 months ago

Hey, that's a good catch. You're not doing anything wrong per se. It's just that the API for GeoRaster definitely needs a refresh with more customizability. I'm working on a new major version, but can't say when that would be done.

The original logic behind not calculating stats when loaded from a url was to avoid situations where we tried to calculate stats on really large geotiffs, potentially fetching hundreds of megabytes.

If you want to calculate stats, you could use geoblaze like:

import geoblaze from "geoblaze";

const stats = await geoblaze.stats("https://example.org/imagery.tif", undefined, { stats: ["max", "min", "range"] });

Feel free to create an issue on https://github.com/GeoTIFF/geoblaze/issues regarding the identify problem.

I should mention that if you prefer not to use geoblaze, you could use: https://github.com/geotiff/geotiff-stats

Lastly, I don't think we have any test data on https://github.com/geotiff/test-data where the gdal metadata includes AUTHOR and CREATION_DATE. Would you be open to contributing your geotiff to https://github.com/geotiff/test-data? That'll help increase the visibility of your test case in the ecosystem of libraries that use this test data.