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()
 
  107    mMode = Qgis::RasterExportType::RenderedImage;
 
  114  QgsDebugMsgLevel( QStringLiteral( 
"reading from %1" ).arg( 
typeid( *iface ).name() ), 4 );
 
  123  QgsDebugMsgLevel( QStringLiteral( 
"srcInput = %1" ).arg( 
typeid( srcInput ).name() ), 4 );
 
  126  mFeedback = feedback;
 
  133    const QFileInfo fileInfo( mOutputUrl );
 
  134    if ( !fileInfo.exists() )
 
  136      const QDir dir = fileInfo.dir();
 
  137      if ( !dir.mkdir( fileInfo.fileName() ) )
 
  139        QgsDebugError( 
"Cannot create output VRT directory " + fileInfo.fileName() + 
" in " + dir.absolutePath() );
 
  146  QFile pyramidFile( mOutputUrl + ( mTiledMode ? 
".vrt.ovr" : 
".ovr" ) );
 
  147  if ( pyramidFile.exists() )
 
  148    pyramidFile.remove();
 
  149  pyramidFile.setFileName( mOutputUrl + ( mTiledMode ? 
".vrt.rrd" : 
".rrd" ) );
 
  150  if ( pyramidFile.exists() )
 
  151    pyramidFile.remove();
 
  153  if ( mMode == Qgis::RasterExportType::RenderedImage )
 
  155    return writeImageRaster( &iter, nCols, nRows, outputExtent, 
crs, feedback );
 
  159    return writeDataRaster( pipe, &iter, nCols, nRows, outputExtent, 
crs, transformContext, feedback );
 
  181    QgsDebugError( QStringLiteral( 
"Cannot get source data provider" ) );
 
  198  for ( 
int i = 2; i <= nBands; ++i )
 
  202      return Qgis::RasterFileWriterResult::DestinationProviderError;
 
  210  QList<bool> destHasNoDataValueList;
 
  211  QList<double> destNoDataValueList;
 
  212  QList<Qgis::DataType> destDataTypeList;
 
  213  destDataTypeList.reserve( nBands );
 
  214  destHasNoDataValueList.reserve( nBands );
 
  215  destNoDataValueList.reserve( nBands );
 
  217  const bool isGpkgOutput = mOutputProviderKey == 
"gdal" &&
 
  218                            mOutputFormat.compare( QLatin1String( 
"gpkg" ), Qt::CaseInsensitive ) == 0;
 
  220  double geoTransform[6];
 
  221  globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
 
  222  const auto srcProviderExtent( srcProvider->
extent() );
 
  224  for ( 
int bandNo = 1; bandNo <= nBands; bandNo++ )
 
  229    bool destHasNoDataValue = 
false;
 
  230    double destNoDataValue = std::numeric_limits<double>::quiet_NaN();
 
  235    if ( srcHasNoDataValue )
 
  240      destHasNoDataValue = 
true;
 
  242    else if ( nuller && !nuller->
noData( bandNo ).isEmpty() )
 
  245      destNoDataValue = nuller->
noData( bandNo ).value( 0 ).min();
 
  246      destHasNoDataValue = 
true;
 
  259        ct.setBallparkTransformsAreAppropriate( 
true );
 
  260        outputExtentInSrcCrs = ct.transformBoundingBox( outputExtent );
 
  262      if ( !srcProviderExtent.contains( outputExtentInSrcCrs ) &&
 
  263           ( std::fabs( srcProviderExtent.xMinimum() - outputExtentInSrcCrs.
xMinimum() ) > geoTransform[1] / 2 ||
 
  264             std::fabs( srcProviderExtent.xMaximum() - outputExtentInSrcCrs.
xMaximum() ) > geoTransform[1] / 2 ||
 
  265             std::fabs( srcProviderExtent.yMinimum() - outputExtentInSrcCrs.
yMinimum() ) > std::fabs( geoTransform[5] ) / 2 ||
 
  266             std::fabs( srcProviderExtent.yMaximum() - outputExtentInSrcCrs.
yMaximum() ) > std::fabs( geoTransform[5] ) / 2 ) )
 
  277          destNoDataValue = typeMinValue;
 
  281          destNoDataValue = typeMaxValue;
 
  288        destHasNoDataValue = 
