18#include <cpl_string.h>
35#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>() );
113 QgsDebugMsgLevel( QStringLiteral(
"reading from %1" ).arg(
typeid( *iface ).name() ), 4 );
122 QgsDebugMsgLevel( QStringLiteral(
"srcInput = %1" ).arg(
typeid( srcInput ).name() ), 4 );
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() ) );
180 QgsDebugError( QStringLiteral(
"Cannot get source data provider" ) );
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( QLatin1String(
"gpkg" ), 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( QStringLiteral(
"bandNo = %1 destDataType = %2 destHasNoDataValue = %3 destNoDataValue = %4" ).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( QStringLiteral(
"Created raster does not have requested dimensions" ) );
339 feedback->
appendError( QObject::tr(
"Created raster does not have requested dimensions" ) );
343 if ( nBands != destProvider->bandCount() )
345 QgsDebugError( QStringLiteral(
"Created raster does not have requested band count" ) );
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.get(), 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,
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;
455 for (
int i = 1; i <= nBands; ++i )
457 QgsRasterBlock *block =
nullptr;
463 const QString vrtFilePath( mOutputUrl +
'/' + vrtFileName() );
464 writeVRT( vrtFilePath );
467 buildPyramids( vrtFilePath );
474 buildPyramids( mOutputUrl, destProvider );
481 blockList[i - 1].reset( block );
485 if ( feedback && fileIndex < ( nParts - 1 ) )
487 feedback->
setProgress( 100.0 * fileIndex /
static_cast< double >( nParts ) );
495 for (
int i = 1; i <= nBands; ++i )
497 if ( srcProvider && srcProvider->
dataType( i ) == destDataType )
504 blockList[i - 1]->convert( destDataType );
506 destBlockList[i - 1] = std::move( blockList[i - 1] );
511 std::unique_ptr< QgsRasterDataProvider > partDestProvider( createPartProvider( outputExtent,
512 nCols, iterCols, iterRows,
513 iterLeft, iterTop, mOutputUrl,
514 fileIndex, nBands, destDataType, crs ) );
516 if ( !partDestProvider || !partDestProvider->isValid() )
522 for (
int i = 1; i <= nBands; ++i )
524 if ( destHasNoDataValueList.value( i - 1 ) )
526 partDestProvider->setNoDataValue( i, destNoDataValueList.value( i - 1 ) );
528 if ( destBlockList[ i - 1 ]->isEmpty() )
531 if ( !partDestProvider->write( destBlockList[i - 1]->constBits( 0 ), i, iterCols, iterRows, 0, 0 ) )
535 addToVRT( partFileName( fileIndex ), i, iterCols, iterRows, iterLeft, iterTop );
539 else if ( destProvider )
542 for (
int i = 1; i <= nBands; ++i )
544 if ( destBlockList[ i - 1 ]->isEmpty() )
547 if ( !destProvider->
write( destBlockList[i - 1]->constBits( 0 ), i, iterCols, iterRows, iterLeft, iterTop ) )
569 const QgsRasterInterface *iface = iter->
input();
583 const size_t nMaxPixels =
static_cast<size_t>( mMaxTileWidth ) * mMaxTileHeight;
584 std::vector<unsigned char> redData( nMaxPixels );
585 std::vector<unsigned char> greenData( nMaxPixels );
586 std::vector<unsigned char> blueData( nMaxPixels );
587 std::vector<unsigned char> alphaData( nMaxPixels );
588 int iterLeft = 0, iterTop = 0, iterCols = 0, iterRows = 0;
593 double geoTransform[6];
594 globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
596 const int nOutputBands = 4;
597 std::unique_ptr< QgsRasterDataProvider > destProvider( initOutput( nCols, nRows, crs, geoTransform, nOutputBands,
Qgis::DataType::Byte ) );
604 if ( !destProvider->
isValid() )
612 if ( nCols != destProvider->
xSize() || nRows != destProvider->
ySize() )
614 QgsDebugError( QStringLiteral(
"Created raster does not have requested dimensions" ) );
617 feedback->
appendError( QObject::tr(
"Created raster does not have requested dimensions" ) );
621 if ( nOutputBands != destProvider->
bandCount() )
623 QgsDebugError( QStringLiteral(
"Created raster does not have requested band count" ) );
626 feedback->
appendError( QObject::tr(
"Created raster does not have requested band count" ) );
632 QgsDebugError( QStringLiteral(
"Created raster does not have requested data type" ) );
635 feedback->
appendError( QObject::tr(
"Created raster does not have requested data type" ) );
648 nParts = nPartsX * nPartsY;
651 std::unique_ptr< QgsRasterBlock > inputBlock;
652 while ( iter->
readNextRasterPart( 1, iterCols, iterRows, inputBlock, iterLeft, iterTop ) )
654 if ( !inputBlock || inputBlock->isEmpty() )
659 if ( feedback && fileIndex < ( nParts - 1 ) )
661 feedback->
setProgress( 100.0 * fileIndex /
static_cast< double >( nParts ) );
669 const qgssize nPixels =
static_cast< qgssize >( iterCols ) * iterRows;
670 for (
qgssize i = 0; i < nPixels; ++i )
672 QRgb
c = inputBlock->color( i );
673 if ( isPremultiplied )
675 c = qUnpremultiply(
c );
677 redData[i] =
static_cast<unsigned char>( qRed(
c ) );
678 greenData[i] =
static_cast<unsigned char>( qGreen(
c ) );
679 blueData[i] =
static_cast<unsigned char>( qBlue(
c ) );
680 alphaData[i] =
static_cast<unsigned char>( qAlpha(
c ) );
686 std::unique_ptr< QgsRasterDataProvider > partDestProvider( createPartProvider( outputExtent,
687 nCols, iterCols, iterRows,
688 iterLeft, iterTop, mOutputUrl, fileIndex,
691 if ( !partDestProvider || partDestProvider->isValid() )
697 if ( !partDestProvider->write( &redData[0], 1, iterCols, iterRows, 0, 0 ) ||
698 !partDestProvider->write( &greenData[0], 2, iterCols, iterRows, 0, 0 ) ||
699 !partDestProvider->write( &blueData[0], 3, iterCols, iterRows, 0, 0 ) ||
700 !partDestProvider->write( &alphaData[0], 4, iterCols, iterRows, 0, 0 ) )
705 addToVRT( partFileName( fileIndex ), 1, iterCols, iterRows, iterLeft, iterTop );
706 addToVRT( partFileName( fileIndex ), 2, iterCols, iterRows, iterLeft, iterTop );
707 addToVRT( partFileName( fileIndex ), 3, iterCols, iterRows, iterLeft, iterTop );
708 addToVRT( partFileName( fileIndex ), 4, iterCols, iterRows, iterLeft, iterTop );
710 else if ( destProvider )
712 if ( !destProvider->
write( &redData[0], 1, iterCols, iterRows, iterLeft, iterTop ) ||
713 !destProvider->
write( &greenData[0], 2, iterCols, iterRows, iterLeft, iterTop ) ||
714 !destProvider->
write( &blueData[0], 3, iterCols, iterRows, iterLeft, iterTop ) ||
715 !destProvider->
write( &alphaData[0], 4, iterCols, iterRows, iterLeft, iterTop ) )
723 destProvider.reset();
732 const QString vrtFilePath( mOutputUrl +
'/' + vrtFileName() );
733 writeVRT( vrtFilePath );
736 buildPyramids( vrtFilePath );
743 buildPyramids( mOutputUrl );
749void QgsRasterFileWriter::addToVRT(
const QString &filename,
int band,
int xSize,
int ySize,
int xOffset,
int yOffset )
751 QDomElement bandElem = mVRTBands.value( band - 1 );
753 QDomElement simpleSourceElem = mVRTDocument.createElement( QStringLiteral(
"SimpleSource" ) );
756 QDomElement sourceFilenameElem = mVRTDocument.createElement( QStringLiteral(
"SourceFilename" ) );
757 sourceFilenameElem.setAttribute( QStringLiteral(
"relativeToVRT" ), QStringLiteral(
"1" ) );
758 const QDomText sourceFilenameText = mVRTDocument.createTextNode( filename );
759 sourceFilenameElem.appendChild( sourceFilenameText );
760 simpleSourceElem.appendChild( sourceFilenameElem );
763 QDomElement sourceBandElem = mVRTDocument.createElement( QStringLiteral(
"SourceBand" ) );
764 const QDomText sourceBandText = mVRTDocument.createTextNode( QString::number( band ) );
765 sourceBandElem.appendChild( sourceBandText );
766 simpleSourceElem.appendChild( sourceBandElem );
769 QDomElement sourcePropertiesElem = mVRTDocument.createElement( QStringLiteral(
"SourceProperties" ) );
770 sourcePropertiesElem.setAttribute( QStringLiteral(
"RasterXSize" ), xSize );
771 sourcePropertiesElem.setAttribute( QStringLiteral(
"RasterYSize" ), ySize );
772 sourcePropertiesElem.setAttribute( QStringLiteral(
"BlockXSize" ), xSize );
773 sourcePropertiesElem.setAttribute( QStringLiteral(
"BlockYSize" ), ySize );
774 sourcePropertiesElem.setAttribute( QStringLiteral(
"DataType" ), QStringLiteral(
"Byte" ) );
775 simpleSourceElem.appendChild( sourcePropertiesElem );
778 QDomElement srcRectElem = mVRTDocument.createElement( QStringLiteral(
"SrcRect" ) );
779 srcRectElem.setAttribute( QStringLiteral(
"xOff" ), QStringLiteral(
"0" ) );
780 srcRectElem.setAttribute( QStringLiteral(
"yOff" ), QStringLiteral(
"0" ) );
781 srcRectElem.setAttribute( QStringLiteral(
"xSize" ), xSize );
782 srcRectElem.setAttribute( QStringLiteral(
"ySize" ), ySize );
783 simpleSourceElem.appendChild( srcRectElem );
786 QDomElement dstRectElem = mVRTDocument.createElement( QStringLiteral(
"DstRect" ) );
787 dstRectElem.setAttribute( QStringLiteral(
"xOff" ), xOffset );
788 dstRectElem.setAttribute( QStringLiteral(
"yOff" ), yOffset );
789 dstRectElem.setAttribute( QStringLiteral(
"xSize" ), xSize );
790 dstRectElem.setAttribute( QStringLiteral(
"ySize" ), ySize );
791 simpleSourceElem.appendChild( dstRectElem );
793 bandElem.appendChild( simpleSourceElem );
796void QgsRasterFileWriter::buildPyramids(
const QString &filename,
QgsRasterDataProvider *destProviderIn )
800 const QgsDataProvider::ProviderOptions providerOptions;
801 QgsRasterDataProvider *destProvider = destProviderIn;
804 destProvider = qobject_cast< QgsRasterDataProvider * >(
QgsProviderRegistry::instance()->createProvider( mOutputProviderKey, filename, providerOptions ) );
805 if ( !destProvider || !destProvider->
isValid() )
815 QList< QgsRasterPyramid> myPyramidList;
816 if ( ! mPyramidsList.isEmpty() )
818 for (
int myCounterInt = 0; myCounterInt < myPyramidList.count(); myCounterInt++ )
820 myPyramidList[myCounterInt].setBuild(
true );
823 QgsDebugMsgLevel( QStringLiteral(
"building pyramids : %1 pyramids, %2 resampling, %3 format, %4 options" ).arg( myPyramidList.count() ).arg( mPyramidsResampling ).arg(
qgsEnumValueToKey( mPyramidsFormat ) ).arg( mPyramidsConfigOptions.count() ), 4 );
825 const QString res = destProvider->
buildPyramids( myPyramidList, mPyramidsResampling,
826 mPyramidsFormat, mPyramidsConfigOptions );
832 QString title, message;
833 if ( res == QLatin1String(
"ERROR_WRITE_ACCESS" ) )
835 title = QObject::tr(
"Building Pyramids" );
836 message = QObject::tr(
"Write access denied. Adjust the file permissions and try again." );
838 else if ( res == QLatin1String(
"ERROR_WRITE_FORMAT" ) )
840 title = QObject::tr(
"Building Pyramids" );
841 message = QObject::tr(
"The file was not writable. Some formats do not "
842 "support pyramid overviews. Consult the GDAL documentation if in doubt." );
844 else if ( res == QLatin1String(
"FAILED_NOT_SUPPORTED" ) )
846 title = QObject::tr(
"Building Pyramids" );
847 message = QObject::tr(
"Building pyramid overviews is not supported on this type of raster." );
849 else if ( res == QLatin1String(
"ERROR_VIRTUAL" ) )
851 title = QObject::tr(
"Building Pyramids" );
852 message = QObject::tr(
"Building pyramid overviews is not supported on this type of raster." );
854 QMessageBox::warning(
nullptr, title, message );
857 if ( !destProviderIn )
862int QgsRasterFileWriter::pyramidsProgress(
double dfComplete,
const char *pszMessage,
void *pData )
864 Q_UNUSED( pszMessage )
865 GDALTermProgress( dfComplete, 0, 0 );
866 QProgressDialog *progressDialog =
static_cast<QProgressDialog *
>( pData );
867 if ( pData && progressDialog->wasCanceled() )
874 progressDialog->setRange( 0, 100 );
875 progressDialog->setValue( dfComplete * 100 );
881void QgsRasterFileWriter::createVRT(
int xSize,
int ySize,
const QgsCoordinateReferenceSystem &crs,
double *geoTransform,
Qgis::DataType type,
const QList<bool> &destHasNoDataValueList,
const QList<double> &destNoDataValueList )
883 mVRTDocument.clear();
884 QDomElement VRTDatasetElem = mVRTDocument.createElement( QStringLiteral(
"VRTDataset" ) );
887 VRTDatasetElem.setAttribute( QStringLiteral(
"rasterXSize" ), xSize );
888 VRTDatasetElem.setAttribute( QStringLiteral(
"rasterYSize" ), ySize );
889 mVRTDocument.appendChild( VRTDatasetElem );
892 QDomElement SRSElem = mVRTDocument.createElement( QStringLiteral(
"SRS" ) );
893 const QDomText crsText = mVRTDocument.createTextNode( crs.
toWkt() );
894 SRSElem.appendChild( crsText );
895 VRTDatasetElem.appendChild( SRSElem );
900 QDomElement geoTransformElem = mVRTDocument.createElement( QStringLiteral(
"GeoTransform" ) );
901 const QString geoTransformString = QString::number( geoTransform[0],
'f', 6 ) +
", " + QString::number( geoTransform[1] ) +
", " + QString::number( geoTransform[2] ) +
902 ", " + QString::number( geoTransform[3],
'f', 6 ) +
", " + QString::number( geoTransform[4] ) +
", " + QString::number( geoTransform[5] );
903 const QDomText geoTransformText = mVRTDocument.createTextNode( geoTransformString );
904 geoTransformElem.appendChild( geoTransformText );
905 VRTDatasetElem.appendChild( geoTransformElem );
911 nBands = mInput->bandCount();
918 QStringList colorInterp;
919 colorInterp << QStringLiteral(
"Red" ) << QStringLiteral(
"Green" ) << QStringLiteral(
"Blue" ) << QStringLiteral(
"Alpha" );
921 QMap<Qgis::DataType, QString> dataTypes;
934 for (
int i = 1; i <= nBands; i++ )
936 QDomElement VRTBand = mVRTDocument.createElement( QStringLiteral(
"VRTRasterBand" ) );
938 VRTBand.setAttribute( QStringLiteral(
"band" ), QString::number( i ) );
939 const QString dataType = dataTypes.value( type );
940 VRTBand.setAttribute( QStringLiteral(
"dataType" ), dataType );
945 VRTBand.setAttribute( QStringLiteral(
"dataType" ), QStringLiteral(
"Byte" ) );
946 QDomElement colorInterpElement = mVRTDocument.createElement( QStringLiteral(
"ColorInterp" ) );
947 const QDomText interpText = mVRTDocument.createTextNode( colorInterp.value( i - 1 ) );
948 colorInterpElement.appendChild( interpText );
949 VRTBand.appendChild( colorInterpElement );
952 if ( !destHasNoDataValueList.isEmpty() && destHasNoDataValueList.value( i - 1 ) )
954 VRTBand.setAttribute( QStringLiteral(
"NoDataValue" ), QString::number( destNoDataValueList.value( i - 1 ) ) );
957 mVRTBands.append( VRTBand );
958 VRTDatasetElem.appendChild( VRTBand );
962bool QgsRasterFileWriter::writeVRT(
const QString &file )
964 QFile outputFile( file );
965 if ( ! outputFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
970 QTextStream outStream( &outputFile );
971 mVRTDocument.save( outStream, 2 );
976 int iterRows,
int iterLeft,
int iterTop,
const QString &outputUrl,
int fileIndex,
int nBands,
Qgis::DataType type,
979 const double mup = extent.
width() / nCols;
980 const double mapLeft = extent.
xMinimum() + iterLeft * mup;
981 const double mapRight = mapLeft + mup * iterCols;
982 const double mapTop = extent.
yMaximum() - iterTop * mup;
983 const double mapBottom = mapTop - iterRows * mup;
984 const QgsRectangle mapRect( mapLeft, mapBottom, mapRight, mapTop );
986 const QString outputFile =
outputUrl +
'/' + partFileName( fileIndex );
989 double geoTransform[6];
990 geoTransform[0] = mapRect.xMinimum();
991 geoTransform[1] = mup;
992 geoTransform[2] = 0.0;
993 geoTransform[3] = mapRect.yMaximum();
994 geoTransform[4] = 0.0;
995 geoTransform[5] = -mup;
999 QgsRasterDataProvider *destProvider =
QgsRasterDataProvider::create( mOutputProviderKey, outputFile, mOutputFormat, nBands, type, iterCols, iterRows, geoTransform, crs, mCreationOptions );
1002 return destProvider;
1007 const QList<bool> &destHasNoDataValueList,
const QList<double> &destNoDataValueList )
1011 createVRT( nCols, nRows, crs, geoTransform, type, destHasNoDataValueList, destNoDataValueList );
1019 if ( mBuildPyramidsFlag == -4 && mOutputProviderKey ==
"gdal" && mOutputFormat.compare( QLatin1String(
"gtiff" ), Qt::CaseInsensitive ) == 0 )
1020 mCreationOptions <<
"COPY_SRC_OVERVIEWS=YES";
1023 QgsRasterDataProvider *destProvider =
QgsRasterDataProvider::create( mOutputProviderKey, mOutputUrl, mOutputFormat, nBands, type, nCols, nRows, geoTransform, crs, mCreationOptions );
1025 if ( !destProvider )
1030 return destProvider;
1034void QgsRasterFileWriter::globalOutputParameters(
const QgsRectangle &extent,
int nCols,
int &nRows,
1035 double *geoTransform,
double &pixelSize )
1037 pixelSize = extent.
width() / nCols;
1042 nRows =
static_cast< double >( nCols ) / extent.
width() * extent.
height() + 0.5;
1044 geoTransform[0] = extent.
xMinimum();
1045 geoTransform[1] = pixelSize;
1046 geoTransform[2] = 0.0;
1047 geoTransform[3] = extent.
yMaximum();
1048 geoTransform[4] = 0.0;
1049 geoTransform[5] = -( extent.
height() / nRows );
1052QString QgsRasterFileWriter::partFileName(
int fileIndex )
1055 const QFileInfo outputInfo( mOutputUrl );
1056 return QStringLiteral(
"%1.%2.tif" ).arg( outputInfo.fileName() ).arg( fileIndex );
1059QString QgsRasterFileWriter::vrtFileName()
1061 const QFileInfo outputInfo( mOutputUrl );
1062 return QStringLiteral(
"%1.vrt" ).arg( outputInfo.fileName() );
1067 QString ext = extension.trimmed();
1068 if ( ext.isEmpty() )
1071 if ( ext.startsWith(
'.' ) )
1074 if ( ext.compare( QLatin1String(
"tif" ), Qt::CaseInsensitive ) == 0 ||
1075 ext.compare( QLatin1String(
"tiff" ), Qt::CaseInsensitive ) == 0 )
1080 if ( GDALGetDriverByName(
"GTiff" ) )
1085 int const drvCount = GDALGetDriverCount();
1087 for (
int i = 0; i < drvCount; ++i )
1089 GDALDriverH drv = GDALGetDriver( i );
1092 char **driverMetadata = GDALGetMetadata( drv,
nullptr );
1093 if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER,
false ) )
1095 QString drvName = GDALGetDriverShortName( drv );
1096 const QStringList driverExtensions = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) ).split(
' ' );
1098 const auto constDriverExtensions = driverExtensions;
1099 for (
const QString &driver : constDriverExtensions )
1101 if ( driver.compare( ext, Qt::CaseInsensitive ) == 0 )
1112 GDALDriverH drv = GDALGetDriverByName( format.toLocal8Bit().data() );
1115 char **driverMetadata = GDALGetMetadata( drv,
nullptr );
1116 if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER,
false ) )
1118 return QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) ).split(
' ' );
1121 return QStringList();
1126 GDALDriverH drv = GDALGetDriverByName( driverName.toLocal8Bit().data() );
1129 const QString drvName = GDALGetDriverLongName( drv );
1130 const QString extensionsString = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) );
1131 if ( extensionsString.isEmpty() )
1135 const QStringList extensions = extensionsString.split(
' ' );
1136 QString filter = drvName +
" (";
1137 for (
const QString &ext : extensions )
1139 filter.append( QStringLiteral(
"*.%1 *.%2 " ).arg( ext.toLower(), ext.toUpper() ) );
1141 filter = filter.trimmed().append( QStringLiteral(
")" ) );
1150 static QReadWriteLock sFilterLock;
1151 static QMap< RasterFormatOptions, QList< QgsRasterFileWriter::FilterFormatDetails > > sFilters;
1155 const auto it = sFilters.constFind( options );
1156 if ( it != sFilters.constEnd() )
1160 int const drvCount = GDALGetDriverCount();
1163 QList< QgsRasterFileWriter::FilterFormatDetails > results;
1167 for (
int i = 0; i < drvCount; ++i )
1169 GDALDriverH drv = GDALGetDriver( i );
1174 const QString drvName = GDALGetDriverShortName( drv );
1176 if ( filterString.isEmpty() )
1183 if ( options & SortRecommended )
1185 if ( drvName == QLatin1String(
"GTiff" ) )
1187 tifFormat = details;
1199 return a.driverName < b.driverName;
1202 if ( options & SortRecommended )
1206 results.insert( 0, tifFormat );
1210 sFilters.insert( options, results );
1218 QSet< QString > extensions;
1220 const thread_local QRegularExpression rx( QStringLiteral(
"\\*\\.([a-zA-Z0-9]*)" ) );
1224 const QString ext = format.filterString;
1225 const QRegularExpressionMatch match = rx.match( ext );
1226 if ( !match.hasMatch() )
1229 const QString matched = match.captured( 1 );
1230 extensions.insert( matched );
1233 QStringList extensionList( extensions.constBegin(), extensions.constEnd() );
1235 std::sort( extensionList.begin(), extensionList.end(), [options](
const QString & a,
const QString & b ) ->
bool
1237 if ( options & SortRecommended )
1239 if ( a == QLatin1String(
"tif" ) )
1241 else if ( b == QLatin1String(
"tif" ) )
1243 if ( a == QLatin1String(
"tiff" ) )
1245 else if ( b == QLatin1String(
"tiff" ) )
1247 if ( a == QLatin1String(
"gpkg" ) )
1249 else if ( b == QLatin1String(
"gpkg" ) )
1253 return a.toLower().localeAwareCompare( b.toLower() ) < 0;
1256 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).
@ 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.
virtual QgsError error() const
Gets current status error.
bool isEmpty() const
Test if no error is set.
QString summary() const
Short error description, usually the first error in chain, the real error.
bool isCanceled() const
Tells whether the operation has been canceled already.
void setProgress(double progress)
Sets the current progress for the feedback object.
static bool supportsRasterCreate(GDALDriverH driver)
Reads whether a driver supports GDALCreate() for raster purposes.
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 write(const void *data, int band, int width, int height, int xOffset, int yOffset)
Writes into the provider datasource.
virtual bool sourceHasNoDataValue(int bandNo) const
Returns true if source band has no data value.
virtual bool setNoDataValue(int bandNo, double noDataValue)
Set no data value on created dataset.
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
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.
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.
virtual int xSize() const
Gets raster size.
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 int ySize() const
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)