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