30#include <QCoreApplication>
31#include <QProgressDialog>
34#include <QRegularExpression>
39#include <cpl_string.h>
48 double geoTransform[6];
49 globalOutputParameters( extent, width, height, geoTransform, pixelSize );
51 return initOutput( width, height,
crs, geoTransform, 1, dataType, QList<bool>(), QList<double>() );
60 double geoTransform[6];
61 globalOutputParameters( extent, width, height, geoTransform, pixelSize );
63 return initOutput( width, height,
crs, geoTransform, nBands, dataType, QList<bool>(), QList<double>() );
67 : mOutputUrl( outputUrl )
72QgsRasterFileWriter::QgsRasterFileWriter()
114 QgsDebugMsgLevel( QStringLiteral(
"reading from %1" ).arg(
typeid( *iface ).name() ), 4 );
123 QgsDebugMsgLevel( QStringLiteral(
"srcInput = %1" ).arg(
typeid( srcInput ).name() ), 4 );
126 mFeedback = feedback;
133 const QFileInfo fileInfo( mOutputUrl );
134 if ( !fileInfo.exists() )
136 const QDir dir = fileInfo.dir();
137 if ( !dir.mkdir( fileInfo.fileName() ) )
139 QgsDebugError(
"Cannot create output VRT directory " + fileInfo.fileName() +
" in " + dir.absolutePath() );
146 QFile pyramidFile( mOutputUrl + ( mTiledMode ?
".vrt.ovr" :
".ovr" ) );
147 if ( pyramidFile.exists() )
148 pyramidFile.remove();
149 pyramidFile.setFileName( mOutputUrl + ( mTiledMode ?
".vrt.rrd" :
".rrd" ) );
150 if ( pyramidFile.exists() )
151 pyramidFile.remove();
155 return writeImageRaster( &iter, nCols, nRows, outputExtent,
crs, feedback );
159 return writeDataRaster( pipe, &iter, nCols, nRows, outputExtent,
crs, transformContext, feedback );
181 QgsDebugError( QStringLiteral(
"Cannot get source data provider" ) );
198 for (
int i = 2; i <= nBands; ++i )
210 QList<bool> destHasNoDataValueList;
211 QList<double> destNoDataValueList;
212 QList<Qgis::DataType> destDataTypeList;
213 destDataTypeList.reserve( nBands );
214 destHasNoDataValueList.reserve( nBands );
215 destNoDataValueList.reserve( nBands );
217 const bool isGpkgOutput = mOutputProviderKey ==
"gdal" &&
218 mOutputFormat.compare( QLatin1String(
"gpkg" ), Qt::CaseInsensitive ) == 0;
220 double geoTransform[6];
221 globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
222 const auto srcProviderExtent( srcProvider->
extent() );
224 for (
int bandNo = 1; bandNo <= nBands; bandNo++ )
229 bool destHasNoDataValue =
false;
230 double destNoDataValue = std::numeric_limits<double>::quiet_NaN();
235 if ( srcHasNoDataValue )
240 destHasNoDataValue =
true;
242 else if ( nuller && !nuller->
noData( bandNo ).isEmpty() )
245 destNoDataValue = nuller->
noData( bandNo ).value( 0 ).min();
246 destHasNoDataValue =
true;
259 ct.setBallparkTransformsAreAppropriate(
true );
260 outputExtentInSrcCrs = ct.transformBoundingBox( outputExtent );
262 if ( !srcProviderExtent.contains( outputExtentInSrcCrs ) &&
263 ( std::fabs( srcProviderExtent.xMinimum() - outputExtentInSrcCrs.
xMinimum() ) > geoTransform[1] / 2 ||
264 std::fabs( srcProviderExtent.xMaximum() - outputExtentInSrcCrs.
xMaximum() ) > geoTransform[1] / 2 ||
265 std::fabs( srcProviderExtent.yMinimum() - outputExtentInSrcCrs.
yMinimum() ) > std::fabs( geoTransform[5] ) / 2 ||
266 std::fabs( srcProviderExtent.yMaximum() - outputExtentInSrcCrs.
yMaximum() ) > std::fabs( geoTransform[5] ) / 2 ) )
277 destNoDataValue = typeMinValue;
281 destNoDataValue = typeMaxValue;
288 destHasNoDataValue =
true;
292 if ( nuller && destHasNoDataValue )
297 QgsDebugMsgLevel( QStringLiteral(
"bandNo = %1 destDataType = %2 destHasNoDataValue = %3 destNoDataValue = %4" ).arg( bandNo ).arg(
qgsEnumValueToKey( destDataType ) ).arg( destHasNoDataValue ).arg( destNoDataValue ), 4 );
298 destDataTypeList.append( destDataType );
299 destHasNoDataValueList.append( destHasNoDataValue );
300 destNoDataValueList.append( destNoDataValue );
305 for (
int i = 1; i < nBands; i++ )
307 if ( destDataTypeList.value( i ) > destDataType )
309 destDataType = destDataTypeList.value( i );
315 for (
int attempt = 0; attempt < 2; attempt ++ )
319 std::unique_ptr<QgsRasterDataProvider> destProvider(
320 initOutput( nCols, nRows,
crs, geoTransform, nBands, destDataType, destHasNoDataValueList, destNoDataValueList ) );
327 if ( !destProvider->isValid() )
329 if ( feedback && !destProvider->error().isEmpty() )
331 feedback->
appendError( destProvider->error().summary() );
335 if ( nCols != destProvider->xSize() || nRows != destProvider->ySize() )
337 QgsDebugError( QStringLiteral(
"Created raster does not have requested dimensions" ) );
340 feedback->
appendError( QObject::tr(
"Created raster does not have requested dimensions" ) );
344 if ( nBands != destProvider->bandCount() )
346 QgsDebugError( QStringLiteral(
"Created raster does not have requested band count" ) );
349 feedback->
appendError( QObject::tr(
"Created raster does not have requested band count" ) );
357 destDataType = destProvider->dataType( 1 );
361 error = writeDataRaster( pipe, iter, nCols, nRows, outputExtent,
crs, destDataType, destHasNoDataValueList, destNoDataValueList, destProvider.get(), feedback );
368 destProvider->remove();
369 destProvider.reset();
377 for (
int i = 0; i < nBands; i++ )
379 double destNoDataValue;
381 destDataTypeList.replace( i, destDataType );
382 destNoDataValueList.replace( i, destNoDataValue );
384 destDataType = destDataTypeList.value( 0 );
397static int qgsDivRoundUp(
int a,
int b )
399 return a / b + ( ( ( a % b ) != 0 ) ? 1 : 0 );
404 int nCols,
int nRows,
408 const QList<bool> &destHasNoDataValueList,
409 const QList<double> &destNoDataValueList,
414 Q_UNUSED( destHasNoDataValueList )
428 std::vector< std::unique_ptr<QgsRasterBlock> > blockList;
429 std::vector< std::unique_ptr<QgsRasterBlock> > destBlockList;
431 blockList.resize( nBands );
432 destBlockList.resize( nBands );
434 for (
int i = 1; i <= nBands; ++i )
437 if ( destProvider && destHasNoDataValueList.value( i - 1 ) )
439 destProvider->
setNoDataValue( i, destNoDataValueList.value( i - 1 ) );
449 nParts = nPartsX * nPartsY;
456 for (
int i = 1; i <= nBands; ++i )
464 const QString vrtFilePath( mOutputUrl +
'/' + vrtFileName() );
465 writeVRT( vrtFilePath );
468 buildPyramids( vrtFilePath );
475 buildPyramids( mOutputUrl, destProvider );
482 blockList[i - 1].reset( block );
486 if ( feedback && fileIndex < ( nParts - 1 ) )
488 feedback->
setProgress( 100.0 * fileIndex /
static_cast< double >( nParts ) );
496 for (
int i = 1; i <= nBands; ++i )
498 if ( srcProvider && srcProvider->
dataType( i ) == destDataType )
505 blockList[i - 1]->convert( destDataType );
507 destBlockList[i - 1] = std::move( blockList[i - 1] );
512 std::unique_ptr< QgsRasterDataProvider > partDestProvider( createPartProvider( outputExtent,
513 nCols, iterCols, iterRows,
514 iterLeft, iterTop, mOutputUrl,
515 fileIndex, nBands, destDataType,
crs ) );
517 if ( !partDestProvider || !partDestProvider->isValid() )
523 for (
int i = 1; i <= nBands; ++i )
525 if ( destHasNoDataValueList.value( i - 1 ) )
527 partDestProvider->setNoDataValue( i, destNoDataValueList.value( i - 1 ) );
529 if ( destBlockList[ i - 1 ]->isEmpty() )
532 if ( !partDestProvider->write( destBlockList[i - 1]->constBits( 0 ), i, iterCols, iterRows, 0, 0 ) )
536 addToVRT( partFileName( fileIndex ), i, iterCols, iterRows, iterLeft, iterTop );
540 else if ( destProvider )
543 for (
int i = 1; i <= nBands; ++i )
545 if ( destBlockList[ i - 1 ]->isEmpty() )
548 if ( !destProvider->
write( destBlockList[i - 1]->constBits( 0 ), i, iterCols, iterRows, iterLeft, iterTop ) )
584 const size_t nMaxPixels =
static_cast<size_t>( mMaxTileWidth ) * mMaxTileHeight;
585 std::vector<unsigned char> redData( nMaxPixels );
586 std::vector<unsigned char> greenData( nMaxPixels );
587 std::vector<unsigned char> blueData( nMaxPixels );
588 std::vector<unsigned char> alphaData( nMaxPixels );
589 int iterLeft = 0, iterTop = 0, iterCols = 0, iterRows = 0;
594 double geoTransform[6];
595 globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
597 const int nOutputBands = 4;
598 std::unique_ptr< QgsRasterDataProvider > destProvider( initOutput( nCols, nRows,
crs, geoTransform, nOutputBands,
Qgis::DataType::Byte ) );
605 if ( !destProvider->
isValid() )
613 if ( nCols != destProvider->
xSize() || nRows != destProvider->
ySize() )
615 QgsDebugError( QStringLiteral(
"Created raster does not have requested dimensions" ) );
618 feedback->
appendError( QObject::tr(
"Created raster does not have requested dimensions" ) );
622 if ( nOutputBands != destProvider->
bandCount() )
624 QgsDebugError( QStringLiteral(
"Created raster does not have requested band count" ) );
627 feedback->
appendError( QObject::tr(
"Created raster does not have requested band count" ) );
633 QgsDebugError( QStringLiteral(
"Created raster does not have requested data type" ) );
636 feedback->
appendError( QObject::tr(
"Created raster does not have requested data type" ) );
649 nParts = nPartsX * nPartsY;
652 std::unique_ptr< QgsRasterBlock > inputBlock;
653 while ( iter->
readNextRasterPart( 1, iterCols, iterRows, inputBlock, iterLeft, iterTop ) )
655 if ( !inputBlock || inputBlock->isEmpty() )
660 if ( feedback && fileIndex < ( nParts - 1 ) )
662 feedback->
setProgress( 100.0 * fileIndex /
static_cast< double >( nParts ) );
670 const qgssize nPixels =
static_cast< qgssize >( iterCols ) * iterRows;
671 for (
qgssize i = 0; i < nPixels; ++i )
673 QRgb
c = inputBlock->color( i );
674 if ( isPremultiplied )
676 c = qUnpremultiply(
c );
678 redData[i] =
static_cast<unsigned char>( qRed(
c ) );
679 greenData[i] =
static_cast<unsigned char>( qGreen(
c ) );
680 blueData[i] =
static_cast<unsigned char>( qBlue(
c ) );
681 alphaData[i] =
static_cast<unsigned char>( qAlpha(
c ) );
687 std::unique_ptr< QgsRasterDataProvider > partDestProvider( createPartProvider( outputExtent,
688 nCols, iterCols, iterRows,
689 iterLeft, iterTop, mOutputUrl, fileIndex,
692 if ( !partDestProvider || partDestProvider->isValid() )
698 if ( !partDestProvider->write( &redData[0], 1, iterCols, iterRows, 0, 0 ) ||
699 !partDestProvider->write( &greenData[0], 2, iterCols, iterRows, 0, 0 ) ||
700 !partDestProvider->write( &blueData[0], 3, iterCols, iterRows, 0, 0 ) ||
701 !partDestProvider->write( &alphaData[0], 4, iterCols, iterRows, 0, 0 ) )
706 addToVRT( partFileName( fileIndex ), 1, iterCols, iterRows, iterLeft, iterTop );
707 addToVRT( partFileName( fileIndex ), 2, iterCols, iterRows, iterLeft, iterTop );
708 addToVRT( partFileName( fileIndex ), 3, iterCols, iterRows, iterLeft, iterTop );
709 addToVRT( partFileName( fileIndex ), 4, iterCols, iterRows, iterLeft, iterTop );
711 else if ( destProvider )
713 if ( !destProvider->
write( &redData[0], 1, iterCols, iterRows, iterLeft, iterTop ) ||
714 !destProvider->
write( &greenData[0], 2, iterCols, iterRows, iterLeft, iterTop ) ||
715 !destProvider->
write( &blueData[0], 3, iterCols, iterRows, iterLeft, iterTop ) ||
716 !destProvider->
write( &alphaData[0], 4, iterCols, iterRows, iterLeft, iterTop ) )
724 destProvider.reset();
733 const QString vrtFilePath( mOutputUrl +
'/' + vrtFileName() );
734 writeVRT( vrtFilePath );
737 buildPyramids( vrtFilePath );
744 buildPyramids( mOutputUrl );
750void QgsRasterFileWriter::addToVRT(
const QString &filename,
int band,
int xSize,
int ySize,
int xOffset,
int yOffset )
752 QDomElement bandElem = mVRTBands.value( band - 1 );
754 QDomElement simpleSourceElem = mVRTDocument.createElement( QStringLiteral(
"SimpleSource" ) );
757 QDomElement sourceFilenameElem = mVRTDocument.createElement( QStringLiteral(
"SourceFilename" ) );
758 sourceFilenameElem.setAttribute( QStringLiteral(
"relativeToVRT" ), QStringLiteral(
"1" ) );
759 const QDomText sourceFilenameText = mVRTDocument.createTextNode( filename );
760 sourceFilenameElem.appendChild( sourceFilenameText );
761 simpleSourceElem.appendChild( sourceFilenameElem );
764 QDomElement sourceBandElem = mVRTDocument.createElement( QStringLiteral(
"SourceBand" ) );
765 const QDomText sourceBandText = mVRTDocument.createTextNode( QString::number( band ) );
766 sourceBandElem.appendChild( sourceBandText );
767 simpleSourceElem.appendChild( sourceBandElem );
770 QDomElement sourcePropertiesElem = mVRTDocument.createElement( QStringLiteral(
"SourceProperties" ) );
771 sourcePropertiesElem.setAttribute( QStringLiteral(
"RasterXSize" ), xSize );
772 sourcePropertiesElem.setAttribute( QStringLiteral(
"RasterYSize" ), ySize );
773 sourcePropertiesElem.setAttribute( QStringLiteral(
"BlockXSize" ), xSize );
774 sourcePropertiesElem.setAttribute( QStringLiteral(
"BlockYSize" ), ySize );
775 sourcePropertiesElem.setAttribute( QStringLiteral(
"DataType" ), QStringLiteral(
"Byte" ) );
776 simpleSourceElem.appendChild( sourcePropertiesElem );
779 QDomElement srcRectElem = mVRTDocument.createElement( QStringLiteral(
"SrcRect" ) );
780 srcRectElem.setAttribute( QStringLiteral(
"xOff" ), QStringLiteral(
"0" ) );
781 srcRectElem.setAttribute( QStringLiteral(
"yOff" ), QStringLiteral(
"0" ) );
782 srcRectElem.setAttribute( QStringLiteral(
"xSize" ), xSize );
783 srcRectElem.setAttribute( QStringLiteral(
"ySize" ), ySize );
784 simpleSourceElem.appendChild( srcRectElem );
787 QDomElement dstRectElem = mVRTDocument.createElement( QStringLiteral(
"DstRect" ) );
788 dstRectElem.setAttribute( QStringLiteral(
"xOff" ), xOffset );
789 dstRectElem.setAttribute( QStringLiteral(
"yOff" ), yOffset );
790 dstRectElem.setAttribute( QStringLiteral(
"xSize" ), xSize );
791 dstRectElem.setAttribute( QStringLiteral(
"ySize" ), ySize );
792 simpleSourceElem.appendChild( dstRectElem );
794 bandElem.appendChild( simpleSourceElem );
797void QgsRasterFileWriter::buildPyramids(
const QString &filename,
QgsRasterDataProvider *destProviderIn )
805 destProvider = qobject_cast< QgsRasterDataProvider * >(
QgsProviderRegistry::instance()->createProvider( mOutputProviderKey, filename, providerOptions ) );
806 if ( !destProvider || !destProvider->
isValid() )
816 QList< QgsRasterPyramid> myPyramidList;
817 if ( ! mPyramidsList.isEmpty() )
819 for (
int myCounterInt = 0; myCounterInt < myPyramidList.count(); myCounterInt++ )
821 myPyramidList[myCounterInt].setBuild(
true );
824 QgsDebugMsgLevel( QStringLiteral(
"building pyramids : %1 pyramids, %2 resampling, %3 format, %4 options" ).arg( myPyramidList.count() ).arg( mPyramidsResampling ).arg(
qgsEnumValueToKey( mPyramidsFormat ) ).arg( mPyramidsConfigOptions.count() ), 4 );
826 const QString res = destProvider->
buildPyramids( myPyramidList, mPyramidsResampling,
827 mPyramidsFormat, mPyramidsConfigOptions );
833 QString title, message;
834 if ( res == QLatin1String(
"ERROR_WRITE_ACCESS" ) )
836 title = QObject::tr(
"Building Pyramids" );
837 message = QObject::tr(
"Write access denied. Adjust the file permissions and try again." );
839 else if ( res == QLatin1String(
"ERROR_WRITE_FORMAT" ) )
841 title = QObject::tr(
"Building Pyramids" );
842 message = QObject::tr(
"The file was not writable. Some formats do not "
843 "support pyramid overviews. Consult the GDAL documentation if in doubt." );
845 else if ( res == QLatin1String(
"FAILED_NOT_SUPPORTED" ) )
847 title = QObject::tr(
"Building Pyramids" );
848 message = QObject::tr(
"Building pyramid overviews is not supported on this type of raster." );
850 else if ( res == QLatin1String(
"ERROR_VIRTUAL" ) )
852 title = QObject::tr(
"Building Pyramids" );
853 message = QObject::tr(
"Building pyramid overviews is not supported on this type of raster." );
855 QMessageBox::warning(
nullptr, title, message );
858 if ( !destProviderIn )
863int QgsRasterFileWriter::pyramidsProgress(
double dfComplete,
const char *pszMessage,
void *pData )
865 Q_UNUSED( pszMessage )
866 GDALTermProgress( dfComplete, 0, 0 );
867 QProgressDialog *progressDialog =
static_cast<QProgressDialog *
>( pData );
868 if ( pData && progressDialog->wasCanceled() )
875 progressDialog->setRange( 0, 100 );
876 progressDialog->setValue( dfComplete * 100 );
882void QgsRasterFileWriter::createVRT(
int xSize,
int ySize,
const QgsCoordinateReferenceSystem &
crs,
double *geoTransform,
Qgis::DataType type,
const QList<bool> &destHasNoDataValueList,
const QList<double> &destNoDataValueList )
884 mVRTDocument.clear();
885 QDomElement VRTDatasetElem = mVRTDocument.createElement( QStringLiteral(
"VRTDataset" ) );
888 VRTDatasetElem.setAttribute( QStringLiteral(
"rasterXSize" ), xSize );
889 VRTDatasetElem.setAttribute( QStringLiteral(
"rasterYSize" ), ySize );
890 mVRTDocument.appendChild( VRTDatasetElem );
893 QDomElement SRSElem = mVRTDocument.createElement( QStringLiteral(
"SRS" ) );
894 const QDomText crsText = mVRTDocument.createTextNode(
crs.
toWkt() );
895 SRSElem.appendChild( crsText );
896 VRTDatasetElem.appendChild( SRSElem );
901 QDomElement geoTransformElem = mVRTDocument.createElement( QStringLiteral(
"GeoTransform" ) );
902 const QString geoTransformString = QString::number( geoTransform[0],
'f', 6 ) +
", " + QString::number( geoTransform[1] ) +
", " + QString::number( geoTransform[2] ) +
903 ", " + QString::number( geoTransform[3],
'f', 6 ) +
", " + QString::number( geoTransform[4] ) +
", " + QString::number( geoTransform[5] );
904 const QDomText geoTransformText = mVRTDocument.createTextNode( geoTransformString );
905 geoTransformElem.appendChild( geoTransformText );
906 VRTDatasetElem.appendChild( geoTransformElem );
919 QStringList colorInterp;
920 colorInterp << QStringLiteral(
"Red" ) << QStringLiteral(
"Green" ) << QStringLiteral(
"Blue" ) << QStringLiteral(
"Alpha" );
922 QMap<Qgis::DataType, QString> dataTypes;
935 for (
int i = 1; i <= nBands; i++ )
937 QDomElement VRTBand = mVRTDocument.createElement( QStringLiteral(
"VRTRasterBand" ) );
939 VRTBand.setAttribute( QStringLiteral(
"band" ), QString::number( i ) );
940 const QString dataType = dataTypes.value( type );
941 VRTBand.setAttribute( QStringLiteral(
"dataType" ), dataType );
946 VRTBand.setAttribute( QStringLiteral(
"dataType" ), QStringLiteral(
"Byte" ) );
947 QDomElement colorInterpElement = mVRTDocument.createElement( QStringLiteral(
"ColorInterp" ) );
948 const QDomText interpText = mVRTDocument.createTextNode( colorInterp.value( i - 1 ) );
949 colorInterpElement.appendChild( interpText );
950 VRTBand.appendChild( colorInterpElement );
953 if ( !destHasNoDataValueList.isEmpty() && destHasNoDataValueList.value( i - 1 ) )
955 VRTBand.setAttribute( QStringLiteral(
"NoDataValue" ), QString::number( destNoDataValueList.value( i - 1 ) ) );
958 mVRTBands.append( VRTBand );
959 VRTDatasetElem.appendChild( VRTBand );
963bool QgsRasterFileWriter::writeVRT(
const QString &file )
965 QFile outputFile( file );
966 if ( ! outputFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
971 QTextStream outStream( &outputFile );
972 mVRTDocument.save( outStream, 2 );
977 int iterRows,
int iterLeft,
int iterTop,
const QString &outputUrl,
int fileIndex,
int nBands,
Qgis::DataType type,
980 const double mup = extent.
width() / nCols;
981 const double mapLeft = extent.
xMinimum() + iterLeft * mup;
982 const double mapRight = mapLeft + mup * iterCols;
983 const double mapTop = extent.
yMaximum() - iterTop * mup;
984 const double mapBottom = mapTop - iterRows * mup;
985 const QgsRectangle mapRect( mapLeft, mapBottom, mapRight, mapTop );
987 const QString outputFile =
outputUrl +
'/' + partFileName( fileIndex );
990 double geoTransform[6];
991 geoTransform[0] = mapRect.xMinimum();
992 geoTransform[1] = mup;
993 geoTransform[2] = 0.0;
994 geoTransform[3] = mapRect.yMaximum();
995 geoTransform[4] = 0.0;
996 geoTransform[5] = -mup;
1003 return destProvider;
1008 const QList<bool> &destHasNoDataValueList,
const QList<double> &destNoDataValueList )
1012 createVRT( nCols, nRows,
crs, geoTransform, type, destHasNoDataValueList, destNoDataValueList );
1020 if ( mBuildPyramidsFlag == -4 && mOutputProviderKey ==
"gdal" && mOutputFormat.compare( QLatin1String(
"gtiff" ), Qt::CaseInsensitive ) == 0 )
1021 mCreateOptions <<
"COPY_SRC_OVERVIEWS=YES";
1026 if ( !destProvider )
1031 return destProvider;
1035void QgsRasterFileWriter::globalOutputParameters(
const QgsRectangle &extent,
int nCols,
int &nRows,
1036 double *geoTransform,
double &pixelSize )
1038 pixelSize = extent.
width() / nCols;
1043 nRows =
static_cast< double >( nCols ) / extent.
width() * extent.
height() + 0.5;
1045 geoTransform[0] = extent.
xMinimum();
1046 geoTransform[1] = pixelSize;
1047 geoTransform[2] = 0.0;
1048 geoTransform[3] = extent.
yMaximum();
1049 geoTransform[4] = 0.0;
1050 geoTransform[5] = -( extent.
height() / nRows );
1053QString QgsRasterFileWriter::partFileName(
int fileIndex )
1056 const QFileInfo outputInfo( mOutputUrl );
1057 return QStringLiteral(
"%1.%2.tif" ).arg( outputInfo.fileName() ).arg( fileIndex );
1060QString QgsRasterFileWriter::vrtFileName()
1062 const QFileInfo outputInfo( mOutputUrl );
1063 return QStringLiteral(
"%1.vrt" ).arg( outputInfo.fileName() );
1068 QString ext = extension.trimmed();
1069 if ( ext.isEmpty() )
1072 if ( ext.startsWith(
'.' ) )
1075 if ( ext.compare( QLatin1String(
"tif" ), Qt::CaseInsensitive ) == 0 ||
1076 ext.compare( QLatin1String(
"tiff" ), Qt::CaseInsensitive ) == 0 )
1081 if ( GDALGetDriverByName(
"GTiff" ) )
1086 int const drvCount = GDALGetDriverCount();
1088 for (
int i = 0; i < drvCount; ++i )
1090 GDALDriverH drv = GDALGetDriver( i );
1093 char **driverMetadata = GDALGetMetadata( drv,
nullptr );
1094 if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER,
false ) )
1096 QString drvName = GDALGetDriverShortName( drv );
1097 const QStringList driverExtensions = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) ).split(
' ' );
1099 const auto constDriverExtensions = driverExtensions;
1100 for (
const QString &driver : constDriverExtensions )
1102 if ( driver.compare( ext, Qt::CaseInsensitive ) == 0 )
1113 GDALDriverH drv = GDALGetDriverByName( format.toLocal8Bit().data() );
1116 char **driverMetadata = GDALGetMetadata( drv,
nullptr );
1117 if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER,
false ) )
1119 return QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) ).split(
' ' );
1122 return QStringList();
1127 GDALDriverH drv = GDALGetDriverByName( driverName.toLocal8Bit().data() );
1130 const QString drvName = GDALGetDriverLongName( drv );
1131 const QString extensionsString = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) );
1132 if ( extensionsString.isEmpty() )
1136 const QStringList extensions = extensionsString.split(
' ' );
1137 QString filter = drvName +
" (";
1138 for (
const QString &ext : extensions )
1140 filter.append( QStringLiteral(
"*.%1 *.%2 " ).arg( ext.toLower(), ext.toUpper() ) );
1142 filter = filter.trimmed().append( QStringLiteral(
")" ) );
1151 static QReadWriteLock sFilterLock;
1152 static QMap< RasterFormatOptions, QList< QgsRasterFileWriter::FilterFormatDetails > > sFilters;
1156 const auto it = sFilters.constFind( options );
1157 if ( it != sFilters.constEnd() )
1161 int const drvCount = GDALGetDriverCount();
1164 QList< QgsRasterFileWriter::FilterFormatDetails > results;
1168 for (
int i = 0; i < drvCount; ++i )
1170 GDALDriverH drv = GDALGetDriver( i );
1175 const QString drvName = GDALGetDriverShortName( drv );
1177 if ( filterString.isEmpty() )
1184 if ( options & SortRecommended )
1186 if ( drvName == QLatin1String(
"GTiff" ) )
1188 tifFormat = details;
1200 return a.driverName < b.driverName;
1203 if ( options & SortRecommended )
1207 results.insert( 0, tifFormat );
1211 sFilters.insert( options, results );
1219 QSet< QString > extensions;
1221 const thread_local QRegularExpression rx( QStringLiteral(
"\\*\\.([a-zA-Z0-9]*)" ) );
1225 const QString ext = format.filterString;
1226 const QRegularExpressionMatch match = rx.match( ext );
1227 if ( !match.hasMatch() )
1230 const QString matched = match.captured( 1 );
1231 extensions.insert( matched );
1234 QStringList extensionList( extensions.constBegin(), extensions.constEnd() );
1236 std::sort( extensionList.begin(), extensionList.end(), [options](
const QString & a,
const QString & b ) ->
bool
1238 if ( options & SortRecommended )
1240 if ( a == QLatin1String(
"tif" ) )
1242 else if ( b == QLatin1String(
"tif" ) )
1244 if ( a == QLatin1String(
"tiff" ) )
1246 else if ( b == QLatin1String(
"tiff" ) )
1248 if ( a == QLatin1String(
"gpkg" ) )
1250 else if ( b == QLatin1String(
"gpkg" ) )
1254 return a.toLower().localeAwareCompare( b.toLower() ) < 0;
1257 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.
This class 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 any 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.
The RasterBandStats struct is a container for statistics about a single raster band.
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 data type is color.
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.
Raster pipe that deals with null values.
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.
Implements approximate projection support for optimised raster transformation.
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination CRS.
QgsCoordinateReferenceSystem sourceCrs() const
Returns the source CRS.
The QgsReadWriteLocker class is a convenience class that simplifies locking and unlocking QReadWriteL...
void changeMode(Mode mode)
Change the mode of the lock to mode.
A rectangle specified with double values.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
double width() const
Returns the width of the rectangle.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
double yMaximum() const
Returns the y maximum value (top side of rectangle).
double height() const
Returns the height of the rectangle.
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)
const QgsCoordinateReferenceSystem & crs
Setting options for creating vector data providers.