QGIS API Documentation  3.4.15-Madeira (e83d02e274)
qgsrasterfilewriter.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrasterfilewriter.cpp
3  ---------------------
4  begin : July 2012
5  copyright : (C) 2012 by Marco Hugentobler
6  email : marco dot hugentobler at sourcepole dot ch
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 #include <typeinfo>
16 
17 #include "qgsgdalutils.h"
18 #include "qgsrasterfilewriter.h"
19 #include "qgscoordinatetransform.h"
20 #include "qgsproviderregistry.h"
21 #include "qgsrasterinterface.h"
22 #include "qgsrasteriterator.h"
23 #include "qgsrasterlayer.h"
24 #include "qgsrasterprojector.h"
25 #include "qgsrasterdataprovider.h"
26 #include "qgsrasternuller.h"
27 
28 #include <QCoreApplication>
29 #include <QProgressDialog>
30 #include <QTextStream>
31 #include <QMessageBox>
32 
33 #include <cmath>
34 
35 #include <gdal.h>
36 #include <cpl_string.h>
37 
39 {
40  if ( mTiledMode )
41  return nullptr; // does not make sense with tiled mode
42 
43  double pixelSize;
44  double geoTransform[6];
45  globalOutputParameters( extent, width, height, geoTransform, pixelSize );
46 
47  return initOutput( width, height, crs, geoTransform, 1, dataType, QList<bool>(), QList<double>() );
48 }
49 
51 {
52  if ( mTiledMode )
53  return nullptr; // does not make sense with tiled mode
54 
55  double pixelSize;
56  double geoTransform[6];
57  globalOutputParameters( extent, width, height, geoTransform, pixelSize );
58 
59  return initOutput( width, height, crs, geoTransform, nBands, dataType, QList<bool>(), QList<double>() );
60 }
61 
63  : mOutputUrl( outputUrl )
64 {
65 
66 }
67 
69 {
70 
71 }
72 
73 QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeRaster( const QgsRasterPipe *pipe, int nCols, int nRows, const QgsRectangle &outputExtent,
75 {
76  QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
77 
78  if ( !pipe )
79  {
80  return SourceProviderError;
81  }
82  mPipe = pipe;
83 
84  //const QgsRasterInterface* iface = iter->input();
85  const QgsRasterInterface *iface = pipe->last();
86  if ( !iface )
87  {
88  return SourceProviderError;
89  }
90  mInput = iface;
91 
92  if ( QgsRasterBlock::typeIsColor( iface->dataType( 1 ) ) )
93  {
94  mMode = Image;
95  }
96  else
97  {
98  mMode = Raw;
99  }
100 
101  QgsDebugMsgLevel( QStringLiteral( "reading from %1" ).arg( typeid( *iface ).name() ), 4 );
102 
103  if ( !iface->sourceInput() )
104  {
105  QgsDebugMsg( QStringLiteral( "iface->srcInput() == 0" ) );
106  return SourceProviderError;
107  }
108 #ifdef QGISDEBUG
109  const QgsRasterInterface &srcInput = *iface->sourceInput();
110  QgsDebugMsgLevel( QStringLiteral( "srcInput = %1" ).arg( typeid( srcInput ).name() ), 4 );
111 #endif
112 
113  mFeedback = feedback;
114 
115  QgsRasterIterator iter( pipe->last() );
116 
117  //create directory for output files
118  if ( mTiledMode )
119  {
120  QFileInfo fileInfo( mOutputUrl );
121  if ( !fileInfo.exists() )
122  {
123  QDir dir = fileInfo.dir();
124  if ( !dir.mkdir( fileInfo.fileName() ) )
125  {
126  QgsDebugMsg( "Cannot create output VRT directory " + fileInfo.fileName() + " in " + dir.absolutePath() );
127  return CreateDatasourceError;
128  }
129  }
130  }
131 
132  // Remove pre-existing overview files to avoid using those with new raster
133  QFile pyramidFile( mOutputUrl + ( mTiledMode ? ".vrt.ovr" : ".ovr" ) );
134  if ( pyramidFile.exists() )
135  pyramidFile.remove();
136  pyramidFile.setFileName( mOutputUrl + ( mTiledMode ? ".vrt.rrd" : ".rrd" ) );
137  if ( pyramidFile.exists() )
138  pyramidFile.remove();
139 
140  if ( mMode == Image )
141  {
142  WriterError e = writeImageRaster( &iter, nCols, nRows, outputExtent, crs, feedback );
143  return e;
144  }
145  else
146  {
147  WriterError e = writeDataRaster( pipe, &iter, nCols, nRows, outputExtent, crs, feedback );
148  return e;
149  }
150 }
151 
152 QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( const QgsRasterPipe *pipe, QgsRasterIterator *iter, int nCols, int nRows, const QgsRectangle &outputExtent,
154 {
155  QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
156  if ( !iter )
157  {
158  return SourceProviderError;
159  }
160 
161  const QgsRasterInterface *iface = pipe->last();
162  if ( !iface )
163  {
164  return SourceProviderError;
165  }
166 
167  QgsRasterDataProvider *srcProvider = const_cast<QgsRasterDataProvider *>( dynamic_cast<const QgsRasterDataProvider *>( iface->sourceInput() ) );
168  if ( !srcProvider )
169  {
170  QgsDebugMsg( QStringLiteral( "Cannot get source data provider" ) );
171  return SourceProviderError;
172  }
173 
174  iter->setMaximumTileWidth( mMaxTileWidth );
175  iter->setMaximumTileHeight( mMaxTileHeight );
176 
177  int nBands = iface->bandCount();
178  if ( nBands < 1 )
179  {
180  return SourceProviderError;
181  }
182 
183 
184  //check if all the bands have the same data type size, otherwise we cannot write it to the provider
185  //(at least not with the current interface)
186  int dataTypeSize = QgsRasterBlock::typeSize( srcProvider->sourceDataType( 1 ) );
187  for ( int i = 2; i <= nBands; ++i )
188  {
189  if ( QgsRasterBlock::typeSize( srcProvider->sourceDataType( 1 ) ) != dataTypeSize )
190  {
191  return DestProviderError;
192  }
193  }
194 
195  // Output data type - source data type is preferred but it may happen that we need
196  // to set 'no data' value (which was not set on source data) if output extent
197  // is larger than source extent (with or without reprojection) and there is no 'free'
198  // (not used) value available
199  QList<bool> destHasNoDataValueList;
200  QList<double> destNoDataValueList;
201  QList<Qgis::DataType> destDataTypeList;
202  destDataTypeList.reserve( nBands );
203  destHasNoDataValueList.reserve( nBands );
204  destNoDataValueList.reserve( nBands );
205 
206  const bool isGpkgOutput = mOutputProviderKey == "gdal" &&
207  mOutputFormat.compare( QLatin1String( "gpkg" ), Qt::CaseInsensitive ) == 0;
208  double pixelSize;
209  double geoTransform[6];
210  globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
211  const auto srcProviderExtent( srcProvider->extent() );
212 
213  for ( int bandNo = 1; bandNo <= nBands; bandNo++ )
214  {
215  QgsRasterNuller *nuller = pipe->nuller();
216 
217  const bool srcHasNoDataValue = srcProvider->sourceHasNoDataValue( bandNo );
218  bool destHasNoDataValue = false;
219  double destNoDataValue = std::numeric_limits<double>::quiet_NaN();
220  const Qgis::DataType srcDataType = srcProvider->sourceDataType( bandNo );
221  Qgis::DataType destDataType = srcDataType;
222  // TODO: verify what happens/should happen if srcNoDataValue is disabled by setUseSrcNoDataValue
223  QgsDebugMsgLevel( QStringLiteral( "srcHasNoDataValue = %1 srcNoDataValue = %2" ).arg( srcHasNoDataValue ).arg( srcProvider->sourceNoDataValue( bandNo ) ), 4 );
224  if ( srcHasNoDataValue )
225  {
226 
227  // If source has no data value, it is used by provider
228  destNoDataValue = srcProvider->sourceNoDataValue( bandNo );
229  destHasNoDataValue = true;
230  }
231  else if ( nuller && !nuller->noData( bandNo ).isEmpty() )
232  {
233  // Use one user defined no data value
234  destNoDataValue = nuller->noData( bandNo ).value( 0 ).min();
235  destHasNoDataValue = true;
236  }
237  // GeoPackage does not support nodata for Byte output, and does not
238  // support non-Byte multiband output, so do not take the risk of an accidental
239  // data type promotion.
240  else if ( !( isGpkgOutput && destDataType == Qgis::Byte ) )
241  {
242  // Verify if we really need no data value, i.e.
243  QgsRectangle outputExtentInSrcCrs = outputExtent;
244  QgsRasterProjector *projector = pipe->projector();
245  if ( projector && projector->destinationCrs() != projector->sourceCrs() )
246  {
248  QgsCoordinateTransform ct( projector->destinationCrs(), projector->sourceCrs() );
250  outputExtentInSrcCrs = ct.transformBoundingBox( outputExtent );
251  }
252  if ( !srcProviderExtent.contains( outputExtentInSrcCrs ) &&
253  ( std::fabs( srcProviderExtent.xMinimum() - outputExtentInSrcCrs.xMinimum() ) > geoTransform[1] / 2 ||
254  std::fabs( srcProviderExtent.xMaximum() - outputExtentInSrcCrs.xMaximum() ) > geoTransform[1] / 2 ||
255  std::fabs( srcProviderExtent.yMinimum() - outputExtentInSrcCrs.yMinimum() ) > std::fabs( geoTransform[5] ) / 2 ||
256  std::fabs( srcProviderExtent.yMaximum() - outputExtentInSrcCrs.yMaximum() ) > std::fabs( geoTransform[5] ) / 2 ) )
257  {
258  // Destination extent is (at least partially) outside of source extent, we need destination no data values
259  // Get src sample statistics (estimation from sample)
260  QgsRasterBandStats stats = srcProvider->bandStatistics( bandNo, QgsRasterBandStats::Min | QgsRasterBandStats::Max, outputExtentInSrcCrs, 250000 );
261 
262  // Test if we have free (not used) values
263  const double typeMinValue = QgsContrastEnhancement::minimumValuePossible( srcDataType );
264  const double typeMaxValue = QgsContrastEnhancement::maximumValuePossible( srcDataType );
265  if ( stats.minimumValue > typeMinValue )
266  {
267  destNoDataValue = typeMinValue;
268  }
269  else if ( stats.maximumValue < typeMaxValue )
270  {
271  destNoDataValue = typeMaxValue;
272  }
273  else
274  {
275  // We have to use wider type
276  destDataType = QgsRasterBlock::typeWithNoDataValue( destDataType, &destNoDataValue );
277  }
278  destHasNoDataValue = true;
279  }
280  }
281 
282  if ( nuller && destHasNoDataValue )
283  {
284  nuller->setOutputNoDataValue( bandNo, destNoDataValue );
285  }
286 
287  QgsDebugMsgLevel( QStringLiteral( "bandNo = %1 destDataType = %2 destHasNoDataValue = %3 destNoDataValue = %4" ).arg( bandNo ).arg( destDataType ).arg( destHasNoDataValue ).arg( destNoDataValue ), 4 );
288  destDataTypeList.append( destDataType );
289  destHasNoDataValueList.append( destHasNoDataValue );
290  destNoDataValueList.append( destNoDataValue );
291  }
292 
293  Qgis::DataType destDataType = destDataTypeList.value( 0 );
294  // Currently write API supports one output type for dataset only -> find the widest
295  for ( int i = 1; i < nBands; i++ )
296  {
297  if ( destDataTypeList.value( i ) > destDataType )
298  {
299  destDataType = destDataTypeList.value( i );
300  // no data value may be left per band (for future)
301  }
302  }
303 
304  WriterError error;
305  for ( int attempt = 0; attempt < 2; attempt ++ )
306  {
307  //create destProvider for whole dataset here
308  // initOutput() returns 0 in tile mode!
309  std::unique_ptr<QgsRasterDataProvider> destProvider(
310  initOutput( nCols, nRows, crs, geoTransform, nBands, destDataType, destHasNoDataValueList, destNoDataValueList ) );
311  if ( !mTiledMode )
312  {
313  if ( !destProvider )
314  {
315  return CreateDatasourceError;
316  }
317  if ( !destProvider->isValid() )
318  {
319  return CreateDatasourceError;
320  }
321  if ( nCols != destProvider->xSize() || nRows != destProvider->ySize() )
322  {
323  QgsDebugMsg( QStringLiteral( "Created raster does not have requested dimensions" ) );
324  return CreateDatasourceError;
325  }
326  if ( nBands != destProvider->bandCount() )
327  {
328  QgsDebugMsg( QStringLiteral( "Created raster does not have requested band count" ) );
329  return CreateDatasourceError;
330  }
331  if ( nBands )
332  {
333  // Some driver like GS7BG may accept Byte as requested data type,
334  // but actually return a driver with Float64...
335  destDataType = destProvider->dataType( 1 );
336  }
337  }
338 
339  error = writeDataRaster( pipe, iter, nCols, nRows, outputExtent, crs, destDataType, destHasNoDataValueList, destNoDataValueList, destProvider.get(), feedback );
340 
341  if ( attempt == 0 && error == NoDataConflict )
342  {
343  // The value used for no data was found in source data, we must use wider data type
344  if ( destProvider ) // no tiles
345  {
346  destProvider->remove();
347  destProvider.reset();
348  }
349  else // VRT
350  {
351  // TODO: remove created VRT
352  }
353 
354  // But we don't know which band -> wider all
355  for ( int i = 0; i < nBands; i++ )
356  {
357  double destNoDataValue;
358  Qgis::DataType destDataType = QgsRasterBlock::typeWithNoDataValue( destDataTypeList.value( i ), &destNoDataValue );
359  destDataTypeList.replace( i, destDataType );
360  destNoDataValueList.replace( i, destNoDataValue );
361  }
362  destDataType = destDataTypeList.value( 0 );
363 
364  // Try again
365  }
366  else
367  {
368  break;
369  }
370  }
371 
372  return error;
373 }
374 
375 static int qgsDivRoundUp( int a, int b )
376 {
377  return a / b + ( ( ( a % b ) != 0 ) ? 1 : 0 );
378 }
379 
380 QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( const QgsRasterPipe *pipe,
381  QgsRasterIterator *iter,
382  int nCols, int nRows,
383  const QgsRectangle &outputExtent,
384  const QgsCoordinateReferenceSystem &crs,
385  Qgis::DataType destDataType,
386  const QList<bool> &destHasNoDataValueList,
387  const QList<double> &destNoDataValueList,
388  QgsRasterDataProvider *destProvider,
389  QgsRasterBlockFeedback *feedback )
390 {
391  Q_UNUSED( pipe );
392  Q_UNUSED( destHasNoDataValueList );
393  QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
394 
395  const QgsRasterInterface *iface = iter->input();
396  const QgsRasterDataProvider *srcProvider = dynamic_cast<const QgsRasterDataProvider *>( iface->sourceInput() );
397  int nBands = iface->bandCount();
398  QgsDebugMsgLevel( QStringLiteral( "nBands = %1" ).arg( nBands ), 4 );
399 
400  //Get output map units per pixel
401  int iterLeft = 0;
402  int iterTop = 0;
403  int iterCols = 0;
404  int iterRows = 0;
405 
406  std::vector< std::unique_ptr<QgsRasterBlock> > blockList;
407  std::vector< std::unique_ptr<QgsRasterBlock> > destBlockList;
408 
409  blockList.resize( nBands );
410  destBlockList.resize( nBands );
411 
412  for ( int i = 1; i <= nBands; ++i )
413  {
414  iter->startRasterRead( i, nCols, nRows, outputExtent );
415  if ( destProvider && destHasNoDataValueList.value( i - 1 ) ) // no tiles
416  {
417  destProvider->setNoDataValue( i, destNoDataValueList.value( i - 1 ) );
418  }
419  }
420 
421  int nParts = 0;
422  int fileIndex = 0;
423  if ( feedback )
424  {
425  int nPartsX = qgsDivRoundUp( nCols, iter->maximumTileWidth() );
426  int nPartsY = qgsDivRoundUp( nRows, iter->maximumTileHeight() );
427  nParts = nPartsX * nPartsY;
428  }
429 
430  // hmm why is there a for(;;) here ..
431  // not good coding practice IMHO, it might be better to use [ for() and break ] or [ while (test) ]
432  Q_FOREVER
433  {
434  for ( int i = 1; i <= nBands; ++i )
435  {
436  QgsRasterBlock *block = nullptr;
437  if ( !iter->readNextRasterPart( i, iterCols, iterRows, &block, iterLeft, iterTop ) )
438  {
439  // No more parts, create VRT and return
440  if ( mTiledMode )
441  {
442  QString vrtFilePath( mOutputUrl + '/' + vrtFileName() );
443  writeVRT( vrtFilePath );
444  if ( mBuildPyramidsFlag == QgsRaster::PyramidsFlagYes )
445  {
446  buildPyramids( vrtFilePath );
447  }
448  }
449  else
450  {
451  if ( mBuildPyramidsFlag == QgsRaster::PyramidsFlagYes )
452  {
453  buildPyramids( mOutputUrl, destProvider );
454  }
455  }
456 
457  QgsDebugMsgLevel( QStringLiteral( "Done" ), 4 );
458  return NoError; //reached last tile, bail out
459  }
460  blockList[i - 1].reset( block );
461  // TODO: verify if NoDataConflict happened, to do that we need the whole pipe or nuller interface
462  }
463 
464  if ( feedback && fileIndex < ( nParts - 1 ) )
465  {
466  feedback->setProgress( 100.0 * fileIndex / static_cast< double >( nParts ) );
467  if ( feedback->isCanceled() )
468  {
469  break;
470  }
471  }
472 
473  // It may happen that internal data type (dataType) is wider than destDataType
474  for ( int i = 1; i <= nBands; ++i )
475  {
476  if ( srcProvider && srcProvider->dataType( i ) == destDataType )
477  {
478  // nothing
479  }
480  else
481  {
482  // TODO: this conversion should go to QgsRasterDataProvider::write with additional input data type param
483  blockList[i - 1]->convert( destDataType );
484  }
485  destBlockList[i - 1] = std::move( blockList[i - 1] );
486  }
487 
488  if ( mTiledMode ) //write to file
489  {
490  std::unique_ptr< QgsRasterDataProvider > partDestProvider( createPartProvider( outputExtent,
491  nCols, iterCols, iterRows,
492  iterLeft, iterTop, mOutputUrl,
493  fileIndex, nBands, destDataType, crs ) );
494 
495  if ( !partDestProvider || !partDestProvider->isValid() )
496  {
497  return DestProviderError;
498  }
499 
500  //write data to output file. todo: loop over the data list
501  for ( int i = 1; i <= nBands; ++i )
502  {
503  if ( destHasNoDataValueList.value( i - 1 ) )
504  {
505  partDestProvider->setNoDataValue( i, destNoDataValueList.value( i - 1 ) );
506  }
507  if ( !partDestProvider->write( destBlockList[i - 1]->bits( 0 ), i, iterCols, iterRows, 0, 0 ) )
508  {
509  return WriteError;
510  }
511  addToVRT( partFileName( fileIndex ), i, iterCols, iterRows, iterLeft, iterTop );
512  }
513 
514  }
515  else if ( destProvider )
516  {
517  //loop over data
518  for ( int i = 1; i <= nBands; ++i )
519  {
520  if ( !destProvider->write( destBlockList[i - 1]->bits( 0 ), i, iterCols, iterRows, iterLeft, iterTop ) )
521  {
522  return WriteError;
523  }
524  }
525  }
526  ++fileIndex;
527  }
528 
529  QgsDebugMsgLevel( QStringLiteral( "Done" ), 4 );
530  return ( feedback && feedback->isCanceled() ) ? WriteCanceled : NoError;
531 }
532 
533 QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeImageRaster( QgsRasterIterator *iter, int nCols, int nRows, const QgsRectangle &outputExtent,
535 {
536  QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
537  if ( !iter )
538  {
539  return SourceProviderError;
540  }
541 
542  const QgsRasterInterface *iface = iter->input();
543  if ( !iface )
544  return SourceProviderError;
545 
546  Qgis::DataType inputDataType = iface->dataType( 1 );
547  if ( inputDataType != Qgis::ARGB32 && inputDataType != Qgis::ARGB32_Premultiplied )
548  {
549  return SourceProviderError;
550  }
551  const bool isPremultiplied = ( inputDataType == Qgis::ARGB32_Premultiplied );
552 
553  iter->setMaximumTileWidth( mMaxTileWidth );
554  iter->setMaximumTileHeight( mMaxTileHeight );
555 
556  const size_t nMaxPixels = static_cast<size_t>( mMaxTileWidth ) * mMaxTileHeight;
557  std::vector<unsigned char> redData( nMaxPixels );
558  std::vector<unsigned char> greenData( nMaxPixels );
559  std::vector<unsigned char> blueData( nMaxPixels );
560  std::vector<unsigned char> alphaData( nMaxPixels );
561 
562  int iterLeft = 0, iterTop = 0, iterCols = 0, iterRows = 0;
563  int fileIndex = 0;
564 
565  //create destProvider for whole dataset here
566  double pixelSize;
567  double geoTransform[6];
568  globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
569 
570  const int nOutputBands = 4;
571  std::unique_ptr< QgsRasterDataProvider > destProvider( initOutput( nCols, nRows, crs, geoTransform, nOutputBands, Qgis::Byte ) );
572  if ( !mTiledMode )
573  {
574  if ( !destProvider )
575  {
576  return CreateDatasourceError;
577  }
578  if ( !destProvider->isValid() )
579  {
580  return CreateDatasourceError;
581  }
582  if ( nCols != destProvider->xSize() || nRows != destProvider->ySize() )
583  {
584  QgsDebugMsg( QStringLiteral( "Created raster does not have requested dimensions" ) );
585  return CreateDatasourceError;
586  }
587  if ( nOutputBands != destProvider->bandCount() )
588  {
589  QgsDebugMsg( QStringLiteral( "Created raster does not have requested band count" ) );
590  return CreateDatasourceError;
591  }
592  if ( Qgis::Byte != destProvider->dataType( 1 ) )
593  {
594  QgsDebugMsg( QStringLiteral( "Created raster does not have requested data type" ) );
595  return CreateDatasourceError;
596  }
597  }
598 
599  iter->startRasterRead( 1, nCols, nRows, outputExtent, feedback );
600 
601  int nParts = 0;
602  if ( feedback )
603  {
604  int nPartsX = qgsDivRoundUp( nCols, iter->maximumTileWidth() );
605  int nPartsY = qgsDivRoundUp( nRows, iter->maximumTileHeight() );
606  nParts = nPartsX * nPartsY;
607  }
608 
609  std::unique_ptr< QgsRasterBlock > inputBlock;
610  while ( iter->readNextRasterPart( 1, iterCols, iterRows, inputBlock, iterLeft, iterTop ) )
611  {
612  if ( !inputBlock )
613  {
614  continue;
615  }
616 
617  if ( feedback && fileIndex < ( nParts - 1 ) )
618  {
619  feedback->setProgress( 100.0 * fileIndex / static_cast< double >( nParts ) );
620  if ( feedback->isCanceled() )
621  {
622  break;
623  }
624  }
625 
626  //fill into red/green/blue/alpha channels
627  qgssize nPixels = static_cast< qgssize >( iterCols ) * iterRows;
628  for ( qgssize i = 0; i < nPixels; ++i )
629  {
630  QRgb c = inputBlock->color( i );
631  if ( isPremultiplied )
632  {
633  c = qUnpremultiply( c );
634  }
635  redData[i] = static_cast<unsigned char>( qRed( c ) );
636  greenData[i] = static_cast<unsigned char>( qGreen( c ) );
637  blueData[i] = static_cast<unsigned char>( qBlue( c ) );
638  alphaData[i] = static_cast<unsigned char>( qAlpha( c ) );
639  }
640 
641  //create output file
642  if ( mTiledMode )
643  {
644  std::unique_ptr< QgsRasterDataProvider > partDestProvider( createPartProvider( outputExtent,
645  nCols, iterCols, iterRows,
646  iterLeft, iterTop, mOutputUrl, fileIndex,
647  4, Qgis::Byte, crs ) );
648 
649  if ( !partDestProvider || partDestProvider->isValid() )
650  {
651  return DestProviderError;
652  }
653 
654  //write data to output file
655  if ( !partDestProvider->write( &redData[0], 1, iterCols, iterRows, 0, 0 ) ||
656  !partDestProvider->write( &greenData[0], 2, iterCols, iterRows, 0, 0 ) ||
657  !partDestProvider->write( &blueData[0], 3, iterCols, iterRows, 0, 0 ) ||
658  !partDestProvider->write( &alphaData[0], 4, iterCols, iterRows, 0, 0 ) )
659  {
660  return WriteError;
661  }
662 
663  addToVRT( partFileName( fileIndex ), 1, iterCols, iterRows, iterLeft, iterTop );
664  addToVRT( partFileName( fileIndex ), 2, iterCols, iterRows, iterLeft, iterTop );
665  addToVRT( partFileName( fileIndex ), 3, iterCols, iterRows, iterLeft, iterTop );
666  addToVRT( partFileName( fileIndex ), 4, iterCols, iterRows, iterLeft, iterTop );
667  }
668  else if ( destProvider )
669  {
670  if ( !destProvider->write( &redData[0], 1, iterCols, iterRows, iterLeft, iterTop ) ||
671  !destProvider->write( &greenData[0], 2, iterCols, iterRows, iterLeft, iterTop ) ||
672  !destProvider->write( &blueData[0], 3, iterCols, iterRows, iterLeft, iterTop ) ||
673  !destProvider->write( &alphaData[0], 4, iterCols, iterRows, iterLeft, iterTop ) )
674  {
675  return WriteError;
676  }
677  }
678 
679  ++fileIndex;
680  }
681  destProvider.reset();
682 
683  if ( feedback )
684  {
685  feedback->setProgress( 100.0 );
686  }
687 
688  if ( mTiledMode )
689  {
690  QString vrtFilePath( mOutputUrl + '/' + vrtFileName() );
691  writeVRT( vrtFilePath );
692  if ( mBuildPyramidsFlag == QgsRaster::PyramidsFlagYes )
693  {
694  buildPyramids( vrtFilePath );
695  }
696  }
697  else
698  {
699  if ( mBuildPyramidsFlag == QgsRaster::PyramidsFlagYes )
700  {
701  buildPyramids( mOutputUrl );
702  }
703  }
704  return ( feedback && feedback->isCanceled() ) ? WriteCanceled : NoError;
705 }
706 
707 void QgsRasterFileWriter::addToVRT( const QString &filename, int band, int xSize, int ySize, int xOffset, int yOffset )
708 {
709  QDomElement bandElem = mVRTBands.value( band - 1 );
710 
711  QDomElement simpleSourceElem = mVRTDocument.createElement( QStringLiteral( "SimpleSource" ) );
712 
713  //SourceFilename
714  QDomElement sourceFilenameElem = mVRTDocument.createElement( QStringLiteral( "SourceFilename" ) );
715  sourceFilenameElem.setAttribute( QStringLiteral( "relativeToVRT" ), QStringLiteral( "1" ) );
716  QDomText sourceFilenameText = mVRTDocument.createTextNode( filename );
717  sourceFilenameElem.appendChild( sourceFilenameText );
718  simpleSourceElem.appendChild( sourceFilenameElem );
719 
720  //SourceBand
721  QDomElement sourceBandElem = mVRTDocument.createElement( QStringLiteral( "SourceBand" ) );
722  QDomText sourceBandText = mVRTDocument.createTextNode( QString::number( band ) );
723  sourceBandElem.appendChild( sourceBandText );
724  simpleSourceElem.appendChild( sourceBandElem );
725 
726  //SourceProperties
727  QDomElement sourcePropertiesElem = mVRTDocument.createElement( QStringLiteral( "SourceProperties" ) );
728  sourcePropertiesElem.setAttribute( QStringLiteral( "RasterXSize" ), xSize );
729  sourcePropertiesElem.setAttribute( QStringLiteral( "RasterYSize" ), ySize );
730  sourcePropertiesElem.setAttribute( QStringLiteral( "BlockXSize" ), xSize );
731  sourcePropertiesElem.setAttribute( QStringLiteral( "BlockYSize" ), ySize );
732  sourcePropertiesElem.setAttribute( QStringLiteral( "DataType" ), QStringLiteral( "Byte" ) );
733  simpleSourceElem.appendChild( sourcePropertiesElem );
734 
735  //SrcRect
736  QDomElement srcRectElem = mVRTDocument.createElement( QStringLiteral( "SrcRect" ) );
737  srcRectElem.setAttribute( QStringLiteral( "xOff" ), QStringLiteral( "0" ) );
738  srcRectElem.setAttribute( QStringLiteral( "yOff" ), QStringLiteral( "0" ) );
739  srcRectElem.setAttribute( QStringLiteral( "xSize" ), xSize );
740  srcRectElem.setAttribute( QStringLiteral( "ySize" ), ySize );
741  simpleSourceElem.appendChild( srcRectElem );
742 
743  //DstRect
744  QDomElement dstRectElem = mVRTDocument.createElement( QStringLiteral( "DstRect" ) );
745  dstRectElem.setAttribute( QStringLiteral( "xOff" ), xOffset );
746  dstRectElem.setAttribute( QStringLiteral( "yOff" ), yOffset );
747  dstRectElem.setAttribute( QStringLiteral( "xSize" ), xSize );
748  dstRectElem.setAttribute( QStringLiteral( "ySize" ), ySize );
749  simpleSourceElem.appendChild( dstRectElem );
750 
751  bandElem.appendChild( simpleSourceElem );
752 }
753 
754 void QgsRasterFileWriter::buildPyramids( const QString &filename, QgsRasterDataProvider *destProviderIn )
755 {
756  QgsDebugMsgLevel( "filename = " + filename, 4 );
757  // open new dataProvider so we can build pyramids with it
758  QgsDataProvider::ProviderOptions providerOptions;
759  QgsRasterDataProvider *destProvider = destProviderIn;
760  if ( !destProvider )
761  {
762  destProvider = dynamic_cast< QgsRasterDataProvider * >( QgsProviderRegistry::instance()->createProvider( mOutputProviderKey, filename, providerOptions ) );
763  if ( !destProvider || !destProvider->isValid() )
764  {
765  delete destProvider;
766  return;
767  }
768  }
769 
770  // TODO progress report
771  // TODO test mTiledMode - not tested b/c segfault at line # 289
772  // connect( provider, SIGNAL( progressUpdate( int ) ), mPyramidProgress, SLOT( setValue( int ) ) );
773  QList< QgsRasterPyramid> myPyramidList;
774  if ( ! mPyramidsList.isEmpty() )
775  myPyramidList = destProvider->buildPyramidList( mPyramidsList );
776  for ( int myCounterInt = 0; myCounterInt < myPyramidList.count(); myCounterInt++ )
777  {
778  myPyramidList[myCounterInt].build = true;
779  }
780 
781  QgsDebugMsgLevel( QStringLiteral( "building pyramids : %1 pyramids, %2 resampling, %3 format, %4 options" ).arg( myPyramidList.count() ).arg( mPyramidsResampling ).arg( mPyramidsFormat ).arg( mPyramidsConfigOptions.count() ), 4 );
782  // QApplication::setOverrideCursor( Qt::WaitCursor );
783  QString res = destProvider->buildPyramids( myPyramidList, mPyramidsResampling,
784  mPyramidsFormat, mPyramidsConfigOptions );
785  // QApplication::restoreOverrideCursor();
786 
787  // TODO put this in provider or elsewhere
788  if ( !res.isNull() )
789  {
790  QString title, message;
791  if ( res == QLatin1String( "ERROR_WRITE_ACCESS" ) )
792  {
793  title = QObject::tr( "Building Pyramids" );
794  message = QObject::tr( "Write access denied. Adjust the file permissions and try again." );
795  }
796  else if ( res == QLatin1String( "ERROR_WRITE_FORMAT" ) )
797  {
798  title = QObject::tr( "Building Pyramids" );
799  message = QObject::tr( "The file was not writable. Some formats do not "
800  "support pyramid overviews. Consult the GDAL documentation if in doubt." );
801  }
802  else if ( res == QLatin1String( "FAILED_NOT_SUPPORTED" ) )
803  {
804  title = QObject::tr( "Building Pyramids" );
805  message = QObject::tr( "Building pyramid overviews is not supported on this type of raster." );
806  }
807  else if ( res == QLatin1String( "ERROR_VIRTUAL" ) )
808  {
809  title = QObject::tr( "Building Pyramids" );
810  message = QObject::tr( "Building pyramid overviews is not supported on this type of raster." );
811  }
812  QMessageBox::warning( nullptr, title, message );
813  QgsDebugMsgLevel( res + " - " + message, 4 );
814  }
815  if ( !destProviderIn )
816  delete destProvider;
817 }
818 
819 #if 0
820 int QgsRasterFileWriter::pyramidsProgress( double dfComplete, const char *pszMessage, void *pData )
821 {
822  Q_UNUSED( pszMessage );
823  GDALTermProgress( dfComplete, 0, 0 );
824  QProgressDialog *progressDialog = static_cast<QProgressDialog *>( pData );
825  if ( pData && progressDialog->wasCanceled() )
826  {
827  return 0;
828  }
829 
830  if ( pData )
831  {
832  progressDialog->setRange( 0, 100 );
833  progressDialog->setValue( dfComplete * 100 );
834  }
835  return 1;
836 }
837 #endif
838 
839 void QgsRasterFileWriter::createVRT( int xSize, int ySize, const QgsCoordinateReferenceSystem &crs, double *geoTransform, Qgis::DataType type, const QList<bool> &destHasNoDataValueList, const QList<double> &destNoDataValueList )
840 {
841  mVRTDocument.clear();
842  QDomElement VRTDatasetElem = mVRTDocument.createElement( QStringLiteral( "VRTDataset" ) );
843 
844  //xsize / ysize
845  VRTDatasetElem.setAttribute( QStringLiteral( "rasterXSize" ), xSize );
846  VRTDatasetElem.setAttribute( QStringLiteral( "rasterYSize" ), ySize );
847  mVRTDocument.appendChild( VRTDatasetElem );
848 
849  //CRS
850  QDomElement SRSElem = mVRTDocument.createElement( QStringLiteral( "SRS" ) );
851  QDomText crsText = mVRTDocument.createTextNode( crs.toWkt() );
852  SRSElem.appendChild( crsText );
853  VRTDatasetElem.appendChild( SRSElem );
854 
855  //geotransform
856  if ( geoTransform )
857  {
858  QDomElement geoTransformElem = mVRTDocument.createElement( QStringLiteral( "GeoTransform" ) );
859  QString geoTransformString = QString::number( geoTransform[0], 'f', 6 ) + ", " + QString::number( geoTransform[1] ) + ", " + QString::number( geoTransform[2] ) +
860  ", " + QString::number( geoTransform[3], 'f', 6 ) + ", " + QString::number( geoTransform[4] ) + ", " + QString::number( geoTransform[5] );
861  QDomText geoTransformText = mVRTDocument.createTextNode( geoTransformString );
862  geoTransformElem.appendChild( geoTransformText );
863  VRTDatasetElem.appendChild( geoTransformElem );
864  }
865 
866  int nBands;
867  if ( mMode == Raw )
868  {
869  nBands = mInput->bandCount();
870  }
871  else
872  {
873  nBands = 4;
874  }
875 
876  QStringList colorInterp;
877  colorInterp << QStringLiteral( "Red" ) << QStringLiteral( "Green" ) << QStringLiteral( "Blue" ) << QStringLiteral( "Alpha" );
878 
879  QMap<Qgis::DataType, QString> dataTypes;
880  dataTypes.insert( Qgis::Byte, QStringLiteral( "Byte" ) );
881  dataTypes.insert( Qgis::UInt16, QStringLiteral( "UInt16" ) );
882  dataTypes.insert( Qgis::Int16, QStringLiteral( "Int16" ) );
883  dataTypes.insert( Qgis::UInt32, QStringLiteral( "Int32" ) );
884  dataTypes.insert( Qgis::Float32, QStringLiteral( "Float32" ) );
885  dataTypes.insert( Qgis::Float64, QStringLiteral( "Float64" ) );
886  dataTypes.insert( Qgis::CInt16, QStringLiteral( "CInt16" ) );
887  dataTypes.insert( Qgis::CInt32, QStringLiteral( "CInt32" ) );
888  dataTypes.insert( Qgis::CFloat32, QStringLiteral( "CFloat32" ) );
889  dataTypes.insert( Qgis::CFloat64, QStringLiteral( "CFloat64" ) );
890 
891  for ( int i = 1; i <= nBands; i++ )
892  {
893  QDomElement VRTBand = mVRTDocument.createElement( QStringLiteral( "VRTRasterBand" ) );
894 
895  VRTBand.setAttribute( QStringLiteral( "band" ), QString::number( i ) );
896  QString dataType = dataTypes.value( type );
897  VRTBand.setAttribute( QStringLiteral( "dataType" ), dataType );
898 
899  if ( mMode == Image )
900  {
901  VRTBand.setAttribute( QStringLiteral( "dataType" ), QStringLiteral( "Byte" ) );
902  QDomElement colorInterpElement = mVRTDocument.createElement( QStringLiteral( "ColorInterp" ) );
903  QDomText interpText = mVRTDocument.createTextNode( colorInterp.value( i - 1 ) );
904  colorInterpElement.appendChild( interpText );
905  VRTBand.appendChild( colorInterpElement );
906  }
907 
908  if ( !destHasNoDataValueList.isEmpty() && destHasNoDataValueList.value( i - 1 ) )
909  {
910  VRTBand.setAttribute( QStringLiteral( "NoDataValue" ), QString::number( destNoDataValueList.value( i - 1 ) ) );
911  }
912 
913  mVRTBands.append( VRTBand );
914  VRTDatasetElem.appendChild( VRTBand );
915  }
916 }
917 
918 bool QgsRasterFileWriter::writeVRT( const QString &file )
919 {
920  QFile outputFile( file );
921  if ( ! outputFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
922  {
923  return false;
924  }
925 
926  QTextStream outStream( &outputFile );
927  mVRTDocument.save( outStream, 2 );
928  return true;
929 }
930 
931 QgsRasterDataProvider *QgsRasterFileWriter::createPartProvider( const QgsRectangle &extent, int nCols, int iterCols,
932  int iterRows, int iterLeft, int iterTop, const QString &outputUrl, int fileIndex, int nBands, Qgis::DataType type,
933  const QgsCoordinateReferenceSystem &crs )
934 {
935  double mup = extent.width() / nCols;
936  double mapLeft = extent.xMinimum() + iterLeft * mup;
937  double mapRight = mapLeft + mup * iterCols;
938  double mapTop = extent.yMaximum() - iterTop * mup;
939  double mapBottom = mapTop - iterRows * mup;
940  QgsRectangle mapRect( mapLeft, mapBottom, mapRight, mapTop );
941 
942  QString outputFile = outputUrl + '/' + partFileName( fileIndex );
943 
944  //geotransform
945  double geoTransform[6];
946  geoTransform[0] = mapRect.xMinimum();
947  geoTransform[1] = mup;
948  geoTransform[2] = 0.0;
949  geoTransform[3] = mapRect.yMaximum();
950  geoTransform[4] = 0.0;
951  geoTransform[5] = -mup;
952 
953  // perhaps we need a separate createOptions for tiles ?
954 
955  QgsRasterDataProvider *destProvider = QgsRasterDataProvider::create( mOutputProviderKey, outputFile, mOutputFormat, nBands, type, iterCols, iterRows, geoTransform, crs, mCreateOptions );
956 
957  // TODO: return provider and report error
958  return destProvider;
959 }
960 
961 QgsRasterDataProvider *QgsRasterFileWriter::initOutput( int nCols, int nRows, const QgsCoordinateReferenceSystem &crs,
962  double *geoTransform, int nBands, Qgis::DataType type,
963  const QList<bool> &destHasNoDataValueList, const QList<double> &destNoDataValueList )
964 {
965  if ( mTiledMode )
966  {
967  createVRT( nCols, nRows, crs, geoTransform, type, destHasNoDataValueList, destNoDataValueList );
968  return nullptr;
969  }
970  else
971  {
972 #if 0
973  // TODO enable "use existing", has no effect for now, because using Create() in gdal provider
974  // should this belong in provider? should also test that source provider is gdal
975  if ( mBuildPyramidsFlag == -4 && mOutputProviderKey == "gdal" && mOutputFormat.compare( QLatin1String( "gtiff" ), Qt::CaseInsensitive ) == 0 )
976  mCreateOptions << "COPY_SRC_OVERVIEWS=YES";
977 #endif
978 
979  QgsRasterDataProvider *destProvider = QgsRasterDataProvider::create( mOutputProviderKey, mOutputUrl, mOutputFormat, nBands, type, nCols, nRows, geoTransform, crs, mCreateOptions );
980 
981  if ( !destProvider )
982  {
983  QgsDebugMsg( QStringLiteral( "No provider created" ) );
984  }
985 
986  return destProvider;
987  }
988 }
989 
990 void QgsRasterFileWriter::globalOutputParameters( const QgsRectangle &extent, int nCols, int &nRows,
991  double *geoTransform, double &pixelSize )
992 {
993  pixelSize = extent.width() / nCols;
994 
995  //calculate nRows automatically for providers without exact resolution
996  if ( nRows < 0 )
997  {
998  nRows = static_cast< double >( nCols ) / extent.width() * extent.height() + 0.5; //NOLINT
999  }
1000  geoTransform[0] = extent.xMinimum();
1001  geoTransform[1] = pixelSize;
1002  geoTransform[2] = 0.0;
1003  geoTransform[3] = extent.yMaximum();
1004  geoTransform[4] = 0.0;
1005  geoTransform[5] = -( extent.height() / nRows );
1006 }
1007 
1008 QString QgsRasterFileWriter::partFileName( int fileIndex )
1009 {
1010  // .tif for now
1011  QFileInfo outputInfo( mOutputUrl );
1012  return QStringLiteral( "%1.%2.tif" ).arg( outputInfo.fileName() ).arg( fileIndex );
1013 }
1014 
1015 QString QgsRasterFileWriter::vrtFileName()
1016 {
1017  QFileInfo outputInfo( mOutputUrl );
1018  return QStringLiteral( "%1.vrt" ).arg( outputInfo.fileName() );
1019 }
1020 
1021 QString QgsRasterFileWriter::driverForExtension( const QString &extension )
1022 {
1023  QString ext = extension.trimmed();
1024  if ( ext.isEmpty() )
1025  return QString();
1026 
1027  if ( ext.startsWith( '.' ) )
1028  ext.remove( 0, 1 );
1029 
1030  GDALAllRegister();
1031  int const drvCount = GDALGetDriverCount();
1032 
1033  for ( int i = 0; i < drvCount; ++i )
1034  {
1035  GDALDriverH drv = GDALGetDriver( i );
1036  if ( drv )
1037  {
1038  char **driverMetadata = GDALGetMetadata( drv, nullptr );
1039  if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER, false ) )
1040  {
1041  QString drvName = GDALGetDriverShortName( drv );
1042  QStringList driverExtensions = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS, nullptr ) ).split( ' ' );
1043 
1044  Q_FOREACH ( const QString &driver, driverExtensions )
1045  {
1046  if ( driver.compare( ext, Qt::CaseInsensitive ) == 0 )
1047  return drvName;
1048  }
1049  }
1050  }
1051  }
1052  return QString();
1053 }
1054 
1055 QStringList QgsRasterFileWriter::extensionsForFormat( const QString &format )
1056 {
1057  GDALDriverH drv = GDALGetDriverByName( format.toLocal8Bit().data() );
1058  if ( drv )
1059  {
1060  char **driverMetadata = GDALGetMetadata( drv, nullptr );
1061  if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER, false ) )
1062  {
1063  return QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS, nullptr ) ).split( ' ' );
1064  }
1065  }
1066  return QStringList();
1067 }
1068 
1069 QString QgsRasterFileWriter::filterForDriver( const QString &driverName )
1070 {
1071  GDALDriverH drv = GDALGetDriverByName( driverName.toLocal8Bit().data() );
1072  if ( drv )
1073  {
1074  QString drvName = GDALGetDriverLongName( drv );
1075  QString extensionsString = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS, nullptr ) );
1076  if ( extensionsString.isEmpty() )
1077  {
1078  return QString();
1079  }
1080  QStringList extensions = extensionsString.split( ' ' );
1081  QString filter = drvName + " (";
1082  for ( const QString &ext : extensions )
1083  {
1084  filter.append( QStringLiteral( "*.%1 *.%2 " ).arg( ext.toLower(), ext.toUpper() ) );
1085  }
1086  filter = filter.trimmed().append( QStringLiteral( ")" ) );
1087  return filter;
1088  }
1089 
1090  return QString();
1091 }
1092 
1093 QList< QgsRasterFileWriter::FilterFormatDetails > QgsRasterFileWriter::supportedFiltersAndFormats( RasterFormatOptions options )
1094 {
1095  QList< FilterFormatDetails > results;
1096 
1097  GDALAllRegister();
1098  int const drvCount = GDALGetDriverCount();
1099 
1100  FilterFormatDetails tifFormat;
1101 
1102  for ( int i = 0; i < drvCount; ++i )
1103  {
1104  GDALDriverH drv = GDALGetDriver( i );
1105  if ( drv )
1106  {
1108  {
1109  QString drvName = GDALGetDriverShortName( drv );
1110  QString filterString = filterForDriver( drvName );
1111  if ( filterString.isEmpty() )
1112  continue;
1113 
1114  FilterFormatDetails details;
1115  details.driverName = drvName;
1116  details.filterString = filterString;
1117 
1118  if ( options & SortRecommended )
1119  {
1120  if ( drvName == QLatin1String( "GTiff" ) )
1121  {
1122  tifFormat = details;
1123  continue;
1124  }
1125  }
1126 
1127  results << details;
1128  }
1129  }
1130  }
1131 
1132  std::sort( results.begin(), results.end(), []( const FilterFormatDetails & a, const FilterFormatDetails & b ) -> bool
1133  {
1134  return a.driverName < b.driverName;
1135  } );
1136 
1137  if ( options & SortRecommended )
1138  {
1139  if ( !tifFormat.filterString.isEmpty() )
1140  {
1141  results.insert( 0, tifFormat );
1142  }
1143  }
1144 
1145  return results;
1146 }
1147 
1148 QStringList QgsRasterFileWriter::supportedFormatExtensions( const RasterFormatOptions options )
1149 {
1150  const auto formats = supportedFiltersAndFormats( options );
1151  QStringList extensions;
1152 
1153  QRegularExpression rx( QStringLiteral( "\\*\\.([a-zA-Z0-9]*)" ) );
1154 
1155  for ( const FilterFormatDetails &format : formats )
1156  {
1157  QString ext = format.filterString;
1158  QRegularExpressionMatch match = rx.match( ext );
1159  if ( !match.hasMatch() )
1160  continue;
1161 
1162  QString matched = match.captured( 1 );
1163  extensions << matched;
1164  }
1165  return extensions;
1166 }
virtual int bandCount() const =0
Gets number of bands.
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.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
A rectangle specified with double values.
Definition: qgsrectangle.h:40
QgsCoordinateReferenceSystem sourceCrs() const
Returns the source CRS.
QgsRasterFileWriter(const QString &outputUrl)
Base class for processing modules.
Definition: qgsrasterpipe.h:46
QgsRasterNuller * nuller() const
Iterator for sequentially processing raster cells.
Writing was manually canceled.
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination CRS.
static double minimumValuePossible(Qgis::DataType)
Helper function that returns the minimum possible value for a GDAL data type.
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.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:171
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
static QString filterForDriver(const QString &driverName)
Creates a filter for an GDAL driver key.
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:63
Raster pipe that deals with null values.
QString toWkt() const
Returns a WKT representation of this CRS.
Thirty two bit unsigned integer (quint32)
Definition: qgis.h:98
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:614
DataType
Raster data types.
Definition: qgis.h:92
double maximumValue
The maximum cell value in the raster band.
QgsRasterInterface * last() const
static QStringList extensionsForFormat(const QString &format)
Returns a list of known file extensions for the given GDAL driver format.
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 bool setNoDataValue(int bandNo, double noDataValue)
Set no data value on created dataset.
virtual Qgis::DataType dataType(int bandNo) const =0
Returns data type for the band specified by number.
Thirty two bit floating point (float)
Definition: qgis.h:100
const QgsCoordinateReferenceSystem & crs
virtual QString buildPyramids(const QList< QgsRasterPyramid > &pyramidList, const QString &resamplingMethod="NEAREST", QgsRaster::RasterPyramidsFormat format=QgsRaster::PyramidsGTiff, const QStringList &configOptions=QStringList(), QgsRasterBlockFeedback *feedback=nullptr)
Create pyramid overviews.
static bool supportsRasterCreate(GDALDriverH driver)
Reads whether a driver supports GDALCreate() for raster purposes.
Sixteen bit signed integer (qint16)
Definition: qgis.h:97
Complex Int16.
Definition: qgis.h:102
Sixty four bit floating point (double)
Definition: qgis.h:101
QgsDataProvider * createProvider(const QString &providerKey, const QString &dataSource, const QgsDataProvider::ProviderOptions &options=QgsDataProvider::ProviderOptions())
Creates a new instance of a provider.
virtual bool sourceHasNoDataValue(int bandNo) const
Returns true if source band has no data value.
QString outputUrl() const
Returns the output URL for the raster.
int maximumTileWidth() const
Returns the maximum tile width returned during iteration.
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
static QString driverForExtension(const QString &extension)
Returns the GDAL driver name for a specified file extension.
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition: qgis.h:107
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.
The RasterBandStats struct is a container for statistics about a single raster band.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
static QStringList supportedFormatExtensions(RasterFormatOptions options=SortRecommended)
Returns a list of file extensions for supported formats.
Raster data container.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:176
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:161
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
virtual QList< QgsRasterPyramid > buildPyramidList(QList< int > overviewList=QList< int >())
Returns the raster layers pyramid list.
QgsRectangle extent() const override=0
Returns the extent of the layer.
virtual bool isValid() const =0
Returns true if this is a valid layer.
Complex Float32.
Definition: qgis.h:104
int maximumTileHeight() const
Returns the minimum tile width returned during iteration.
Complex Int32.
Definition: qgis.h:103
static int typeSize(int dataType)
Sixteen bit unsigned integer (quint16)
Definition: qgis.h:96
QgsRasterProjector * projector() const
WriterError writeRaster(const QgsRasterPipe *pipe, int nCols, int nRows, const QgsRectangle &outputExtent, const QgsCoordinateReferenceSystem &crs, QgsRasterBlockFeedback *feedback=nullptr)
Write raster file.
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...
Base class for processing filters like renderers, reprojector, resampler etc.
virtual double sourceNoDataValue(int bandNo) const
Value representing no data value.
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...
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...
Definition: qgis.h:586
void setOutputNoDataValue(int bandNo, double noData)
Sets the output no data value.
QgsRasterProjector implements approximate projection support for it calculates grid of points in sour...
virtual QgsRasterBandStats bandStatistics(int bandNo, int stats=QgsRasterBandStats::All, const QgsRectangle &extent=QgsRectangle(), int sampleSize=0, QgsRasterBlockFeedback *feedback=nullptr)
Returns the band statistics.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:615
void setMaximumTileWidth(int w)
Sets the maximum tile width returned during iteration.
Setting options for creating vector data providers.
void setMaximumTileHeight(int h)
Sets the minimum tile height returned during iteration.
Internal error if a value used for &#39;no data&#39; was found in input.
static double maximumValuePossible(Qgis::DataType)
Helper function that returns the maximum possible value for a GDAL data type.
QgsRasterRangeList noData(int bandNo) const
This class represents a coordinate reference system (CRS).
Use recommended sort order, with extremely commonly used formats listed first.
Class for doing transforms between two map coordinate systems.
double minimumValue
The minimum cell value in the raster band.
virtual bool write(void *data, int band, int width, int height, int xOffset, int yOffset)
Writes into the provider datasource.
Details of available filters and formats.
virtual const QgsRasterInterface * sourceInput() const
Gets source / raw input, the first in pipe, usually provider.
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:201
Complex Float64.
Definition: qgis.h:105
QString filterString
Filter string for file picker dialogs.
Feedback object tailored for raster block reading.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:166
void startRasterRead(int bandNumber, int nCols, int nRows, const QgsRectangle &extent, QgsRasterBlockFeedback *feedback=nullptr)
Start reading of raster band.
Eight bit unsigned integer (quint8)
Definition: qgis.h:95
const QgsRasterInterface * input() const
Returns the input raster interface which is being iterated over.
Qgis::DataType dataType(int bandNo) const override=0
Returns data type for the band specified by number.
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition: qgis.h:106
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:208
Base class for raster data providers.
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.