true;
 
  292    if ( nuller && destHasNoDataValue )
 
  297    QgsDebugMsgLevel( QStringLiteral( 
"bandNo = %1 destDataType = %2 destHasNoDataValue = %3 destNoDataValue = %4" ).arg( bandNo ).arg( 
qgsEnumValueToKey( destDataType ) ).arg( destHasNoDataValue ).arg( destNoDataValue ), 4 );
 
  298    destDataTypeList.append( destDataType );
 
  299    destHasNoDataValueList.append( destHasNoDataValue );
 
  300    destNoDataValueList.append( destNoDataValue );
 
  305  for ( 
int i = 1; i < nBands; i++ )
 
  307    if ( destDataTypeList.value( i ) > destDataType )
 
  309      destDataType = destDataTypeList.value( i );
 
  315  for ( 
int attempt = 0; attempt < 2; attempt ++ )
 
  319    std::unique_ptr<QgsRasterDataProvider> destProvider(
 
  320      initOutput( nCols, nRows, 
crs, geoTransform, nBands, destDataType, destHasNoDataValueList, destNoDataValueList ) );
 
  327      if ( !destProvider->isValid() )
 
  329        if ( feedback && !destProvider->error().isEmpty() )
 
  331          feedback->
appendError( destProvider->error().summary() );
 
  335      if ( nCols != destProvider->xSize() || nRows != destProvider->ySize() )
 
  337        QgsDebugError( QStringLiteral( 
"Created raster does not have requested dimensions" ) );
 
  340          feedback->
appendError( QObject::tr( 
"Created raster does not have requested dimensions" ) );
 
  344      if ( nBands != destProvider->bandCount() )
 
  346        QgsDebugError( QStringLiteral( 
"Created raster does not have requested band count" ) );
 
  349          feedback->
appendError( QObject::tr( 
"Created raster does not have requested band count" ) );
 
  357        destDataType = destProvider->dataType( 1 );
 
  361    error = writeDataRaster( pipe, iter, nCols, nRows, outputExtent, 
crs, destDataType, destHasNoDataValueList, destNoDataValueList, destProvider.get(), feedback );
 
  368        destProvider->remove();
 
  369        destProvider.reset();
 
  377      for ( 
int i = 0; i < nBands; i++ )
 
  379        double destNoDataValue;
 
  381        destDataTypeList.replace( i, destDataType );
 
  382        destNoDataValueList.replace( i, destNoDataValue );
 
  384      destDataType = destDataTypeList.value( 0 );
 
  397static int qgsDivRoundUp( 
int a, 
int b )
 
  399  return a / b + ( ( ( a % b ) != 0 ) ? 1 : 0 );
 
  404    int nCols, 
int nRows,
 
  408    const QList<bool> &destHasNoDataValueList,
 
  409    const QList<double> &destNoDataValueList,
 
  414  Q_UNUSED( destHasNoDataValueList )
 
  428  std::vector< std::unique_ptr<QgsRasterBlock> > blockList;
 
  429  std::vector< std::unique_ptr<QgsRasterBlock> > destBlockList;
 
  431  blockList.resize( nBands );
 
  432  destBlockList.resize( nBands );
 
  434  for ( 
int i = 1; i <= nBands; ++i )
 
  437    if ( destProvider && destHasNoDataValueList.value( i - 1 ) ) 
 
  439      destProvider->
setNoDataValue( i, destNoDataValueList.value( i - 1 ) );
 
  449    nParts = nPartsX * nPartsY;
 
  456    for ( 
int i = 1; i <= nBands; ++i )
 
  464          const QString vrtFilePath( mOutputUrl + 
'/' + vrtFileName() );
 
  465          writeVRT( vrtFilePath );
 
  466          if ( mBuildPyramidsFlag == Qgis::RasterBuildPyramidOption::Yes )
 
  468            buildPyramids( vrtFilePath );
 
  473          if ( mBuildPyramidsFlag == Qgis::RasterBuildPyramidOption::Yes )
 
  475            buildPyramids( mOutputUrl, destProvider );
 
  480        return Qgis::RasterFileWriterResult::Success; 
 
  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() )
 
  519        return Qgis::RasterFileWriterResult::DestinationProviderError;
 
  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 ) )
 
  558  return ( feedback && feedback->
isCanceled() ) ? Qgis::RasterFileWriterResult::Canceled : Qgis::RasterFileWriterResult::Success;
 
  584  const size_t nMaxPixels = 
