Skip to content

Commit

Permalink
[GDAL provider] Minimal support for GDT_Int8 of GDAL 3.7.0
Browse files Browse the repository at this point in the history
Fixes #50907

GDAL 3.7.0 brings GDT_Int8, which triggers compiler warnings
in QGIS due to those new enumeration values not being handled.

We do a minimal handling of them, by exposing them as QGIS Int16 rasters

A more ambitious fix would be to add proper Int8 support to QGIS.
  • Loading branch information
rouault authored and nyalldawson committed Jan 27, 2023
1 parent d33b875 commit 5986a80
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 0 deletions.
23 changes: 23 additions & 0 deletions src/core/providers/gdal/qgsgdalprovider.cpp
Expand Up @@ -1427,6 +1427,16 @@ double QgsGdalProvider::sample( const QgsPointXY &point, int band, bool *ok, con
const GDALDataType dataType {GDALGetRasterDataType( hBand )};
switch ( dataType )
{
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
case GDT_Int8:
{
int8_t tempVal{0};
err = GDALRasterIO( hBand, GF_Read, col, row, 1, 1,
&tempVal, 1, 1, dataType, 0, 0 );
value = static_cast<double>( tempVal );
break;
}
#endif
case GDT_Byte:
{
unsigned char tempVal{0};
Expand Down Expand Up @@ -3312,6 +3322,9 @@ void QgsGdalProvider::initBaseDataset()
case GDT_Unknown:
case GDT_TypeCount:
break;
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
case GDT_Int8:
#endif
case GDT_Byte:
case GDT_UInt16:
case GDT_Int16:
Expand All @@ -3335,6 +3348,12 @@ void QgsGdalProvider::initBaseDataset()
}
}

#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
if ( myGdalDataType == GDT_Int8 )
{
myGdalDataType = GDT_Int16;
}
#endif
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,5,0)
if ( myGdalDataType == GDT_Int64 || myGdalDataType == GDT_UInt64 )
{
Expand Down Expand Up @@ -3410,6 +3429,10 @@ bool QgsGdalProvider::write( void *data, int band, int width, int height, int xO
return false;
}
GDALDataType gdalDataType = GDALGetRasterDataType( rasterBand );
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
if ( gdalDataType == GDT_Int8 )
gdalDataType = GDT_Int16;
#endif
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,5,0)
if ( gdalDataType == GDT_Int64 || gdalDataType == GDT_UInt64 )
gdalDataType = GDT_Float64;
Expand Down
5 changes: 5 additions & 0 deletions src/core/providers/gdal/qgsgdalproviderbase.cpp
Expand Up @@ -152,6 +152,11 @@ Qgis::DataType QgsGdalProviderBase::dataTypeFromGdal( const GDALDataType gdalDat
{
switch ( gdalDataType )
{
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
case GDT_Int8:
// Promote to Int16 due to lack of native Qgis data type for Int8
return Qgis::DataType::Int16;
#endif
case GDT_Byte:
return Qgis::DataType::Byte;
case GDT_UInt16:
Expand Down
36 changes: 36 additions & 0 deletions tests/src/python/test_provider_gdal.py
Expand Up @@ -273,6 +273,42 @@ def testSanitizeVRT(self):

assert 'OverviewList' not in open(vrtfilename, 'rt').read()

@unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 7, 0), "GDAL 3.7.0 required")
def testInt8(self):
"""Test Int8 support"""

tmp_dir = QTemporaryDir()
tmpfile = os.path.join(tmp_dir.path(), 'testInt8.tif')
ds = gdal.GetDriverByName('GTiff').Create(tmpfile, 2, 2, 1, gdal.GDT_Int8)
ds.WriteRaster(0, 0, 2, 2, struct.pack('b' * 4, 1, 127, 0, -128))
ds = None

raster_layer = QgsRasterLayer(tmpfile, 'test')
self.assertTrue(raster_layer.isValid())
self.assertEqual(raster_layer.dataProvider().dataType(1), Qgis.Int16)

extent = raster_layer.extent()
block = raster_layer.dataProvider().block(1, extent, 2, 2)

full_content = [1, 127, 0, -128]
self.checkBlockContents(block, full_content)

pos = QgsPointXY(0, 0)
value_sample = raster_layer.dataProvider().sample(pos, 1)[0]
self.assertEqual(value_sample, full_content[0])

pos = QgsPointXY(1, 0)
value_sample = raster_layer.dataProvider().sample(pos, 1)[0]
self.assertEqual(value_sample, full_content[1])

pos = QgsPointXY(0, -1)
value_sample = raster_layer.dataProvider().sample(pos, 1)[0]
self.assertEqual(value_sample, full_content[2])

pos = QgsPointXY(1, -1)
value_sample = raster_layer.dataProvider().sample(pos, 1)[0]
self.assertEqual(value_sample, full_content[3])


if __name__ == '__main__':
unittest.main()

0 comments on commit 5986a80

Please sign in to comment.