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