static_cast<size_t>( mMaxTileWidth ) * mMaxTileHeight;
 
  585  std::vector<unsigned char> redData( nMaxPixels );
 
  586  std::vector<unsigned char> greenData( nMaxPixels );
 
  587  std::vector<unsigned char> blueData( nMaxPixels );
 
  588  std::vector<unsigned char> alphaData( nMaxPixels );
 
  589  int iterLeft = 0, iterTop = 0, iterCols = 0, iterRows = 0;
 
  594  double geoTransform[6];
 
  595  globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
 
  597  const int nOutputBands = 4;
 
  598  std::unique_ptr< QgsRasterDataProvider > destProvider( initOutput( nCols, nRows, 
crs, geoTransform, nOutputBands, 
Qgis::DataType::Byte ) );
 
  605    if ( !destProvider->
isValid() )
 
  613    if ( nCols != destProvider->
xSize() || nRows != destProvider->
ySize() )
 
  615      QgsDebugError( QStringLiteral( 
"Created raster does not have requested dimensions" ) );
 
  618        feedback->
appendError( QObject::tr( 
"Created raster does not have requested dimensions" ) );
 
  622    if ( nOutputBands != destProvider->
bandCount() )
 
  624      QgsDebugError( QStringLiteral( 
"Created raster does not have requested band count" ) );
 
  627        feedback->
appendError( QObject::tr( 
"Created raster does not have requested band count" ) );
 
  633      QgsDebugError( QStringLiteral( 
"Created raster does not have requested data type" ) );
 
  636        feedback->
appendError( QObject::tr( 
"Created raster does not have requested data type" ) );
 
  649    nParts = nPartsX * nPartsY;
 
  652  std::unique_ptr< QgsRasterBlock > inputBlock;
 
  653  while ( iter->
readNextRasterPart( 1, iterCols, iterRows, inputBlock, iterLeft, iterTop ) )
 
  655    if ( !inputBlock || inputBlock->isEmpty() )
 
  660    if ( feedback && fileIndex < ( nParts - 1 ) )
 
  662      feedback->
setProgress( 100.0 * fileIndex / 
static_cast< double >( nParts ) );
 
  670    const qgssize nPixels = 
static_cast< qgssize >( iterCols ) * iterRows;
 
  671    for ( 
qgssize i = 0; i < nPixels; ++i )
 
  673      QRgb 
c = inputBlock->color( i );
 
  674      if ( isPremultiplied )
 
  676        c = qUnpremultiply( 
c );
 
  678      redData[i] = 
static_cast<unsigned char>( qRed( 
c ) );
 
  679      greenData[i] = 
static_cast<unsigned char>( qGreen( 
c ) );
 
  680      blueData[i] = 
static_cast<unsigned char>( qBlue( 
c ) );
 
  681      alphaData[i] = 
