Skip to content

Commit e4013c6

Browse files
authored
Merge pull request #14629 from rouault/GDALLoadEsriCLRAsRAT
Add GDALLoadEsriCLRAsRAT() to load Esri .clr files as RAT
2 parents 64131d3 + 59cfc5e commit e4013c6

4 files changed

Lines changed: 107 additions & 59 deletions

File tree

autotest/cpp/test_gdal.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6575,4 +6575,28 @@ TEST_F(test_gdal, GDALRasterBand_HasConflictingMaskSources)
65756575
}
65766576
}
65776577

6578+
TEST_F(test_gdal, GDALLoadEsriCLRAsRAT)
6579+
{
6580+
auto poRAT = GDALLoadEsriCLRAsRAT(GDRIVERS_DATA_DIR "ehdr/int16_rat.clr");
6581+
ASSERT_TRUE(poRAT != nullptr);
6582+
6583+
ASSERT_EQ(poRAT->GetColumnCount(), 4);
6584+
ASSERT_EQ(poRAT->GetRowCount(), 25);
6585+
6586+
ASSERT_STREQ(poRAT->GetNameOfCol(0), "Value");
6587+
ASSERT_STREQ(poRAT->GetNameOfCol(1), "Red");
6588+
ASSERT_STREQ(poRAT->GetNameOfCol(2), "Green");
6589+
ASSERT_STREQ(poRAT->GetNameOfCol(3), "Blue");
6590+
6591+
ASSERT_EQ(poRAT->GetValueAsInt(0, 0), -500);
6592+
ASSERT_EQ(poRAT->GetValueAsInt(0, 1), 127);
6593+
ASSERT_EQ(poRAT->GetValueAsInt(0, 2), 40);
6594+
ASSERT_EQ(poRAT->GetValueAsInt(0, 3), 65);
6595+
6596+
ASSERT_EQ(poRAT->GetValueAsInt(24, 0), 2000);
6597+
ASSERT_EQ(poRAT->GetValueAsInt(24, 1), 145);
6598+
ASSERT_EQ(poRAT->GetValueAsInt(24, 2), 97);
6599+
ASSERT_EQ(poRAT->GetValueAsInt(24, 3), 47);
6600+
}
6601+
65786602
} // namespace

frmts/raw/ehdrdataset.cpp

Lines changed: 27 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1532,54 +1532,26 @@ GDALDataset *EHdrDataset::Open(GDALOpenInfo *poOpenInfo, bool bFileSizeCheck)
15321532

15331533
// Only read the .clr for byte, int16 or uint16 bands.
15341534
if (nItemSize <= 2)
1535-
fp = VSIFOpenL(osCLRFilename.c_str(), "r");
1536-
else
1537-
fp = nullptr;
1538-
1539-
if (fp != nullptr)
15401535
{
1541-
std::shared_ptr<GDALRasterAttributeTable> poRat(
1542-
new GDALDefaultRasterAttributeTable());
1543-
poRat->CreateColumn("Value", GFT_Integer, GFU_Generic);
1544-
poRat->CreateColumn("Red", GFT_Integer, GFU_Red);
1545-
poRat->CreateColumn("Green", GFT_Integer, GFU_Green);
1546-
poRat->CreateColumn("Blue", GFT_Integer, GFU_Blue);
1547-
1548-
poDS->m_poColorTable.reset(new GDALColorTable());
1549-
1550-
bool bHasFoundNonCTValues = false;
1551-
int nRatRow = 0;
1552-
1553-
while (true)
1536+
auto poRAT = GDALLoadEsriCLRAsRAT(osCLRFilename.c_str());
1537+
if (poRAT && poRAT->GetColumnCount() == 4)
15541538
{
1555-
pszLine = CPLReadLineL(fp);
1556-
if (!pszLine)
1557-
break;
1558-
1559-
if (*pszLine == '#' || *pszLine == '!')
1560-
continue;
1539+
poDS->m_poColorTable = std::make_unique<GDALColorTable>();
15611540

1562-
char **papszValues =
1563-
CSLTokenizeString2(pszLine, "\t ", CSLT_HONOURSTRINGS);
1541+
bool bHasFoundNonCTValues = false;
15641542

1565-
if (CSLCount(papszValues) >= 4)
1543+
for (int iRow = 0; iRow < poRAT->GetRowCount(); ++iRow)
15661544
{
1567-
const int nIndex = atoi(papszValues[0]);
1568-
poRat->SetValue(nRatRow, 0, nIndex);
1569-
poRat->SetValue(nRatRow, 1, atoi(papszValues[1]));
1570-
poRat->SetValue(nRatRow, 2, atoi(papszValues[2]));
1571-
poRat->SetValue(nRatRow, 3, atoi(papszValues[3]));
1572-
nRatRow++;
1573-
1545+
const int nIndex = poRAT->GetValueAsInt(iRow, 0);
15741546
if (nIndex >= 0 && nIndex < 65536)
15751547
{
15761548
const GDALColorEntry oEntry = {
1577-
static_cast<short>(
1578-
std::clamp(atoi(papszValues[1]), 0, 255)), // Red
1579-
static_cast<short>(
1580-
std::clamp(atoi(papszValues[2]), 0, 255)), // Green
1581-
static_cast<short>(
1582-
std::clamp(atoi(papszValues[3]), 0, 255)), // Blue
1549+
static_cast<short>(std::clamp(
1550+
poRAT->GetValueAsInt(iRow, 1), 0, 255)), // Red
1551+
static_cast<short>(std::clamp(
1552+
poRAT->GetValueAsInt(iRow, 2), 0, 255)), // Green
1553+
static_cast<short>(std::clamp(
1554+
poRAT->GetValueAsInt(iRow, 3), 0, 255)), // Blue
15831555
255};
15841556

15851557
poDS->m_poColorTable->SetColorEntry(nIndex, &oEntry);
@@ -1591,32 +1563,28 @@ GDALDataset *EHdrDataset::Open(GDALOpenInfo *poOpenInfo, bool bFileSizeCheck)
15911563
// http://www.ngdc.noaa.gov/mgg/topo/elev/esri/clr/
15921564
// But, there's no way of representing them with GDAL color
15931565
// table model.
1594-
if (!bHasFoundNonCTValues)
1595-
CPLDebug("EHdr", "Ignoring color index : %d", nIndex);
1566+
CPLDebug("EHdr", "Ignoring color index : %d", nIndex);
15961567
bHasFoundNonCTValues = true;
1568+
break;
15971569
}
15981570
}
15991571

1600-
CSLDestroy(papszValues);
1601-
}
1602-
1603-
CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
1572+
if (bHasFoundNonCTValues)
1573+
{
1574+
poDS->m_poRAT.reset(poRAT.release());
1575+
}
16041576

1605-
if (bHasFoundNonCTValues)
1606-
{
1607-
poDS->m_poRAT.swap(poRat);
1608-
}
1577+
for (int i = 1; i <= poDS->nBands; i++)
1578+
{
1579+
EHdrRasterBand *poBand =
1580+
cpl::down_cast<EHdrRasterBand *>(poDS->GetRasterBand(i));
1581+
poBand->m_poColorTable = poDS->m_poColorTable;
1582+
poBand->m_poRAT = poDS->m_poRAT;
1583+
poBand->SetColorInterpretation(GCI_PaletteIndex);
1584+
}
16091585

1610-
for (int i = 1; i <= poDS->nBands; i++)
1611-
{
1612-
EHdrRasterBand *poBand =
1613-
cpl::down_cast<EHdrRasterBand *>(poDS->GetRasterBand(i));
1614-
poBand->m_poColorTable = poDS->m_poColorTable;
1615-
poBand->m_poRAT = poDS->m_poRAT;
1616-
poBand->SetColorInterpretation(GCI_PaletteIndex);
1586+
poDS->bCLRDirty = false;
16171587
}
1618-
1619-
poDS->bCLRDirty = false;
16201588
}
16211589

