18#include <cpl_string.h>
36#include <QCoreApplication>
37#include <QProgressDialog>
38#include <QRegularExpression>
42using namespace Qt::StringLiterals;
50 double geoTransform[6];
51 globalOutputParameters( extent, width, height, geoTransform, pixelSize );
53 return initOutput( width, height, crs, geoTransform, 1, dataType, QList<bool>(), QList<double>() );
62 double geoTransform[6];
63 globalOutputParameters( extent, width, height, geoTransform, pixelSize );
65 return initOutput( width, height, crs, geoTransform, nBands, dataType, QList<bool>(), QList<double>() );
125 mFeedback = feedback;
132 const QFileInfo fileInfo( mOutputUrl );
133 if ( !fileInfo.exists() )
135 const QDir dir = fileInfo.dir();
136 if ( !dir.mkdir( fileInfo.fileName() ) )
138 QgsDebugError(
"Cannot create output VRT directory " + fileInfo.fileName() +
" in " + dir.absolutePath() );
145 QFile pyramidFile( mOutputUrl + ( mTiledMode ?
".vrt.ovr" :
".ovr" ) );
146 if ( pyramidFile.exists() )
147 pyramidFile.remove();
148 pyramidFile.setFileName( mOutputUrl + ( mTiledMode ?
".vrt.rrd" :
".rrd" ) );
149 if ( pyramidFile.exists() )
150 pyramidFile.remove();
154 return writeImageRaster( &iter, nCols, nRows, outputExtent, crs, feedback );
158 return writeDataRaster( pipe, &iter, nCols, nRows, outputExtent, crs, transformContext, feedback );
179 const QgsRasterInterface *iface = pipe->
last();
185 QgsRasterDataProvider *srcProvider =
const_cast<QgsRasterDataProvider *
>(
dynamic_cast<const QgsRasterDataProvider *
>( iface->
sourceInput() ) );
205 for (
int i = 2; i <= nBands; ++i )
217 QList<bool> destHasNoDataValueList;
218 QList<double> destNoDataValueList;
219 QList<Qgis::DataType> destDataTypeList;
220 destDataTypeList.reserve( nBands );
221 destHasNoDataValueList.reserve( nBands );
222 destNoDataValueList.reserve( nBands );
224 const bool isGpkgOutput = mOutputProviderKey ==
"gdal" && mOutputFormat.compare(
"gpkg"_L1, Qt::CaseInsensitive ) == 0;
226 double geoTransform[6];
227 globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
228 const auto srcProviderExtent( srcProvider->
extent() );
230 for (
int bandNo = 1; bandNo <= nBands; bandNo++ )
232 QgsRasterNuller *nuller = pipe->
nuller();
235 bool destHasNoDataValue =
false;
236 double destNoDataValue = std::numeric_limits<double>::quiet_NaN();
241 if ( srcHasNoDataValue )
245 destHasNoDataValue =
true;
247 else if ( nuller && !nuller->
noData( bandNo ).isEmpty() )
250 destNoDataValue = nuller->
noData( bandNo ).value( 0 ).min();
251 destHasNoDataValue =
true;
259 QgsRectangle outputExtentInSrcCrs = outputExtent;
260 QgsRasterProjector *projector = pipe->
projector();
264 ct.setBallparkTransformsAreAppropriate(
true );
265 outputExtentInSrcCrs = ct.transformBoundingBox( outputExtent );
267 if ( !srcProviderExtent.contains( outputExtentInSrcCrs ) &&
268 ( std::fabs( srcProviderExtent.xMinimum() - outputExtentInSrcCrs.
xMinimum() ) > geoTransform[1] / 2 ||
269 std::fabs( srcProviderExtent.xMaximum() - outputExtentInSrcCrs.
xMaximum() ) > geoTransform[1] / 2 ||
270 std::fabs( srcProviderExtent.yMinimum() - outputExtentInSrcCrs.
yMinimum() ) > std::fabs( geoTransform[5] ) / 2 ||
271 std::fabs( srcProviderExtent.yMaximum() - outputExtentInSrcCrs.
yMaximum() ) > std::fabs( geoTransform[5] ) / 2 ) )
282 destNoDataValue = typeMinValue;
286 destNoDataValue = typeMaxValue;
293 destHasNoDataValue =
true;
297 if ( nuller && destHasNoDataValue )
302 QgsDebugMsgLevel( u
"bandNo = %1 destDataType = %2 destHasNoDataValue = %3 destNoDataValue = %4"_s.arg( bandNo ).arg(
qgsEnumValueToKey( destDataType ) ).arg( destHasNoDataValue ).arg( destNoDataValue ), 4 );
303 destDataTypeList.append( destDataType );
304 destHasNoDataValueList.append( destHasNoDataValue );
305 destNoDataValueList.append( destNoDataValue );
310 for (
int i = 1; i < nBands; i++ )
312 if ( destDataTypeList.value( i ) > destDataType )
314 destDataType = destDataTypeList.value( i );
320 for (
int attempt = 0; attempt < 2; attempt++ )
324 std::unique_ptr<QgsRasterDataProvider> destProvider( initOutput( nCols, nRows, crs, geoTransform, nBands, destDataType, destHasNoDataValueList, destNoDataValueList ) );
331 if ( !destProvider->isValid() )
333 if ( feedback && !destProvider->error().isEmpty() )
335 feedback->
appendError( destProvider->error().summary() );
339 if ( nCols != destProvider->xSize() || nRows != destProvider->ySize() )
341 QgsDebugError( u
"Created raster does not have requested dimensions"_s );
344 feedback->
appendError( QObject::tr(
"Created raster does not have requested dimensions" ) );
348 if ( nBands != destProvider->bandCount() )
350 QgsDebugError( u
"Created raster does not have requested band count"_s );
353 feedback->
appendError( QObject::tr(
"Created raster does not have requested band count" ) );
361 destDataType = destProvider->dataType( 1 );
365 error = writeDataRaster( pipe, iter, nCols, nRows, outputExtent, crs, destDataType, destHasNoDataValueList, destNoDataValueList, destProvider, feedback );
372 destProvider->remove();
373 destProvider.reset();
381 for (
int i = 0; i < nBands; i++ )
383 double destNoDataValue;
385 destDataTypeList.replace( i, destDataType );
386 destNoDataValueList.replace( i, destNoDataValue );
388 destDataType = destDataTypeList.value( 0 );
401static int qgsDivRoundUp(
int a,
int b )
403 return a / b + ( ( ( a % b ) != 0 ) ? 1 : 0 );
414 const QList<bool> &destHasNoDataValueList,
415 const QList<double> &destNoDataValueList,
416 std::unique_ptr<QgsRasterDataProvider> &destProvider,
421 Q_UNUSED( destHasNoDataValueList )
424 const QgsRasterInterface *iface = iter->
input();
425 const QgsRasterDataProvider *srcProvider =
dynamic_cast<const QgsRasterDataProvider *
>( iface->
sourceInput() );
435 std::vector< std::unique_ptr<QgsRasterBlock> > blockList;
436 std::vector< std::unique_ptr<QgsRasterBlock> > destBlockList;
438 blockList.resize( nBands );
439 destBlockList.resize( nBands );
441 for (
int i = 1; i <= nBands; ++i )
444 if ( destProvider && destHasNoDataValueList.value( i - 1 ) )
446 destProvider->setNoDataValue( i, destNoDataValueList.value( i - 1 ) );
456 nParts = nPartsX * nPartsY;
459 const bool hasReportsDuringClose = destProvider && destProvider->hasReportsDuringClose();
466 for (
int i = 1; i <= nBands && !done; ++i )
468 QgsRasterBlock *block =
nullptr;
474 const QString vrtFilePath( mOutputUrl +
'/' + vrtFileName() );
475 writeVRT( vrtFilePath );
478 if ( !buildPyramids( vrtFilePath ) )
488 mOutputFormat !=
"COG"_L1 )
490 if ( !buildPyramids( mOutputUrl, destProvider.get() ) )
500 blockList[i - 1].reset( block );
508 if ( feedback && fileIndex < ( nParts - 1 ) )
510 const double maxProgress = hasReportsDuringClose ? 50.0 : 100.0;
511 feedback->
setProgress( maxProgress * fileIndex /
static_cast< double >( nParts ) );
519 for (
int i = 1; i <= nBands; ++i )
521 if ( srcProvider && srcProvider->
dataType( i ) == destDataType )
528 blockList[i - 1]->convert( destDataType );
530 destBlockList[i - 1] = std::move( blockList[i - 1] );
535 std::unique_ptr< QgsRasterDataProvider > partDestProvider( createPartProvider( outputExtent, nCols, iterCols, iterRows, iterLeft, iterTop, mOutputUrl, fileIndex, nBands, destDataType, crs ) );
537 if ( !partDestProvider || !partDestProvider->isValid() )
543 for (
int i = 1; i <= nBands; ++i )
545 if ( destHasNoDataValueList.value( i - 1 ) )
547 partDestProvider->setNoDataValue( i, destNoDataValueList.value( i - 1 ) );
549 if ( destBlockList[i - 1]->isEmpty() )
552 if ( !partDestProvider->write( destBlockList[i - 1]->constBits( 0 ), i, iterCols, iterRows, 0, 0 ) )
556 addToVRT( partFileName( fileIndex ), i, iterCols, iterRows, iterLeft, iterTop );
559 else if ( destProvider )
562 for (
int i = 1; i <= nBands; ++i )
564 if ( destBlockList[i - 1]->isEmpty() )
567 if ( !destProvider->write( destBlockList[i - 1]->constBits( 0 ), i, iterCols, iterRows, iterLeft, iterTop ) )
578 if ( feedback && destProvider && hasReportsDuringClose )
581 if ( !destProvider->closeWithProgress( scaledFeedback.get() ) )
583 destProvider->remove();
584 destProvider.reset();
603 const QgsRasterInterface *iface = iter->
input();
617 const size_t nMaxPixels =
static_cast<size_t>( mMaxTileWidth ) * mMaxTileHeight;
618 std::vector<unsigned char> redData( nMaxPixels );
619 std::vector<unsigned char> greenData( nMaxPixels );
620 std::vector<unsigned char> blueData( nMaxPixels );
621 std::vector<unsigned char> alphaData( nMaxPixels );
622 int iterLeft = 0, iterTop = 0, iterCols = 0, iterRows = 0;
627 double geoTransform[6];
628 globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
630 const int nOutputBands = 4;
631 std::unique_ptr< QgsRasterDataProvider > destProvider( initOutput( nCols, nRows, crs, geoTransform, nOutputBands,
Qgis::DataType::Byte ) );
638 if ( !destProvider->isValid() )
640 if ( feedback && !destProvider->error().isEmpty() )
642 feedback->
appendError( destProvider->error().summary() );
646 if ( nCols != destProvider->xSize() || nRows != destProvider->ySize() )
648 QgsDebugError( u
"Created raster does not have requested dimensions"_s );
651 feedback->
appendError( QObject::tr(
"Created raster does not have requested dimensions" ) );
655 if ( nOutputBands != destProvider->bandCount() )
657 QgsDebugError( u
"Created raster does not have requested band count"_s );
660 feedback->
appendError( QObject::tr(
"Created raster does not have requested band count" ) );
666 QgsDebugError( u
"Created raster does not have requested data type"_s );
669 feedback->
appendError( QObject::tr(
"Created raster does not have requested data type" ) );
682 nParts = nPartsX * nPartsY;
685 const bool hasReportsDuringClose = !mTiledMode && destProvider && destProvider->hasReportsDuringClose();
686 const double maxProgress = hasReportsDuringClose ? 50.0 : 100.0;
688 std::unique_ptr< QgsRasterBlock > inputBlock;
689 while ( iter->
readNextRasterPart( 1, iterCols, iterRows, inputBlock, iterLeft, iterTop ) )
691 if ( !inputBlock || inputBlock->isEmpty() )
696 if ( feedback && fileIndex < ( nParts - 1 ) )
698 feedback->
setProgress( maxProgress * fileIndex /
static_cast< double >( nParts ) );
706 const qgssize nPixels =
static_cast< qgssize >( iterCols ) * iterRows;
707 for (
qgssize i = 0; i < nPixels; ++i )
709 QRgb
c = inputBlock->color( i );
710 if ( isPremultiplied )
712 c = qUnpremultiply(
c );
714 redData[i] =
static_cast<unsigned char>( qRed(
c ) );
715 greenData[i] =
static_cast<unsigned char>( qGreen(
c ) );
716 blueData[i] =
static_cast<unsigned char>( qBlue(
c ) );
717 alphaData[i] =
static_cast<unsigned char>( qAlpha(
c ) );
723 std::unique_ptr< QgsRasterDataProvider > partDestProvider( createPartProvider( outputExtent, nCols, iterCols, iterRows, iterLeft, iterTop, mOutputUrl, fileIndex, 4,
Qgis::DataType::Byte, crs ) );
725 if ( !partDestProvider || partDestProvider->isValid() )
731 if ( !partDestProvider->write( &redData[0], 1, iterCols, iterRows, 0, 0 )
732 || !partDestProvider->write( &greenData[0], 2, iterCols, iterRows, 0, 0 )
733 || !partDestProvider->write( &blueData[0], 3, iterCols, iterRows, 0, 0 )
734 || !partDestProvider->write( &alphaData[0], 4, iterCols, iterRows, 0, 0 ) )
739 addToVRT( partFileName( fileIndex ), 1, iterCols, iterRows, iterLeft, iterTop );
740 addToVRT( partFileName( fileIndex ), 2, iterCols, iterRows, iterLeft, iterTop );
741 addToVRT( partFileName( fileIndex ), 3, iterCols, iterRows, iterLeft, iterTop );
742 addToVRT( partFileName( fileIndex ), 4, iterCols, iterRows, iterLeft, iterTop );
744 else if ( destProvider )
746 if ( !destProvider->write( &redData[0], 1, iterCols, iterRows, iterLeft, iterTop )
747 || !destProvider->write( &greenData[0], 2, iterCols, iterRows, iterLeft, iterTop )
748 || !destProvider->write( &blueData[0], 3, iterCols, iterRows, iterLeft, iterTop )
749 || !destProvider->write( &alphaData[0], 4, iterCols, iterRows, iterLeft, iterTop ) )
765 destProvider.reset();
767 const QString vrtFilePath( mOutputUrl +
'/' + vrtFileName() );
768 writeVRT( vrtFilePath );
771 if ( !buildPyramids( vrtFilePath ) )
779 if ( destProvider && hasReportsDuringClose )
781 QgsFeedback closingProgress;
788 if ( !destProvider->closeWithProgress( feedback ? &closingProgress :
nullptr ) )
790 destProvider->remove();
791 destProvider.reset();
796 destProvider.reset();
800 mOutputFormat !=
"COG"_L1 )
802 if ( !buildPyramids( mOutputUrl ) )
809void QgsRasterFileWriter::addToVRT(
const QString &filename,
int band,
int xSize,
int ySize,
int xOffset,
int yOffset )
811 QDomElement bandElem = mVRTBands.value( band - 1 );
813 QDomElement simpleSourceElem = mVRTDocument.createElement( u
"SimpleSource"_s );
816 QDomElement sourceFilenameElem = mVRTDocument.createElement( u
"SourceFilename"_s );
817 sourceFilenameElem.setAttribute( u
"relativeToVRT"_s, u
"1"_s );
818 const QDomText sourceFilenameText = mVRTDocument.createTextNode( filename );
819 sourceFilenameElem.appendChild( sourceFilenameText );
820 simpleSourceElem.appendChild( sourceFilenameElem );
823 QDomElement sourceBandElem = mVRTDocument.createElement( u
"SourceBand"_s );
824 const QDomText sourceBandText = mVRTDocument.createTextNode( QString::number( band ) );
825 sourceBandElem.appendChild( sourceBandText );
826 simpleSourceElem.appendChild( sourceBandElem );
829 QDomElement sourcePropertiesElem = mVRTDocument.createElement( u
"SourceProperties"_s );
830 sourcePropertiesElem.setAttribute( u
"RasterXSize"_s, xSize );
831 sourcePropertiesElem.setAttribute( u
"RasterYSize"_s, ySize );
832 sourcePropertiesElem.setAttribute( u
"BlockXSize"_s, xSize );
833 sourcePropertiesElem.setAttribute( u
"BlockYSize"_s, ySize );
834 sourcePropertiesElem.setAttribute( u
"DataType"_s, u
"Byte"_s );
835 simpleSourceElem.appendChild( sourcePropertiesElem );
838 QDomElement srcRectElem = mVRTDocument.createElement( u
"SrcRect"_s );
839 srcRectElem.setAttribute( u
"xOff"_s, u
"0"_s );
840 srcRectElem.setAttribute( u
"yOff"_s, u
"0"_s );
841 srcRectElem.setAttribute( u
"xSize"_s, xSize );
842 srcRectElem.setAttribute( u
"ySize"_s, ySize );
843 simpleSourceElem.appendChild( srcRectElem );
846 QDomElement dstRectElem = mVRTDocument.createElement( u
"DstRect"_s );
847 dstRectElem.setAttribute( u
"xOff"_s, xOffset );
848 dstRectElem.setAttribute( u
"yOff"_s, yOffset );
849 dstRectElem.setAttribute( u
"xSize"_s, xSize );
850 dstRectElem.setAttribute( u
"ySize"_s, ySize );
851 simpleSourceElem.appendChild( dstRectElem );
853 bandElem.appendChild( simpleSourceElem );
856bool QgsRasterFileWriter::buildPyramids(
const QString &filename,
QgsRasterDataProvider *destProviderIn )
860 const QgsDataProvider::ProviderOptions providerOptions;
861 QgsRasterDataProvider *destProvider = destProviderIn;
864 destProvider = qobject_cast< QgsRasterDataProvider * >(
QgsProviderRegistry::instance()->createProvider( mOutputProviderKey, filename, providerOptions ) );
865 if ( !destProvider || !destProvider->
isValid() )
875 QList< QgsRasterPyramid> myPyramidList;
876 if ( !mPyramidsList.isEmpty() )
878 for (
int myCounterInt = 0; myCounterInt < myPyramidList.count(); myCounterInt++ )
880 myPyramidList[myCounterInt].setBuild(
true );
884 u
"building pyramids : %1 pyramids, %2 resampling, %3 format, %4 options"_s.arg( myPyramidList.count() )
885 .arg( mPyramidsResampling )
887 .arg( mPyramidsConfigOptions.count() ),
891 const QString res = destProvider->
buildPyramids( myPyramidList, mPyramidsResampling, mPyramidsFormat, mPyramidsConfigOptions );
898 if ( res ==
"ERROR_WRITE_ACCESS"_L1 )
900 message = QObject::tr(
"Write access denied. Adjust the file permissions and try again." );
902 else if ( res ==
"ERROR_WRITE_FORMAT"_L1 )
904 message = QObject::tr(
905 "The file was not writable. Some formats do not "
906 "support pyramid overviews. Consult the GDAL documentation if in doubt."
909 else if ( res ==
"FAILED_NOT_SUPPORTED"_L1 )
911 message = QObject::tr(
"Building pyramid overviews is not supported on this type of raster." );
913 else if ( res ==
"ERROR_VIRTUAL"_L1 )
915 message = QObject::tr(
"Building pyramid overviews is not supported on this type of raster." );
922 if ( !destProviderIn )
929int QgsRasterFileWriter::pyramidsProgress(
double dfComplete,
const char *pszMessage,
void *pData )
931 Q_UNUSED( pszMessage )
932 GDALTermProgress( dfComplete, 0, 0 );
933 QProgressDialog *progressDialog =
static_cast<QProgressDialog *
>( pData );
934 if ( pData && progressDialog->wasCanceled() )
941 progressDialog->setRange( 0, 100 );
942 progressDialog->setValue( dfComplete * 100 );
948void QgsRasterFileWriter::createVRT(
952 mVRTDocument.clear();
953 QDomElement VRTDatasetElem = mVRTDocument.createElement( u
"VRTDataset"_s );
956 VRTDatasetElem.setAttribute( u
"rasterXSize"_s, xSize );
957 VRTDatasetElem.setAttribute( u
"rasterYSize"_s, ySize );
958 mVRTDocument.appendChild( VRTDatasetElem );
961 QDomElement SRSElem = mVRTDocument.createElement( u
"SRS"_s );
962 const QDomText crsText = mVRTDocument.createTextNode( crs.
toWkt() );
963 SRSElem.appendChild( crsText );
964 VRTDatasetElem.appendChild( SRSElem );
969 QDomElement geoTransformElem = mVRTDocument.createElement( u
"GeoTransform"_s );
970 const QString geoTransformString = QString::number( geoTransform[0],
'f', 6 )
972 + QString::number( geoTransform[1] )
974 + QString::number( geoTransform[2] )
976 + QString::number( geoTransform[3],
'f', 6 )
978 + QString::number( geoTransform[4] )
980 + QString::number( geoTransform[5] );
981 const QDomText geoTransformText = mVRTDocument.createTextNode( geoTransformString );
982 geoTransformElem.appendChild( geoTransformText );
983 VRTDatasetElem.appendChild( geoTransformElem );
989 nBands = mInput->bandCount();
996 QStringList colorInterp;
997 colorInterp << u
"Red"_s << u
"Green"_s << u
"Blue"_s << u
"Alpha"_s;
999 QMap<Qgis::DataType, QString> dataTypes;
1012 for (
int i = 1; i <= nBands; i++ )
1014 QDomElement VRTBand = mVRTDocument.createElement( u
"VRTRasterBand"_s );
1016 VRTBand.setAttribute( u
"band"_s, QString::number( i ) );
1017 const QString dataType = dataTypes.value( type );
1018 VRTBand.setAttribute( u
"dataType"_s, dataType );
1022 VRTBand.setAttribute( u
"dataType"_s, u
"Byte"_s );
1023 QDomElement colorInterpElement = mVRTDocument.createElement( u
"ColorInterp"_s );
1024 const QDomText interpText = mVRTDocument.createTextNode( colorInterp.value( i - 1 ) );
1025 colorInterpElement.appendChild( interpText );
1026 VRTBand.appendChild( colorInterpElement );
1029 if ( !destHasNoDataValueList.isEmpty() && destHasNoDataValueList.value( i - 1 ) )
1031 VRTBand.setAttribute( u
"NoDataValue"_s, QString::number( destNoDataValueList.value( i - 1 ) ) );
1034 mVRTBands.append( VRTBand );
1035 VRTDatasetElem.appendChild( VRTBand );
1039bool QgsRasterFileWriter::writeVRT(
const QString &file )
1041 QFile outputFile( file );
1042 if ( !outputFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
1047 QTextStream outStream( &outputFile );
1048 mVRTDocument.save( outStream, 2 );
1053 const QgsRectangle &extent,
int nCols,
int iterCols,
int iterRows,
int iterLeft,
int iterTop,
const QString &outputUrl,
int fileIndex,
int nBands,
Qgis::DataType type,
const QgsCoordinateReferenceSystem &crs
1056 const double mup = extent.
width() / nCols;
1057 const double mapLeft = extent.
xMinimum() + iterLeft * mup;
1058 const double mapRight = mapLeft + mup * iterCols;
1059 const double mapTop = extent.
yMaximum() - iterTop * mup;
1060 const double mapBottom = mapTop - iterRows * mup;
1061 const QgsRectangle mapRect( mapLeft, mapBottom, mapRight, mapTop );
1063 const QString outputFile =
outputUrl +
'/' + partFileName( fileIndex );
1066 double geoTransform[6];
1067 geoTransform[0] = mapRect.xMinimum();
1068 geoTransform[1] = mup;
1069 geoTransform[2] = 0.0;
1070 geoTransform[3] = mapRect.yMaximum();
1071 geoTransform[4] = 0.0;
1072 geoTransform[5] = -mup;
1076 QgsRasterDataProvider *destProvider =
QgsRasterDataProvider::create( mOutputProviderKey, outputFile, mOutputFormat, nBands, type, iterCols, iterRows, geoTransform, crs, mCreationOptions );
1079 return destProvider;
1084 mOutputFormat = format;
1085 if ( !mBuildPyramidsFlagSet && format ==
"COG"_L1 )
1093 mBuildPyramidsFlag = flag;
1094 mBuildPyramidsFlagSet =
true;
1103 createVRT( nCols, nRows, crs, geoTransform, type, destHasNoDataValueList, destNoDataValueList );
1111 if ( mBuildPyramidsFlag == -4 && mOutputProviderKey ==
"gdal" && mOutputFormat.compare(
"gtiff"_L1, Qt::CaseInsensitive ) == 0 )
1112 mCreationOptions <<
"COPY_SRC_OVERVIEWS=YES";
1115 if ( mOutputFormat ==
"COG"_L1 )
1122 for (
const QString &opt : std::as_const( mPyramidsConfigOptions ) )
1124 const std::string optStr( opt.toStdString() );
1125 char *key =
nullptr;
1126 const char *value = CPLParseNameValue( optStr.c_str(), &key );
1129 if ( EQUAL( key,
"JPEG_QUALITY_OVERVIEW" ) )
1133 else if ( EQUAL( key,
"COMPRESS_OVERVIEW" ) )
1137 else if ( EQUAL( key,
"PREDICTOR_OVERVIEW" ) )
1149 if ( !destProvider )
1154 return destProvider;
1158void QgsRasterFileWriter::globalOutputParameters(
const QgsRectangle &extent,
int nCols,
int &nRows,
double *geoTransform,
double &pixelSize )
1160 pixelSize = extent.
width() / nCols;
1165 nRows =
static_cast< double >( nCols ) / extent.
width() * extent.
height() + 0.5;
1167 geoTransform[0] = extent.
xMinimum();
1168 geoTransform[1] = pixelSize;
1169 geoTransform[2] = 0.0;
1170 geoTransform[3] = extent.
yMaximum();
1171 geoTransform[4] = 0.0;
1172 geoTransform[5] = -( extent.
height() / nRows );
1175QString QgsRasterFileWriter::partFileName(
int fileIndex )
1178 const QFileInfo outputInfo( mOutputUrl );
1179 return u
"%1.%2.tif"_s.arg( outputInfo.fileName() ).arg( fileIndex );
1182QString QgsRasterFileWriter::vrtFileName()
1184 const QFileInfo outputInfo( mOutputUrl );
1185 return u
"%1.vrt"_s.arg( outputInfo.fileName() );
1190 QString ext = extension.trimmed();
1191 if ( ext.isEmpty() )
1194 if ( ext.startsWith(
'.' ) )
1197 if ( ext.compare(
"tif"_L1, Qt::CaseInsensitive ) == 0 || ext.compare(
"tiff"_L1, Qt::CaseInsensitive ) == 0 )
1202 if ( GDALGetDriverByName(
"GTiff" ) )
1207 int const drvCount = GDALGetDriverCount();
1209 for (
int i = 0; i < drvCount; ++i )
1211 GDALDriverH drv = GDALGetDriver( i );
1214 CSLConstList driverMetadata = GDALGetMetadata( drv,
nullptr );
1215 if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER,
false ) )
1217 QString drvName = GDALGetDriverShortName( drv );
1218 const QStringList driverExtensions = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) ).split(
' ' );
1220 const auto constDriverExtensions = driverExtensions;
1221 for (
const QString &driver : constDriverExtensions )
1223 if ( driver.compare( ext, Qt::CaseInsensitive ) == 0 )
1234 GDALDriverH drv = GDALGetDriverByName( format.toLocal8Bit().data() );
1237 CSLConstList driverMetadata = GDALGetMetadata( drv,
nullptr );
1238 if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER,
false ) )
1240 return QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) ).split(
' ' );
1243 return QStringList();
1248 GDALDriverH drv = GDALGetDriverByName( driverName.toLocal8Bit().data() );
1251 const QString drvName = GDALGetDriverLongName( drv );
1252 const QString extensionsString = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) );
1253 if ( extensionsString.isEmpty() )
1257 const QStringList extensions = extensionsString.split(
' ' );
1258 QString filter = drvName +
" (";
1259 for (
const QString &ext : extensions )
1261 filter.append( u
"*.%1 *.%2 "_s.arg( ext.toLower(), ext.toUpper() ) );
1263 filter = filter.trimmed().append( u
")"_s );
1272 static QReadWriteLock sFilterLock;
1273 static QMap< RasterFormatOptions, QList< QgsRasterFileWriter::FilterFormatDetails > > sFilters;
1277 const auto it = sFilters.constFind( options );
1278 if ( it != sFilters.constEnd() )
1282 int const drvCount = GDALGetDriverCount();
1285 QList< QgsRasterFileWriter::FilterFormatDetails > results;
1289 for (
int i = 0; i < drvCount; ++i )
1291 GDALDriverH drv = GDALGetDriver( i );
1296 const QString drvName = GDALGetDriverShortName( drv );
1298 if ( filterString.isEmpty() )
1305 if ( options & SortRecommended )
1307 if ( drvName ==
"GTiff"_L1 )
1309 tifFormat = details;
1321 if ( options & SortRecommended )
1325 results.insert( 0, tifFormat );
1329 sFilters.insert( options, results );
1337 QSet< QString > extensions;
1339 const thread_local QRegularExpression rx( u
"\\*\\.([a-zA-Z0-9]*)"_s );
1343 const QString ext = format.filterString;
1344 const QRegularExpressionMatch match = rx.match( ext );
1345 if ( !match.hasMatch() )
1348 const QString matched = match.captured( 1 );
1349 extensions.insert( matched );
1352 QStringList extensionList( extensions.constBegin(), extensions.constEnd() );
1354 std::sort( extensionList.begin(), extensionList.end(), [options](
const QString &a,
const QString &b ) ->
bool {
1355 if ( options & SortRecommended )
1357 if ( a ==
"tif"_L1 )
1359 else if ( b ==
"tif"_L1 )
1361 if ( a ==
"tiff"_L1 )
1363 else if ( b ==
"tiff"_L1 )
1365 if ( a ==
"gpkg"_L1 )
1367 else if ( b ==
"gpkg"_L1 )
1371 return a.toLower().localeAwareCompare( b.toLower() ) < 0;
1374 return extensionList;
RasterFileWriterResult
Raster file export results.
@ Canceled
Writing was manually canceled.
@ NoDataConflict
Internal error if a value used for 'no data' was found in input.
@ Success
Successful export.
@ CreateDatasourceError
Data source creation error.
@ DestinationProviderError
Destination data provider error.
@ SourceProviderError
Source data provider error.
DataType
Raster data types.
@ Float32
Thirty two bit floating point (float).
@ CFloat64
Complex Float64.
@ Int16
Sixteen bit signed integer (qint16).
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
@ Int8
Eight bit signed integer (qint8) (added in QGIS 3.30).
@ UInt16
Sixteen bit unsigned integer (quint16).
@ Byte
Eight bit unsigned integer (quint8).
@ ARGB32
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
@ Float64
Sixty four bit floating point (double).
@ CFloat32
Complex Float32.
@ UInt32
Thirty two bit unsigned integer (quint32).
RasterBuildPyramidOption
Raster pyramid building options.
@ RenderedImage
Rendered image.
static double maximumValuePossible(Qgis::DataType dataType)
Helper function that returns the maximum possible value for a data type.
static double minimumValuePossible(Qgis::DataType dataType)
Helper function that returns the minimum possible value for a data type.
Represents a coordinate reference system (CRS).
QString toWkt(Qgis::CrsWktVariant variant=Qgis::CrsWktVariant::Wkt1Gdal, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
Contains information about the context in which a coordinate transform is executed.
QgsCoordinateTransformContext transformContext() const
Returns data provider coordinate transform context.
virtual bool isValid() const =0
Returns true if this is a valid layer.
bool isCanceled() const
Tells whether the operation has been canceled already.
void progressChanged(double progress)
Emitted when the feedback object reports a progress change.
void canceled()
Internal routines can connect to this signal if they use event loop.
void cancel()
Tells the internal routines that the current operation should be canceled. This should be run by the ...
void setProgress(double progress)
Sets the current progress for the feedback object.
static std::unique_ptr< QgsFeedback > createScaledFeedback(QgsFeedback *parentFeedback, double startPercentage, double endPercentage)
Returns a feedback object whose [0, 100] progression range will be mapped to parentFeedback [startPer...
static bool supportsRasterCreate(GDALDriverH driver)
Reads whether a driver supports GDALCreate() for raster purposes.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
double minimumValue
The minimum cell value in the raster band.
double maximumValue
The maximum cell value in the raster band.
Feedback object tailored for raster block reading.
void appendError(const QString &error)
Appends an error message to the stored list of errors.
static int typeSize(Qgis::DataType dataType)
Returns the size in bytes for the specified dataType.
static Qgis::DataType typeWithNoDataValue(Qgis::DataType dataType, double *noDataValue)
For given data type returns wider type and sets no data value.
static bool typeIsColor(Qgis::DataType type)
Returns true if a data type is a color type.
Base class for raster data providers.
virtual bool sourceHasNoDataValue(int bandNo) const
Returns true if source band has no data value.
virtual QString buildPyramids(const QList< QgsRasterPyramid > &pyramidList, const QString &resamplingMethod="NEAREST", Qgis::RasterPyramidFormat format=Qgis::RasterPyramidFormat::GeoTiff, const QStringList &configOptions=QStringList(), QgsRasterBlockFeedback *feedback=nullptr)
Creates pyramid overviews.
Qgis::DataType sourceDataType(int bandNo) const override=0
Returns source data type for the band specified by number, source data type may be shorter than dataT...
virtual double sourceNoDataValue(int bandNo) const
Value representing no data value.
QgsRectangle extent() const override=0
Returns the extent of the layer.
Qgis::DataType dataType(int bandNo) const override=0
Returns data type for the band specified by number.
static QgsRasterDataProvider * create(const QString &providerKey, const QString &uri, const QString &format, int nBands, Qgis::DataType type, int width, int height, double *geoTransform, const QgsCoordinateReferenceSystem &crs, const QStringList &createOptions=QStringList())
Creates a new dataset with mDataSourceURI.
virtual QList< QgsRasterPyramid > buildPyramidList(const QList< int > &overviewList=QList< int >())
Returns the raster layers pyramid list.
Q_DECL_DEPRECATED Qgis::RasterFileWriterResult writeRaster(const QgsRasterPipe *pipe, int nCols, int nRows, const QgsRectangle &outputExtent, const QgsCoordinateReferenceSystem &crs, QgsRasterBlockFeedback *feedback=nullptr) SIP_DEPRECATED
Write raster file.
static QStringList extensionsForFormat(const QString &format)
Returns a list of known file extensions for the given GDAL driver format.
static QString filterForDriver(const QString &driverName)
Creates a filter for an GDAL driver key.
static QString driverForExtension(const QString &extension)
Returns the GDAL driver name for a specified file extension.
QgsRasterFileWriter(const QString &outputUrl)
Constructor for QgsRasterFileWriter, writing to the specified output URL/filename.
static QStringList supportedFormatExtensions(RasterFormatOptions options=SortRecommended)
Returns a list of file extensions for supported formats.
QString outputUrl() const
Returns the output URL (filename) for the raster.
QFlags< RasterFormatOption > RasterFormatOptions
void setBuildPyramidsFlag(Qgis::RasterBuildPyramidOption flag)
Sets the pyramid building option.
QgsRasterDataProvider * createMultiBandRaster(Qgis::DataType dataType, int width, int height, const QgsRectangle &extent, const QgsCoordinateReferenceSystem &crs, int nBands) SIP_FACTORY
Create a raster file with given number of bands without initializing the pixel data.
QStringList creationOptions() const
Returns the list of data source creation options which will be used when creating the output raster f...
void setOutputFormat(const QString &format)
Sets the output format.
static QList< QgsRasterFileWriter::FilterFormatDetails > supportedFiltersAndFormats(RasterFormatOptions options=SortRecommended)
Returns a list or pairs, with format filter string as first element and GDAL format key as second ele...
QgsRasterDataProvider * createOneBandRaster(Qgis::DataType dataType, int width, int height, const QgsRectangle &extent, const QgsCoordinateReferenceSystem &crs) SIP_FACTORY
Create a raster file with one band without initializing the pixel data.
Base class for processing filters like renderers, reprojector, resampler etc.
virtual Qgis::DataType dataType(int bandNo) const =0
Returns data type for the band specified by number.
Q_DECL_DEPRECATED QgsRasterBandStats bandStatistics(int bandNo, int stats, const QgsRectangle &extent=QgsRectangle(), int sampleSize=0, QgsRasterBlockFeedback *feedback=nullptr)
Returns the band statistics.
virtual int bandCount() const =0
Gets number of bands.
virtual const QgsRasterInterface * sourceInput() const
Gets source / raw input, the first in pipe, usually provider.
Iterator for sequentially processing raster cells.
int maximumTileWidth() const
Returns the maximum tile width returned during iteration.
const QgsRasterInterface * input() const
Returns the input raster interface which is being iterated over.
void setMaximumTileWidth(int w)
Sets the maximum tile width returned during iteration.
bool readNextRasterPart(int bandNumber, int &nCols, int &nRows, QgsRasterBlock **block, int &topLeftCol, int &topLeftRow)
Fetches next part of raster data, caller takes ownership of the block and caller should delete the bl...
int maximumTileHeight() const
Returns the minimum tile width returned during iteration.
void startRasterRead(int bandNumber, qgssize nCols, qgssize nRows, const QgsRectangle &extent, QgsRasterBlockFeedback *feedback=nullptr)
Start reading of raster band.
void setMaximumTileHeight(int h)
Sets the minimum tile height returned during iteration.
void setOutputNoDataValue(int bandNo, double noData)
Sets the output no data value.
QgsRasterRangeList noData(int bandNo) const
Contains a pipeline of raster interfaces for sequential raster processing.
QgsRasterInterface * last() const
Returns last interface in the pipe.
QgsRasterDataProvider * provider() const
Returns the data provider interface, or nullptr if no data provider is present in the pipe.
QgsRasterProjector * projector() const
Returns the projector interface, or nullptr if no projector is present in the pipe.
QgsRasterNuller * nuller() const
Returns the raster nuller interface, or nullptr if no raster nuller is present in the pipe.
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination CRS.
QgsCoordinateReferenceSystem sourceCrs() const
Returns the source CRS.
A convenience class that simplifies locking and unlocking QReadWriteLocks.
void changeMode(Mode mode)
Change the mode of the lock to mode.
A rectangle specified with double values.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
unsigned long long qgssize
Qgssize is used instead of size_t, because size_t is stdlib type, unknown by SIP, and it would be har...
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)