static_cast<unsigned char>( qAlpha( 
c ) );
 
  687      std::unique_ptr< QgsRasterDataProvider > partDestProvider( createPartProvider( outputExtent,
 
  688          nCols, iterCols, iterRows,
 
  689          iterLeft, iterTop, mOutputUrl, fileIndex,
 
  692      if ( !partDestProvider || partDestProvider->isValid() )
 
  694        return Qgis::RasterFileWriterResult::DestinationProviderError;
 
  698      if ( !partDestProvider->write( &redData[0], 1, iterCols, iterRows, 0, 0 ) ||
 
  699           !partDestProvider->write( &greenData[0], 2, iterCols, iterRows, 0, 0 ) ||
 
  700           !partDestProvider->write( &blueData[0], 3, iterCols, iterRows, 0, 0 ) ||
 
  701           !partDestProvider->write( &alphaData[0], 4, iterCols, iterRows, 0, 0 ) )
 
  706      addToVRT( partFileName( fileIndex ), 1, iterCols, iterRows, iterLeft, iterTop );
 
  707      addToVRT( partFileName( fileIndex ), 2, iterCols, iterRows, iterLeft, iterTop );
 
  708      addToVRT( partFileName( fileIndex ), 3, iterCols, iterRows, iterLeft, iterTop );
 
  709      addToVRT( partFileName( fileIndex ), 4, iterCols, iterRows, iterLeft, iterTop );
 
  711    else if ( destProvider )
 
  713      if ( !destProvider->
write( &redData[0], 1, iterCols, iterRows, iterLeft, iterTop ) ||
 
  714           !destProvider->
write( &greenData[0], 2, iterCols, iterRows, iterLeft, iterTop ) ||
 
  715           !destProvider->
write( &blueData[0], 3, iterCols, iterRows, iterLeft, iterTop ) ||
 
  716           !destProvider->
write( &alphaData[0], 4, iterCols, iterRows, iterLeft, iterTop ) )
 
  724  destProvider.reset();
 
  733    const QString vrtFilePath( mOutputUrl + 
'/' + vrtFileName() );
 
  734    writeVRT( vrtFilePath );
 
  735    if ( mBuildPyramidsFlag == Qgis::RasterBuildPyramidOption::Yes )
 
  737      buildPyramids( vrtFilePath );
 
  742    if ( mBuildPyramidsFlag == Qgis::RasterBuildPyramidOption::Yes )
 
  744      buildPyramids( mOutputUrl );
 
  747  return ( feedback && feedback->
isCanceled() ) ? Qgis::RasterFileWriterResult::Canceled : Qgis::RasterFileWriterResult::Success;
 
  750void QgsRasterFileWriter::addToVRT( 
const QString &filename, 
int band, 
int xSize, 
int ySize, 
int xOffset, 
int yOffset )
 
  752  QDomElement bandElem = mVRTBands.value( band - 1 );
 
  754  QDomElement simpleSourceElem = mVRTDocument.createElement( QStringLiteral( 
"SimpleSource" ) );
 
  757  QDomElement sourceFilenameElem = mVRTDocument.createElement( QStringLiteral( 
"SourceFilename" ) );
 
  758  sourceFilenameElem.setAttribute( QStringLiteral( 
"relativeToVRT" ), QStringLiteral( 
"1" ) );
 
  759  const QDomText sourceFilenameText = mVRTDocument.createTextNode( filename );
 
  760  sourceFilenameElem.appendChild( sourceFilenameText );
 
  761  simpleSourceElem.appendChild( sourceFilenameElem );
 
  764  QDomElement sourceBandElem = mVRTDocument.createElement( QStringLiteral( 
"SourceBand" ) );
 
  765  const QDomText sourceBandText = mVRTDocument.createTextNode( QString::number( band ) );
 
  766  sourceBandElem.appendChild( sourceBandText );
 
  767  simpleSourceElem.appendChild( sourceBandElem );
 
  770  QDomElement sourcePropertiesElem = mVRTDocument.createElement( QStringLiteral( 
"SourceProperties" ) );
 
  771  sourcePropertiesElem.setAttribute( QStringLiteral( 
"RasterXSize" ), xSize );
 
  772  sourcePropertiesElem.setAttribute( QStringLiteral( 
"RasterYSize" ), ySize );
 
  773  sourcePropertiesElem.setAttribute( QStringLiteral( 
"BlockXSize" ), xSize );
 
  774  sourcePropertiesElem.setAttribute( QStringLiteral( 
"BlockYSize" ), ySize );
 
  775  sourcePropertiesElem.setAttribute( QStringLiteral( 
"DataType" ), QStringLiteral( 
"Byte" ) );
 
  776  simpleSourceElem.appendChild( sourcePropertiesElem );
 
  779  QDomElement srcRectElem = mVRTDocument.createElement( QStringLiteral( 
"SrcRect" ) );
 
  780  srcRectElem.setAttribute( QStringLiteral( 
"xOff" ), QStringLiteral( 
"0" ) );
 
  781  srcRectElem.setAttribute( QStringLiteral( 
"yOff" ), QStringLiteral( 
"0" ) );
 
  782  srcRectElem.setAttribute( QStringLiteral( 
"xSize" ), xSize );
 
  783  srcRectElem.setAttribute( QStringLiteral( 
"ySize" ), ySize );
 
  784  simpleSourceElem.appendChild( srcRectElem );
 
  787  QDomElement dstRectElem = mVRTDocument.createElement( QStringLiteral( 
"DstRect" ) );
 
  788  dstRectElem.setAttribute( QStringLiteral( 
"xOff" ), xOffset );
 
  789  dstRectElem.setAttribute( QStringLiteral( 
"yOff" ), yOffset );
 
  790  dstRectElem.setAttribute( QStringLiteral( 
"xSize" ), xSize );
 
  791  dstRectElem.setAttribute( QStringLiteral( 
"ySize" ), ySize );
 
  792  simpleSourceElem.appendChild( dstRectElem );
 
  794  bandElem.appendChild( simpleSourceElem );
 
  797void QgsRasterFileWriter::buildPyramids( 
const QString &filename, 
QgsRasterDataProvider *destProviderIn )
 
  805    destProvider = qobject_cast< QgsRasterDataProvider * >( 
QgsProviderRegistry::instance()->createProvider( mOutputProviderKey, filename, providerOptions ) );
 
  806    if ( !destProvider || !destProvider->
isValid() )
 
  816  QList< QgsRasterPyramid> myPyramidList;
 
  817  if ( ! mPyramidsList.isEmpty() )
 
  819  for ( 
int myCounterInt = 0; myCounterInt < myPyramidList.count(); myCounterInt++ )
 
  821    myPyramidList[myCounterInt].setBuild( 
true );
 
  824  QgsDebugMsgLevel( QStringLiteral( 
"building pyramids : %1 pyramids, %2 resampling, %3 format, %4 options" ).arg( myPyramidList.count() ).arg( mPyramidsResampling ).arg( 
qgsEnumValueToKey( mPyramidsFormat ) ).arg( mPyramidsConfigOptions.count() ), 4 );
 
  826  const QString res = destProvider->
buildPyramids( myPyramidList, mPyramidsResampling,
 
  827                      mPyramidsFormat, mPyramidsConfigOptions );
 
  833    QString title, message;
 
  834    if ( res == QLatin1String( 
"ERROR_WRITE_ACCESS" ) )
 
  836      title = QObject::tr( 
"Building Pyramids" );
 
  837      message = QObject::tr( 
"Write access denied. Adjust the file permissions and try again." );
 
  839    else if ( res == QLatin1String( 
"ERROR_WRITE_FORMAT" ) )
 
  841      title = QObject::tr( 
"Building Pyramids" );
 
  842      message = QObject::tr( 
"The file was not writable. Some formats do not " 
  843                             "support pyramid overviews. Consult the GDAL documentation if in doubt." );
 
  845    else if ( res == QLatin1String( 
"FAILED_NOT_SUPPORTED" ) )
 
  847      title = QObject::tr( 
"Building Pyramids" );
 
  848      message = QObject::tr( 
"Building pyramid overviews is not supported on this type of raster." );
 
  850    else if ( res == QLatin1String( 
"ERROR_VIRTUAL" ) )
 
  852      title = QObject::tr( 
"Building Pyramids" );
 
  853      message = QObject::tr( 
"Building pyramid overviews is not supported on this type of raster." );
 
  855    QMessageBox::warning( 
nullptr, title, message );
 
  858  if ( !destProviderIn )
 
  863int QgsRasterFileWriter::pyramidsProgress( 
double dfComplete, 
const char *pszMessage, 
void *pData )
 
  865  Q_UNUSED( pszMessage )
 
  866  GDALTermProgress( dfComplete, 0, 0 );
 
  867  QProgressDialog *progressDialog = 
static_cast<QProgressDialog *
>( pData );
 
  868  if ( pData && progressDialog->wasCanceled() )
 
  875    progressDialog->setRange( 0, 100 );
 
  876    progressDialog->setValue( dfComplete * 100 );
 
  882void QgsRasterFileWriter::createVRT( 
int xSize, 
int ySize, 
const QgsCoordinateReferenceSystem &
crs, 
double *geoTransform, 
Qgis::DataType type, 
const QList<bool> &destHasNoDataValueList, 
const QList<double> &destNoDataValueList )
 
  884  mVRTDocument.clear();
 
  885  QDomElement VRTDatasetElem = mVRTDocument.createElement( QStringLiteral( 
"VRTDataset" ) );
 
  888  VRTDatasetElem.setAttribute( QStringLiteral( 
"rasterXSize" ), xSize );
 
  889  VRTDatasetElem.setAttribute( QStringLiteral( 
"rasterYSize" ), ySize );
 
  890  mVRTDocument.appendChild( VRTDatasetElem );
 
  893  QDomElement SRSElem = mVRTDocument.createElement( QStringLiteral( 
"SRS" ) );
 
  894  const QDomText crsText = mVRTDocument.createTextNode( 
crs.
toWkt() );
 
  895  SRSElem.appendChild( crsText );
 
  896  VRTDatasetElem.appendChild( SRSElem );
 
  901    QDomElement geoTransformElem = mVRTDocument.createElement( QStringLiteral( 
"GeoTransform" ) );
 
  902    const QString geoTransformString = QString::number( geoTransform[0], 
'f', 6 ) + 
", " + QString::number( geoTransform[1] ) + 
", " + QString::number( geoTransform[2] ) +
 
  903                                       ", "  + QString::number( geoTransform[3], 
'f', 6 ) + 
", " + QString::number( geoTransform[4] ) + 
", " + QString::number( geoTransform[5] );
 
  904    const QDomText geoTransformText = mVRTDocument.createTextNode( geoTransformString );
 
  905    geoTransformElem.appendChild( geoTransformText );
 
  906    VRTDatasetElem.appendChild( geoTransformElem );
 
  919  QStringList colorInterp;
 
  920  colorInterp << QStringLiteral( 
"Red" ) << QStringLiteral( 
"Green" ) << QStringLiteral( 
"Blue" ) << QStringLiteral( 
"Alpha" );
 
  922  QMap<Qgis::DataType, QString> dataTypes;
 
  935  for ( 
int i = 1; i <= nBands; i++ )
 
  937    QDomElement VRTBand = mVRTDocument.createElement( QStringLiteral( 
"VRTRasterBand" ) );
 
  939    VRTBand.setAttribute( QStringLiteral( 
"band" ), QString::number( i ) );
 
  940    const QString dataType = dataTypes.value( type );
 
  941    VRTBand.setAttribute( QStringLiteral( 
"dataType" ), dataType );
 
  943    if ( mMode == Qgis::RasterExportType::RenderedImage )
 
  946      VRTBand.setAttribute( QStringLiteral( 
"dataType" ), QStringLiteral( 
"Byte" ) );
 
  947      QDomElement colorInterpElement = mVRTDocument.createElement( QStringLiteral( 
"ColorInterp" ) );
 
  948      const QDomText interpText = mVRTDocument.createTextNode( colorInterp.value( i - 1 ) );
 
  949      colorInterpElement.appendChild( interpText );
 
  950      VRTBand.appendChild( colorInterpElement );
 
  953    if ( !destHasNoDataValueList.isEmpty() && destHasNoDataValueList.value( i - 1 ) )
 
  955      VRTBand.setAttribute( QStringLiteral( 
"NoDataValue" ), QString::number( destNoDataValueList.value( i - 1 ) ) );
 
  958    mVRTBands.append( VRTBand );
 
  959    VRTDatasetElem.appendChild( VRTBand );
 
  963bool QgsRasterFileWriter::writeVRT( 
const QString &file )
 
  965  QFile outputFile( file );
 
  966  if ( ! outputFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
 
  971  QTextStream outStream( &outputFile );
 
  972  mVRTDocument.save( outStream, 2 );
 
  977    int iterRows, 
int iterLeft, 
int iterTop, 
const QString &outputUrl, 
int fileIndex, 
int nBands, 
Qgis::DataType type,
 
  980  const double mup = extent.
width() / nCols;
 
  981  const double mapLeft = extent.
xMinimum() + iterLeft * mup;
 
  982  const double mapRight = mapLeft + mup * iterCols;
 
  983  const double mapTop = extent.
yMaximum() - iterTop * mup;
 
  984  const double mapBottom = mapTop - iterRows * mup;
 
  985  const QgsRectangle mapRect( mapLeft, mapBottom, mapRight, mapTop );
 
  987  const QString outputFile = 
outputUrl + 
'/' + partFileName( fileIndex );
 
  990  double geoTransform[6];
 
  991  geoTransform[0] = mapRect.xMinimum();
 
  992  geoTransform[1] = mup;
 
  993  geoTransform[2] = 0.0;
 
  994  geoTransform[3] = mapRect.yMaximum();
 
  995  geoTransform[4] = 0.0;
 
  996  geoTransform[5] = -mup;
 
 1003  return destProvider;
 
 1008    const QList<bool> &destHasNoDataValueList, 
const QList<double> &destNoDataValueList )
 
 1012    createVRT( nCols, nRows, 
crs, geoTransform, type, destHasNoDataValueList, destNoDataValueList );
 
 1020    if ( mBuildPyramidsFlag == -4 && mOutputProviderKey == 
"gdal" && mOutputFormat.compare( QLatin1String( 
"gtiff" ), Qt::CaseInsensitive ) == 0 )
 
 1021      mCreateOptions << 
"COPY_SRC_OVERVIEWS=YES";
 
 1026    if ( !destProvider )
 
 1031    return destProvider;
 
 1035void QgsRasterFileWriter::globalOutputParameters( 
const QgsRectangle &extent, 
int nCols, 
int &nRows,
 
 1036    double *geoTransform, 
double &pixelSize )
 
 1038  pixelSize = extent.
width() / nCols;
 
 1043    nRows = 
static_cast< double >( nCols ) / extent.
width() * extent.
height() + 0.5; 
 
 1045  geoTransform[0] = extent.
xMinimum();
 
 1046  geoTransform[1] = pixelSize;
 
 1047  geoTransform[2] = 0.0;
 
 1048  geoTransform[3] = extent.
yMaximum();
 
 1049  geoTransform[4] = 0.0;
 
 1050  geoTransform[5] = -( extent.
height() / nRows );
 
 1053QString QgsRasterFileWriter::partFileName( 
int fileIndex )
 
 1056  const QFileInfo outputInfo( mOutputUrl );
 
 1057  return QStringLiteral( 
"%1.%2.tif" ).arg( outputInfo.fileName() ).arg( fileIndex );
 
 1060QString QgsRasterFileWriter::vrtFileName()
 
 1062  const QFileInfo outputInfo( mOutputUrl );
 
 1063  return QStringLiteral( 
"%1.vrt" ).arg( outputInfo.fileName() );
 
 1068  QString ext = extension.trimmed();
 
 1069  if ( ext.isEmpty() )
 
 1072  if ( ext.startsWith( 
'.' ) )
 
 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 thread_local 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;
 
RasterFileWriterResult
Raster file export results.
 
@ NoDataConflict
Internal error if a value used for 'no data' was found in input.
 
@ CreateDatasourceError
Data source creation error.
 
@ SourceProviderError
Source data provider error.
 
DataType
Raster data types.
 
@ Float32
Thirty two bit floating point (float)
 
@ CFloat64
Complex Float64.
 
@ Int16
Sixteen bit signed integer (qint16)
 
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
 
@ Int8
Eight bit signed integer (qint8) (added in QGIS 3.30)
 
@ UInt16
Sixteen bit unsigned integer (quint16)
 
@ Byte
Eight bit unsigned integer (quint8)
 
@ ARGB32
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
 
@ Float64
Sixty four bit floating point (double)
 
@ CFloat32
Complex Float32.
 
@ UInt32
Thirty two bit unsigned integer (quint32)
 
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 Qgis::RasterFileWriterResult writeRaster(const QgsRasterPipe *pipe, int nCols, int nRows, const QgsRectangle &outputExtent, const QgsCoordinateReferenceSystem &crs, QgsRasterBlockFeedback *feedback=nullptr) SIP_DEPRECATED
Write raster file.
 
static QStringList extensionsForFormat(const QString &format)
Returns a list of known file extensions for the given GDAL driver format.
 
static QString filterForDriver(const QString &driverName)
Creates a filter for an GDAL driver key.
 
static QString driverForExtension(const QString &extension)
Returns the GDAL driver name for a specified file extension.
 
QgsRasterFileWriter(const QString &outputUrl)
Constructor for QgsRasterFileWriter, writing to the specified output URL/filename.
 
static QStringList supportedFormatExtensions(RasterFormatOptions options=SortRecommended)
Returns a list of file extensions for supported formats.
 
QString outputUrl() const
Returns the output URL (filename) for the raster.
 
QgsRasterDataProvider * createMultiBandRaster(Qgis::DataType dataType, int width, int height, const QgsRectangle &extent, const QgsCoordinateReferenceSystem &crs, int nBands) SIP_FACTORY
Create a raster file with given number of bands without initializing the pixel data.
 
@ 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...
 
QgsRasterDataProvider * createOneBandRaster(Qgis::DataType dataType, int width, int height, const QgsRectangle &extent, const QgsCoordinateReferenceSystem &crs) SIP_FACTORY
Create a raster file with one band without initializing the pixel data.
 
Base class for processing filters like renderers, reprojector, resampler etc.
 
virtual Qgis::DataType dataType(int bandNo) const =0
Returns data type for the band specified by number.
 
virtual int xSize() const
Gets raster size.
 
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)
 
#define QgsDebugError(str)
 
const QgsCoordinateReferenceSystem & crs
 
Setting options for creating vector data providers.