18#include <cpl_string.h>
36#include <QCoreApplication>
37#include <QProgressDialog>
38#include <QRegularExpression>
47 double geoTransform[6];
48 globalOutputParameters( extent, width, height, geoTransform, pixelSize );
50 return initOutput( width, height, crs, geoTransform, 1, dataType, QList<bool>(), QList<double>() );
59 double geoTransform[6];
60 globalOutputParameters( extent, width, height, geoTransform, pixelSize );
62 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 );
171 const QgsRasterInterface *iface = pipe->
last();
177 QgsRasterDataProvider *srcProvider =
const_cast<QgsRasterDataProvider *
>(
dynamic_cast<const QgsRasterDataProvider *
>( iface->
sourceInput() ) );
197 for (
int i = 2; i <= nBands; ++i )
209 QList<bool> destHasNoDataValueList;
210 QList<double> destNoDataValueList;
211 QList<Qgis::DataType> destDataTypeList;
212 destDataTypeList.reserve( nBands );
213 destHasNoDataValueList.reserve( nBands );
214 destNoDataValueList.reserve( nBands );
216 const bool isGpkgOutput = mOutputProviderKey ==
"gdal" &&
217 mOutputFormat.compare(
"gpkg"_L1, Qt::CaseInsensitive ) == 0;
219 double geoTransform[6];
220 globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
221 const auto srcProviderExtent( srcProvider->
extent() );
223 for (
int bandNo = 1; bandNo <= nBands; bandNo++ )
225 QgsRasterNuller *nuller = pipe->
nuller();
228 bool destHasNoDataValue =
false;
229 double destNoDataValue = std::numeric_limits<double>::quiet_NaN();
234 if ( srcHasNoDataValue )
239 destHasNoDataValue =
true;
241 else if ( nuller && !nuller->
noData( bandNo ).isEmpty() )
244 destNoDataValue = nuller->
noData( bandNo ).value( 0 ).min();
245 destHasNoDataValue =
true;
253 QgsRectangle outputExtentInSrcCrs = outputExtent;
254 QgsRasterProjector *projector = pipe->
projector();
258 ct.setBallparkTransformsAreAppropriate(
true );
259 outputExtentInSrcCrs = ct.transformBoundingBox( outputExtent );
261 if ( !srcProviderExtent.contains( outputExtentInSrcCrs ) &&
262 ( std::fabs( srcProviderExtent.xMinimum() - outputExtentInSrcCrs.
xMinimum() ) > geoTransform[1] / 2 ||
263 std::fabs( srcProviderExtent.xMaximum() - outputExtentInSrcCrs.
xMaximum() ) > geoTransform[1] / 2 ||
264 std::fabs( srcProviderExtent.yMinimum() - outputExtentInSrcCrs.
yMinimum() ) > std::fabs( geoTransform[5] ) / 2 ||
265 std::fabs( srcProviderExtent.yMaximum() - outputExtentInSrcCrs.
yMaximum() ) > std::fabs( geoTransform[5] ) / 2 ) )
276 destNoDataValue = typeMinValue;
280 destNoDataValue = typeMaxValue;
287 destHasNoDataValue =
true;
291 if ( nuller && destHasNoDataValue )
296 QgsDebugMsgLevel( u
"bandNo = %1 destDataType = %2 destHasNoDataValue = %3 destNoDataValue = %4"_s.arg( bandNo ).arg(
qgsEnumValueToKey( destDataType ) ).arg( destHasNoDataValue ).arg( destNoDataValue ), 4 );
297 destDataTypeList.append( destDataType );
298 destHasNoDataValueList.append( destHasNoDataValue );
299 destNoDataValueList.append( destNoDataValue );
304 for (
int i = 1; i < nBands; i++ )
306 if ( destDataTypeList.value( i ) > destDataType )
308 destDataType = destDataTypeList.value( i );
314 for (
int attempt = 0; attempt < 2; attempt ++ )
318 std::unique_ptr<QgsRasterDataProvider> destProvider(
319 initOutput( nCols, nRows, crs, geoTransform, nBands, destDataType, destHasNoDataValueList, destNoDataValueList ) );
326 if ( !destProvider->isValid() )
328 if ( feedback && !destProvider->error().isEmpty() )
330 feedback->
appendError( destProvider->error().summary() );
334 if ( nCols != destProvider->xSize() || nRows != destProvider->ySize() )
336 QgsDebugError( u
"Created raster does not have requested dimensions"_s );
339 feedback->
appendError( QObject::tr(
"Created raster does not have requested dimensions" ) );
343 if ( nBands != destProvider->bandCount() )
345 QgsDebugError( u
"Created raster does not have requested band count"_s );
348 feedback->
appendError( QObject::tr(
"Created raster does not have requested band count" ) );
356 destDataType = destProvider->dataType( 1 );
360 error = writeDataRaster( pipe, iter, nCols, nRows, outputExtent, crs, destDataType, destHasNoDataValueList, destNoDataValueList, destProvider, feedback );
367 destProvider->remove();
368 destProvider.reset();
376 for (
int i = 0; i < nBands; i++ )
378 double destNoDataValue;
380 destDataTypeList.replace( i, destDataType );
381 destNoDataValueList.replace( i, destNoDataValue );
383 destDataType = destDataTypeList.value( 0 );
396static int qgsDivRoundUp(
int a,
int b )
398 return a / b + ( ( ( a % b ) != 0 ) ? 1 : 0 );
403 int nCols,
int nRows,
407 const QList<bool> &destHasNoDataValueList,
408 const QList<double> &destNoDataValueList,
409 std::unique_ptr<QgsRasterDataProvider> &destProvider,
413 Q_UNUSED( destHasNoDataValueList )
416 const QgsRasterInterface *iface = iter->
input();
417 const QgsRasterDataProvider *srcProvider =
dynamic_cast<const QgsRasterDataProvider *
>( iface->
sourceInput() );
427 std::vector< std::unique_ptr<QgsRasterBlock> > blockList;
428 std::vector< std::unique_ptr<QgsRasterBlock> > destBlockList;
430 blockList.resize( nBands );
431 destBlockList.resize( nBands );
433 for (
int i = 1; i <= nBands; ++i )
436 if ( destProvider && destHasNoDataValueList.value( i - 1 ) )
438 destProvider->setNoDataValue( i, destNoDataValueList.value( i - 1 ) );
448 nParts = nPartsX * nPartsY;
451 const bool hasReportsDuringClose = destProvider && destProvider->hasReportsDuringClose();
458 for (
int i = 1; i <= nBands && !done; ++i )
460 QgsRasterBlock *block =
nullptr;
466 const QString vrtFilePath( mOutputUrl +
'/' + vrtFileName() );
467 writeVRT( vrtFilePath );
470 if ( !buildPyramids( vrtFilePath ) )
480 mOutputFormat !=
"COG"_L1 )
482 if ( !buildPyramids( mOutputUrl, destProvider.get() ) )
492 blockList[i - 1].reset( block );
500 if ( feedback && fileIndex < ( nParts - 1 ) )
502 const double maxProgress = hasReportsDuringClose ? 50.0 : 100.0;
503 feedback->
setProgress( maxProgress * fileIndex /
static_cast< double >( nParts ) );
511 for (
int i = 1; i <= nBands; ++i )
513 if ( srcProvider && srcProvider->
dataType( i ) == destDataType )
520 blockList[i - 1]->convert( destDataType );
522 destBlockList[i - 1] = std::move( blockList[i - 1] );
527 std::unique_ptr< QgsRasterDataProvider > partDestProvider( createPartProvider( outputExtent,
528 nCols, iterCols, iterRows,
529 iterLeft, iterTop, mOutputUrl,
530 fileIndex, nBands, destDataType, crs ) );
532 if ( !partDestProvider || !partDestProvider->isValid() )
538 for (
int i = 1; i <= nBands; ++i )
540 if ( destHasNoDataValueList.value( i - 1 ) )
542 partDestProvider->setNoDataValue( i, destNoDataValueList.value( i - 1 ) );
544 if ( destBlockList[ i - 1 ]->isEmpty() )
547 if ( !partDestProvider->write( destBlockList[i - 1]->constBits( 0 ), i, iterCols, iterRows, 0, 0 ) )
551 addToVRT( partFileName( fileIndex ), i, iterCols, iterRows, iterLeft, iterTop );
555 else if ( destProvider )
558 for (
int i = 1; i <= nBands; ++i )
560 if ( destBlockList[ i - 1 ]->isEmpty() )
563 if ( !destProvider->write( destBlockList[i - 1]->constBits( 0 ), i, iterCols, iterRows, iterLeft, iterTop ) )
574 if ( feedback && destProvider && hasReportsDuringClose )
577 if ( !destProvider->closeWithProgress( scaledFeedback.get() ) )
579 destProvider->remove();
580 destProvider.reset();
581 return ( feedback && feedback->
isCanceled() ) ?
600 const QgsRasterInterface *iface = iter->
input();
614 const size_t nMaxPixels =
static_cast<size_t>( mMaxTileWidth ) * mMaxTileHeight;
615 std::vector<unsigned char> redData( nMaxPixels );
616 std::vector<unsigned char> greenData( nMaxPixels );
617 std::vector<unsigned char> blueData( nMaxPixels );
618 std::vector<unsigned char> alphaData( nMaxPixels );
619 int iterLeft = 0, iterTop = 0, iterCols = 0, iterRows = 0;
624 double geoTransform[6];
625 globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
627 const int nOutputBands = 4;
628 std::unique_ptr< QgsRasterDataProvider > destProvider( initOutput( nCols, nRows, crs, geoTransform, nOutputBands,
Qgis::DataType::Byte ) );
635 if ( !destProvider->isValid() )
637 if ( feedback && !destProvider->error().isEmpty() )
639 feedback->
appendError( destProvider->error().summary() );
643 if ( nCols != destProvider->xSize() || nRows != destProvider->ySize() )
645 QgsDebugError( u
"Created raster does not have requested dimensions"_s );
648 feedback->
appendError( QObject::tr(
"Created raster does not have requested dimensions" ) );
652 if ( nOutputBands != destProvider->bandCount() )
654 QgsDebugError( u
"Created raster does not have requested band count"_s );
657 feedback->
appendError( QObject::tr(
"Created raster does not have requested band count" ) );
663 QgsDebugError( u
"Created raster does not have requested data type"_s );
666 feedback->
appendError( QObject::tr(
"Created raster does not have requested data type" ) );
679 nParts = nPartsX * nPartsY;
682 const bool hasReportsDuringClose = !mTiledMode && destProvider && destProvider->hasReportsDuringClose();
683 const double maxProgress = hasReportsDuringClose ? 50.0 : 100.0;
685 std::unique_ptr< QgsRasterBlock > inputBlock;
686 while ( iter->
readNextRasterPart( 1, iterCols, iterRows, inputBlock, iterLeft, iterTop ) )
688 if ( !inputBlock || inputBlock->isEmpty() )
693 if ( feedback && fileIndex < ( nParts - 1 ) )
695 feedback->
setProgress( maxProgress * fileIndex /
static_cast< double >( nParts ) );
703 const qgssize nPixels =
static_cast< qgssize >( iterCols ) * iterRows;
704 for (
qgssize i = 0; i < nPixels; ++i )
706 QRgb
c = inputBlock->color( i );
707 if ( isPremultiplied )
709 c = qUnpremultiply(
c );
711 redData[i] =
static_cast<unsigned char>( qRed(
c ) );
712 greenData[i] =
static_cast<unsigned char>( qGreen(
c ) );
713 blueData[i] =
static_cast<unsigned char>( qBlue(
c ) );
714 alphaData[i] =
static_cast<unsigned char>( qAlpha(
c ) );
720 std::unique_ptr< QgsRasterDataProvider > partDestProvider( createPartProvider( outputExtent,
721 nCols, iterCols, iterRows,
722 iterLeft, iterTop, mOutputUrl, fileIndex,
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;
785 feedback, [feedback](
double progress )
793 if ( !destProvider->closeWithProgress( feedback ? &closingProgress :
nullptr ) )
795 destProvider->remove();
796 destProvider.reset();
797 return ( feedback && feedback->
isCanceled() ) ?
803 destProvider.reset();
807 mOutputFormat !=
"COG"_L1 )
809 if ( !buildPyramids( mOutputUrl ) )
816void QgsRasterFileWriter::addToVRT(
const QString &filename,
int band,
int xSize,
int ySize,
int xOffset,
int yOffset )
818 QDomElement bandElem = mVRTBands.value( band - 1 );
820 QDomElement simpleSourceElem = mVRTDocument.createElement( u
"SimpleSource"_s );
823 QDomElement sourceFilenameElem = mVRTDocument.createElement( u
"SourceFilename"_s );
824 sourceFilenameElem.setAttribute( u
"relativeToVRT"_s, u
"1"_s );
825 const QDomText sourceFilenameText = mVRTDocument.createTextNode( filename );
826 sourceFilenameElem.appendChild( sourceFilenameText );
827 simpleSourceElem.appendChild( sourceFilenameElem );
830 QDomElement sourceBandElem = mVRTDocument.createElement( u
"SourceBand"_s );
831 const QDomText sourceBandText = mVRTDocument.createTextNode( QString::number( band ) );
832 sourceBandElem.appendChild( sourceBandText );
833 simpleSourceElem.appendChild( sourceBandElem );
836 QDomElement sourcePropertiesElem = mVRTDocument.createElement( u
"SourceProperties"_s );
837 sourcePropertiesElem.setAttribute( u
"RasterXSize"_s, xSize );
838 sourcePropertiesElem.setAttribute( u
"RasterYSize"_s, ySize );
839 sourcePropertiesElem.setAttribute( u
"BlockXSize"_s, xSize );
840 sourcePropertiesElem.setAttribute( u
"BlockYSize"_s, ySize );
841 sourcePropertiesElem.setAttribute( u
"DataType"_s, u
"Byte"_s );
842 simpleSourceElem.appendChild( sourcePropertiesElem );
845 QDomElement srcRectElem = mVRTDocument.createElement( u
"SrcRect"_s );
846 srcRectElem.setAttribute( u
"xOff"_s, u
"0"_s );
847 srcRectElem.setAttribute( u
"yOff"_s, u
"0"_s );
848 srcRectElem.setAttribute( u
"xSize"_s, xSize );
849 srcRectElem.setAttribute( u
"ySize"_s, ySize );
850 simpleSourceElem.appendChild( srcRectElem );
853 QDomElement dstRectElem = mVRTDocument.createElement( u
"DstRect"_s );
854 dstRectElem.setAttribute( u
"xOff"_s, xOffset );
855 dstRectElem.setAttribute( u
"yOff"_s, yOffset );
856 dstRectElem.setAttribute( u
"xSize"_s, xSize );
857 dstRectElem.setAttribute( u
"ySize"_s, ySize );
858 simpleSourceElem.appendChild( dstRectElem );
860 bandElem.appendChild( simpleSourceElem );
863bool QgsRasterFileWriter::buildPyramids(
const QString &filename,
QgsRasterDataProvider *destProviderIn )
867 const QgsDataProvider::ProviderOptions providerOptions;
868 QgsRasterDataProvider *destProvider = destProviderIn;
871 destProvider = qobject_cast< QgsRasterDataProvider * >(
QgsProviderRegistry::instance()->createProvider( mOutputProviderKey, filename, providerOptions ) );
872 if ( !destProvider || !destProvider->
isValid() )
882 QList< QgsRasterPyramid> myPyramidList;
883 if ( ! mPyramidsList.isEmpty() )
885 for (
int myCounterInt = 0; myCounterInt < myPyramidList.count(); myCounterInt++ )
887 myPyramidList[myCounterInt].setBuild(
true );
890 QgsDebugMsgLevel( u
"building pyramids : %1 pyramids, %2 resampling, %3 format, %4 options"_s.arg( myPyramidList.count() ).arg( mPyramidsResampling ).arg(
qgsEnumValueToKey( mPyramidsFormat ) ).arg( mPyramidsConfigOptions.count() ), 4 );
892 const QString res = destProvider->
buildPyramids( myPyramidList, mPyramidsResampling,
893 mPyramidsFormat, mPyramidsConfigOptions );
900 if ( res ==
"ERROR_WRITE_ACCESS"_L1 )
902 message = QObject::tr(
"Write access denied. Adjust the file permissions and try again." );
904 else if ( res ==
"ERROR_WRITE_FORMAT"_L1 )
906 message = QObject::tr(
"The file was not writable. Some formats do not "
907 "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(
int xSize,
int ySize,
const QgsCoordinateReferenceSystem &crs,
double *geoTransform,
Qgis::DataType type,
const QList<bool> &destHasNoDataValueList,
const QList<double> &destNoDataValueList )
950 mVRTDocument.clear();
951 QDomElement VRTDatasetElem = mVRTDocument.createElement( u
"VRTDataset"_s );
954 VRTDatasetElem.setAttribute( u
"rasterXSize"_s, xSize );
955 VRTDatasetElem.setAttribute( u
"rasterYSize"_s, ySize );
956 mVRTDocument.appendChild( VRTDatasetElem );
959 QDomElement SRSElem = mVRTDocument.createElement( u
"SRS"_s );
960 const QDomText crsText = mVRTDocument.createTextNode( crs.
toWkt() );
961 SRSElem.appendChild( crsText );
962 VRTDatasetElem.appendChild( SRSElem );
967 QDomElement geoTransformElem = mVRTDocument.createElement( u
"GeoTransform"_s );
968 const QString geoTransformString = QString::number( geoTransform[0],
'f', 6 ) +
", " + QString::number( geoTransform[1] ) +
", " + QString::number( geoTransform[2] ) +
969 ", " + QString::number( geoTransform[3],
'f', 6 ) +
", " + QString::number( geoTransform[4] ) +
", " + QString::number( geoTransform[5] );
970 const QDomText geoTransformText = mVRTDocument.createTextNode( geoTransformString );
971 geoTransformElem.appendChild( geoTransformText );
972 VRTDatasetElem.appendChild( geoTransformElem );
978 nBands = mInput->bandCount();
985 QStringList colorInterp;
986 colorInterp << u
"Red"_s << u
"Green"_s << u
"Blue"_s << u
"Alpha"_s;
988 QMap<Qgis::DataType, QString> dataTypes;
1001 for (
int i = 1; i <= nBands; i++ )
1003 QDomElement VRTBand = mVRTDocument.createElement( u
"VRTRasterBand"_s );
1005 VRTBand.setAttribute( u
"band"_s, QString::number( i ) );
1006 const QString dataType = dataTypes.value( type );
1007 VRTBand.setAttribute( u
"dataType"_s, dataType );
1012 VRTBand.setAttribute( u
"dataType"_s, u
"Byte"_s );
1013 QDomElement colorInterpElement = mVRTDocument.createElement( u
"ColorInterp"_s );
1014 const QDomText interpText = mVRTDocument.createTextNode( colorInterp.value( i - 1 ) );
1015 colorInterpElement.appendChild( interpText );
1016 VRTBand.appendChild( colorInterpElement );
1019 if ( !destHasNoDataValueList.isEmpty() && destHasNoDataValueList.value( i - 1 ) )
1021 VRTBand.setAttribute( u
"NoDataValue"_s, QString::number( destNoDataValueList.value( i - 1 ) ) );
1024 mVRTBands.append( VRTBand );
1025 VRTDatasetElem.appendChild( VRTBand );
1029bool QgsRasterFileWriter::writeVRT(
const QString &file )
1031 QFile outputFile( file );
1032 if ( ! outputFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
1037 QTextStream outStream( &outputFile );
1038 mVRTDocument.save( outStream, 2 );
1043 int iterRows,
int iterLeft,
int iterTop,
const QString &outputUrl,
int fileIndex,
int nBands,
Qgis::DataType type,
1046 const double mup = extent.
width() / nCols;
1047 const double mapLeft = extent.
xMinimum() + iterLeft * mup;
1048 const double mapRight = mapLeft + mup * iterCols;
1049 const double mapTop = extent.
yMaximum() - iterTop * mup;
1050 const double mapBottom = mapTop - iterRows * mup;
1051 const QgsRectangle mapRect( mapLeft, mapBottom, mapRight, mapTop );
1053 const QString outputFile =
outputUrl +
'/' + partFileName( fileIndex );
1056 double geoTransform[6];
1057 geoTransform[0] = mapRect.xMinimum();
1058 geoTransform[1] = mup;
1059 geoTransform[2] = 0.0;
1060 geoTransform[3] = mapRect.yMaximum();
1061 geoTransform[4] = 0.0;
1062 geoTransform[5] = -mup;
1066 QgsRasterDataProvider *destProvider =
QgsRasterDataProvider::create( mOutputProviderKey, outputFile, mOutputFormat, nBands, type, iterCols, iterRows, geoTransform, crs, mCreationOptions );
1069 return destProvider;
1074 mOutputFormat = format;
1075 if ( !mBuildPyramidsFlagSet && format ==
"COG"_L1 )
1083 mBuildPyramidsFlag = flag;
1084 mBuildPyramidsFlagSet =
true;
1089 const QList<bool> &destHasNoDataValueList,
const QList<double> &destNoDataValueList )
1093 createVRT( nCols, nRows, crs, geoTransform, type, destHasNoDataValueList, destNoDataValueList );
1101 if ( mBuildPyramidsFlag == -4 && mOutputProviderKey ==
"gdal" && mOutputFormat.compare(
"gtiff"_L1, Qt::CaseInsensitive ) == 0 )
1102 mCreationOptions <<
"COPY_SRC_OVERVIEWS=YES";
1105 if ( mOutputFormat ==
"COG"_L1 )
1112 for (
const QString &opt : std::as_const( mPyramidsConfigOptions ) )
1114 const std::string optStr( opt.toStdString() );
1115 char *key =
nullptr;
1116 const char *value = CPLParseNameValue( optStr.c_str(), &key );
1119 if ( EQUAL( key,
"JPEG_QUALITY_OVERVIEW" ) )
1123 else if ( EQUAL( key,
"COMPRESS_OVERVIEW" ) )
1127 else if ( EQUAL( key,
"PREDICTOR_OVERVIEW" ) )
1139 if ( !destProvider )
1144 return destProvider;
1148void QgsRasterFileWriter::globalOutputParameters(
const QgsRectangle &extent,
int nCols,
int &nRows,
1149 double *geoTransform,
double &pixelSize )
1151 pixelSize = extent.
width() / nCols;
1156 nRows =
static_cast< double >( nCols ) / extent.
width() * extent.
height() + 0.5;
1158 geoTransform[0] = extent.
xMinimum();
1159 geoTransform[1] = pixelSize;
1160 geoTransform[2] = 0.0;
1161 geoTransform[3] = extent.
yMaximum();
1162 geoTransform[4] = 0.0;
1163 geoTransform[5] = -( extent.
height() / nRows );
1166QString QgsRasterFileWriter::partFileName(
int fileIndex )
1169 const QFileInfo outputInfo( mOutputUrl );
1170 return u
"%1.%2.tif"_s.arg( outputInfo.fileName() ).arg( fileIndex );
1173QString QgsRasterFileWriter::vrtFileName()
1175 const QFileInfo outputInfo( mOutputUrl );
1176 return u
"%1.vrt"_s.arg( outputInfo.fileName() );
1181 QString ext = extension.trimmed();
1182 if ( ext.isEmpty() )
1185 if ( ext.startsWith(
'.' ) )
1188 if ( ext.compare(
"tif"_L1, Qt::CaseInsensitive ) == 0 ||
1189 ext.compare(
"tiff"_L1, Qt::CaseInsensitive ) == 0 )
1194 if ( GDALGetDriverByName(
"GTiff" ) )
1199 int const drvCount = GDALGetDriverCount();
1201 for (
int i = 0; i < drvCount; ++i )
1203 GDALDriverH drv = GDALGetDriver( i );
1206 CSLConstList driverMetadata = GDALGetMetadata( drv,
nullptr );
1207 if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER,
false ) )
1209 QString drvName = GDALGetDriverShortName( drv );
1210 const QStringList driverExtensions = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) ).split(
' ' );
1212 const auto constDriverExtensions = driverExtensions;
1213 for (
const QString &driver : constDriverExtensions )
1215 if ( driver.compare( ext, Qt::CaseInsensitive ) == 0 )
1226 GDALDriverH drv = GDALGetDriverByName( format.toLocal8Bit().data() );
1229 CSLConstList driverMetadata = GDALGetMetadata( drv,
nullptr );
1230 if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER,
false ) )
1232 return QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) ).split(
' ' );
1235 return QStringList();
1240 GDALDriverH drv = GDALGetDriverByName( driverName.toLocal8Bit().data() );
1243 const QString drvName = GDALGetDriverLongName( drv );
1244 const QString extensionsString = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) );
1245 if ( extensionsString.isEmpty() )
1249 const QStringList extensions = extensionsString.split(
' ' );
1250 QString filter = drvName +
" (";
1251 for (
const QString &ext : extensions )
1253 filter.append( u
"*.%1 *.%2 "_s.arg( ext.toLower(), ext.toUpper() ) );
1255 filter = filter.trimmed().append( u
")"_s );
1264 static QReadWriteLock sFilterLock;
1265 static QMap< RasterFormatOptions, QList< QgsRasterFileWriter::FilterFormatDetails > > sFilters;
1269 const auto it = sFilters.constFind( options );
1270 if ( it != sFilters.constEnd() )
1274 int const drvCount = GDALGetDriverCount();
1277 QList< QgsRasterFileWriter::FilterFormatDetails > results;
1281 for (
int i = 0; i < drvCount; ++i )
1283 GDALDriverH drv = GDALGetDriver( i );
1288 const QString drvName = GDALGetDriverShortName( drv );
1290 if ( filterString.isEmpty() )
1297 if ( options & SortRecommended )
1299 if ( drvName ==
"GTiff"_L1 )
1301 tifFormat = details;
1313 return a.driverName < b.driverName;
1316 if ( options & SortRecommended )
1320 results.insert( 0, tifFormat );
1324 sFilters.insert( options, results );
1332 QSet< QString > extensions;
1334 const thread_local QRegularExpression rx( u
"\\*\\.([a-zA-Z0-9]*)"_s );
1338 const QString ext = format.filterString;
1339 const QRegularExpressionMatch match = rx.match( ext );
1340 if ( !match.hasMatch() )
1343 const QString matched = match.captured( 1 );
1344 extensions.insert( matched );
1347 QStringList extensionList( extensions.constBegin(), extensions.constEnd() );
1349 std::sort( extensionList.begin(), extensionList.end(), [options](
const QString & a,
const QString & b ) ->
bool
1351 if ( options & SortRecommended )
1353 if ( a ==
"tif"_L1 )
1355 else if ( b ==
"tif"_L1 )
1357 if ( a ==
"tiff"_L1 )
1359 else if ( b ==
"tiff"_L1 )
1361 if ( a ==
"gpkg"_L1 )
1363 else if ( b ==
"gpkg"_L1 )
1367 return a.toLower().localeAwareCompare( b.toLower() ) < 0;
1370 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())
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)