Skip to content

Commit 1ef346e

Browse files
committed
Zarr classic dataset: make SetScale(), SetOffset() work on multi-band datasets
1 parent ffb4c4b commit 1ef346e

3 files changed

Lines changed: 196 additions & 25 deletions

File tree

autotest/gdrivers/zarr_driver.py

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9518,3 +9518,99 @@ def test_zarr_setnodatavalue_uint64_multiband_different(tmp_vsimem):
95189518
ds.GetRasterBand(1).SetNoDataValueAsUInt64(0)
95199519
with pytest.raises(Exception, match="Not all bands have the same nodata value"):
95209520
ds.Close()
9521+
9522+
9523+
###############################################################################
9524+
9525+
9526+
@gdaltest.enable_exceptions()
9527+
def test_zarr_setscale_multiband_ok(tmp_path):
9528+
9529+
ds = gdal.GetDriverByName("Zarr").Create(
9530+
tmp_path / "test.zarr", 1, 1, 2, gdal.GDT_Byte
9531+
)
9532+
ds.GetRasterBand(1).SetScale(0.5)
9533+
assert ds.GetRasterBand(1).GetScale() == 0.5
9534+
ds.GetRasterBand(2).SetScale(0.5)
9535+
ds.Close()
9536+
9537+
ds = gdal.Open(tmp_path / "test.zarr")
9538+
assert ds.GetRasterBand(1).GetScale() == 0.5
9539+
assert ds.GetRasterBand(2).GetScale() == 0.5
9540+
9541+
9542+
###############################################################################
9543+
9544+
9545+
@gdaltest.enable_exceptions()
9546+
def test_zarr_setscale_multiband_only_one_set(tmp_vsimem):
9547+
9548+
ds = gdal.GetDriverByName("Zarr").Create(
9549+
tmp_vsimem / "test.zarr", 1, 1, 2, gdal.GDT_Byte
9550+
)
9551+
ds.GetRasterBand(1).SetScale(0.5)
9552+
with pytest.raises(Exception, match="Not all bands have the same scale value"):
9553+
ds.Close()
9554+
9555+
9556+
###############################################################################
9557+
9558+
9559+
@gdaltest.enable_exceptions()
9560+
def test_zarr_setscale_multiband_different(tmp_vsimem):
9561+
9562+
ds = gdal.GetDriverByName("Zarr").Create(
9563+
tmp_vsimem / "test.zarr", 1, 1, 2, gdal.GDT_Byte
9564+
)
9565+
ds.GetRasterBand(1).SetScale(0.5)
9566+
ds.GetRasterBand(1).SetScale(1)
9567+
with pytest.raises(Exception, match="Not all bands have the same scale value"):
9568+
ds.Close()
9569+
9570+
9571+
###############################################################################
9572+
9573+
9574+
@gdaltest.enable_exceptions()
9575+
def test_zarr_setoffset_multiband_ok(tmp_path):
9576+
9577+
ds = gdal.GetDriverByName("Zarr").Create(
9578+
tmp_path / "test.zarr", 1, 1, 2, gdal.GDT_Byte
9579+
)
9580+
ds.GetRasterBand(1).SetOffset(0.5)
9581+
assert ds.GetRasterBand(1).GetOffset() == 0.5
9582+
ds.GetRasterBand(2).SetOffset(0.5)
9583+
ds.Close()
9584+
9585+
ds = gdal.Open(tmp_path / "test.zarr")
9586+
assert ds.GetRasterBand(1).GetOffset() == 0.5
9587+
assert ds.GetRasterBand(2).GetOffset() == 0.5
9588+
9589+
9590+
###############################################################################
9591+
9592+
9593+
@gdaltest.enable_exceptions()
9594+
def test_zarr_setoffset_multiband_only_one_set(tmp_vsimem):
9595+
9596+
ds = gdal.GetDriverByName("Zarr").Create(
9597+
tmp_vsimem / "test.zarr", 1, 1, 2, gdal.GDT_Byte
9598+
)
9599+
ds.GetRasterBand(1).SetOffset(0.5)
9600+
with pytest.raises(Exception, match="Not all bands have the same offset value"):
9601+
ds.Close()
9602+
9603+
9604+
###############################################################################
9605+
9606+
9607+
@gdaltest.enable_exceptions()
9608+
def test_zarr_setoffset_multiband_different(tmp_vsimem):
9609+
9610+
ds = gdal.GetDriverByName("Zarr").Create(
9611+
tmp_vsimem / "test.zarr", 1, 1, 2, gdal.GDT_Byte
9612+
)
9613+
ds.GetRasterBand(1).SetOffset(0.5)
9614+
ds.GetRasterBand(1).SetOffset(1)
9615+
with pytest.raises(Exception, match="Not all bands have the same offset value"):
9616+
ds.Close()

frmts/zarr/zarr.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ class ZarrRasterBand final : public GDALRasterBand
136136
std::optional<double> m_dfNoData{};
137137
std::optional<uint64_t> m_nNoDataUInt64{};
138138
std::optional<int64_t> m_nNoDataInt64{};
139+
std::optional<double> m_dfOffset{};
140+
std::optional<double> m_dfScale{};
139141

