30#include <QCoreApplication> 
   31#include <QProgressDialog> 
   34#include <QRegularExpression> 
   39#include <cpl_string.h> 
   48  double geoTransform[6];
 
   49  globalOutputParameters( extent, width, height, geoTransform, pixelSize );
 
   51  return initOutput( width, height, 
crs, geoTransform, 1, dataType, QList<bool>(), QList<double>() );
 
 
   60  double geoTransform[6];
 
   61  globalOutputParameters( extent, width, height, geoTransform, pixelSize );
 
   63  return initOutput( width, height, 
crs, geoTransform, nBands, dataType, QList<bool>(), QList<double>() );
 
 
   67  : mOutputUrl( outputUrl )
 
 
   72QgsRasterFileWriter::QgsRasterFileWriter()
 
  114  QgsDebugMsgLevel( QStringLiteral( 
"reading from %1" ).arg( 
typeid( *iface ).name() ), 4 );
 
  123  QgsDebugMsgLevel( QStringLiteral( 
"srcInput = %1" ).arg( 
typeid( srcInput ).name() ), 4 );
 
  126  mFeedback = feedback;
 
  133    const QFileInfo fileInfo( mOutputUrl );
 
  134    if ( !fileInfo.exists() )
 
  136      const QDir dir = fileInfo.dir();
 
  137      if ( !dir.mkdir( fileInfo.fileName() ) )
 
  139        QgsDebugError( 
"Cannot create output VRT directory " + fileInfo.fileName() + 
" in " + dir.absolutePath() );
 
  146  QFile pyramidFile( mOutputUrl + ( mTiledMode ? 
".vrt.ovr" : 
".ovr" ) );
 
  147  if ( pyramidFile.exists() )
 
  148    pyramidFile.remove();
 
  149  pyramidFile.setFileName( mOutputUrl + ( mTiledMode ? 
".vrt.rrd" : 
".rrd" ) );
 
  150  if ( pyramidFile.exists() )
 
  151    pyramidFile.remove();
 
  155    return writeImageRaster( &iter, nCols, nRows, outputExtent, 
crs, feedback );
 
  159    return writeDataRaster( pipe, &iter, nCols, nRows, outputExtent, 
crs, transformContext, feedback );
 
 
  181    QgsDebugError( QStringLiteral( 
"Cannot get source data provider" ) );
 
  198  for ( 
int i = 2; i <= nBands; ++i )
 
  210  QList<bool> destHasNoDataValueList;
 
  211  QList<double> destNoDataValueList;
 
  212  QList<Qgis::DataType> destDataTypeList;
 
  213  destDataTypeList.reserve( nBands );
 
  214  destHasNoDataValueList.reserve( nBands );
 
  215  destNoDataValueList.reserve( nBands );
 
  217  const bool isGpkgOutput = mOutputProviderKey == 
"gdal" &&
 
  218                            mOutputFormat.compare( QLatin1String( 
"gpkg" ), Qt::CaseInsensitive ) == 0;
 
  220  double geoTransform[6];
 
  221  globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
 
  222  const auto srcProviderExtent( srcProvider->
extent() );
 
  224  for ( 
int bandNo = 1; bandNo <= nBands; bandNo++ )
 
  229    bool destHasNoDataValue = 
false;
 
  230    double destNoDataValue = std::numeric_limits<double>::quiet_NaN();
 
  235    if ( srcHasNoDataValue )
 
  240      destHasNoDataValue = 
true;
 
  242    else if ( nuller && !nuller->
noData( bandNo ).isEmpty() )
 
  245      destNoDataValue = nuller->
noData( bandNo ).value( 0 ).min();
 
  246      destHasNoDataValue = 
true;
 
  259        ct.setBallparkTransformsAreAppropriate( 
true );
 
  260        outputExtentInSrcCrs = ct.transformBoundingBox( outputExtent );
 
  262      if ( !srcProviderExtent.contains( outputExtentInSrcCrs ) &&
 
  263           ( std::fabs( srcProviderExtent.xMinimum() - outputExtentInSrcCrs.
xMinimum() ) > geoTransform[1] / 2 ||
 
  264             std::fabs( srcProviderExtent.xMaximum() - outputExtentInSrcCrs.
xMaximum() ) > geoTransform[1] / 2 ||
 
  265             std::fabs( srcProviderExtent.yMinimum() - outputExtentInSrcCrs.
yMinimum() ) > std::fabs( geoTransform[5] ) / 2 ||
 
  266             std::fabs( srcProviderExtent.yMaximum() - outputExtentInSrcCrs.
yMaximum() ) > std::fabs( geoTransform[5] ) / 2 ) )
 
  277          destNoDataValue = typeMinValue;
 
  281          destNoDataValue = typeMaxValue;
 
  288        destHasNoDataValue = 
