29 #include <QCoreApplication> 
   30 #include <QProgressDialog> 
   31 #include <QTextStream> 
   32 #include <QMessageBox> 
   33 #include <QRegularExpression> 
   38 #include <cpl_string.h> 
   47   double geoTransform[6];
 
   48   globalOutputParameters( extent, width, height, geoTransform, pixelSize );
 
   50   return initOutput( width, height, 
crs, geoTransform, 1, dataType, QList<bool>(), QList<double>() );
 
   59   double geoTransform[6];
 
   60   globalOutputParameters( extent, width, height, geoTransform, pixelSize );
 
   62   return initOutput( width, height, 
crs, geoTransform, nBands, dataType, QList<bool>(), QList<double>() );
 
   66   : mOutputUrl( outputUrl )
 
   71 QgsRasterFileWriter::QgsRasterFileWriter()
 
  113   QgsDebugMsgLevel( QStringLiteral( 
"reading from %1" ).arg( 
typeid( *iface ).name() ), 4 );
 
  117     QgsDebugMsg( QStringLiteral( 
"iface->srcInput() == 0" ) );
 
  122   QgsDebugMsgLevel( QStringLiteral( 
"srcInput = %1" ).arg( 
typeid( srcInput ).name() ), 4 );
 
  125   mFeedback = feedback;
 
  132     QFileInfo fileInfo( mOutputUrl );
 
  133     if ( !fileInfo.exists() )
 
  135       QDir dir = fileInfo.dir();
 
  136       if ( !dir.mkdir( fileInfo.fileName() ) )
 
  138         QgsDebugMsg( 
"Cannot create output VRT directory " + fileInfo.fileName() + 
" in " + dir.absolutePath() );
 
  145   QFile pyramidFile( mOutputUrl + ( mTiledMode ? 
".vrt.ovr" : 
".ovr" ) );
 
  146   if ( pyramidFile.exists() )
 
  147     pyramidFile.remove();
 
  148   pyramidFile.setFileName( mOutputUrl + ( mTiledMode ? 
".vrt.rrd" : 
".rrd" ) );
 
  149   if ( pyramidFile.exists() )
 
  150     pyramidFile.remove();
 
  152   if ( mMode == 
Image )
 
  154     WriterError e = writeImageRaster( &iter, nCols, nRows, outputExtent, 
crs, feedback );
 
  159     WriterError e = writeDataRaster( pipe, &iter, nCols, nRows, outputExtent, 
crs, transformContext, feedback );
 
  182     QgsDebugMsg( QStringLiteral( 
"Cannot get source data provider" ) );
 
  199   for ( 
int i = 2; i <= nBands; ++i )
 
  211   QList<bool> destHasNoDataValueList;
 
  212   QList<double> destNoDataValueList;
 
  213   QList<Qgis::DataType> destDataTypeList;
 
  214   destDataTypeList.reserve( nBands );
 
  215   destHasNoDataValueList.reserve( nBands );
 
  216   destNoDataValueList.reserve( nBands );
 
  218   const bool isGpkgOutput = mOutputProviderKey == 
"gdal" &&
 
  219                             mOutputFormat.compare( QLatin1String( 
"gpkg" ), Qt::CaseInsensitive ) == 0;
 
  221   double geoTransform[6];
 
  222   globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
 
  223   const auto srcProviderExtent( srcProvider->
extent() );
 
  225   for ( 
int bandNo = 1; bandNo <= nBands; bandNo++ )
 
  230     bool destHasNoDataValue = 
false;
 
  231     double destNoDataValue = std::numeric_limits<double>::quiet_NaN();
 
  236     if ( srcHasNoDataValue )
 
  241       destHasNoDataValue = 
true;
 
  243     else if ( nuller && !nuller->
noData( bandNo ).isEmpty() )
 
  246       destNoDataValue = nuller->
