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