16221590
// Read statistics (.STX).

gcore/gdal_rat.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "cpl_error.h"
2828
#include "cpl_string.h"
2929
#include "cpl_vsi.h"
30+
#include "cpl_vsi_virtual.h"
3031

3132
#ifdef __clang__
3233
#pragma clang diagnostic push
@@ -3421,3 +3422,55 @@ void CPL_STDCALL GDALRATRemoveStatistics(GDALRasterAttributeTableH hRAT)
34213422

34223423
GDALRasterAttributeTable::FromHandle(hRAT)->RemoveStatistics();
34233424
}
3425+
3426+
/************************************************************************/
3427+
/* GDALLoadEsriCLRAsRAT() */
3428+
/************************************************************************/
3429+
3430+
/**
3431+
* \brief Load a Esri .clr as a RAT.
3432+
*
3433+
* @param pszFilename .clr filename
3434+
*
3435+
* @return a new RAT, or nullptr in case of error.
3436+
*
3437+
* @since GDAL 3.14
3438+
*/
3439+
std::unique_ptr<GDALRasterAttributeTable>
3440+
GDALLoadEsriCLRAsRAT(const char *pszFilename)
3441+
{
3442+
auto fp = VSIFilesystemHandler::OpenStatic(pszFilename, "rb");
3443+
if (!fp)
3444+
return nullptr;
3445+
3446+
auto poRAT = std::make_unique<GDALDefaultRasterAttributeTable>();
3447+
poRAT->CreateColumn("Value", GFT_Integer, GFU_Generic);
3448+
poRAT->CreateColumn("Red", GFT_Integer, GFU_Red);
3449+
poRAT->CreateColumn("Green", GFT_Integer, GFU_Green);
3450+
poRAT->CreateColumn("Blue", GFT_Integer, GFU_Blue);
3451+
3452+
int nRatRow = 0;
3453+
3454+
constexpr int MAX_LINE_SIZE = 1000; // Arbitary
3455+
while (const char *pszLine =
3456+
CPLReadLine2L(fp.get(), MAX_LINE_SIZE, nullptr))
3457+
{
3458+
if (*pszLine == '#' || *pszLine == '!')
3459+
continue;
3460+
3461+
const CPLStringList aosTokens(
3462+
CSLTokenizeString2(pszLine, "\t ", CSLT_HONOURSTRINGS));
3463+
3464+
if (aosTokens.size() >= 4)
3465+
{
3466+
const int nIndex = atoi(aosTokens[0]);
3467+
poRAT->SetValue(nRatRow, 0, nIndex);
3468+
poRAT->SetValue(nRatRow, 1, atoi(aosTokens[1]));
3469+
poRAT->SetValue(nRatRow, 2, atoi(aosTokens[2]));
3470+
poRAT->SetValue(nRatRow, 3, atoi(aosTokens[3]));
3471+
nRatRow++;
3472+
}
3473+
}
3474+
3475+
return poRAT;
3476+
}

gcore/gdal_rat.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,4 +586,7 @@ class CPL_DLL GDALDefaultRasterAttributeTable : public GDALRasterAttributeTable
586586
std::unique_ptr<GDALRasterAttributeTable>
587587
CPL_DLL GDALLoadVATDBF(const char *pszFilename);
588588

589+
std::unique_ptr<GDALRasterAttributeTable>
590+
CPL_DLL GDALLoadEsriCLRAsRAT(const char *pszFilename);
591+
589592
#endif /* ndef GDAL_RAT_H_INCLUDED */

0 commit comments

Comments
 (0)