noData( bandNo ).value( 0 ).min();
 
  247       destHasNoDataValue = 
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         QgsDebugMsg( 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         QgsDebugMsg( 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 );
 
  397 static 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           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]->bits( 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]->bits( 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       QgsDebugMsg( 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       QgsDebugMsg( QStringLiteral( 
"Created raster does not have requested band count" ) );
 
  627         feedback->
appendError( QObject::tr( 
"Created raster does not have requested band count" ) );
 
  633       QgsDebugMsg( 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 ) );
 
  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     QString vrtFilePath( mOutputUrl + 
'/' + vrtFileName() );
 
  734     writeVRT( vrtFilePath );
 
  737       buildPyramids( vrtFilePath );
 
  744       buildPyramids( mOutputUrl );
 
  750 void 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   QDomText sourceFilenameText = mVRTDocument.createTextNode( filename );
 
  760   sourceFilenameElem.appendChild( sourceFilenameText );
 
  761   simpleSourceElem.appendChild( sourceFilenameElem );
 
  764   QDomElement sourceBandElem = mVRTDocument.createElement( QStringLiteral( 
"SourceBand" ) );
 
  765   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 );
 
  797 void 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( mPyramidsFormat ).arg( mPyramidsConfigOptions.count() ), 4 );
 
  826   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 )
 
  863 int 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 );
 
  882 void 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   QDomText crsText = mVRTDocument.createTextNode( 
crs.
toWkt() );
 
  895   SRSElem.appendChild( crsText );
 
  896   VRTDatasetElem.appendChild( SRSElem );
 
  901     QDomElement geoTransformElem = mVRTDocument.createElement( QStringLiteral( 
"GeoTransform" ) );
 
  902     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     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;
 
  934   for ( 
int i = 1; i <= nBands; i++ )
 
  936     QDomElement VRTBand = mVRTDocument.createElement( QStringLiteral( 
"VRTRasterBand" ) );
 
  938     VRTBand.setAttribute( QStringLiteral( 
"band" ), QString::number( i ) );
 
  939     QString dataType = dataTypes.value( type );
 
  940     VRTBand.setAttribute( QStringLiteral( 
"dataType" ), dataType );
 
  942     if ( mMode == 
Image )
 
  944       VRTBand.setAttribute( QStringLiteral( 
"dataType" ), QStringLiteral( 
"Byte" ) );
 
  945       QDomElement colorInterpElement = mVRTDocument.createElement( QStringLiteral( 
"ColorInterp" ) );
 
  946       QDomText interpText = mVRTDocument.createTextNode( colorInterp.value( i - 1 ) );
 
  947       colorInterpElement.appendChild( interpText );
 
  948       VRTBand.appendChild( colorInterpElement );
 
  951     if ( !destHasNoDataValueList.isEmpty() && destHasNoDataValueList.value( i - 1 ) )
 
  953       VRTBand.setAttribute( QStringLiteral( 
"NoDataValue" ), QString::number( destNoDataValueList.value( i - 1 ) ) );
 
  956     mVRTBands.append( VRTBand );
 
  957     VRTDatasetElem.appendChild( VRTBand );
 
  961 bool QgsRasterFileWriter::writeVRT( 
const QString &file )
 
  963   QFile outputFile( file );
 
  964   if ( ! outputFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
 
  969   QTextStream outStream( &outputFile );
 
  970   mVRTDocument.save( outStream, 2 );
 
  975     int iterRows, 
int iterLeft, 
int iterTop, 
const QString &outputUrl, 
int fileIndex, 
int nBands, 
Qgis::DataType type,
 
  978   double mup = extent.
width() / nCols;
 
  979   double mapLeft = extent.
xMinimum() + iterLeft * mup;
 
  980   double mapRight = mapLeft + mup * iterCols;
 
  981   double mapTop = extent.
yMaximum() - iterTop * mup;
 
  982   double mapBottom = mapTop - iterRows * mup;
 
  983   QgsRectangle mapRect( mapLeft, mapBottom, mapRight, mapTop );
 
  985   QString outputFile = 
outputUrl + 
'/' + partFileName( fileIndex );
 
  988   double geoTransform[6];
 
  989   geoTransform[0] = mapRect.xMinimum();
 
  990   geoTransform[1] = mup;
 
  991   geoTransform[2] = 0.0;
 
  992   geoTransform[3] = mapRect.yMaximum();
 
  993   geoTransform[4] = 0.0;
 
  994   geoTransform[5] = -mup;
 
 1001   return destProvider;
 
 1006     const QList<bool> &destHasNoDataValueList, 
const QList<double> &destNoDataValueList )
 
 1010     createVRT( nCols, nRows, 
crs, geoTransform, type, destHasNoDataValueList, destNoDataValueList );
 
 1018     if ( mBuildPyramidsFlag == -4 && mOutputProviderKey == 
"gdal" && mOutputFormat.compare( QLatin1String( 
"gtiff" ), Qt::CaseInsensitive ) == 0 )
 
 1019       mCreateOptions << 
"COPY_SRC_OVERVIEWS=YES";
 
 1024     if ( !destProvider )
 
 1026       QgsDebugMsg( QStringLiteral( 
"No provider created" ) );
 
 1029     return destProvider;
 
 1033 void QgsRasterFileWriter::globalOutputParameters( 
const QgsRectangle &extent, 
int nCols, 
int &nRows,
 
 1034     double *geoTransform, 
double &pixelSize )
 
 1036   pixelSize = extent.
