Skip to content

Commit

Permalink
Merge pull request #11760 from rouault/fix_11753
Browse files Browse the repository at this point in the history
STACIT: STAC 1.1 support
  • Loading branch information
rouault authored Jan 31, 2025
2 parents fe23c7b + 3bd2ec0 commit 86193bf
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 29 deletions.
53 changes: 53 additions & 0 deletions autotest/gdrivers/data/stacit/test_stac_1.1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"type": "Feature",
"stac_version": "1.1.0",
"stac_extensions": [
"https://stac-extensions.github.io/eo/v2.0.0/schema.json",
"https://stac-extensions.github.io/projection/v2.0.0/schema.json"
],
"id": "byte",
"geometry": null,
"properties": {
"datetime": "2021-07-19T10:57:30Z",
"proj:code": "EPSG:26711",
"proj:bbox": [
440720.000, 3750120.000,
441920.000, 3751320.000
],
"proj:transform": [
60,
0,
440720,
0,
-60,
3751320
]
},
"collection": "my_collection",
"assets": {
"metadata": {
"title": "Original XML metadata",
"type": "application/xml",
"roles": [
"metadata"
],
"href": "https://example.com/metadata.xml"
},
"B01": {
"title": "Band 1 (coastal)",
"type": "image/tiff; application=geotiff; profile=cloud-optimized",
"roles": [
"data"
],
"bands": [
{
"name": "B01",
"eo:common_name": "coastal",
"eo:center_wavelength": 0.4439,
"eo:full_width_half_max": 0.027
}
],
"href": "data/byte.tif"
}
}
}
25 changes: 25 additions & 0 deletions autotest/gdrivers/stacit.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,3 +361,28 @@ def test_stacit_single_feature(tmp_vsimem):
assert ds is not None
assert ds.RasterXSize == 20
assert ds.GetRasterBand(1).Checksum() == 4672


###############################################################################
# Test STAC 1.1


def test_stacit_stac_1_1(tmp_vsimem):

filename = str(tmp_vsimem / "feature.json")
with gdaltest.tempfile(
filename, open("data/stacit/test_stac_1.1.json", "rb").read()
):
ds = gdal.Open(filename)
assert ds is not None
assert ds.RasterXSize == 20
assert ds.GetSpatialRef().GetName() == "NAD27 / UTM zone 11N"
assert ds.GetGeoTransform() == pytest.approx(
[440720.0, 60.0, 0.0, 3751320.0, 0.0, -60.0], rel=1e-8
)
assert ds.GetRasterBand(1).GetMetadata() == {
"eo:center_wavelength": "0.4439",
"eo:full_width_half_max": "0.027",
}
assert ds.GetRasterBand(1).GetColorInterpretation() == gdal.GCI_CoastalBand
assert ds.GetRasterBand(1).Checksum() == 4672
82 changes: 53 additions & 29 deletions frmts/stacit/stacitdataset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ struct AssetSetByProjection
struct Asset
{
std::string osName{};
CPLJSONArray eoBands{};
CPLJSONArray bands{};
std::map<std::string, AssetSetByProjection> assets{};
};

Expand Down Expand Up @@ -123,10 +123,19 @@ int STACITDataset::Identify(GDALOpenInfo *poOpenInfo)
return pszHeader[0] == '{';
}

if (strstr(pszHeader, "\"stac_version\"") != nullptr &&
strstr(pszHeader, "\"proj:transform\"") != nullptr)
if (strstr(pszHeader, "\"stac_version\"") != nullptr)
{
return true;
int nTransformBBOXShapeCount = 0;
for (const char *pszItem :
{"\"proj:transform\"", "\"proj:bbox\"", "\"proj:shape\""})
{
if (strstr(pszHeader, pszItem))
nTransformBBOXShapeCount++;
}
if (nTransformBBOXShapeCount >= 2)
{
return true;
}
}

if (i == 0)
Expand Down Expand Up @@ -218,34 +227,44 @@ static void ParseAsset(const CPLJSONObject &jAsset,
return oProperties[pszName];
};

