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>() );
128 mFeedback = feedback;
135 const QFileInfo fileInfo( mOutputUrl );
136 if ( !fileInfo.exists() )
138 const QDir dir = fileInfo.dir();
139 if ( !dir.mkdir( fileInfo.fileName() ) )
141 QgsDebugError(
"Cannot create output VRT directory " + fileInfo.fileName() +
" in " + dir.absolutePath() );
148 QFile pyramidFile( mOutputUrl + ( mTiledMode ?
".vrt.ovr" :
".ovr" ) );
149 if ( pyramidFile.exists() )
150 pyramidFile.remove();
151 pyramidFile.setFileName( mOutputUrl + ( mTiledMode ?
".vrt.rrd" :
".rrd" ) );
152 if ( pyramidFile.exists() )
153 pyramidFile.remove();
157 return writeImageRaster( &iter, nCols, nRows, outputExtent, crs, feedback );
161 return writeDataRaster( pipe, &iter, nCols, nRows, outputExtent, crs, transformContext, feedback );
174 const QgsRasterInterface *iface = pipe->
last();
180 QgsRasterDataProvider *srcProvider =
const_cast<QgsRasterDataProvider *
>(
dynamic_cast<const QgsRasterDataProvider *
>( iface->
sourceInput() ) );
200 for (
int i = 2; i <= nBands; ++i )
212 QList<bool> destHasNoDataValueList;
213 QList<double> destNoDataValueList;
214 QList<Qgis::DataType> destDataTypeList;
215 destDataTypeList.reserve( nBands );
216 destHasNoDataValueList.reserve( nBands );
217 destNoDataValueList.reserve( nBands );
219 const bool isGpkgOutput = mOutputProviderKey ==
"gdal" &&
220 mOutputFormat.compare(
"gpkg"_L1, Qt::CaseInsensitive ) == 0;
222 double geoTransform[6];
223 globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
224 const auto srcProviderExtent( srcProvider->
extent() );
226 for (
int bandNo = 1; bandNo <= nBands; bandNo++ )
228 QgsRasterNuller *nuller = pipe->
nuller();
231 bool destHasNoDataValue =
false;
232 double destNoDataValue = std::numeric_limits<double>::quiet_NaN();
237 if ( srcHasNoDataValue )
242 destHasNoDataValue =
true;
244 else if ( nuller && !nuller->
noData( bandNo ).isEmpty() )
247 destNoDataValue = nuller->
noData( bandNo ).value( 0 ).min();
248 destHasNoDataValue =
true;
256 QgsRectangle outputExtentInSrcCrs = outputExtent;
257 QgsRasterProjector *projector = pipe->
projector();
261 ct.setBallparkTransformsAreAppropriate(
true );
262 outputExtentInSrcCrs = ct.transformBoundingBox( outputExtent );
264 if ( !srcProviderExtent.contains( outputExtentInSrcCrs ) &&
265 ( std::fabs( srcProviderExtent.xMinimum() - outputExtentInSrcCrs.
xMinimum() ) > geoTransform[1] / 2 ||
266 std::fabs( srcProviderExtent.xMaximum() - outputExtentInSrcCrs.
xMaximum() ) > geoTransform[1] / 2 ||
267 std::fabs( srcProviderExtent.yMinimum() - outputExtentInSrcCrs.
yMinimum() ) > std::fabs( geoTransform[5] ) / 2 ||
268 std::fabs( srcProviderExtent.yMaximum() - outputExtentInSrcCrs.
yMaximum() ) > std::fabs( geoTransform[5] ) / 2 ) )
279 destNoDataValue = typeMinValue;
283 destNoDataValue = typeMaxValue;
290 destHasNoDataValue =
true;
294 if ( nuller && destHasNoDataValue )
299 QgsDebugMsgLevel( u
"bandNo = %1 destDataType = %2 destHasNoDataValue = %3 destNoDataValue = %4"_s.arg( bandNo ).arg(
qgsEnumValueToKey( destDataType ) ).arg( destHasNoDataValue ).arg( destNoDataValue ), 4 );
300 destDataTypeList.append( destDataType );
301 destHasNoDataValueList.append( destHasNoDataValue );
302 destNoDataValueList.append( destNoDataValue );
307 for (
int i = 1; i < nBands; i++ )
309 if ( destDataTypeList.value( i ) > destDataType )
311 destDataType = destDataTypeList.value( i );
317 for (
int attempt = 0; attempt < 2; attempt ++ )
321 std::unique_ptr<QgsRasterDataProvider> destProvider(
322 initOutput( nCols, nRows, crs, geoTransform, nBands, destDataType, destHasNoDataValueList, destNoDataValueList ) );
329 if ( !destProvider->isValid() )
331 if ( feedback && !destProvider->error().isEmpty() )
333 feedback->
appendError( destProvider->error().summary() );
337 if ( nCols != destProvider->xSize() || nRows != destProvider->ySize() )
339 QgsDebugError( u
"Created raster does not have requested dimensions"_s );
342 feedback->
appendError( QObject::tr(
"Created raster does not have requested dimensions" ) );
346 if ( nBands != destProvider->bandCount() )
348 QgsDebugError( u
"Created raster does not have requested band count"_s );
351 feedback->
appendError( QObject::tr(
"Created raster does not have requested band count" ) );
359 destDataType = destProvider->dataType( 1 );
363 error = writeDataRaster( pipe, iter, nCols, nRows, outputExtent, crs, destDataType, destHasNoDataValueList, destNoDataValueList, destProvider, feedback );
370 destProvider->remove();
371 destProvider.reset();
379 for (
int i = 0; i < nBands; i++ )
381 double destNoDataValue;
383 destDataTypeList.replace( i, destDataType );
384 destNoDataValueList.replace( i, destNoDataValue );
386 destDataType = destDataTypeList.value( 0 );
399static int qgsDivRoundUp(
int a,
int b )
401 return a / b + ( ( ( a % b ) != 0 ) ? 1 : 0 );
406 int nCols,
int nRows,
410 const QList<bool> &destHasNoDataValueList,
411 const QList<double> &destNoDataValueList,
412 std::unique_ptr<QgsRasterDataProvider> &destProvider,
416 Q_UNUSED( destHasNoDataValueList )
419 const QgsRasterInterface *iface = iter->
input();
420 const QgsRasterDataProvider *srcProvider =
dynamic_cast<const QgsRasterDataProvider *
>( iface->
sourceInput() );
430 std::vector< std::unique_ptr<QgsRasterBlock> > blockList;
431 std::vector< std::unique_ptr<QgsRasterBlock> > destBlockList;
433 blockList.resize( nBands );
434 destBlockList.resize( nBands );
436 for (
int i = 1; i <= nBands; ++i )
439 if ( destProvider && destHasNoDataValueList.value( i - 1 ) )
441 destProvider->setNoDataValue( i, destNoDataValueList.value( i - 1 ) );
451 nParts = nPartsX * nPartsY;
454 const bool hasReportsDuringClose = destProvider && destProvider->hasReportsDuringClose();
461 for (
int i = 1; i <= nBands && !done; ++i )
463 QgsRasterBlock *block =
nullptr;
469 const QString vrtFilePath( mOutputUrl +
'/' + vrtFileName() );
470 writeVRT( vrtFilePath );
473 if ( !buildPyramids( vrtFilePath ) )
483 mOutputFormat !=
"COG"_L1 )
485 if ( !buildPyramids( mOutputUrl, destProvider.get() ) )
495 blockList[i - 1].reset( block );
503 if ( feedback && fileIndex < ( nParts - 1 ) )
505 const double maxProgress = hasReportsDuringClose ? 50.0 : 100.0;
506 feedback->
setProgress( maxProgress * fileIndex /
static_cast< double >( nParts ) );
514 for (
int i = 1; i <= nBands; ++i )
516 if ( srcProvider && srcProvider->
dataType( i ) == destDataType )
523 blockList[i - 1]->convert( destDataType );
525 destBlockList[i - 1] = std::move( blockList[i - 1] );
530 std::unique_ptr< QgsRasterDataProvider > partDestProvider( createPartProvider( outputExtent,
531 nCols, iterCols, iterRows,
532 iterLeft, iterTop, mOutputUrl,
533 fileIndex, nBands, destDataType, crs ) );
535 if ( !partDestProvider || !partDestProvider->isValid() )
541 for (
int i = 1; i <= nBands; ++i )
543 if ( destHasNoDataValueList.value( i - 1 ) )
545 partDestProvider->setNoDataValue( i, destNoDataValueList.value( i - 1 ) );
547 if ( destBlockList[ i - 1 ]->isEmpty() )
550 if ( !partDestProvider->write( destBlockList[i - 1]->constBits( 0 ), i, iterCols, iterRows, 0, 0 ) )
554 addToVRT( partFileName( fileIndex ), i, iterCols, iterRows, iterLeft, iterTop );
558 else if ( destProvider )
561 for (
int i = 1; i <= nBands; ++i )
563 if ( destBlockList[ i - 1 ]->isEmpty() )
566 if ( !destProvider->write( destBlockList[i - 1]->constBits( 0 ), i, iterCols, iterRows, iterLeft, iterTop ) )
577 if ( feedback && destProvider && hasReportsDuringClose )
580 if ( !destProvider->closeWithProgress( scaledFeedback.get() ) )
582 destProvider->remove();
583 destProvider.reset();
584 return ( feedback && feedback->
isCanceled() ) ?
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,
724 nCols, iterCols, iterRows,
725 iterLeft, iterTop, mOutputUrl, fileIndex,
728 if ( !partDestProvider || partDestProvider->isValid() )
734 if ( !partDestProvider->write( &redData[0], 1, iterCols, iterRows, 0, 0 ) ||
735 !partDestProvider->write( &greenData[0], 2, iterCols, iterRows, 0, 0 ) ||
736 !partDestProvider->write( &blueData[0], 3, iterCols, iterRows, 0, 0 ) ||
737 !partDestProvider->write( &alphaData[0], 4, iterCols, iterRows, 0, 0 ) )
742 addToVRT( partFileName( fileIndex ), 1, iterCols, iterRows, iterLeft, iterTop );
743 addToVRT( partFileName( fileIndex ), 2, iterCols, iterRows, iterLeft, iterTop );
744 addToVRT( partFileName( fileIndex ), 3, iterCols, iterRows, iterLeft, iterTop );
745 addToVRT( partFileName( fileIndex ), 4, iterCols, iterRows, iterLeft, iterTop );
747 else if ( destProvider )
749 if ( !destProvider->write( &redData[0], 1, iterCols, iterRows, iterLeft, iterTop ) ||
750 !destProvider->write( &greenData[0], 2, iterCols, iterRows, iterLeft, iterTop ) ||
751 !destProvider->write( &blueData[0], 3, iterCols, iterRows, iterLeft, iterTop ) ||
752 !destProvider->write( &alphaData[0], 4, iterCols, iterRows, iterLeft, iterTop ) )
768 destProvider.reset();
770 const QString vrtFilePath( mOutputUrl +
'/' + vrtFileName() );
771 writeVRT( vrtFilePath );
774 if ( !buildPyramids( vrtFilePath ) )
782 if ( destProvider && hasReportsDuringClose )
784 QgsFeedback closingProgress;
788 feedback, [feedback](
double progress )
796 if ( !destProvider->closeWithProgress( feedback ? &closingProgress :
nullptr ) )
798 destProvider->remove();
799 destProvider.reset();
800 return ( feedback && feedback->
isCanceled() ) ?
806 destProvider.reset();
810 mOutputFormat !=
"COG"_L1 )
812 if ( !buildPyramids( mOutputUrl ) )
819void QgsRasterFileWriter::addToVRT(
const QString &filename,
int band,
int xSize,
int ySize,
int xOffset,
int yOffset )
821 QDomElement bandElem = mVRTBands.value( band - 1 );
823 QDomElement simpleSourceElem = mVRTDocument.createElement( u
"SimpleSource"_s );
826 QDomElement sourceFilenameElem = mVRTDocument.createElement( u
"SourceFilename"_s );
827 sourceFilenameElem.setAttribute( u
"relativeToVRT"_s, u
"1"_s );
828 const QDomText sourceFilenameText = mVRTDocument.createTextNode( filename );
829 sourceFilenameElem.appendChild( sourceFilenameText );
830 simpleSourceElem.appendChild( sourceFilenameElem );
833 QDomElement sourceBandElem = mVRTDocument.createElement( u
"SourceBand"_s );
834 const QDomText sourceBandText = mVRTDocument.createTextNode( QString::number( band ) );
835 sourceBandElem.appendChild( sourceBandText );
836 simpleSourceElem.appendChild( sourceBandElem );
839 QDomElement sourcePropertiesElem = mVRTDocument.createElement( u
"SourceProperties"_s );
840 sourcePropertiesElem.setAttribute( u
"RasterXSize"_s, xSize );
841 sourcePropertiesElem.setAttribute( u
"RasterYSize"_s, ySize );
842 sourcePropertiesElem.setAttribute( u
"BlockXSize"_s, xSize );
843 sourcePropertiesElem.setAttribute( u
"BlockYSize"_s, ySize );
844 sourcePropertiesElem.setAttribute( u
"DataType"_s, u
"Byte"_s );
845 simpleSourceElem.appendChild( sourcePropertiesElem );
848 QDomElement srcRectElem = mVRTDocument.createElement( u
"SrcRect"_s );
849 srcRectElem.setAttribute( u
"xOff"_s, u
"0"_s );
850 srcRectElem.setAttribute( u
"yOff"_s, u
"0"_s );
851 srcRectElem.setAttribute( u
"xSize"_s, xSize );
852 srcRectElem.setAttribute( u
"ySize"_s, ySize );
853 simpleSourceElem.appendChild( srcRectElem );
856 QDomElement dstRectElem = mVRTDocument.createElement( u
"DstRect"_s );
857 dstRectElem.setAttribute( u
"xOff"_s, xOffset );
858 dstRectElem.setAttribute( u
"yOff"_s, yOffset );
859 dstRectElem.setAttribute( u
"xSize"_s, xSize );
860 dstRectElem.setAttribute( u
"ySize"_s, ySize );
861 simpleSourceElem.appendChild( dstRectElem );
863 bandElem.appendChild( simpleSourceElem );
866bool QgsRasterFileWriter::buildPyramids(
const QString &filename,
QgsRasterDataProvider *destProviderIn )
870 const QgsDataProvider::ProviderOptions providerOptions;
871 QgsRasterDataProvider *destProvider = destProviderIn;
874 destProvider = qobject_cast< QgsRasterDataProvider * >(
QgsProviderRegistry::instance()->createProvider( mOutputProviderKey, filename, providerOptions ) );
875 if ( !destProvider || !destProvider->
isValid() )
885 QList< QgsRasterPyramid> myPyramidList;
886 if ( ! mPyramidsList.isEmpty() )
888 for (
int myCounterInt = 0; myCounterInt < myPyramidList.count(); myCounterInt++ )
890 myPyramidList[myCounterInt].setBuild(
true );
893 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 );
895 const QString res = destProvider->
buildPyramids( myPyramidList, mPyramidsResampling,
896 mPyramidsFormat, mPyramidsConfigOptions );
903 if ( res ==
"ERROR_WRITE_ACCESS"_L1 )
905 message = QObject::tr(
"Write access denied. Adjust the file permissions and try again." );
907 else if ( res ==
"ERROR_WRITE_FORMAT"_L1 )
909 message = QObject::tr(
"The file was not writable. Some formats do not "
910 "support pyramid overviews. Consult the GDAL documentation if in doubt." );
912 else if ( res ==
"FAILED_NOT_SUPPORTED"_L1 )
914 message = QObject::tr(
"Building pyramid overviews is not supported on this type of raster." );
916 else if ( res ==
"ERROR_VIRTUAL"_L1 )
918 message = QObject::tr(
"Building pyramid overviews is not supported on this type of raster." );
925 if ( !destProviderIn )
932int QgsRasterFileWriter::pyramidsProgress(
double dfComplete,
const char *pszMessage,
void *pData )
934 Q_UNUSED( pszMessage )
935 GDALTermProgress( dfComplete, 0, 0 );
936 QProgressDialog *progressDialog =
static_cast<QProgressDialog *
>( pData );
937 if ( pData && progressDialog->wasCanceled() )
944 progressDialog->setRange( 0, 100 );
945 progressDialog->setValue( dfComplete * 100 );
951void QgsRasterFileWriter::createVRT(
int xSize,
int ySize,
const QgsCoordinateReferenceSystem &crs,
double *geoTransform,
Qgis::DataType type,
const QList<bool> &destHasNoDataValueList,
const QList<double> &destNoDataValueList )
953 mVRTDocument.clear();
954 QDomElement VRTDatasetElem = mVRTDocument.createElement( u
"VRTDataset"_s );
957 VRTDatasetElem.setAttribute( u
"rasterXSize"_s, xSize );
958 VRTDatasetElem.setAttribute( u
"rasterYSize"_s, ySize );
959 mVRTDocument.appendChild( VRTDatasetElem );
962 QDomElement SRSElem = mVRTDocument.createElement( u
"SRS"_s );
963 const QDomText crsText = mVRTDocument.createTextNode( crs.
toWkt() );
964 SRSElem.appendChild( crsText );
965 VRTDatasetElem.appendChild( SRSElem );
970 QDomElement geoTransformElem = mVRTDocument.createElement( u
"GeoTransform"_s );
971 const QString geoTransformString = QString::number( geoTransform[0],
'f', 6 ) +
", " + QString::number( geoTransform[1] ) +
", " + QString::number( geoTransform[2] ) +
972 ", " + QString::number( geoTransform[3],
'f', 6 ) +
", " + QString::number( geoTransform[4] ) +
", " + QString::number( geoTransform[5] );
973 const QDomText geoTransformText = mVRTDocument.createTextNode( geoTransformString );
974 geoTransformElem.appendChild( geoTransformText );
975 VRTDatasetElem.appendChild( geoTransformElem );
981 nBands = mInput->bandCount();
988 QStringList colorInterp;
989 colorInterp << u
"Red"_s << u
"Green"_s << u
"Blue"_s << u
"Alpha"_s;
991 QMap<Qgis::DataType, QString> dataTypes;
1004 for (
int i = 1; i <= nBands; i++ )
1006 QDomElement VRTBand = mVRTDocument.createElement( u
"VRTRasterBand"_s );
1008 VRTBand.setAttribute( u
"band"_s, QString::number( i ) );
1009 const QString dataType = dataTypes.value( type );
1010 VRTBand.setAttribute( u
"dataType"_s, dataType );
1015 VRTBand.setAttribute( u
"dataType"_s, u
"Byte"_s );
1016 QDomElement colorInterpElement = mVRTDocument.createElement( u
"ColorInterp"_s );
1017 const QDomText interpText = mVRTDocument.createTextNode( colorInterp.value( i - 1 ) );
1018 colorInterpElement.appendChild( interpText );
1019 VRTBand.appendChild( colorInterpElement );
1022 if ( !destHasNoDataValueList.isEmpty() && destHasNoDataValueList.value( i - 1 ) )
1024 VRTBand.setAttribute( u
"NoDataValue"_s, QString::number( destNoDataValueList.value( i - 1 ) ) );
1027 mVRTBands.append( VRTBand );
1028 VRTDatasetElem.appendChild( VRTBand );
1032bool QgsRasterFileWriter::writeVRT(
const QString &file )
1034 QFile outputFile( file );
1035 if ( ! outputFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
1040 QTextStream outStream( &outputFile );
1041 mVRTDocument.save( outStream, 2 );
1046 int iterRows,
int iterLeft,
int iterTop,
const QString &outputUrl,
int fileIndex,
int nBands,
Qgis::DataType type,
1049 const double mup = extent.
width() / nCols;
1050 const double mapLeft = extent.
xMinimum() + iterLeft * mup;
1051 const double mapRight = mapLeft + mup * iterCols;
1052 const double mapTop = extent.
yMaximum() - iterTop * mup;
1053 const double mapBottom = mapTop - iterRows * mup;
1054 const QgsRectangle mapRect( mapLeft, mapBottom, mapRight, mapTop );
1056 const QString outputFile =
outputUrl +
'/' + partFileName( fileIndex );
1059 double geoTransform[6];
1060 geoTransform[0] = mapRect.xMinimum();
1061 geoTransform[1] = mup;
1062 geoTransform[2] = 0.0;
1063 geoTransform[3] = mapRect.yMaximum();
1064 geoTransform[4] = 0.0;
1065 geoTransform[5] = -mup;
1069 QgsRasterDataProvider *destProvider =
QgsRasterDataProvider::create( mOutputProviderKey, outputFile, mOutputFormat, nBands, type, iterCols, iterRows, geoTransform, crs, mCreationOptions );
1072 return destProvider;
1077 mOutputFormat = format;
1078 if ( !mBuildPyramidsFlagSet && format ==
"COG"_L1 )
1086 mBuildPyramidsFlag = flag;
1087 mBuildPyramidsFlagSet =
true;
1092 const QList<bool> &destHasNoDataValueList,
const QList<double> &destNoDataValueList )
1096 createVRT( nCols, nRows, crs, geoTransform, type, destHasNoDataValueList, destNoDataValueList );
1104 if ( mBuildPyramidsFlag == -4 && mOutputProviderKey ==
"gdal" && mOutputFormat.compare(
"gtiff"_L1, Qt::CaseInsensitive ) == 0 )
1105 mCreationOptions <<
"COPY_SRC_OVERVIEWS=YES";
1108 if ( mOutputFormat ==
"COG"_L1 )
1115 for (
const QString &opt : std::as_const( mPyramidsConfigOptions ) )
1117 const std::string optStr( opt.toStdString() );
1118 char *key =
nullptr;
1119 const char *value = CPLParseNameValue( optStr.c_str(), &key );
1122 if ( EQUAL( key,
"JPEG_QUALITY_OVERVIEW" ) )
1126 else if ( EQUAL( key,
"COMPRESS_OVERVIEW" ) )
1130 else if ( EQUAL( key,
"PREDICTOR_OVERVIEW" ) )
1142 if ( !destProvider )
1147 return destProvider;
1151void QgsRasterFileWriter::globalOutputParameters(
const QgsRectangle &extent,
int nCols,
int &nRows,
1152 double *geoTransform,
double &pixelSize )
1154 pixelSize = extent.
width() / nCols;
1159 nRows =
static_cast< double >( nCols ) / extent.
width() * extent.
height() + 0.5;
1161 geoTransform[0] = extent.
xMinimum();
1162 geoTransform[1] = pixelSize;
1163 geoTransform[2] = 0.0;
1164 geoTransform[3] = extent.
yMaximum();
1165 geoTransform[4] = 0.0;
1166 geoTransform[5] = -( extent.
height() / nRows );
1169QString QgsRasterFileWriter::partFileName(
int fileIndex )
1172 const QFileInfo outputInfo( mOutputUrl );
1173 return u
"%1.%2.tif"_s.arg( outputInfo.fileName() ).arg( fileIndex );
1176QString QgsRasterFileWriter::vrtFileName()
1178 const QFileInfo outputInfo( mOutputUrl );
1179 return u
"%1.vrt"_s.arg( outputInfo.fileName() );
1184 QString ext = extension.trimmed();
1185 if ( ext.isEmpty() )
1188 if ( ext.startsWith(
'.' ) )
1191 if ( ext.compare(
"tif"_L1, Qt::CaseInsensitive ) == 0 ||
1192 ext.compare(
"tiff"_L1, Qt::CaseInsensitive ) == 0 )
1197 if ( GDALGetDriverByName(
"GTiff" ) )
1202 int const drvCount = GDALGetDriverCount();
1204 for (
int i = 0; i < drvCount; ++i )
1206 GDALDriverH drv = GDALGetDriver( i );
1209 CSLConstList driverMetadata = GDALGetMetadata( drv,
nullptr );
1210 if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER,
false ) )
1212 QString drvName = GDALGetDriverShortName( drv );
1213 const QStringList driverExtensions = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) ).split(
' ' );
1215 const auto constDriverExtensions = driverExtensions;
1216 for (
const QString &driver : constDriverExtensions )
1218 if ( driver.compare( ext, Qt::CaseInsensitive ) == 0 )
1229 GDALDriverH drv = GDALGetDriverByName( format.toLocal8Bit().data() );
1232 CSLConstList driverMetadata = GDALGetMetadata( drv,
nullptr );
1233 if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER,
false ) )
1235 return QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) ).split(
' ' );
1238 return QStringList();
1243 GDALDriverH drv = GDALGetDriverByName( driverName.toLocal8Bit().data() );
1246 const QString drvName = GDALGetDriverLongName( drv );
1247 const QString extensionsString = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) );
1248 if ( extensionsString.isEmpty() )
1252 const QStringList extensions = extensionsString.split(
' ' );
1253 QString filter = drvName +
" (";
1254 for (
const QString &ext : extensions )
1256 filter.append( u
"*.%1 *.%2 "_s.arg( ext.toLower(), ext.toUpper() ) );
1258 filter = filter.trimmed().append( u
")"_s );
1267 static QReadWriteLock sFilterLock;
1268 static QMap< RasterFormatOptions, QList< QgsRasterFileWriter::FilterFormatDetails > > sFilters;
1272 const auto it = sFilters.constFind( options );
1273 if ( it != sFilters.constEnd() )
1277 int const drvCount = GDALGetDriverCount();
1280 QList< QgsRasterFileWriter::FilterFormatDetails > results;
1284 for (
int i = 0; i < drvCount; ++i )
1286 GDALDriverH drv = GDALGetDriver( i );
1291 const QString drvName = GDALGetDriverShortName( drv );
1293 if ( filterString.isEmpty() )
1300 if ( options & SortRecommended )
1302 if ( drvName ==
"GTiff"_L1 )
1304 tifFormat = details;
1316 return a.driverName < b.driverName;
1319 if ( options & SortRecommended )
1323 results.insert( 0, tifFormat );
1327 sFilters.insert( options, results );
1335 QSet< QString > extensions;
1337 const thread_local QRegularExpression rx( u
"\\*\\.([a-zA-Z0-9]*)"_s );
1341 const QString ext = format.filterString;
1342 const QRegularExpressionMatch match = rx.match( ext );
1343 if ( !match.hasMatch() )
1346 const QString matched = match.captured( 1 );
1347 extensions.insert( matched );
1350 QStringList extensionList( extensions.constBegin(), extensions.constEnd() );
1352 std::sort( extensionList.begin(), extensionList.end(), [options](
const QString & a,
const QString & b ) ->
bool
1354 if ( options & SortRecommended )
1356 if ( a ==
"tif"_L1 )
1358 else if ( b ==
"tif"_L1 )
1360 if ( a ==
"tiff"_L1 )
1362 else if ( b ==
"tiff"_L1 )
1364 if ( a ==
"gpkg"_L1 )
1366 else if ( b ==
"gpkg"_L1 )
1370 return a.toLower().localeAwareCompare( b.toLower() ) < 0;
1373 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)