width() / nCols;
 
 1041     nRows = 
static_cast< double >( nCols ) / extent.
width() * extent.
height() + 0.5; 
 
 1043   geoTransform[0] = extent.
xMinimum();
 
 1044   geoTransform[1] = pixelSize;
 
 1045   geoTransform[2] = 0.0;
 
 1046   geoTransform[3] = extent.
yMaximum();
 
 1047   geoTransform[4] = 0.0;
 
 1048   geoTransform[5] = -( extent.
height() / nRows );
 
 1051 QString QgsRasterFileWriter::partFileName( 
int fileIndex )
 
 1054   QFileInfo outputInfo( mOutputUrl );
 
 1055   return QStringLiteral( 
"%1.%2.tif" ).arg( outputInfo.fileName() ).arg( fileIndex );
 
 1058 QString QgsRasterFileWriter::vrtFileName()
 
 1060   QFileInfo outputInfo( mOutputUrl );
 
 1061   return QStringLiteral( 
"%1.vrt" ).arg( outputInfo.fileName() );
 
 1066   QString ext = extension.trimmed();
 
 1067   if ( ext.isEmpty() )
 
 1070   if ( ext.startsWith( 
'.' ) )
 
 1074   int const drvCount = GDALGetDriverCount();
 
 1076   for ( 
int i = 0; i < drvCount; ++i )
 
 1078     GDALDriverH drv = GDALGetDriver( i );
 
 1081       char **driverMetadata = GDALGetMetadata( drv, 
nullptr );
 
 1082       if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER, 
false ) )
 
 1084         QString drvName = GDALGetDriverShortName( drv );
 
 1085         QStringList driverExtensions = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS, 
nullptr ) ).split( 
' ' );
 
 1087         const auto constDriverExtensions = driverExtensions;
 
 1088         for ( 
const QString &driver : constDriverExtensions )
 
 1090           if ( driver.compare( ext, Qt::CaseInsensitive ) == 0 )
 
 1101   GDALDriverH drv = GDALGetDriverByName( format.toLocal8Bit().data() );
 
 1104     char **driverMetadata = GDALGetMetadata( drv, 
nullptr );
 
 1105     if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER, 
false ) )
 
 1107       return QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS, 
nullptr ) ).split( 
' ' );
 
 1110   return QStringList();
 
 1115   GDALDriverH drv = GDALGetDriverByName( driverName.toLocal8Bit().data() );
 
 1118     QString drvName = GDALGetDriverLongName( drv );
 
 1119     QString extensionsString = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS, 
nullptr ) );
 
 1120     if ( extensionsString.isEmpty() )
 
 1124     QStringList extensions = extensionsString.split( 
' ' );
 
 1125     QString filter = drvName + 
" (";
 
 1126     for ( 
const QString &ext : extensions )
 
 1128       filter.append( QStringLiteral( 
"*.%1 *.%2 " ).arg( ext.toLower(), ext.toUpper() ) );
 
 1130     filter = filter.trimmed().append( QStringLiteral( 
")" ) );
 
 1139   static QReadWriteLock sFilterLock;
 
 1140   static QMap< RasterFormatOptions, QList< QgsRasterFileWriter::FilterFormatDetails > > sFilters;
 
 1144   const auto it = sFilters.constFind( options );
 
 1145   if ( it != sFilters.constEnd() )
 
 1149   int const drvCount = GDALGetDriverCount();
 
 1152   QList< QgsRasterFileWriter::FilterFormatDetails > results;
 
 1156   for ( 
int i = 0; i < drvCount; ++i )
 
 1158     GDALDriverH drv = GDALGetDriver( i );
 
 1163         QString drvName = GDALGetDriverShortName( drv );
 
 1165         if ( filterString.isEmpty() )
 
 1174           if ( drvName == QLatin1String( 
"GTiff" ) )
 
 1176             tifFormat = details;
 
 1188     return a.driverName < b.driverName;
 
 1195       results.insert( 0, tifFormat );
 
 1199   sFilters.insert( options, results );
 
 1207   QStringList extensions;
 
 1209   QRegularExpression rx( QStringLiteral( 
"\\*\\.([a-zA-Z0-9]*)" ) );
 
 1213     QString ext = format.filterString;
 
 1214     QRegularExpressionMatch match = rx.match( ext );
 
 1215     if ( !match.hasMatch() )
 
 1218     QString matched = match.captured( 1 );
 
 1219     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
Base class for processing modules.
QgsRasterDataProvider * provider() const
QgsRasterProjector * projector() const
QgsRasterInterface * last() const
QgsRasterNuller * nuller() const
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.