@@ -720,9 +720,6 @@ bool QgsGdalProvider::canDoResampling(
720
720
int bufferWidthPix,
721
721
int bufferHeightPix )
722
722
{
723
- if ( !mProviderResamplingEnabled )
724
- return false ;
725
-
726
723
QMutexLocker locker ( mpMutex );
727
724
if ( !initIfNeeded () )
728
725
return false ;
@@ -816,6 +813,7 @@ bool QgsGdalProvider::readBlock( int bandNo, QgsRectangle const &reqExtent, int
816
813
const double srcXRes = mGeoTransform [1 ];
817
814
const double srcYRes = mGeoTransform [5 ]; // may be negative?
818
815
QgsDebugMsgLevel ( QStringLiteral ( " reqXRes = %1 reqYRes = %2 srcXRes = %3 srcYRes = %4" ).arg ( reqXRes ).arg ( reqYRes ).arg ( srcXRes ).arg ( srcYRes ), 5 );
816
+ const double resamplingFactor = std::max ( reqXRes / srcXRes, reqYRes / srcYRes );
819
817
820
818
GDALRasterBandH gdalBand = getBand ( bandNo );
821
819
const GDALDataType type = static_cast <GDALDataType>( mGdalDataType .at ( bandNo - 1 ) );
@@ -860,7 +858,8 @@ bool QgsGdalProvider::readBlock( int bandNo, QgsRectangle const &reqExtent, int
860
858
const int srcHeight = srcBottom - srcTop + 1 ;
861
859
862
860
// Use GDAL resampling if asked and possible
863
- if ( canDoResampling ( bandNo, reqExtent, bufferWidthPix, bufferHeightPix ) )
861
+ if ( mProviderResamplingEnabled &&
862
+ canDoResampling ( bandNo, reqExtent, bufferWidthPix, bufferHeightPix ) )
864
863
{
865
864
int tgtTop = tgtTopOri;
866
865
int tgtBottom = tgtBottomOri;
@@ -927,7 +926,6 @@ bool QgsGdalProvider::readBlock( int bandNo, QgsRectangle const &reqExtent, int
927
926
GDALRasterIOExtraArg sExtraArg ;
928
927
INIT_RASTERIO_EXTRA_ARG ( sExtraArg );
929
928
930
- const double resamplingFactor = std::max ( reqXRes / srcXRes, reqYRes / std::fabs ( srcYRes ) );
931
929
ResamplingMethod method;
932
930
if ( resamplingFactor < 1 )
933
931
{
@@ -972,6 +970,100 @@ bool QgsGdalProvider::readBlock( int bandNo, QgsRectangle const &reqExtent, int
972
970
&sExtraArg ) == CE_None;
973
971
}
974
972
}
973
+ // Provider resampling was asked but we cannot do it in a performant way
974
+ // (too much downsampling compared to the allowed maximum resampling factor),
975
+ // so fallback to something replicating QgsRasterResampleFilter behaviour
976
+ else if ( mProviderResamplingEnabled &&
977
+ mZoomedOutResamplingMethod != QgsRasterDataProvider::ResamplingMethod::Nearest &&
978
+ resamplingFactor > 1 )
979
+ {
980
+ // Do the resampling in two steps:
981
+ // - downsample with nearest neighbour down to tgtWidth * mMaxOversampling, tgtHeight * mMaxOversampling
982
+ // - then downsample with mZoomedOutResamplingMethod down to tgtWidth, tgtHeight
983
+ const int tgtWidth = tgtRightOri - tgtLeftOri + 1 ;
984
+ const int tgtHeight = tgtBottomOri - tgtTopOri + 1 ;
985
+
986
+ const int tmpWidth = static_cast <int >( tgtWidth * mMaxOversampling + 0.5 );
987
+ const int tmpHeight = static_cast <int >( tgtHeight * mMaxOversampling + 0.5 );
988
+
989
+ // Allocate temporary block
990
+ size_t bufferSize = dataSize * static_cast <size_t >( tmpWidth ) * static_cast <size_t >( tmpHeight );
991
+ #ifdef Q_PROCESSOR_X86_32
992
+ // Safety check for 32 bit systems
993
+ qint64 _buffer_size = dataSize * static_cast <qint64>( tmpWidth ) * static_cast <qint64>( tmpHeight );
994
+ if ( _buffer_size != static_cast <qint64>( bufferSize ) )
995
+ {
996
+ QgsDebugMsg ( QStringLiteral ( " Integer overflow calculating buffer size on a 32 bit system." ) );
997
+ return false ;
998
+ }
999
+ #endif
1000
+ char *tmpBlock = static_cast <char *>( qgsMalloc ( bufferSize ) );
1001
+ if ( ! tmpBlock )
1002
+ {
1003
+ QgsDebugMsgLevel ( QStringLiteral ( " Couldn't allocate temporary buffer of %1 bytes" ).arg ( dataSize * tmpWidth * tmpHeight ), 5 );
1004
+ return false ;
1005
+ }
1006
+ CPLErrorReset ();
1007
+
1008
+
1009
+ CPLErr err = gdalRasterIO ( gdalBand, GF_Read,
1010
+ srcLeft, srcTop, srcWidth, srcHeight,
1011
+ static_cast <void *>( tmpBlock ),
1012
+ tmpWidth, tmpHeight, type,
1013
+ 0 , 0 , feedback );
1014
+
1015
+ if ( err != CPLE_None )
1016
+ {
1017
+ const QString lastError = QString::fromUtf8 ( CPLGetLastErrorMsg () ) ;
1018
+ if ( feedback )
1019
+ feedback->appendError ( lastError );
1020
+
1021
+ QgsLogger::warning ( " RasterIO error: " + lastError );
1022
+ qgsFree ( tmpBlock );
1023
+ return false ;
1024
+ }
1025
+
1026
+ GDALDriverH hDriverMem = GDALGetDriverByName ( " MEM" );
1027
+ if ( !hDriverMem )
1028
+ {
1029
+ qgsFree ( tmpBlock );
1030
+ return false ;
1031
+ }
1032
+ gdal::dataset_unique_ptr hSrcDS ( GDALCreate (
1033
+ hDriverMem, " " , tmpWidth, tmpHeight, 0 , GDALGetRasterDataType ( gdalBand ), nullptr ) );
1034
+
1035
+ char **papszOptions = QgsGdalUtils::papszFromStringList ( QStringList ()
1036
+ << QStringLiteral ( " PIXELOFFSET=%1" ).arg ( dataSize )
1037
+ << QStringLiteral ( " LINEOFFSET=%1" ).arg ( dataSize * tmpWidth )
1038
+ << QStringLiteral ( " DATAPOINTER=%1" ).arg ( reinterpret_cast < qulonglong >( tmpBlock ) ) );
1039
+ GDALAddBand ( hSrcDS.get (), GDALGetRasterDataType ( gdalBand ), papszOptions );
1040
+ CSLDestroy ( papszOptions );
1041
+
1042
+ GDALRasterIOExtraArg sExtraArg ;
1043
+ INIT_RASTERIO_EXTRA_ARG ( sExtraArg );
1044
+
1045
+ if ( mZoomedOutResamplingMethod == ResamplingMethod::Bilinear )
1046
+ sExtraArg .eResampleAlg = GRIORA_Bilinear;
1047
+ else if ( mZoomedOutResamplingMethod == ResamplingMethod::Cubic )
1048
+ sExtraArg .eResampleAlg = GRIORA_Cubic;
1049
+ else
1050
+ sExtraArg .eResampleAlg = GRIORA_NearestNeighbour;
1051
+ CPLErr eErr = GDALRasterIOEx ( GDALGetRasterBand ( hSrcDS.get (), 1 ),
1052
+ GF_Read,
1053
+ 0 , 0 , tmpWidth, tmpHeight,
1054
+ static_cast <char *>( data ) +
1055
+ ( tgtTopOri * bufferWidthPix + tgtLeftOri ) * dataSize,
1056
+ tgtWidth,
1057
+ tgtHeight,
1058
+ type,
1059
+ dataSize,
1060
+ dataSize * bufferWidthPix,
1061
+ &sExtraArg );
1062
+
1063
+ qgsFree ( tmpBlock );
1064
+
1065
+ return eErr == CE_None;
1066
+ }
975
1067
976
1068
const int tgtTop = tgtTopOri;
977
1069
const int tgtBottom = tgtBottomOri;
0 commit comments