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