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