true;
 
  292    if ( nuller && destHasNoDataValue )
 
  297    QgsDebugMsgLevel( QStringLiteral( 
"bandNo = %1 destDataType = %2 destHasNoDataValue = %3 destNoDataValue = %4" ).arg( bandNo ).arg( 
qgsEnumValueToKey( destDataType ) ).arg( destHasNoDataValue ).arg( destNoDataValue ), 4 );
 
  298    destDataTypeList.append( destDataType );
 
  299    destHasNoDataValueList.append( destHasNoDataValue );
 
  300    destNoDataValueList.append( destNoDataValue );
 
  305  for ( 
int i = 1; i < nBands; i++ )
 
  307    if ( destDataTypeList.value( i ) > destDataType )
 
  309      destDataType = destDataTypeList.value( i );
 
  315  for ( 
int attempt = 0; attempt < 2; attempt ++ )
 
  319    std::unique_ptr<QgsRasterDataProvider> destProvider(
 
  320      initOutput( nCols, nRows, 
crs, geoTransform, nBands, destDataType, destHasNoDataValueList, destNoDataValueList ) );
 
  327      if ( !destProvider->isValid() )
 
  329        if ( feedback && !destProvider->error().isEmpty() )
 
  331          feedback->
appendError( destProvider->error().summary() );
 
  335      if ( nCols != destProvider->xSize() || nRows != destProvider->ySize() )
 
  337        QgsDebugError( QStringLiteral( 
"Created raster does not have requested dimensions" ) );
 
  340          feedback->
appendError( QObject::tr( 
"Created raster does not have requested dimensions" ) );
 
  344      if ( nBands != destProvider->bandCount() )
 
  346        QgsDebugError( QStringLiteral( 
"Created raster does not have requested band count" ) );
 
  349          feedback->
appendError( QObject::tr( 
"Created raster does not have requested band count" ) );
 
  357        destDataType = destProvider->dataType( 1 );
 
  361    error = writeDataRaster( pipe, iter, nCols, nRows, outputExtent, 
crs, destDataType, destHasNoDataValueList, destNoDataValueList, destProvider.get(), feedback );
 
  368        destProvider->remove();
 
  369        destProvider.reset();
 
  377      for ( 
int i = 0; i < nBands; i++ )
 
  379        double destNoDataValue;
 
  381        destDataTypeList.replace( i, destDataType );
 
  382        destNoDataValueList.replace( i, destNoDataValue );
 
  384      destDataType = destDataTypeList.value( 0 );
 
  397static int qgsDivRoundUp( 
int a, 
int b )
 
  399  return a / b + ( ( ( a % b ) != 0 ) ? 1 : 0 );
 
  404    int nCols, 
int nRows,
 
  408    const QList<bool> &destHasNoDataValueList,
 
  409    const QList<double> &destNoDataValueList,
 
  414  Q_UNUSED( destHasNoDataValueList )
 
  428  std::vector< std::unique_ptr<QgsRasterBlock> > blockList;
 
  429  std::vector< std::unique_ptr<QgsRasterBlock> > destBlockList;
 
  431  blockList.resize( nBands );
 
  432  destBlockList.resize( nBands );
 
  434  for ( 
int i = 1; i <= nBands; ++i )
 
  437    if ( destProvider && destHasNoDataValueList.value( i - 1 ) ) 
 
  439      destProvider->
setNoDataValue( i, destNoDataValueList.value( i - 1 ) );
 
  449    nParts = nPartsX * nPartsY;
 
  456    for ( 
int i = 1; i <= nBands; ++i )
 
  464          const QString vrtFilePath( mOutputUrl + 
'/' + vrtFileName() );
 
  465          writeVRT( vrtFilePath );
 
  468            buildPyramids( vrtFilePath );
 
  475            buildPyramids( mOutputUrl, destProvider );
 
  482      blockList[i - 1].reset( block );
 
  486    if ( feedback && fileIndex < ( nParts - 1 ) )
 
  488      feedback->
setProgress( 100.0 * fileIndex / 
static_cast< double >( nParts ) );
 
  496    for ( 
int i = 1; i <= nBands; ++i )
 
  498      if ( srcProvider && srcProvider->
dataType( i ) == destDataType )
 
  505        blockList[i - 1]->convert( destDataType );
 
  507      destBlockList[i - 1] = std::move( blockList[i - 1] );
 
  512      std::unique_ptr< QgsRasterDataProvider > partDestProvider( createPartProvider( outputExtent,
 
  513          nCols, iterCols, iterRows,
 
  514          iterLeft, iterTop, mOutputUrl,
 
  515          fileIndex, nBands, destDataType, 
crs ) );
 
  517      if ( !partDestProvider || !partDestProvider->isValid() )
 
  523      for ( 
int i = 1; i <= nBands; ++i )
 
  525        if ( destHasNoDataValueList.value( i - 1 ) )
 
  527          partDestProvider->setNoDataValue( i, destNoDataValueList.value( i - 1 ) );
 
  529        if ( destBlockList[ i - 1 ]->isEmpty() )
 
  532        if ( !partDestProvider->write( destBlockList[i - 1]->constBits( 0 ), i, iterCols, iterRows, 0, 0 ) )
 
  536        addToVRT( partFileName( fileIndex ), i, iterCols, iterRows, iterLeft, iterTop );
 
  540    else if ( destProvider )
 
  543      for ( 
int i = 1; i <= nBands; ++i )
 
  545        if ( destBlockList[ i - 1 ]->isEmpty() )
 
  548        if ( !destProvider->
write( destBlockList[i - 1]->constBits( 0 ), i, iterCols, iterRows, iterLeft, iterTop ) )
 
  584  const size_t nMaxPixels = 
