Skip to content

Commit 0f16eb8

Browse files
committed
[GDAL provider] Expose GDAL mask band as a pseudo alpha band.
Some TIFF formulations, for example RGB TIFF with JPEG YCbCr compression, cannot include a regular alpha band and instead use the GDAL mask band mechanism. Such mask bands were ignored up to now. Now expose them as if they were alpha bands.
1 parent 66888fe commit 0f16eb8

File tree

4 files changed

+75
-13
lines changed

4 files changed

+75
-13
lines changed

src/providers/gdal/qgsgdalprovider.cpp

+45-13
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,10 @@ QString QgsGdalProvider::metadata()
310310
}
311311

312312
}
313+
if ( mMaskBandExposedAsAlpha )
314+
{
315+
myMetadata += "<p class=\"glossy\">" + tr( "Mask band (exposed as alpha band)" ) + "</p>\n";
316+
}
313317

314318
// end my added code
315319

@@ -406,7 +410,7 @@ void QgsGdalProvider::readBlock( int bandNo, int xBlock, int yBlock, void *block
406410

407411
//QgsDebugMsg( "yBlock = " + QString::number( yBlock ) );
408412

409-
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, bandNo );
413+
GDALRasterBandH myGdalBand = getBand( bandNo );
410414
//GDALReadBlock( myGdalBand, xBlock, yBlock, block );
411415

412416
// We have to read with correct data type consistent with other readBlock functions
@@ -584,7 +588,7 @@ void QgsGdalProvider::readBlock( int bandNo, QgsRectangle const & extent, int p
584588
QgsDebugMsg( QString( "Couldn't allocate temporary buffer of %1 bytes" ).arg( dataSize * tmpWidth * tmpHeight ) );
585589
return;
586590
}
587-
GDALRasterBandH gdalBand = GDALGetRasterBand( mGdalDataset, bandNo );
591+
GDALRasterBandH gdalBand = getBand( bandNo );
588592
GDALDataType type = ( GDALDataType )mGdalDataType.at( bandNo - 1 );
589593
CPLErrorReset();
590594

@@ -1055,6 +1059,9 @@ int QgsGdalProvider::capabilities() const
10551059

10561060
Qgis::DataType QgsGdalProvider::sourceDataType( int bandNo ) const
10571061
{
1062+
if ( mMaskBandExposedAsAlpha && bandNo == GDALGetRasterCount( mGdalDataset ) + 1 )
1063+
return dataTypeFromGdal( GDT_Byte );
1064+
10581065
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, bandNo );
10591066
GDALDataType myGdalDataType = GDALGetRasterDataType( myGdalBand );
10601067
Qgis::DataType myDataType = dataTypeFromGdal( myGdalDataType );
@@ -1094,14 +1101,17 @@ Qgis::DataType QgsGdalProvider::sourceDataType( int bandNo ) const
10941101

10951102
Qgis::DataType QgsGdalProvider::dataType( int bandNo ) const
10961103
{
1104+
if ( mMaskBandExposedAsAlpha && bandNo == GDALGetRasterCount( mGdalDataset ) + 1 )
1105+
return dataTypeFromGdal( GDT_Byte );
1106+
10971107
if ( bandNo <= 0 || bandNo > mGdalDataType.count() ) return Qgis::UnknownDataType;
10981108

10991109
return dataTypeFromGdal( mGdalDataType[bandNo-1] );
11001110
}
11011111

11021112
double QgsGdalProvider::bandScale( int bandNo ) const
11031113
{
1104-
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, bandNo );
1114+
GDALRasterBandH myGdalBand = getBand( bandNo );
11051115
int bGotScale;
11061116
double myScale = GDALGetRasterScale( myGdalBand, &bGotScale );
11071117
if ( bGotScale )
@@ -1112,7 +1122,7 @@ double QgsGdalProvider::bandScale( int bandNo ) const
11121122

11131123
double QgsGdalProvider::bandOffset( int bandNo ) const
11141124
{
1115-
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, bandNo );
1125+
GDALRasterBandH myGdalBand = getBand( bandNo );
11161126
int bGotOffset;
11171127
double myOffset = GDALGetRasterOffset( myGdalBand, &bGotOffset );
11181128
if ( bGotOffset )
@@ -1124,13 +1134,15 @@ double QgsGdalProvider::bandOffset( int bandNo ) const
11241134
int QgsGdalProvider::bandCount() const
11251135
{
11261136
if ( mGdalDataset )
1127-
return GDALGetRasterCount( mGdalDataset );
1137+
return GDALGetRasterCount( mGdalDataset ) + ( mMaskBandExposedAsAlpha ? 1 : 0 );
11281138
else
11291139
return 1;
11301140
}
11311141