auto oProjEPSG = GetAssetOrFeatureProperty("proj:epsg");
std::string osProjUserString;
if (oProjEPSG.IsValid() && oProjEPSG.GetType() != CPLJSONObject::Type::Null)
const auto oProjCode = GetAssetOrFeatureProperty("proj:code");
if (oProjCode.IsValid() && oProjCode.GetType() != CPLJSONObject::Type::Null)
{
osProjUserString = "EPSG:" + oProjEPSG.ToString();
osProjUserString = oProjCode.ToString();
}
else
{
auto oProjWKT2 = GetAssetOrFeatureProperty("proj:wkt2");
if (oProjWKT2.IsValid() &&
oProjWKT2.GetType() == CPLJSONObject::Type::String)
const auto oProjEPSG = GetAssetOrFeatureProperty("proj:epsg");
if (oProjEPSG.IsValid() &&
oProjEPSG.GetType() != CPLJSONObject::Type::Null)
{
osProjUserString = oProjWKT2.ToString();
osProjUserString = "EPSG:" + oProjEPSG.ToString();
}
else
{
auto oProjPROJJSON = GetAssetOrFeatureProperty("proj:projjson");
if (oProjPROJJSON.IsValid() &&
oProjPROJJSON.GetType() == CPLJSONObject::Type::Object)
const auto oProjWKT2 = GetAssetOrFeatureProperty("proj:wkt2");
if (oProjWKT2.IsValid() &&
oProjWKT2.GetType() == CPLJSONObject::Type::String)
{
osProjUserString = oProjPROJJSON.ToString();
osProjUserString = oProjWKT2.ToString();
}
else
{
CPLDebug("STACIT",
"Skipping asset %s that lacks a valid CRS member",
osAssetName.c_str());
return;
const auto oProjPROJJSON =
GetAssetOrFeatureProperty("proj:projjson");
if (oProjPROJJSON.IsValid() &&
oProjPROJJSON.GetType() == CPLJSONObject::Type::Object)
{
osProjUserString = oProjPROJJSON.ToString();
}
else
{
CPLDebug("STACIT",
"Skipping asset %s that lacks a valid CRS member",
osAssetName.c_str());
return;
}
}
}
}
Expand Down Expand Up @@ -380,7 +399,9 @@ static void ParseAsset(const CPLJSONObject &jAsset,
{
Asset asset;
asset.osName = osAssetName;
asset.eoBands = jAsset.GetArray("eo:bands");
asset.bands = jAsset.GetArray("bands");
if (!asset.bands.IsValid())
asset.bands = jAsset.GetArray("eo:bands");

collection.assets[osAssetName] = std::move(asset);
}
Expand Down Expand Up @@ -584,15 +605,17 @@ bool STACITDataset::SetupDataset(
poVRTBand->SetColorInterpretation(eInterp);

// Set band properties
if (asset.eoBands.IsValid() &&
asset.eoBands.Size() == poItemDS->GetRasterCount())
if (asset.bands.IsValid() &&
asset.bands.Size() == poItemDS->GetRasterCount())
{
const auto &eoBand = asset.eoBands[i];
const auto osBandName = eoBand["name"].ToString();
const auto &band = asset.bands[i];
const auto osBandName = band["name"].ToString();
if (!osBandName.empty())
poVRTBand->SetDescription(osBandName.c_str());

const auto osCommonName = eoBand["common_name"].ToString();
auto osCommonName = band["eo:common_name"].ToString();
if (osCommonName.empty())
osCommonName = band["common_name"].ToString();
if (!osCommonName.empty())
{
const auto eInterpFromCommonName =
Expand All @@ -601,13 +624,14 @@ bool STACITDataset::SetupDataset(
poVRTBand->SetColorInterpretation(eInterpFromCommonName);
}

for (const auto &eoBandChild : eoBand.GetChildren())
for (const auto &bandChild : band.GetChildren())
{
const auto osChildName = eoBandChild.GetName();
if (osChildName != "name" && osChildName != "common_name")
const auto osChildName = bandChild.GetName();
if (osChildName != "name" && osChildName != "common_name" &&
osChildName != "eo:common_name")
{
poVRTBand->SetMetadataItem(osChildName.c_str(),
eoBandChild.ToString().c_str());
bandChild.ToString().c_str());
}
}
}
Expand Down

0 comments on commit 86193bf

Please sign in to comment.