static_cast<size_t>( mMaxTileWidth ) * mMaxTileHeight;
 
  585  std::vector<unsigned char> redData( nMaxPixels );
 
  586  std::vector<unsigned char> greenData( nMaxPixels );
 
  587  std::vector<unsigned char> blueData( nMaxPixels );
 
  588  std::vector<unsigned char> alphaData( nMaxPixels );
 
  589  int iterLeft = 0, iterTop = 0, iterCols = 0, iterRows = 0;
 
  594  double geoTransform[6];
 
  595  globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
 
  597  const int nOutputBands = 4;
 
  598  std::unique_ptr< QgsRasterDataProvider > destProvider( initOutput( nCols, nRows, 
crs, geoTransform, nOutputBands, 
Qgis::DataType::Byte ) );
 
  605    if ( !destProvider->
isValid() )
 
  613    if ( nCols != destProvider->
xSize() || nRows != destProvider->
ySize() )
 
  615      QgsDebugError( QStringLiteral( 
"Created raster does not have requested dimensions" ) );
 
  618        feedback->
appendError( QObject::tr( 
"Created raster does not have requested dimensions" ) );
 
  622    if ( nOutputBands != destProvider->
bandCount() )
 
  624      QgsDebugError( QStringLiteral( 
"Created raster does not have requested band count" ) );
 
  627        feedback->
appendError( QObject::tr( 
"Created raster does not have requested band count" ) );
 
  633      QgsDebugError( QStringLiteral( 
"Created raster does not have requested data type" ) );
 
  636        feedback->
appendError( QObject::tr( 
"Created raster does not have requested data type" ) );
 
  649    nParts = nPartsX * nPartsY;
 
  652  std::unique_ptr< QgsRasterBlock > inputBlock;
 
  653  while ( iter->
readNextRasterPart( 1, iterCols, iterRows, inputBlock, iterLeft, iterTop ) )
 
  655    if ( !inputBlock || inputBlock->isEmpty() )
 
  660    if ( feedback && fileIndex < ( nParts - 1 ) )
 
  662      feedback->
setProgress( 100.0 * fileIndex / 
static_cast< double >( nParts ) );
 
  670    const qgssize nPixels = 
static_cast< qgssize >( iterCols ) * iterRows;
 
  671    for ( 
qgssize i = 0; i < nPixels; ++i )
 
  673      QRgb 
c = inputBlock->color( i );
 
  674      if ( isPremultiplied )
 
  676        c = qUnpremultiply( 
c );
 
  678      redData[i] = 
static_cast<unsigned char>( qRed( 
c ) );
 
  679      greenData[i] = 
static_cast<unsigned char>( qGreen( 
c ) );
 
  680      blueData[i] = 
static_cast<unsigned char>( qBlue( 
c ) );
 
  681      alphaData[i] = 
