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 );
118 QgsDebugMsg( QStringLiteral(
"iface->srcInput() == 0" ) );
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 QgsDebugMsg(
"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();
153 if ( mMode ==
Image )
155 const WriterError e = writeImageRaster( &iter, nCols, nRows, outputExtent,
crs, feedback );
160 const WriterError e = writeDataRaster( pipe, &iter, nCols, nRows, outputExtent,
crs, transformContext, feedback );
183 QgsDebugMsg( QStringLiteral(
"Cannot get source data provider" ) );
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( QLatin1String(
"gpkg" ), 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++ )
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;
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( QStringLiteral(
"bandNo = %1 destDataType = %2 destHasNoDataValue = %3 destNoDataValue = %4" ).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 QgsDebugMsg( QStringLiteral(
"Created raster does not have requested dimensions" ) );
342 feedback->
appendError( QObject::tr(
"Created raster does not have requested dimensions" ) );
346 if ( nBands != destProvider->bandCount() )
348 QgsDebugMsg( QStringLiteral(
"Created raster does not have requested band count" ) );
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.get(), 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,
416 Q_UNUSED( destHasNoDataValueList )
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;
458 for (
int i = 1; i <= nBands; ++i )
466 const QString vrtFilePath( mOutputUrl +
'/' + vrtFileName() );
467 writeVRT( vrtFilePath );
468 if ( mBuildPyramidsFlag == Qgis::RasterBuildPyramidOption::Yes )
470 buildPyramids( vrtFilePath );
475 if ( mBuildPyramidsFlag == Qgis::RasterBuildPyramidOption::Yes )
477 buildPyramids( mOutputUrl, destProvider );
484 blockList[i - 1].reset( block );
488 if ( feedback && fileIndex < ( nParts - 1 ) )
490 feedback->
setProgress( 100.0 * fileIndex /
static_cast< double >( nParts ) );
498 for (
int i = 1; i <= nBands; ++i )
500 if ( srcProvider && srcProvider->
dataType( i ) == destDataType )
507 blockList[i - 1]->convert( destDataType );
509 destBlockList[i - 1] = std::move( blockList[i - 1] );
514 std::unique_ptr< QgsRasterDataProvider > partDestProvider( createPartProvider( outputExtent,
515 nCols, iterCols, iterRows,
516 iterLeft, iterTop, mOutputUrl,
517 fileIndex, nBands, destDataType,
crs ) );
519 if ( !partDestProvider || !partDestProvider->isValid() )
525 for (
int i = 1; i <= nBands; ++i )
527 if ( destHasNoDataValueList.value( i - 1 ) )
529 partDestProvider->setNoDataValue( i, destNoDataValueList.value( i - 1 ) );
531 if ( destBlockList[ i - 1 ]->isEmpty() )
534 if ( !partDestProvider->write( destBlockList[i - 1]->bits( 0 ), i, iterCols, iterRows, 0, 0 ) )
538 addToVRT( partFileName( fileIndex ), i, iterCols, iterRows, iterLeft, iterTop );
542 else if ( destProvider )
545 for (
int i = 1; i <= nBands; ++i )
547 if ( destBlockList[ i - 1 ]->isEmpty() )
550 if ( !destProvider->
write( destBlockList[i - 1]->bits( 0 ), i, iterCols, iterRows, iterLeft, iterTop ) )
586 const size_t nMaxPixels =
static_cast<size_t>( mMaxTileWidth ) * mMaxTileHeight;
587 std::vector<unsigned char> redData( nMaxPixels );
588 std::vector<unsigned char> greenData( nMaxPixels );
589 std::vector<unsigned char> blueData( nMaxPixels );
590 std::vector<unsigned char> alphaData( nMaxPixels );
591 int iterLeft = 0, iterTop = 0, iterCols = 0, iterRows = 0;
596 double geoTransform[6];
597 globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
599 const int nOutputBands = 4;
600 std::unique_ptr< QgsRasterDataProvider > destProvider( initOutput( nCols, nRows,
crs, geoTransform, nOutputBands,
Qgis::DataType::Byte ) );
607 if ( !destProvider->
isValid() )
615 if ( nCols != destProvider->
xSize() || nRows != destProvider->
ySize() )
617 QgsDebugMsg( QStringLiteral(
"Created raster does not have requested dimensions" ) );
620 feedback->
appendError( QObject::tr(
"Created raster does not have requested dimensions" ) );
624 if ( nOutputBands != destProvider->
bandCount() )
626 QgsDebugMsg( QStringLiteral(
"Created raster does not have requested band count" ) );
629 feedback->
appendError( QObject::tr(
"Created raster does not have requested band count" ) );
635 QgsDebugMsg( QStringLiteral(
"Created raster does not have requested data type" ) );
638 feedback->
appendError( QObject::tr(
"Created raster does not have requested data type" ) );
651 nParts = nPartsX * nPartsY;
654 std::unique_ptr< QgsRasterBlock > inputBlock;
655 while ( iter->
readNextRasterPart( 1, iterCols, iterRows, inputBlock, iterLeft, iterTop ) )
657 if ( !inputBlock || inputBlock->isEmpty() )
662 if ( feedback && fileIndex < ( nParts - 1 ) )
664 feedback->
setProgress( 100.0 * fileIndex /
static_cast< double >( nParts ) );
672 const qgssize nPixels =
static_cast< qgssize >( iterCols ) * iterRows;
673 for (
qgssize i = 0; i < nPixels; ++i )
675 QRgb
c = inputBlock->color( i );
676 if ( isPremultiplied )
678 c = qUnpremultiply(
c );
680 redData[i] =
static_cast<unsigned char>( qRed(
c ) );
681 greenData[i] =
static_cast<unsigned char>( qGreen(
c ) );
682 blueData[i] =
static_cast<unsigned char>( qBlue(
c ) );
683 alphaData[i] =
static_cast<unsigned char>( qAlpha(
c ) );
689 std::unique_ptr< QgsRasterDataProvider > partDestProvider( createPartProvider( outputExtent,
690 nCols, iterCols, iterRows,
691 iterLeft, iterTop, mOutputUrl, fileIndex,
694 if ( !partDestProvider || partDestProvider->isValid() )
700 if ( !partDestProvider->write( &redData[0], 1, iterCols, iterRows, 0, 0 ) ||
701 !partDestProvider->write( &greenData[0], 2, iterCols, iterRows, 0, 0 ) ||
702 !partDestProvider->write( &blueData[0], 3, iterCols, iterRows, 0, 0 ) ||
703 !partDestProvider->write( &alphaData[0], 4, iterCols, iterRows, 0, 0 ) )
708 addToVRT( partFileName( fileIndex ), 1, iterCols, iterRows, iterLeft, iterTop );
709 addToVRT( partFileName( fileIndex ), 2, iterCols, iterRows, iterLeft, iterTop );
710 addToVRT( partFileName( fileIndex ), 3, iterCols, iterRows, iterLeft, iterTop );
711 addToVRT( partFileName( fileIndex ), 4, iterCols, iterRows, iterLeft, iterTop );
713 else if ( destProvider )
715 if ( !destProvider->
write( &redData[0], 1, iterCols, iterRows, iterLeft, iterTop ) ||
716 !destProvider->
write( &greenData[0], 2, iterCols, iterRows, iterLeft, iterTop ) ||
717 !destProvider->
write( &blueData[0], 3, iterCols, iterRows, iterLeft, iterTop ) ||
718 !destProvider->
write( &alphaData[0], 4, iterCols, iterRows, iterLeft, iterTop ) )
726 destProvider.reset();
735 const QString vrtFilePath( mOutputUrl +
'/' + vrtFileName() );
736 writeVRT( vrtFilePath );
737 if ( mBuildPyramidsFlag == Qgis::RasterBuildPyramidOption::Yes )
739 buildPyramids( vrtFilePath );
744 if ( mBuildPyramidsFlag == Qgis::RasterBuildPyramidOption::Yes )
746 buildPyramids( mOutputUrl );
752void QgsRasterFileWriter::addToVRT(
const QString &filename,
int band,
int xSize,
int ySize,
int xOffset,
int yOffset )
754 QDomElement bandElem = mVRTBands.value( band - 1 );
756 QDomElement simpleSourceElem = mVRTDocument.createElement( QStringLiteral(
"SimpleSource" ) );
759 QDomElement sourceFilenameElem = mVRTDocument.createElement( QStringLiteral(
"SourceFilename" ) );
760 sourceFilenameElem.setAttribute( QStringLiteral(
"relativeToVRT" ), QStringLiteral(
"1" ) );
761 const QDomText sourceFilenameText = mVRTDocument.createTextNode( filename );
762 sourceFilenameElem.appendChild( sourceFilenameText );
763 simpleSourceElem.appendChild( sourceFilenameElem );
766 QDomElement sourceBandElem = mVRTDocument.createElement( QStringLiteral(
"SourceBand" ) );
767 const QDomText sourceBandText = mVRTDocument.createTextNode( QString::number( band ) );
768 sourceBandElem.appendChild( sourceBandText );
769 simpleSourceElem.appendChild( sourceBandElem );
772 QDomElement sourcePropertiesElem = mVRTDocument.createElement( QStringLiteral(
"SourceProperties" ) );
773 sourcePropertiesElem.setAttribute( QStringLiteral(
"RasterXSize" ), xSize );
774 sourcePropertiesElem.setAttribute( QStringLiteral(
"RasterYSize" ), ySize );
775 sourcePropertiesElem.setAttribute( QStringLiteral(
"BlockXSize" ), xSize );
776 sourcePropertiesElem.setAttribute( QStringLiteral(
"BlockYSize" ), ySize );
777 sourcePropertiesElem.setAttribute( QStringLiteral(
"DataType" ), QStringLiteral(
"Byte" ) );
778 simpleSourceElem.appendChild( sourcePropertiesElem );
781 QDomElement srcRectElem = mVRTDocument.createElement( QStringLiteral(
"SrcRect" ) );
782 srcRectElem.setAttribute( QStringLiteral(
"xOff" ), QStringLiteral(
"0" ) );
783 srcRectElem.setAttribute( QStringLiteral(
"yOff" ), QStringLiteral(
"0" ) );
784 srcRectElem.setAttribute( QStringLiteral(
"xSize" ), xSize );
785 srcRectElem.setAttribute( QStringLiteral(
"ySize" ), ySize );
786 simpleSourceElem.appendChild( srcRectElem );
789 QDomElement dstRectElem = mVRTDocument.createElement( QStringLiteral(
"DstRect" ) );
790 dstRectElem.setAttribute( QStringLiteral(
"xOff" ), xOffset );
791 dstRectElem.setAttribute( QStringLiteral(
"yOff" ), yOffset );
792 dstRectElem.setAttribute( QStringLiteral(
"xSize" ), xSize );
793 dstRectElem.setAttribute( QStringLiteral(
"ySize" ), ySize );
794 simpleSourceElem.appendChild( dstRectElem );
796 bandElem.appendChild( simpleSourceElem );
799void QgsRasterFileWriter::buildPyramids(
const QString &filename,
QgsRasterDataProvider *destProviderIn )
807 destProvider = qobject_cast< QgsRasterDataProvider * >(
QgsProviderRegistry::instance()->createProvider( mOutputProviderKey, filename, providerOptions ) );
808 if ( !destProvider || !destProvider->
isValid() )
818 QList< QgsRasterPyramid> myPyramidList;
819 if ( ! mPyramidsList.isEmpty() )
821 for (
int myCounterInt = 0; myCounterInt < myPyramidList.count(); myCounterInt++ )
823 myPyramidList[myCounterInt].setBuild(
true );
826 QgsDebugMsgLevel( QStringLiteral(
"building pyramids : %1 pyramids, %2 resampling, %3 format, %4 options" ).arg( myPyramidList.count() ).arg( mPyramidsResampling ).arg(
qgsEnumValueToKey( mPyramidsFormat ) ).arg( mPyramidsConfigOptions.count() ), 4 );
828 const QString res = destProvider->
buildPyramids( myPyramidList, mPyramidsResampling,
829 mPyramidsFormat, mPyramidsConfigOptions );
835 QString title, message;
836 if ( res == QLatin1String(
"ERROR_WRITE_ACCESS" ) )
838 title = QObject::tr(
"Building Pyramids" );
839 message = QObject::tr(
"Write access denied. Adjust the file permissions and try again." );
841 else if ( res == QLatin1String(
"ERROR_WRITE_FORMAT" ) )
843 title = QObject::tr(
"Building Pyramids" );
844 message = QObject::tr(
"The file was not writable. Some formats do not "
845 "support pyramid overviews. Consult the GDAL documentation if in doubt." );
847 else if ( res == QLatin1String(
"FAILED_NOT_SUPPORTED" ) )
849 title = QObject::tr(
"Building Pyramids" );
850 message = QObject::tr(
"Building pyramid overviews is not supported on this type of raster." );
852 else if ( res == QLatin1String(
"ERROR_VIRTUAL" ) )
854 title = QObject::tr(
"Building Pyramids" );
855 message = QObject::tr(
"Building pyramid overviews is not supported on this type of raster." );
857 QMessageBox::warning(
nullptr, title, message );
860 if ( !destProviderIn )
865int QgsRasterFileWriter::pyramidsProgress(
double dfComplete,
const char *pszMessage,
void *pData )
867 Q_UNUSED( pszMessage )
868 GDALTermProgress( dfComplete, 0, 0 );
869 QProgressDialog *progressDialog =
static_cast<QProgressDialog *
>( pData );
870 if ( pData && progressDialog->wasCanceled() )
877 progressDialog->setRange( 0, 100 );
878 progressDialog->setValue( dfComplete * 100 );
884void QgsRasterFileWriter::createVRT(
int xSize,
int ySize,
const QgsCoordinateReferenceSystem &
crs,
double *geoTransform,
Qgis::DataType type,
const QList<bool> &destHasNoDataValueList,
const QList<double> &destNoDataValueList )
886 mVRTDocument.clear();
887 QDomElement VRTDatasetElem = mVRTDocument.createElement( QStringLiteral(
"VRTDataset" ) );
890 VRTDatasetElem.setAttribute( QStringLiteral(
"rasterXSize" ), xSize );
891 VRTDatasetElem.setAttribute( QStringLiteral(
"rasterYSize" ), ySize );
892 mVRTDocument.appendChild( VRTDatasetElem );
895 QDomElement SRSElem = mVRTDocument.createElement( QStringLiteral(
"SRS" ) );
896 const QDomText crsText = mVRTDocument.createTextNode(
crs.
toWkt() );
897 SRSElem.appendChild( crsText );
898 VRTDatasetElem.appendChild( SRSElem );
903 QDomElement geoTransformElem = mVRTDocument.createElement( QStringLiteral(
"GeoTransform" ) );
904 const QString geoTransformString = QString::number( geoTransform[0],
'f', 6 ) +
", " + QString::number( geoTransform[1] ) +
", " + QString::number( geoTransform[2] ) +
905 ", " + QString::number( geoTransform[3],
'f', 6 ) +
", " + QString::number( geoTransform[4] ) +
", " + QString::number( geoTransform[5] );
906 const QDomText geoTransformText = mVRTDocument.createTextNode( geoTransformString );
907 geoTransformElem.appendChild( geoTransformText );
908 VRTDatasetElem.appendChild( geoTransformElem );
921 QStringList colorInterp;
922 colorInterp << QStringLiteral(
"Red" ) << QStringLiteral(
"Green" ) << QStringLiteral(
"Blue" ) << QStringLiteral(
"Alpha" );
924 QMap<Qgis::DataType, QString> dataTypes;
937 for (
int i = 1; i <= nBands; i++ )
939 QDomElement VRTBand = mVRTDocument.createElement( QStringLiteral(
"VRTRasterBand" ) );
941 VRTBand.setAttribute( QStringLiteral(
"band" ), QString::number( i ) );
942 const QString dataType = dataTypes.value( type );
943 VRTBand.setAttribute( QStringLiteral(
"dataType" ), dataType );
945 if ( mMode ==
Image )
947 VRTBand.setAttribute( QStringLiteral(
"dataType" ), QStringLiteral(
"Byte" ) );
948 QDomElement colorInterpElement = mVRTDocument.createElement( QStringLiteral(
"ColorInterp" ) );
949 const QDomText interpText = mVRTDocument.createTextNode( colorInterp.value( i - 1 ) );
950 colorInterpElement.appendChild( interpText );
951 VRTBand.appendChild( colorInterpElement );
954 if ( !destHasNoDataValueList.isEmpty() && destHasNoDataValueList.value( i - 1 ) )
956 VRTBand.setAttribute( QStringLiteral(
"NoDataValue" ), QString::number( destNoDataValueList.value( i - 1 ) ) );
959 mVRTBands.append( VRTBand );
960 VRTDatasetElem.appendChild( VRTBand );
964bool QgsRasterFileWriter::writeVRT(
const QString &file )
966 QFile outputFile( file );
967 if ( ! outputFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
972 QTextStream outStream( &outputFile );
973 mVRTDocument.save( outStream, 2 );
978 int iterRows,
int iterLeft,
int iterTop,
const QString &outputUrl,
int fileIndex,
int nBands,
Qgis::DataType type,
981 const double mup = extent.
width() / nCols;
982 const double mapLeft = extent.
xMinimum() + iterLeft * mup;
983 const double mapRight = mapLeft + mup * iterCols;
984 const double mapTop = extent.
yMaximum() - iterTop * mup;
985 const double mapBottom = mapTop - iterRows * mup;
986 const QgsRectangle mapRect( mapLeft, mapBottom, mapRight, mapTop );
988 const QString outputFile =
outputUrl +
'/' + partFileName( fileIndex );
991 double geoTransform[6];
992 geoTransform[0] = mapRect.xMinimum();
993 geoTransform[1] = mup;
994 geoTransform[2] = 0.0;
995 geoTransform[3] = mapRect.yMaximum();
996 geoTransform[4] = 0.0;
997 geoTransform[5] = -mup;
1004 return destProvider;
1009 const QList<bool> &destHasNoDataValueList,
const QList<double> &destNoDataValueList )
1013 createVRT( nCols, nRows,
crs, geoTransform, type, destHasNoDataValueList, destNoDataValueList );
1021 if ( mBuildPyramidsFlag == -4 && mOutputProviderKey ==
"gdal" && mOutputFormat.compare( QLatin1String(
"gtiff" ), Qt::CaseInsensitive ) == 0 )
1022 mCreateOptions <<
"COPY_SRC_OVERVIEWS=YES";
1027 if ( !destProvider )
1029 QgsDebugMsg( QStringLiteral(
"No provider created" ) );
1032 return destProvider;
1036void QgsRasterFileWriter::globalOutputParameters(
const QgsRectangle &extent,
int nCols,
int &nRows,
1037 double *geoTransform,
double &pixelSize )
1039 pixelSize = extent.
width() / nCols;
1044 nRows =
static_cast< double >( nCols ) / extent.
width() * extent.
height() + 0.5;
1046 geoTransform[0] = extent.
xMinimum();
1047 geoTransform[1] = pixelSize;
1048 geoTransform[2] = 0.0;
1049 geoTransform[3] = extent.
yMaximum();
1050 geoTransform[4] = 0.0;
1051 geoTransform[5] = -( extent.
height() / nRows );
1054QString QgsRasterFileWriter::partFileName(
int fileIndex )
1057 const QFileInfo outputInfo( mOutputUrl );
1058 return QStringLiteral(
"%1.%2.tif" ).arg( outputInfo.fileName() ).arg( fileIndex );
1061QString QgsRasterFileWriter::vrtFileName()
1063 const QFileInfo outputInfo( mOutputUrl );
1064 return QStringLiteral(
"%1.vrt" ).arg( outputInfo.fileName() );
1069 QString ext = extension.trimmed();
1070 if ( ext.isEmpty() )
1073 if ( ext.startsWith(
'.' ) )
1077 int const drvCount = GDALGetDriverCount();
1079 for (
int i = 0; i < drvCount; ++i )
1081 GDALDriverH drv = GDALGetDriver( i );
1084 char **driverMetadata = GDALGetMetadata( drv,
nullptr );
1085 if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER,
false ) )
1087 QString drvName = GDALGetDriverShortName( drv );
1088 const QStringList driverExtensions = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) ).split(
' ' );
1090 const auto constDriverExtensions = driverExtensions;
1091 for (
const QString &driver : constDriverExtensions )
1093 if ( driver.compare( ext, Qt::CaseInsensitive ) == 0 )
1104 GDALDriverH drv = GDALGetDriverByName( format.toLocal8Bit().data() );
1107 char **driverMetadata = GDALGetMetadata( drv,
nullptr );
1108 if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER,
false ) )
1110 return QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) ).split(
' ' );
1113 return QStringList();
1118 GDALDriverH drv = GDALGetDriverByName( driverName.toLocal8Bit().data() );
1121 const QString drvName = GDALGetDriverLongName( drv );
1122 const QString extensionsString = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) );
1123 if ( extensionsString.isEmpty() )
1127 const QStringList extensions = extensionsString.split(
' ' );
1128 QString filter = drvName +
" (";
1129 for (
const QString &ext : extensions )
1131 filter.append( QStringLiteral(
"*.%1 *.%2 " ).arg( ext.toLower(), ext.toUpper() ) );
1133 filter = filter.trimmed().append( QStringLiteral(
")" ) );
1142 static QReadWriteLock sFilterLock;
1143 static QMap< RasterFormatOptions, QList< QgsRasterFileWriter::FilterFormatDetails > > sFilters;
1147 const auto it = sFilters.constFind( options );
1148 if ( it != sFilters.constEnd() )
1152 int const drvCount = GDALGetDriverCount();
1155 QList< QgsRasterFileWriter::FilterFormatDetails > results;
1159 for (
int i = 0; i < drvCount; ++i )
1161 GDALDriverH drv = GDALGetDriver( i );
1166 const QString drvName = GDALGetDriverShortName( drv );
1168 if ( filterString.isEmpty() )
1177 if ( drvName == QLatin1String(
"GTiff" ) )
1179 tifFormat = details;
1191 return a.driverName < b.driverName;
1198 results.insert( 0, tifFormat );
1202 sFilters.insert( options, results );
1210 QStringList extensions;
1212 const QRegularExpression rx( QStringLiteral(
"\\*\\.([a-zA-Z0-9]*)" ) );
1216 const QString ext = format.filterString;
1217 const QRegularExpressionMatch match = rx.match( ext );
1218 if ( !match.hasMatch() )
1221 const QString matched = match.captured( 1 );
1222 extensions << matched;
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)
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(WktVariant variant=WKT1_GDAL, 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 SIP_HOLDGIL
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) SIP_HOLDGIL
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 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 bool write(void *data, int band, int width, int height, int xOffset, int yOffset)
Writes into the provider datasource.
virtual QList< QgsRasterPyramid > buildPyramidList(const QList< int > &overviewList=QList< int >())
Returns the raster layers pyramid list.
Q_DECL_DEPRECATED WriterError writeRaster(const QgsRasterPipe *pipe, int nCols, int nRows, const QgsRectangle &outputExtent, const QgsCoordinateReferenceSystem &crs, QgsRasterBlockFeedback *feedback=nullptr)
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)
static QStringList supportedFormatExtensions(RasterFormatOptions options=SortRecommended)
Returns a list of file extensions for supported formats.
QgsRasterDataProvider * createMultiBandRaster(Qgis::DataType dataType, int width, int height, const QgsRectangle &extent, const QgsCoordinateReferenceSystem &crs, int nBands)
Create a raster file with given number of bands without initializing the pixel data.
QString outputUrl() const
Returns the output URL for the raster.
@ WriteCanceled
Writing was manually canceled.
@ NoDataConflict
Internal error if a value used for 'no data' was found in input.
QgsRasterDataProvider * createOneBandRaster(Qgis::DataType dataType, int width, int height, const QgsRectangle &extent, const QgsCoordinateReferenceSystem &crs)
Create a raster file with one band without initializing the pixel data.
@ SortRecommended
Use recommended sort order, with extremely commonly used formats listed first.
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...
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.
virtual int bandCount() const =0
Gets number of bands.
virtual QgsRasterBandStats bandStatistics(int bandNo, int stats=QgsRasterBandStats::All, const QgsRectangle &extent=QgsRectangle(), int sampleSize=0, QgsRasterBlockFeedback *feedback=nullptr)
Returns the band statistics.
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.
QgsRasterProjector implements approximate projection support for it calculates grid of points in sour...
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 yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
double width() const SIP_HOLDGIL
Returns the width 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)
const QgsCoordinateReferenceSystem & crs
Setting options for creating vector data providers.