11321142
int QgsGdalProvider::colorInterpretation( int bandNo ) const
11331143
{
1144+
if ( mMaskBandExposedAsAlpha && bandNo == GDALGetRasterCount( mGdalDataset ) + 1 )
1145+
return colorInterpretationFromGdal( GCI_AlphaBand );
11341146
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, bandNo );
11351147
return colorInterpretationFromGdal( GDALGetRasterColorInterpretation( myGdalBand ) );
11361148
}
@@ -1229,7 +1241,7 @@ bool QgsGdalProvider::hasHistogram( int bandNo,
12291241

12301242
QgsDebugMsg( "Looking for GDAL histogram" );
12311243

1232-
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, bandNo );
1244+
GDALRasterBandH myGdalBand = getBand( bandNo );
12331245
if ( ! myGdalBand )
12341246
{
12351247
return false;
@@ -1315,7 +1327,7 @@ QgsRasterHistogram QgsGdalProvider::histogram( int bandNo,
13151327

13161328
QgsDebugMsg( "Computing GDAL histogram" );
13171329

1318-
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, bandNo );
1330+
GDALRasterBandH myGdalBand = getBand( bandNo );
13191331

13201332
int bApproxOK = false;
13211333
if ( sampleSize > 0 )
@@ -2204,7 +2216,7 @@ bool QgsGdalProvider::hasStatistics( int bandNo,
22042216

22052217
QgsDebugMsg( "Looking for GDAL statistics" );
22062218

2207-
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, bandNo );
2219+
GDALRasterBandH myGdalBand = getBand( bandNo );
22082220
if ( ! myGdalBand )
22092221
{
22102222
return false;
@@ -2298,7 +2310,7 @@ QgsRasterBandStats QgsGdalProvider::bandStatistics( int bandNo, int stats, const
22982310
}
22992311

23002312
QgsDebugMsg( "Using GDAL statistics." );
2301-
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, bandNo );
2313+
GDALRasterBandH myGdalBand = getBand( bandNo );
23022314

23032315
//int bApproxOK = false; //as we asked for stats, don't get approx values
23042316
// GDAL does not have sample size parameter in API, just bApproxOK or not,
@@ -2551,7 +2563,8 @@ void QgsGdalProvider::initBaseDataset()
25512563
// Determine the nodata value and data type
25522564
//
25532565
//mValidNoDataValue = true;
2554-
for ( int i = 1; i <= GDALGetRasterCount( mGdalBaseDataset ); i++ )
2566+
const int bandCount = GDALGetRasterCount( mGdalBaseDataset );
2567+
for ( int i = 1; i <= bandCount; i++ )
25552568
{
25562569
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, i );
25572570
GDALDataType myGdalDataType = GDALGetRasterDataType( myGdalBand );
@@ -2657,6 +2670,18 @@ void QgsGdalProvider::initBaseDataset()
26572670
//QgsDebugMsg( QString( "mInternalNoDataValue[%1] = %2" ).arg( i - 1 ).arg( mInternalNoDataValue[i-1] ) );
26582671
}
26592672

2673+
// Check if the dataset has a mask band, that applies to the whole dataset
2674+
// If so then expose it as an alpha band.
2675+
int nMaskFlags = GDALGetMaskFlags( myGDALBand );
2676+
if (( nMaskFlags == 0 && bandCount == 1 ) || nMaskFlags == GMF_PER_DATASET )
2677+
{
2678+
mMaskBandExposedAsAlpha = true;
2679+
mSrcNoDataValue.append( std::numeric_limits<double>::quiet_NaN() );
2680+
mSrcHasNoDataValue.append( false );
2681+
mUseSrcNoDataValue.append( false );
2682+
mGdalDataType.append( GDT_Byte );
2683+
}
2684+
26602685
mValid = true;
26612686
}
26622687