static_cast<unsigned char>( qAlpha( 
c ) );
 
  687      std::unique_ptr< QgsRasterDataProvider > partDestProvider( createPartProvider( outputExtent,
 
  688          nCols, iterCols, iterRows,
 
  689          iterLeft, iterTop, mOutputUrl, fileIndex,
 
  692      if ( !partDestProvider || partDestProvider->isValid() )
 
  698      if ( !partDestProvider->write( &redData[0], 1, iterCols, iterRows, 0, 0 ) ||
 
  699           !partDestProvider->write( &greenData[0], 2, iterCols, iterRows, 0, 0 ) ||
 
  700           !partDestProvider->write( &blueData[0], 3, iterCols, iterRows, 0, 0 ) ||
 
  701           !partDestProvider->write( &alphaData[0], 4, iterCols, iterRows, 0, 0 ) )
 
  706      addToVRT( partFileName( fileIndex ), 1, iterCols, iterRows, iterLeft, iterTop );
 
  707      addToVRT( partFileName( fileIndex ), 2, iterCols, iterRows, iterLeft, iterTop );
 
  708      addToVRT( partFileName( fileIndex ), 3, iterCols, iterRows, iterLeft, iterTop );
 
  709      addToVRT( partFileName( fileIndex ), 4, iterCols, iterRows, iterLeft, iterTop );
 
  711    else if ( destProvider )
 
  713      if ( !destProvider->
write( &redData[0], 1, iterCols, iterRows, iterLeft, iterTop ) ||
 
  714           !destProvider->
write( &greenData[0], 2, iterCols, iterRows, iterLeft, iterTop ) ||
 
  715           !destProvider->
write( &blueData[0], 3, iterCols, iterRows, iterLeft, iterTop ) ||
 
  716           !destProvider->
write( &alphaData[0], 4, iterCols, iterRows, iterLeft, iterTop ) )
 
  724  destProvider.reset();
 
  733    const QString vrtFilePath( mOutputUrl + 
'/' + vrtFileName() );
 
  734    writeVRT( vrtFilePath );
 
  737      buildPyramids( vrtFilePath );
 
  744      buildPyramids( mOutputUrl );
 
  750void QgsRasterFileWriter::addToVRT( 
const QString &filename, 
int band, 
int xSize, 
int ySize, 
int xOffset, 
int yOffset )
 
  752  QDomElement bandElem = mVRTBands.value( band - 1 );
 
  754  QDomElement simpleSourceElem = mVRTDocument.createElement( QStringLiteral( 
"SimpleSource" ) );
 
  757  QDomElement sourceFilenameElem = mVRTDocument.createElement( QStringLiteral( 
"SourceFilename" ) );
 
  758  sourceFilenameElem.setAttribute( QStringLiteral( 
"relativeToVRT" ), QStringLiteral( 
"1" ) );
 
  759  const QDomText sourceFilenameText = mVRTDocument.createTextNode( filename );
 
  760  sourceFilenameElem.appendChild( sourceFilenameText );
 
  761  simpleSourceElem.appendChild( sourceFilenameElem );
 
  764  QDomElement sourceBandElem = mVRTDocument.createElement( QStringLiteral( 
"SourceBand" ) );
 
  765  const QDomText sourceBandText = mVRTDocument.createTextNode( QString::number( band ) );
 
  766  sourceBandElem.appendChild( sourceBandText );
 
  767  simpleSourceElem.appendChild( sourceBandElem );
 
  770  QDomElement sourcePropertiesElem = mVRTDocument.createElement( QStringLiteral( 
"SourceProperties" ) );
 
  771  sourcePropertiesElem.setAttribute( QStringLiteral( 
"RasterXSize" ), xSize );
 
  772  sourcePropertiesElem.setAttribute( QStringLiteral( 
"RasterYSize" ), ySize );
 
  773  sourcePropertiesElem.setAttribute( QStringLiteral( 
"BlockXSize" ), xSize );
 
  774  sourcePropertiesElem.setAttribute( QStringLiteral( 
"BlockYSize" ), ySize );
 
  775  sourcePropertiesElem.setAttribute( QStringLiteral( 
"DataType" ), QStringLiteral( 
"Byte" ) );
 
  776  simpleSourceElem.appendChild( sourcePropertiesElem );
 
  779  QDomElement srcRectElem = mVRTDocument.createElement( QStringLiteral( 
"SrcRect" ) );
 
  780  srcRectElem.setAttribute( QStringLiteral( 
"xOff" ), QStringLiteral( 
"0" ) );
 
  781  srcRectElem.setAttribute( QStringLiteral( 
"yOff" ), QStringLiteral( 
"0" ) );
 
  782  srcRectElem.setAttribute( QStringLiteral( 
"xSize" ), xSize );
 
  783  srcRectElem.setAttribute( QStringLiteral( 
"ySize" ), ySize );
 
  784  simpleSourceElem.appendChild( srcRectElem );
 
  787  QDomElement dstRectElem = mVRTDocument.createElement( QStringLiteral( 
"DstRect" ) );
 
  788  dstRectElem.setAttribute( QStringLiteral( 
"xOff" ), xOffset );
 
  789  dstRectElem.setAttribute( QStringLiteral( 
"yOff" ), yOffset );
 
  790  dstRectElem.setAttribute( QStringLiteral( 
"xSize" ), xSize );
 
  791  dstRectElem.setAttribute( QStringLiteral( 
"ySize" ), ySize );
 
  792  simpleSourceElem.appendChild( dstRectElem );
 
  794  bandElem.appendChild( simpleSourceElem );
 
  797void QgsRasterFileWriter::buildPyramids( 
const QString &filename, 
QgsRasterDataProvider *destProviderIn )
 
  805    destProvider = qobject_cast< QgsRasterDataProvider * >( 
QgsProviderRegistry::instance()->createProvider( mOutputProviderKey, filename, providerOptions ) );
 
  806    if ( !destProvider || !destProvider->
isValid() )
 
  816  QList< QgsRasterPyramid> myPyramidList;
 
  817  if ( ! mPyramidsList.isEmpty() )
 
  819  for ( 
int myCounterInt = 0; myCounterInt < myPyramidList.count(); myCounterInt++ )
 
  821    myPyramidList[myCounterInt].setBuild( 
true );
 
  824  QgsDebugMsgLevel( QStringLiteral( 
"building pyramids : %1 pyramids, %2 resampling, %3 format, %4 options" ).arg( myPyramidList.count() ).arg( mPyramidsResampling ).arg( 
qgsEnumValueToKey( mPyramidsFormat ) ).arg( mPyramidsConfigOptions.count() ), 4 );
 
  826  const QString res = destProvider->
buildPyramids( myPyramidList, mPyramidsResampling,
 
  827                      mPyramidsFormat, mPyramidsConfigOptions );
 
  833    QString title, message;
 
  834    if ( res == QLatin1String( 
"ERROR_WRITE_ACCESS" ) )
 
  836      title = QObject::tr( 
"Building Pyramids" );
 
  837      message = QObject::tr( 
"Write access denied. Adjust the file permissions and try again." );
 
  839    else if ( res == QLatin1String( 
"ERROR_WRITE_FORMAT" ) )
 
  841      title = QObject::tr( 
"Building Pyramids" );
 
  842      message = QObject::tr( 
"The file was not writable. Some formats do not " 
  843                             "support pyramid overviews. Consult the GDAL documentation if in doubt." );
 
  845    else if ( res == QLatin1String( 
"FAILED_NOT_SUPPORTED" ) )
 
  847      title = QObject::tr( 
"Building Pyramids" );
 
  848      message = QObject::tr( 
"Building pyramid overviews is not supported on this type of raster." );
 
  850    else if ( res == QLatin1String( 
"ERROR_VIRTUAL" ) )
 
  852      title = QObject::tr( 
"Building Pyramids" );
 
  853      message = QObject::tr( 
"Building pyramid overviews is not supported on this type of raster." );
 
  855    QMessageBox::warning( 
nullptr, title, message );
 
  858  if ( !destProviderIn )
 
  863int QgsRasterFileWriter::pyramidsProgress( 
double dfComplete, 
const char *pszMessage, 
void *pData )
 
  865  Q_UNUSED( pszMessage )
 
  866  GDALTermProgress( dfComplete, 0, 0 );
 
  867  QProgressDialog *progressDialog = 
static_cast<QProgressDialog *
>( pData );
 
  868  if ( pData && progressDialog->wasCanceled() )
 
  875    progressDialog->setRange( 0, 100 );
 
  876    progressDialog->setValue( dfComplete * 100 );
 
  882void QgsRasterFileWriter::createVRT( 
int xSize, 
int ySize, 
const QgsCoordinateReferenceSystem &
crs, 
double *geoTransform, 
Qgis::DataType type, 
const QList<bool> &destHasNoDataValueList, 
const QList<double> &destNoDataValueList )
 
  884  mVRTDocument.clear();
 
  885  QDomElement VRTDatasetElem = mVRTDocument.createElement( QStringLiteral( 
"VRTDataset" ) );
 
  888  VRTDatasetElem.setAttribute( QStringLiteral( 
"rasterXSize" ), xSize );
 
  889  VRTDatasetElem.setAttribute( QStringLiteral( 
"rasterYSize" ), ySize );
 
  890  mVRTDocument.appendChild( VRTDatasetElem );
 
  893  QDomElement SRSElem = mVRTDocument.createElement( QStringLiteral( 
"SRS" ) );
 
  894  const QDomText crsText = mVRTDocument.createTextNode( 
crs.
toWkt() );
 
  895  SRSElem.appendChild( crsText );
 
  896  VRTDatasetElem.appendChild( SRSElem );
 
  901    QDomElement geoTransformElem = mVRTDocument.createElement( QStringLiteral( 
"GeoTransform" ) );
 
  902    const QString geoTransformString = QString::number( geoTransform[0], 
'f', 6 ) + 
", " + QString::number( geoTransform[1] ) + 
", " + QString::number( geoTransform[2] ) +
 
  903                                       ", "  + QString::number( geoTransform[3], 
'f', 6 ) + 
", " + QString::number( geoTransform[4] ) + 
", " + QString::number( geoTransform[5] );
 
  904    const QDomText geoTransformText = mVRTDocument.createTextNode( geoTransformString );
 
  905    geoTransformElem.appendChild( geoTransformText );
 
  906    VRTDatasetElem.appendChild( geoTransformElem );
 
  919  QStringList colorInterp;
 
  920  colorInterp << QStringLiteral( 
"Red" ) << QStringLiteral( 
"Green" ) << QStringLiteral( 
"Blue" ) << QStringLiteral( 
"Alpha" );
 
  922  QMap<Qgis::DataType, QString> dataTypes;
 
  935  for ( 
int i = 1; i <= nBands; i++ )
 
  937    QDomElement VRTBand = mVRTDocument.createElement( QStringLiteral( 
"VRTRasterBand" ) );
 
  939    VRTBand.setAttribute( QStringLiteral( 
"band" ), QString::number( i ) );
 
  940    const QString dataType = dataTypes.value( type );
 
  941    VRTBand.setAttribute( QStringLiteral( 
"dataType" ), dataType );
 
  946      VRTBand.setAttribute( QStringLiteral( 
"dataType" ), QStringLiteral( 
"Byte" ) );
 
  947      QDomElement colorInterpElement = mVRTDocument.createElement( QStringLiteral( 
"ColorInterp" ) );
 
  948      const QDomText interpText = mVRTDocument.createTextNode( colorInterp.value( i - 1 ) );
 
  949      colorInterpElement.appendChild( interpText );
 
  950      VRTBand.appendChild( colorInterpElement );
 
  953    if ( !destHasNoDataValueList.isEmpty() && destHasNoDataValueList.value( i - 1 ) )
 
  955      VRTBand.setAttribute( QStringLiteral( 
"NoDataValue" ), QString::number( destNoDataValueList.value( i - 1 ) ) );
 
  958    mVRTBands.append( VRTBand );
 
  959    VRTDatasetElem.appendChild( VRTBand );
 
  963bool QgsRasterFileWriter::writeVRT( 
const QString &file )
 
  965  QFile outputFile( file );
 
  966  if ( ! outputFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
 
  971  QTextStream outStream( &outputFile );
 
  972  mVRTDocument.save( outStream, 2 );
 
  977    int iterRows, 
int iterLeft, 
int iterTop, 
const QString &outputUrl, 
int fileIndex, 
int nBands, 
Qgis::DataType type,
 
  980  const double mup = extent.
width() / nCols;
 
  981  const double mapLeft = extent.
xMinimum() + iterLeft * mup;
 
  982  const double mapRight = mapLeft + mup * iterCols;
 
  983  const double mapTop = extent.
yMaximum() - iterTop * mup;
 
  984  const double mapBottom = mapTop - iterRows * mup;
 
  985  const QgsRectangle mapRect( mapLeft, mapBottom, mapRight, mapTop );
 
  987  const QString outputFile = 
outputUrl + 
'/' + partFileName( fileIndex );
 
  990  double geoTransform[6];
 
  991  geoTransform[0] = mapRect.xMinimum();
 
  992  geoTransform[1] = mup;
 
  993  geoTransform[2] = 0.0;
 
  994  geoTransform[3] = mapRect.yMaximum();
 
  995  geoTransform[4] = 0.0;
 
  996  geoTransform[5] = -mup;
 
 1003  return destProvider;
 
 1008    const QList<bool> &destHasNoDataValueList, 
const QList<double> &destNoDataValueList )
 
 1012    createVRT( nCols, nRows, 
crs, geoTransform, type, destHasNoDataValueList, destNoDataValueList );
 
 1020    if ( mBuildPyramidsFlag == -4 && mOutputProviderKey == 
"gdal" && mOutputFormat.compare( QLatin1String( 
"gtiff" ), Qt::CaseInsensitive ) == 0 )
 
 1021      mCreationOptions << 
"COPY_SRC_OVERVIEWS=YES";
 
 1026    if ( !destProvider )
 
 1031    return destProvider;
 
 1035void QgsRasterFileWriter::globalOutputParameters( 
const QgsRectangle &extent, 
int nCols, 
int &nRows,
 
 1036    double *geoTransform, 
double &pixelSize )
 
 1038  pixelSize = extent.
width() / nCols;
 
 1043    nRows = 
static_cast< double >( nCols ) / extent.
width() * extent.
height() + 0.5; 
 
 1045  geoTransform[0] = extent.
xMinimum();
 
 1046  geoTransform[1] = pixelSize;
 
 1047  geoTransform[2] = 0.0;
 
 1048  geoTransform[3] = extent.
yMaximum();
 
 1049  geoTransform[4] = 0.0;
 
 1050  geoTransform[5] = -( extent.
height() / nRows );
 
 1053QString QgsRasterFileWriter::partFileName( 
int fileIndex )
 
 1056  const QFileInfo outputInfo( mOutputUrl );
 
 1057  return QStringLiteral( 
"%1.%2.tif" ).arg( outputInfo.fileName() ).arg( fileIndex );
 
 1060QString QgsRasterFileWriter::vrtFileName()
 
 1062  const QFileInfo outputInfo( mOutputUrl );
 
 1063  return QStringLiteral( 
"%1.vrt" ).arg( outputInfo.fileName() );
 
 1068  QString ext = extension.trimmed();
 
 1069  if ( ext.isEmpty() )
 
 1072  if ( ext.startsWith( 
'.' ) )
 
 1075  if ( ext.compare( QLatin1String( 
"tif" ), Qt::CaseInsensitive ) == 0 ||
 
 1076       ext.compare( QLatin1String( 
"tiff" ), Qt::CaseInsensitive ) == 0 )
 
 1081    if ( GDALGetDriverByName( 
"GTiff" ) )
 
 1086  int const drvCount = GDALGetDriverCount();
 
 1088  for ( 
int i = 0; i < drvCount; ++i )
 
 1090    GDALDriverH drv = GDALGetDriver( i );
 
 1093      char **driverMetadata = GDALGetMetadata( drv, 
nullptr );
 
 1094      if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER, 
false ) )
 
 1096        QString drvName = GDALGetDriverShortName( drv );
 
 1097        const QStringList driverExtensions = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS, 
