30 #include <QCoreApplication>
31 #include <QProgressDialog>
32 #include <QTextStream>
33 #include <QMessageBox>
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 )
72 QgsRasterFileWriter::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 );
399 static 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 );
470 buildPyramids( vrtFilePath );
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 );
739 buildPyramids( vrtFilePath );
746 buildPyramids( mOutputUrl );
752 void 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 );
799 void 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( 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 )
865 int 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 );
884 void 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;
936 for (
int i = 1; i <= nBands; i++ )
938 QDomElement VRTBand = mVRTDocument.createElement( QStringLiteral(
"VRTRasterBand" ) );
940 VRTBand.setAttribute( QStringLiteral(
"band" ), QString::number( i ) );
941 const QString dataType = dataTypes.value( type );
942 VRTBand.setAttribute( QStringLiteral(
"dataType" ), dataType );
944 if ( mMode ==
Image )
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 );
963 bool 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 )
1028 QgsDebugMsg( QStringLiteral(
"No provider created" ) );
1031 return destProvider;
1035 void 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 );
1053 QString QgsRasterFileWriter::partFileName(
int fileIndex )
1056 const QFileInfo outputInfo( mOutputUrl );
1057 return QStringLiteral(
"%1.%2.tif" ).arg( outputInfo.fileName() ).arg( fileIndex );
1060 QString 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(
'.' ) )
1076 int const drvCount = GDALGetDriverCount();
1078 for (
int i = 0; i < drvCount; ++i )
1080 GDALDriverH drv = GDALGetDriver( i );
1083 char **driverMetadata = GDALGetMetadata( drv,
nullptr );
1084 if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER,
false ) )
1086 QString drvName = GDALGetDriverShortName( drv );
1087 const QStringList driverExtensions = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) ).split(
' ' );
1089 const auto constDriverExtensions = driverExtensions;
1090 for (
const QString &driver : constDriverExtensions )
1092 if ( driver.compare( ext, Qt::CaseInsensitive ) == 0 )
1103 GDALDriverH drv = GDALGetDriverByName( format.toLocal8Bit().data() );
1106 char **driverMetadata = GDALGetMetadata( drv,
nullptr );
1107 if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER,
false ) )
1109 return QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) ).split(
' ' );
1112 return QStringList();
1117 GDALDriverH drv = GDALGetDriverByName( driverName.toLocal8Bit().data() );
1120 const QString drvName = GDALGetDriverLongName( drv );
1121 const QString extensionsString = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) );
1122 if ( extensionsString.isEmpty() )
1126 const QStringList extensions = extensionsString.split(
' ' );
1127 QString filter = drvName +
" (";
1128 for (
const QString &ext : extensions )
1130 filter.append( QStringLiteral(
"*.%1 *.%2 " ).arg( ext.toLower(), ext.toUpper() ) );
1132 filter = filter.trimmed().append( QStringLiteral(
")" ) );
1141 static QReadWriteLock sFilterLock;
1142 static QMap< RasterFormatOptions, QList< QgsRasterFileWriter::FilterFormatDetails > > sFilters;
1146 const auto it = sFilters.constFind( options );
1147 if ( it != sFilters.constEnd() )
1151 int const drvCount = GDALGetDriverCount();
1154 QList< QgsRasterFileWriter::FilterFormatDetails > results;
1158 for (
int i = 0; i < drvCount; ++i )
1160 GDALDriverH drv = GDALGetDriver( i );
1165 const QString drvName = GDALGetDriverShortName( drv );
1167 if ( filterString.isEmpty() )
1176 if ( drvName == QLatin1String(
"GTiff" ) )
1178 tifFormat = details;
1190 return a.driverName < b.driverName;
1197 results.insert( 0, tifFormat );
1201 sFilters.insert( options, results );
1209 QStringList extensions;
1211 const QRegularExpression rx( QStringLiteral(
"\\*\\.([a-zA-Z0-9]*)" ) );
1215 const QString ext = format.filterString;
1216 const QRegularExpressionMatch match = rx.match( ext );
1217 if ( !match.hasMatch() )
1220 const QString matched = match.captured( 1 );
1221 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.
@ 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 QString buildPyramids(const QList< QgsRasterPyramid > &pyramidList, const QString &resamplingMethod="NEAREST", QgsRaster::RasterPyramidsFormat format=QgsRaster::PyramidsGTiff, const QStringList &configOptions=QStringList(), QgsRasterBlockFeedback *feedback=nullptr)
Creates pyramid overviews.
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 QList< QgsRasterPyramid > buildPyramidList(const QList< int > &overviewList=QList< int >())
Returns the raster layers pyramid list.
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.
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 const QgsRasterInterface * sourceInput() const
Gets source / raw input, the first in pipe, usually provider.
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
Iterator for sequentially processing raster cells.
const QgsRasterInterface * input() const
Returns the input raster interface which is being iterated over.
int maximumTileWidth() const
Returns the maximum tile width returned during iteration.
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.
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.
QgsRasterInterface * last() const
Returns last interface 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)
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.