@@ -2720,8 +2745,7 @@ bool QgsGdalProvider::write( void* data, int band, int width, int height, int xO
27202745
{
27212746
return false;
27222747
}
2723-
2724-
GDALRasterBandH rasterBand = GDALGetRasterBand( mGdalDataset, band );
2748+
GDALRasterBandH rasterBand = getBand( band );
27252749
if ( !rasterBand )
27262750
{
27272751
return false;
@@ -2736,7 +2760,7 @@ bool QgsGdalProvider::setNoDataValue( int bandNo, double noDataValue )
27362760
return false;
27372761
}
27382762

2739-
GDALRasterBandH rasterBand = GDALGetRasterBand( mGdalDataset, bandNo );
2763+
GDALRasterBandH rasterBand = getBand( bandNo );
27402764
CPLErrorReset();
27412765
CPLErr err = GDALSetRasterNoDataValue( rasterBand, noDataValue );
27422766
if ( err != CPLE_None )
@@ -2962,6 +2986,14 @@ bool QgsGdalProvider::setEditable( bool enabled )
29622986
return true;
29632987
}
29642988

2989+
GDALRasterBandH QgsGdalProvider::getBand( int bandNo ) const
2990+
{
2991+
if ( mMaskBandExposedAsAlpha && bandNo == GDALGetRasterCount( mGdalDataset ) + 1 )
2992+
return GDALGetMaskBand( GDALGetRasterBand( mGdalDataset, 1 ) );
2993+
else
2994+
return GDALGetRasterBand( mGdalDataset, bandNo );
2995+
}
2996+
29652997
// pyramids resampling
29662998

29672999
// see http://www.gdal.org/gdaladdo.html

src/providers/gdal/qgsgdalprovider.h

+6
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,12 @@ class QgsGdalProvider : public QgsRasterDataProvider, QgsGdalProviderBase
211211

212212
//! \brief sublayers list saved for subsequent access
213213
QStringList mSubLayers;
214+
215+
//! Whether a per-dataset mask band is exposed as an alpha band for the point of view of the rest of the application.
216+
bool mMaskBandExposedAsAlpha = false;
217+
218+
//! Wrapper for GDALGetRasterBand() that takes into account mMaskBandExposedAsAlpha.
219+
GDALRasterBandH getBand( int bandNo ) const;
214220
};
215221

216222
#endif

tests/src/providers/testqgsgdalprovider.cpp

+24
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class TestQgsGdalProvider : public QObject
4848
void noData();
4949
void invalidNoDataInSourceIgnored();
5050
void isRepresentableValue();
51+
void mask();
5152

5253
private:
5354
QString mTestDataDir;
@@ -196,5 +197,28 @@ void TestQgsGdalProvider::isRepresentableValue()
196197
QCOMPARE( QgsRaster::isRepresentableValue( std::numeric_limits<double>::max(), Qgis::Float64 ), true );
197198
}
198199

200+
void TestQgsGdalProvider::mask()
201+
{
202+
QString raster = QStringLiteral( TEST_DATA_DIR ) + "/raster/rgb_with_mask.tif";
203+
QgsDataProvider* provider = QgsProviderRegistry::instance()->provider( QStringLiteral( "gdal" ), raster );
204+
QVERIFY( provider->isValid() );
205+
QgsRasterDataProvider* rp = dynamic_cast< QgsRasterDataProvider* >( provider );
206+
QVERIFY( rp );
207+
if ( rp )
208+
{
209+
QCOMPARE( rp->bandCount(), 4 );
210+
QCOMPARE( rp->dataType( 4 ), Qgis::Byte );
211+
QCOMPARE( rp->sourceDataType( 4 ), Qgis::Byte );
212+
QCOMPARE( rp->colorInterpretation( 4 ), static_cast<int>( QgsRaster::AlphaBand ) );
213+
QCOMPARE( rp->bandScale( 4 ), 1.0 );
214+
QCOMPARE( rp->bandOffset( 4 ), 0.0 );
215+
QgsRectangle rect( 0, 0, 162, 150 );
216+
QgsRasterBlock* block = rp->block( 4, rect, 162, 150 );
217+
QVERIFY( block );
218+
delete block;
219+
}
220+
delete provider;
221+
}
222+
199223
QGSTEST_MAIN( TestQgsGdalProvider )
200224
#include "testqgsgdalprovider.moc"
126 KB
Binary file not shown.

0 commit comments

Comments
 (0)