nullptr ) ).split( 
' ' );
 
 1099        const auto constDriverExtensions = driverExtensions;
 
 1100        for ( 
const QString &driver : constDriverExtensions )
 
 1102          if ( driver.compare( ext, Qt::CaseInsensitive ) == 0 )
 
 
 1113  GDALDriverH drv = GDALGetDriverByName( format.toLocal8Bit().data() );
 
 1116    char **driverMetadata = GDALGetMetadata( drv, 
nullptr );
 
 1117    if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER, 
false ) )
 
 1119      return QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS, 
nullptr ) ).split( 
' ' );
 
 1122  return QStringList();
 
 
 1127  GDALDriverH drv = GDALGetDriverByName( driverName.toLocal8Bit().data() );
 
 1130    const QString drvName = GDALGetDriverLongName( drv );
 
 1131    const QString extensionsString = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS, 
nullptr ) );
 
 1132    if ( extensionsString.isEmpty() )
 
 1136    const QStringList extensions = extensionsString.split( 
' ' );
 
 1137    QString filter = drvName + 
" (";
 
 1138    for ( 
const QString &ext : extensions )
 
 1140      filter.append( QStringLiteral( 
"*.%1 *.%2 " ).arg( ext.toLower(), ext.toUpper() ) );
 
 1142    filter = filter.trimmed().append( QStringLiteral( 
")" ) );
 
 
 1151  static QReadWriteLock sFilterLock;
 
 1152  static QMap< RasterFormatOptions, QList< QgsRasterFileWriter::FilterFormatDetails > > sFilters;
 
 1156  const auto it = sFilters.constFind( options );
 
 1157  if ( it != sFilters.constEnd() )
 
 1161  int const drvCount = GDALGetDriverCount();
 
 1164  QList< QgsRasterFileWriter::FilterFormatDetails > results;
 
 1168  for ( 
int i = 0; i < drvCount; ++i )
 
 1170    GDALDriverH drv = GDALGetDriver( i );
 
 1175        const QString drvName = GDALGetDriverShortName( drv );
 
 1177        if ( filterString.isEmpty() )
 
 1184        if ( options & SortRecommended )
 
 1186          if ( drvName == QLatin1String( 
"GTiff" ) )
 
 1188            tifFormat = details;
 
 1200    return a.driverName < b.driverName;
 
 1203  if ( options & SortRecommended )
 
 1207      results.insert( 0, tifFormat );
 
 1211  sFilters.insert( options, results );
 
 
 1219  QSet< QString > extensions;
 
 1221  const thread_local QRegularExpression rx( QStringLiteral( 
"\\*\\.([a-zA-Z0-9]*)" ) );
 
 1225    const QString ext = format.filterString;
 
 1226    const QRegularExpressionMatch match = rx.match( ext );
 
 1227    if ( !match.hasMatch() )
 
 1230    const QString matched = match.captured( 1 );
 
 1231    extensions.insert( matched );
 
 1234  QStringList extensionList( extensions.constBegin(), extensions.constEnd() );
 
 1236  std::sort( extensionList.begin(), extensionList.end(), [options]( 
const QString & a, 
const QString & b ) -> 
bool 
 1238    if ( options & SortRecommended )
 
 1240      if ( a == QLatin1String( 
"tif" ) )
 
 1242      else if ( b == QLatin1String( 
"tif" ) )
 
 1244      if ( a == QLatin1String( 
"tiff" ) )
 
 1246      else if ( b == QLatin1String( 
"tiff" ) )
 
 1248      if ( a == QLatin1String( 
"gpkg" ) )
 
 1250      else if ( b == QLatin1String( 
"gpkg" ) )
 
 1254    return a.toLower().localeAwareCompare( b.toLower() ) < 0;
 
 1257  return extensionList;
 
 
RasterFileWriterResult
Raster file export results.
 
@ Canceled
Writing was manually canceled.
 
@ NoDataConflict
Internal error if a value used for 'no data' was found in input.
 
@ Success
Successful export.
 
@ CreateDatasourceError
Data source creation error.
 
@ DestinationProviderError
Destination data provider error.
 
@ SourceProviderError
Source data provider error.
 
DataType
Raster data types.
 
@ Float32
Thirty two bit floating point (float)
 
@ CFloat64
Complex Float64.
 
@ Int16
Sixteen bit signed integer (qint16)
 
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
 
@ Int8
Eight bit signed integer (qint8) (added in QGIS 3.30)
 
@ UInt16
Sixteen bit unsigned integer (quint16)
 
@ Byte
Eight bit unsigned integer (quint8)
 
@ ARGB32
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
 
@ Float64
Sixty four bit floating point (double)
 
@ CFloat32
Complex Float32.
 
@ UInt32
Thirty two bit unsigned integer (quint32)
 
@ RenderedImage
Rendered image.
 
static double maximumValuePossible(Qgis::DataType dataType)
Helper function that returns the maximum possible value for a data type.
 
static double minimumValuePossible(Qgis::DataType dataType)
Helper function that returns the minimum possible value for a data type.
 
Represents a coordinate reference system (CRS).
 
QString toWkt(Qgis::CrsWktVariant variant=Qgis::CrsWktVariant::Wkt1Gdal, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
 
Contains information about the context in which a coordinate transform is executed.
 
QgsCoordinateTransformContext transformContext() const
Returns data provider coordinate transform context.
 
virtual bool isValid() const =0
Returns true if this is a valid layer.
 
virtual QgsError error() const
Gets current status error.
 
bool isEmpty() const
Test if no error is set.
 
QString summary() const
Short error description, usually the first error in chain, the real error.
 
bool isCanceled() const
Tells whether the operation has been canceled already.
 
void setProgress(double progress)
Sets the current progress for the feedback object.
 
static bool supportsRasterCreate(GDALDriverH driver)
Reads whether a driver supports GDALCreate() for raster purposes.
 
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
 
The RasterBandStats struct is a container for statistics about a single raster band.
 
double minimumValue
The minimum cell value in the raster band.
 
double maximumValue
The maximum cell value in the raster band.
 
Feedback object tailored for raster block reading.
 
void appendError(const QString &error)
Appends an error message to the stored list of errors.
 
static int typeSize(Qgis::DataType dataType)
Returns the size in bytes for the specified dataType.
 
static Qgis::DataType typeWithNoDataValue(Qgis::DataType dataType, double *noDataValue)
For given data type returns wider type and sets no data value.
 
static bool typeIsColor(Qgis::DataType type)
Returns true if a data type is a color type.
 
Base class for raster data providers.
 
virtual bool write(const void *data, int band, int width, int height, int xOffset, int yOffset)
Writes into the provider datasource.
 
virtual bool sourceHasNoDataValue(int bandNo) const
Returns true if source band has no data value.
 
virtual bool setNoDataValue(int bandNo, double noDataValue)
Set no data value on created dataset.
 
virtual QString buildPyramids(const QList< QgsRasterPyramid > &pyramidList, const QString &resamplingMethod="NEAREST", Qgis::RasterPyramidFormat format=Qgis::RasterPyramidFormat::GeoTiff, const QStringList &configOptions=QStringList(), QgsRasterBlockFeedback *feedback=nullptr)
Creates pyramid overviews.
 
Qgis::DataType sourceDataType(int bandNo) const override=0
Returns source data type for the band specified by number, source data type may be shorter than dataT...
 
virtual double sourceNoDataValue(int bandNo) const
Value representing no data value.
 
QgsRectangle extent() const override=0
Returns the extent of the layer.
 
Qgis::DataType dataType(int bandNo) const override=0
Returns data type for the band specified by number.
 
static QgsRasterDataProvider * create(const QString &providerKey, const QString &uri, const QString &format, int nBands, Qgis::DataType type, int width, int height, double *geoTransform, const QgsCoordinateReferenceSystem &crs, const QStringList &createOptions=QStringList())
Creates a new dataset with mDataSourceURI.
 
virtual QList< QgsRasterPyramid > buildPyramidList(const QList< int > &overviewList=QList< int >())
Returns the raster layers pyramid list.
 
Q_DECL_DEPRECATED Qgis::RasterFileWriterResult writeRaster(const QgsRasterPipe *pipe, int nCols, int nRows, const QgsRectangle &outputExtent, const QgsCoordinateReferenceSystem &crs, QgsRasterBlockFeedback *feedback=nullptr) SIP_DEPRECATED
Write raster file.
 
static QStringList extensionsForFormat(const QString &format)
Returns a list of known file extensions for the given GDAL driver format.
 
static QString filterForDriver(const QString &driverName)
Creates a filter for an GDAL driver key.
 
static QString driverForExtension(const QString &extension)
Returns the GDAL driver name for a specified file extension.
 
QgsRasterFileWriter(const QString &outputUrl)
Constructor for QgsRasterFileWriter, writing to the specified output URL/filename.
 
static QStringList supportedFormatExtensions(RasterFormatOptions options=SortRecommended)
Returns a list of file extensions for supported formats.
 
QString outputUrl() const
Returns the output URL (filename) for the raster.
 
QFlags< RasterFormatOption > RasterFormatOptions
 
QgsRasterDataProvider * createMultiBandRaster(Qgis::DataType dataType, int width, int height, const QgsRectangle &extent, const QgsCoordinateReferenceSystem &crs, int nBands) SIP_FACTORY
Create a raster file with given number of bands without initializing the pixel data.
 
static QList< QgsRasterFileWriter::FilterFormatDetails > supportedFiltersAndFormats(RasterFormatOptions options=SortRecommended)
Returns a list or pairs, with format filter string as first element and GDAL format key as second ele...
 
QgsRasterDataProvider * createOneBandRaster(Qgis::DataType dataType, int width, int height, const QgsRectangle &extent, const QgsCoordinateReferenceSystem &crs) SIP_FACTORY
Create a raster file with one band without initializing the pixel data.
 
Base class for processing filters like renderers, reprojector, resampler etc.
 
virtual Qgis::DataType dataType(int bandNo) const =0
Returns data type for the band specified by number.
 
virtual int xSize() const
Gets raster size.
 
Q_DECL_DEPRECATED QgsRasterBandStats bandStatistics(int bandNo, int stats, const QgsRectangle &extent=QgsRectangle(), int sampleSize=0, QgsRasterBlockFeedback *feedback=nullptr)
Returns the band statistics.
 
virtual int bandCount() const =0
Gets number of bands.
 
virtual int ySize() const
 
virtual const QgsRasterInterface * sourceInput() const
Gets source / raw input, the first in pipe, usually provider.
 
Iterator for sequentially processing raster cells.
 
int maximumTileWidth() const
Returns the maximum tile width returned during iteration.
 
const QgsRasterInterface * input() const
Returns the input raster interface which is being iterated over.
 
void setMaximumTileWidth(int w)
Sets the maximum tile width returned during iteration.
 
bool readNextRasterPart(int bandNumber, int &nCols, int &nRows, QgsRasterBlock **block, int &topLeftCol, int &topLeftRow)
Fetches next part of raster data, caller takes ownership of the block and caller should delete the bl...
 
int maximumTileHeight() const
Returns the minimum tile width returned during iteration.
 
void startRasterRead(int bandNumber, qgssize nCols, qgssize nRows, const QgsRectangle &extent, QgsRasterBlockFeedback *feedback=nullptr)
Start reading of raster band.
 
void setMaximumTileHeight(int h)
Sets the minimum tile height returned during iteration.
 
Raster pipe that deals with null values.
 
void setOutputNoDataValue(int bandNo, double noData)
Sets the output no data value.
 
QgsRasterRangeList noData(int bandNo) const
 
Contains a pipeline of raster interfaces for sequential raster processing.
 
QgsRasterInterface * last() const
Returns last interface in the pipe.
 
QgsRasterDataProvider * provider() const
Returns the data provider interface, or nullptr if no data provider is present in the pipe.
 
QgsRasterProjector * projector() const
Returns the projector interface, or nullptr if no projector is present in the pipe.
 
QgsRasterNuller * nuller() const
Returns the raster nuller interface, or nullptr if no raster nuller is present in the pipe.
 
Implements approximate projection support for optimised raster transformation.
 
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination CRS.
 
QgsCoordinateReferenceSystem sourceCrs() const
Returns the source CRS.
 
A convenience class that simplifies locking and unlocking QReadWriteLocks.
 
void changeMode(Mode mode)
Change the mode of the lock to mode.
 
A rectangle specified with double values.
 
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.