140142
protected:
141143
CPLErr IReadBlock(int nBlockXOff, int nBlockYOff, void *pData) override;
@@ -1142,9 +1144,11 @@ class ZarrArray CPL_NON_FINAL : public GDALPamMDArray
11421144
double GetScale(bool *pbHasScale,
11431145
GDALDataType *peStorageType) const override;
11441146

1145-
bool SetOffset(double dfOffset, GDALDataType eStorageType) override;
1147+
bool SetOffset(double dfOffset,
1148+
GDALDataType eStorageType = GDT_Unknown) override;
11461149

1147-
bool SetScale(double dfScale, GDALDataType eStorageType) override;
1150+
bool SetScale(double dfScale,
1151+
GDALDataType eStorageType = GDT_Unknown) override;
11481152

11491153
std::vector<std::shared_ptr<GDALMDArray>>
11501154
GetCoordinateVariables() const override;

frmts/zarr/zarrdriver.cpp

Lines changed: 94 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1524,18 +1524,17 @@ CPLErr ZarrDataset::FlushCache(bool bAtClosing)
15241524
auto poFirstBand = cpl::down_cast<ZarrRasterBand *>(papoBands[0]);
15251525
if (poFirstBand->m_dfNoData.has_value())
15261526
{
1527-
bool bSameNoDataValue = true;
1528-
for (int i = 1; bSameNoDataValue && i < nBands; ++i)
1527+
bool bSameValue = true;
1528+
for (int i = 1; bSameValue && i < nBands; ++i)
15291529
{
15301530
auto poBand = cpl::down_cast<ZarrRasterBand *>(papoBands[i]);
1531-
bSameNoDataValue =
1532-
poBand->m_dfNoData.has_value() &&
1533-
((std::isnan(poFirstBand->m_dfNoData.value()) &&
1534-
std::isnan(poBand->m_dfNoData.value())) ||
1535-
(poFirstBand->m_dfNoData.value() ==
1536-
poBand->m_dfNoData.value()));
1531+
bSameValue = poBand->m_dfNoData.has_value() &&
1532+
((std::isnan(poFirstBand->m_dfNoData.value()) &&
1533+
std::isnan(poBand->m_dfNoData.value())) ||
1534+
(poFirstBand->m_dfNoData.value() ==
1535+
poBand->m_dfNoData.value()));
15371536
}
1538-
if (!bSameNoDataValue)
1537+
if (!bSameValue)
15391538
{
15401539
CPLError(CE_Failure, CPLE_NotSupported,
15411540
"Not all bands have the same nodata value. It will be "
@@ -1551,15 +1550,15 @@ CPLErr ZarrDataset::FlushCache(bool bAtClosing)
15511550
}
15521551
else if (poFirstBand->m_nNoDataInt64.has_value())
15531552
{
1554-
bool bSameNoDataValue = true;
1555-
for (int i = 1; bSameNoDataValue && i < nBands; ++i)
1553+
bool bSameValue = true;
1554+
for (int i = 1; bSameValue && i < nBands; ++i)
15561555
{
15571556
auto poBand = cpl::down_cast<ZarrRasterBand *>(papoBands[i]);
1558-
bSameNoDataValue = poBand->m_nNoDataInt64.has_value() &&
1559-
poFirstBand->m_nNoDataInt64.value() ==
1560-
poBand->m_nNoDataInt64.value();
1557+
bSameValue = poBand->m_nNoDataInt64.has_value() &&
1558+
poFirstBand->m_nNoDataInt64.value() ==
1559+
poBand->m_nNoDataInt64.value();
15611560
}
1562-
if (!bSameNoDataValue)
1561+
if (!bSameValue)
15631562
{
15641563
CPLError(CE_Failure, CPLE_NotSupported,
15651564
"Not all bands have the same nodata value. It will be "
@@ -1575,15 +1574,15 @@ CPLErr ZarrDataset::FlushCache(bool bAtClosing)
15751574
}
15761575
else if (poFirstBand->m_nNoDataUInt64.has_value())
15771576
{
1578-
bool bSameNoDataValue = true;
1579-
for (int i = 1; bSameNoDataValue && i < nBands; ++i)
1577+
bool bSameValue = true;
1578+
for (int i = 1; bSameValue && i < nBands; ++i)
15801579
{
15811580
auto poBand = cpl::down_cast<ZarrRasterBand *>(papoBands[i]);
1582-
bSameNoDataValue = poBand->m_nNoDataUInt64.has_value() &&
1583-
poFirstBand->m_nNoDataUInt64.value() ==
1584-
poBand->m_nNoDataUInt64.value();
1581+
bSameValue = poBand->m_nNoDataUInt64.has_value() &&
1582+
poFirstBand->m_nNoDataUInt64.value() ==
1583+
poBand->m_nNoDataUInt64.value();
15851584
}
1586-
if (!bSameNoDataValue)
1585+
if (!bSameValue)
15871586
{
15881587
CPLError(CE_Failure, CPLE_NotSupported,
15891588
"Not all bands have the same nodata value. It will be "
@@ -1598,6 +1597,54 @@ CPLErr ZarrDataset::FlushCache(bool bAtClosing)
15981597
}
15991598
}
16001599

1600+
if (poFirstBand->m_dfOffset.has_value())
1601+
{
1602+
bool bSameValue = true;
1603+
for (int i = 1; bSameValue && i < nBands; ++i)
1604+
{
1605+
auto poBand = cpl::down_cast<ZarrRasterBand *>(papoBands[i]);
1606+
bSameValue = poBand->m_dfOffset.has_value() &&
1607+
poFirstBand->m_dfOffset.value() ==
1608+
poBand->m_dfOffset.value();
1609+
}
1610+
if (!bSameValue)
1611+
{
1612+
CPLError(CE_Failure, CPLE_NotSupported,
1613+
"Not all bands have the same offset value. It will be "
1614+
"ignored as the array can only have a single offset "
1615+
"value for all bands.");
1616+
eErr = CE_Failure;
1617+
}
1618+
else
1619+
{
1620+
m_poSingleArray->SetOffset(poFirstBand->m_dfOffset.value());
1621+
}
1622+
}
1623+
1624+
if (poFirstBand->m_dfScale.has_value())
1625+
{
1626+
bool bSameValue = true;
1627+
for (int i = 1; bSameValue && i < nBands; ++i)
1628+
{
1629+
auto poBand = cpl::down_cast<ZarrRasterBand *>(papoBands[i]);
1630+
bSameValue =
1631+
poBand->m_dfScale.has_value() &&
1632+
poFirstBand->m_dfScale.value() == poBand->m_dfScale.value();
1633+
}
1634+
if (!bSameValue)
1635+
{
1636+
CPLError(CE_Failure, CPLE_NotSupported,
1637+
"Not all bands have the same scale value. It will be "
1638+
"ignored as the array can only have a single scale "
1639+
"value for all bands.");
1640+
eErr = CE_Failure;
1641+
}
1642+
else
1643+
{
1644+
m_poSingleArray->SetScale(poFirstBand->m_dfScale.value());
1645+
}
1646+
}
1647+
16011648
bool bFoundColorInterp = false;
16021649
for (int i = 0; i < nBands; ++i)
16031650
{
@@ -1985,6 +2032,12 @@ CPLErr ZarrRasterBand::SetNoDataValueAsUInt64(uint64_t nNoData)
19852032

19862033
double ZarrRasterBand::GetOffset(int *pbSuccess)
19872034
{
2035+
if (m_dfOffset.has_value())
2036+
{
2037+
if (pbSuccess)
2038+
*pbSuccess = true;
2039+
return m_dfOffset.value();
2040+
}
19882041
bool bHasValue = false;
19892042
double dfRet = m_poArray->GetOffset(&bHasValue);
19902043
if (pbSuccess)
@@ -1998,7 +2051,13 @@ double ZarrRasterBand::GetOffset(int *pbSuccess)
19982051

19992052
CPLErr ZarrRasterBand::SetOffset(double dfNewOffset)
20002053
{
2001-
return m_poArray->SetOffset(dfNewOffset) ? CE_None : CE_Failure;
2054+
auto poGDS = cpl::down_cast<ZarrDataset *>(poDS);
2055+
if (!poGDS->m_poSingleArray)
2056+
{
2057+
return m_poArray->SetOffset(dfNewOffset) ? CE_None : CE_Failure;
2058+
}
2059+
m_dfOffset = dfNewOffset;
2060+
return CE_None;
20022061
}
20032062

20042063
/************************************************************************/
@@ -2007,6 +2066,12 @@ CPLErr ZarrRasterBand::SetOffset(double dfNewOffset)
20072066

20082067
double ZarrRasterBand::GetScale(int *pbSuccess)
20092068
{
2069+
if (m_dfScale.has_value())
2070+
{
2071+
if (pbSuccess)
2072+
*pbSuccess = true;
2073+
return m_dfScale.value();
2074+
}
20102075
bool bHasValue = false;
20112076
double dfRet = m_poArray->GetScale(&bHasValue);
20122077
if (pbSuccess)
@@ -2020,7 +2085,13 @@ double ZarrRasterBand::GetScale(int *pbSuccess)
20202085

20212086
CPLErr ZarrRasterBand::SetScale(double dfNewScale)
20222087
{
2023-
return m_poArray->SetScale(dfNewScale) ? CE_None : CE_Failure;
2088+
auto poGDS = cpl::down_cast<ZarrDataset *>(poDS);
2089+
if (!poGDS->m_poSingleArray)
2090+
{
2091+
return m_poArray->SetScale(dfNewScale) ? CE_None : CE_Failure;
2092+
}
2093+
m_dfScale = dfNewScale;
2094+
return CE_None;
20242095
}
20252096

20262097
/************************************************************************/

0 commit comments

Comments
 (0)