QGIS API Documentation  2.99.0-Master (6c64c5a)
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  QgsRectangle mapRect;
501  int iterLeft = 0, iterTop = 0, iterCols = 0, iterRows = 0;
502  int fileIndex = 0;
503 
504  //create destProvider for whole dataset here
505  QgsRasterDataProvider *destProvider = nullptr;
506  double pixelSize;
507  double geoTransform[6];
508  globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
509 
510  destProvider = initOutput( nCols, nRows, crs, geoTransform, 4, Qgis::Byte );
511 
512  iter->startRasterRead( 1, nCols, nRows, outputExtent, feedback );
513 
514  int nParts = 0;
515  if ( feedback )
516  {
517  int nPartsX = nCols / iter->maximumTileWidth() + 1;
518  int nPartsY = nRows / iter->maximumTileHeight() + 1;
519  nParts = nPartsX * nPartsY;
520  }
521 
522  QgsRasterBlock *inputBlock = nullptr;
523  while ( iter->readNextRasterPart( 1, iterCols, iterRows, &inputBlock, iterLeft, iterTop ) )
524  {
525  if ( !inputBlock )
526  {
527  continue;
528  }
529 
530  if ( feedback && fileIndex < ( nParts - 1 ) )
531  {
532  feedback->setProgress( 100.0 * fileIndex / static_cast< double >( nParts ) );
533  if ( feedback->isCanceled() )
534  {
535  delete inputBlock;
536  break;
537  }
538  }
539 
540  //fill into red/green/blue/alpha channels
541  qgssize nPixels = static_cast< qgssize >( iterCols ) * iterRows;
542  // TODO: should be char not int? we are then copying 1 byte
543  int red = 0;
544  int green = 0;
545  int blue = 0;
546  int alpha = 255;
547  for ( qgssize i = 0; i < nPixels; ++i )
548  {
549  QRgb c = inputBlock->color( i );
550  alpha = qAlpha( c );
551  red = qRed( c );
552  green = qGreen( c );
553  blue = qBlue( c );
554 
555  if ( inputDataType == Qgis::ARGB32_Premultiplied )
556  {
557  double a = alpha / 255.;
558  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 );
559  red /= a;
560  green /= a;
561  blue /= a;
562  }
563  memcpy( reinterpret_cast< char * >( redData ) + i, &red, 1 );
564  memcpy( reinterpret_cast< char * >( greenData ) + i, &green, 1 );
565  memcpy( reinterpret_cast< char * >( blueData ) + i, &blue, 1 );
566  memcpy( reinterpret_cast< char * >( alphaData ) + i, &alpha, 1 );
567  }
568  delete inputBlock;
569 
570  //create output file
571  if ( mTiledMode )
572  {
573  //delete destProvider;
574  QgsRasterDataProvider *partDestProvider = createPartProvider( outputExtent,
575  nCols, iterCols, iterRows,
576  iterLeft, iterTop, mOutputUrl, fileIndex,
577  4, Qgis::Byte, crs );
578 
579  if ( partDestProvider )
580  {
581  //write data to output file
582  partDestProvider->write( redData, 1, iterCols, iterRows, 0, 0 );
583  partDestProvider->write( greenData, 2, iterCols, iterRows, 0, 0 );
584  partDestProvider->write( blueData, 3, iterCols, iterRows, 0, 0 );
585  partDestProvider->write( alphaData, 4, iterCols, iterRows, 0, 0 );
586 
587  addToVRT( partFileName( fileIndex ), 1, iterCols, iterRows, iterLeft, iterTop );
588  addToVRT( partFileName( fileIndex ), 2, iterCols, iterRows, iterLeft, iterTop );
589  addToVRT( partFileName( fileIndex ), 3, iterCols, iterRows, iterLeft, iterTop );
590  addToVRT( partFileName( fileIndex ), 4, iterCols, iterRows, iterLeft, iterTop );
591  delete partDestProvider;
592  }
593  }
594  else if ( destProvider )
595  {
596  destProvider->write( redData, 1, iterCols, iterRows, iterLeft, iterTop );
597  destProvider->write( greenData, 2, iterCols, iterRows, iterLeft, iterTop );
598  destProvider->write( blueData, 3, iterCols, iterRows, iterLeft, iterTop );
599  destProvider->write( alphaData, 4, iterCols, iterRows, iterLeft, iterTop );
600  }
601 
602  ++fileIndex;
603  }
604 
605  delete destProvider;
606 
607  qgsFree( redData );
608  qgsFree( greenData );
609  qgsFree( blueData );
610  qgsFree( alphaData );
611 
612  if ( feedback )
613  {
614  feedback->setProgress( 100.0 );
615  }
616 
617  if ( mTiledMode )
618  {
619  QString vrtFilePath( mOutputUrl + '/' + vrtFileName() );
620  writeVRT( vrtFilePath );
621  if ( mBuildPyramidsFlag == QgsRaster::PyramidsFlagYes )
622  {
623  buildPyramids( vrtFilePath );
624  }
625  }
626  else
627  {
628  if ( mBuildPyramidsFlag == QgsRaster::PyramidsFlagYes )
629  {
630  buildPyramids( mOutputUrl );
631  }
632  }
633  return ( feedback && feedback->isCanceled() ) ? WriteCanceled : NoError;
634 }
635 
636 void QgsRasterFileWriter::addToVRT( const QString &filename, int band, int xSize, int ySize, int xOffset, int yOffset )
637 {
638  QDomElement bandElem = mVRTBands.value( band - 1 );
639 
640  QDomElement simpleSourceElem = mVRTDocument.createElement( QStringLiteral( "SimpleSource" ) );
641 
642  //SourceFilename
643  QDomElement sourceFilenameElem = mVRTDocument.createElement( QStringLiteral( "SourceFilename" ) );
644  sourceFilenameElem.setAttribute( QStringLiteral( "relativeToVRT" ), QStringLiteral( "1" ) );
645  QDomText sourceFilenameText = mVRTDocument.createTextNode( filename );
646  sourceFilenameElem.appendChild( sourceFilenameText );
647  simpleSourceElem.appendChild( sourceFilenameElem );
648 
649  //SourceBand
650  QDomElement sourceBandElem = mVRTDocument.createElement( QStringLiteral( "SourceBand" ) );
651  QDomText sourceBandText = mVRTDocument.createTextNode( QString::number( band ) );
652  sourceBandElem.appendChild( sourceBandText );
653  simpleSourceElem.appendChild( sourceBandElem );
654 
655  //SourceProperties
656  QDomElement sourcePropertiesElem = mVRTDocument.createElement( QStringLiteral( "SourceProperties" ) );
657  sourcePropertiesElem.setAttribute( QStringLiteral( "RasterXSize" ), xSize );
658  sourcePropertiesElem.setAttribute( QStringLiteral( "RasterYSize" ), ySize );
659  sourcePropertiesElem.setAttribute( QStringLiteral( "BlockXSize" ), xSize );
660  sourcePropertiesElem.setAttribute( QStringLiteral( "BlockYSize" ), ySize );
661  sourcePropertiesElem.setAttribute( QStringLiteral( "DataType" ), QStringLiteral( "Byte" ) );
662  simpleSourceElem.appendChild( sourcePropertiesElem );
663 
664  //SrcRect
665  QDomElement srcRectElem = mVRTDocument.createElement( QStringLiteral( "SrcRect" ) );
666  srcRectElem.setAttribute( QStringLiteral( "xOff" ), QStringLiteral( "0" ) );
667  srcRectElem.setAttribute( QStringLiteral( "yOff" ), QStringLiteral( "0" ) );
668  srcRectElem.setAttribute( QStringLiteral( "xSize" ), xSize );
669  srcRectElem.setAttribute( QStringLiteral( "ySize" ), ySize );
670  simpleSourceElem.appendChild( srcRectElem );
671 
672  //DstRect
673  QDomElement dstRectElem = mVRTDocument.createElement( QStringLiteral( "DstRect" ) );
674  dstRectElem.setAttribute( QStringLiteral( "xOff" ), xOffset );
675  dstRectElem.setAttribute( QStringLiteral( "yOff" ), yOffset );
676  dstRectElem.setAttribute( QStringLiteral( "xSize" ), xSize );
677  dstRectElem.setAttribute( QStringLiteral( "ySize" ), ySize );
678  simpleSourceElem.appendChild( dstRectElem );
679 
680  bandElem.appendChild( simpleSourceElem );
681 }
682 
683 #if 0
684 void QgsRasterFileWriter::buildPyramids( const QString &filename )
685 {
686  GDALDatasetH dataSet;
687  GDALAllRegister();
688  dataSet = GDALOpen( filename.toLocal8Bit().data(), GA_Update );
689  if ( !dataSet )
690  {
691  return;
692  }
693 
694  //2,4,8,16,32,64
695  int overviewList[6];
696  overviewList[0] = 2;
697  overviewList[1] = 4;
698  overviewList[2] = 8;
699  overviewList[3] = 16;
700  overviewList[4] = 32;
701  overviewList[5] = 64;
702 
703 #if 0
704  if ( mProgressDialog )
705  {
706  mProgressDialog->setLabelText( QObject::tr( "Building Pyramids..." ) );
707  mProgressDialog->setValue( 0 );
708  mProgressDialog->setWindowModality( Qt::WindowModal );
709  mProgressDialog->show();
710  }
711 #endif
712  GDALBuildOverviews( dataSet, "AVERAGE", 6, overviewList, 0, 0, /*pyramidsProgress*/ 0, /*mProgressDialog*/ 0 );
713 }
714 #endif
715 
716 void QgsRasterFileWriter::buildPyramids( const QString &filename )
717 {
718  QgsDebugMsgLevel( "filename = " + filename, 4 );
719  // open new dataProvider so we can build pyramids with it
720  QgsRasterDataProvider *destProvider = dynamic_cast< QgsRasterDataProvider * >( QgsProviderRegistry::instance()->createProvider( mOutputProviderKey, filename ) );
721  if ( !destProvider )
722  {
723  return;
724  }
725 
726  // TODO progress report
727  // TODO test mTiledMode - not tested b/c segfault at line # 289
728  // connect( provider, SIGNAL( progressUpdate( int ) ), mPyramidProgress, SLOT( setValue( int ) ) );
729  QList< QgsRasterPyramid> myPyramidList;
730  if ( ! mPyramidsList.isEmpty() )
731  myPyramidList = destProvider->buildPyramidList( mPyramidsList );
732  for ( int myCounterInt = 0; myCounterInt < myPyramidList.count(); myCounterInt++ )
733  {
734  myPyramidList[myCounterInt].build = true;
735  }
736 
737  QgsDebugMsgLevel( QString( "building pyramids : %1 pyramids, %2 resampling, %3 format, %4 options" ).arg( myPyramidList.count() ).arg( mPyramidsResampling ).arg( mPyramidsFormat ).arg( mPyramidsConfigOptions.count() ), 4 );
738  // QApplication::setOverrideCursor( Qt::WaitCursor );
739  QString res = destProvider->buildPyramids( myPyramidList, mPyramidsResampling,
740  mPyramidsFormat, mPyramidsConfigOptions );
741  // QApplication::restoreOverrideCursor();
742 
743  // TODO put this in provider or elsewhere
744  if ( !res.isNull() )
745  {
746  QString title, message;
747  if ( res == QLatin1String( "ERROR_WRITE_ACCESS" ) )
748  {
749  title = QObject::tr( "Building pyramids failed - write access denied" );
750  message = QObject::tr( "Write access denied. Adjust the file permissions and try again." );
751  }
752  else if ( res == QLatin1String( "ERROR_WRITE_FORMAT" ) )
753  {
754  title = QObject::tr( "Building pyramids failed." );
755  message = QObject::tr( "The file was not writable. Some formats do not "
756  "support pyramid overviews. Consult the GDAL documentation if in doubt." );
757  }
758  else if ( res == QLatin1String( "FAILED_NOT_SUPPORTED" ) )
759  {
760  title = QObject::tr( "Building pyramids failed." );
761  message = QObject::tr( "Building pyramid overviews is not supported on this type of raster." );
762  }
763  else if ( res == QLatin1String( "ERROR_JPEG_COMPRESSION" ) )
764  {
765  title = QObject::tr( "Building pyramids failed." );
766  message = QObject::tr( "Building internal pyramid overviews is not supported on raster layers with JPEG compression and your current libtiff library." );
767  }
768  else if ( res == QLatin1String( "ERROR_VIRTUAL" ) )
769  {
770  title = QObject::tr( "Building pyramids failed." );
771  message = QObject::tr( "Building pyramid overviews is not supported on this type of raster." );
772  }
773  QMessageBox::warning( nullptr, title, message );
774  QgsDebugMsgLevel( res + " - " + message, 4 );
775  }
776  delete destProvider;
777 }
778 
779 #if 0
780 int QgsRasterFileWriter::pyramidsProgress( double dfComplete, const char *pszMessage, void *pData )
781 {
782  Q_UNUSED( pszMessage );
783  GDALTermProgress( dfComplete, 0, 0 );
784  QProgressDialog *progressDialog = static_cast<QProgressDialog *>( pData );
785  if ( pData && progressDialog->wasCanceled() )
786  {
787  return 0;
788  }
789 
790  if ( pData )
791  {
792  progressDialog->setRange( 0, 100 );
793  progressDialog->setValue( dfComplete * 100 );
794  }
795  return 1;
796 }
797 #endif
798 
799 void QgsRasterFileWriter::createVRT( int xSize, int ySize, const QgsCoordinateReferenceSystem &crs, double *geoTransform, Qgis::DataType type, const QList<bool> &destHasNoDataValueList, const QList<double> &destNoDataValueList )
800 {
801  mVRTDocument.clear();
802  QDomElement VRTDatasetElem = mVRTDocument.createElement( QStringLiteral( "VRTDataset" ) );
803 
804  //xsize / ysize
805  VRTDatasetElem.setAttribute( QStringLiteral( "rasterXSize" ), xSize );
806  VRTDatasetElem.setAttribute( QStringLiteral( "rasterYSize" ), ySize );
807  mVRTDocument.appendChild( VRTDatasetElem );
808 
809  //CRS
810  QDomElement SRSElem = mVRTDocument.createElement( QStringLiteral( "SRS" ) );
811  QDomText crsText = mVRTDocument.createTextNode( crs.toWkt() );
812  SRSElem.appendChild( crsText );
813  VRTDatasetElem.appendChild( SRSElem );
814 
815  //geotransform
816  if ( geoTransform )
817  {
818  QDomElement geoTransformElem = mVRTDocument.createElement( QStringLiteral( "GeoTransform" ) );
819  QString geoTransformString = QString::number( geoTransform[0] ) + ", " + QString::number( geoTransform[1] ) + ", " + QString::number( geoTransform[2] ) +
820  ", " + QString::number( geoTransform[3] ) + ", " + QString::number( geoTransform[4] ) + ", " + QString::number( geoTransform[5] );
821  QDomText geoTransformText = mVRTDocument.createTextNode( geoTransformString );
822  geoTransformElem.appendChild( geoTransformText );
823  VRTDatasetElem.appendChild( geoTransformElem );
824  }
825 
826  int nBands;
827  if ( mMode == Raw )
828  {
829  nBands = mInput->bandCount();
830  }
831  else
832  {
833  nBands = 4;
834  }
835 
836  QStringList colorInterp;
837  colorInterp << QStringLiteral( "Red" ) << QStringLiteral( "Green" ) << QStringLiteral( "Blue" ) << QStringLiteral( "Alpha" );
838 
839  QMap<Qgis::DataType, QString> dataTypes;
840  dataTypes.insert( Qgis::Byte, QStringLiteral( "Byte" ) );
841  dataTypes.insert( Qgis::UInt16, QStringLiteral( "UInt16" ) );
842  dataTypes.insert( Qgis::Int16, QStringLiteral( "Int16" ) );
843  dataTypes.insert( Qgis::UInt32, QStringLiteral( "Int32" ) );
844  dataTypes.insert( Qgis::Float32, QStringLiteral( "Float32" ) );
845  dataTypes.insert( Qgis::Float64, QStringLiteral( "Float64" ) );
846  dataTypes.insert( Qgis::CInt16, QStringLiteral( "CInt16" ) );
847  dataTypes.insert( Qgis::CInt32, QStringLiteral( "CInt32" ) );
848  dataTypes.insert( Qgis::CFloat32, QStringLiteral( "CFloat32" ) );
849  dataTypes.insert( Qgis::CFloat64, QStringLiteral( "CFloat64" ) );
850 
851  for ( int i = 1; i <= nBands; i++ )
852  {
853  QDomElement VRTBand = mVRTDocument.createElement( QStringLiteral( "VRTRasterBand" ) );
854 
855  VRTBand.setAttribute( QStringLiteral( "band" ), QString::number( i ) );
856  QString dataType = dataTypes.value( type );
857  VRTBand.setAttribute( QStringLiteral( "dataType" ), dataType );
858 
859  if ( mMode == Image )
860  {
861  VRTBand.setAttribute( QStringLiteral( "dataType" ), QStringLiteral( "Byte" ) );
862  QDomElement colorInterpElement = mVRTDocument.createElement( QStringLiteral( "ColorInterp" ) );
863  QDomText interpText = mVRTDocument.createTextNode( colorInterp.value( i - 1 ) );
864  colorInterpElement.appendChild( interpText );
865  VRTBand.appendChild( colorInterpElement );
866  }
867 
868  if ( !destHasNoDataValueList.isEmpty() && destHasNoDataValueList.value( i - 1 ) )
869  {
870  VRTBand.setAttribute( QStringLiteral( "NoDataValue" ), QString::number( destNoDataValueList.value( i - 1 ) ) );
871  }
872 
873  mVRTBands.append( VRTBand );
874  VRTDatasetElem.appendChild( VRTBand );
875  }
876 }
877 
878 bool QgsRasterFileWriter::writeVRT( const QString &file )
879 {
880  QFile outputFile( file );
881  if ( ! outputFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
882  {
883  return false;
884  }
885 
886  QTextStream outStream( &outputFile );
887  mVRTDocument.save( outStream, 2 );
888  return true;
889 }
890 
891 QgsRasterDataProvider *QgsRasterFileWriter::createPartProvider( const QgsRectangle &extent, int nCols, int iterCols,
892  int iterRows, int iterLeft, int iterTop, const QString &outputUrl, int fileIndex, int nBands, Qgis::DataType type,
893  const QgsCoordinateReferenceSystem &crs )
894 {
895  double mup = extent.width() / nCols;
896  double mapLeft = extent.xMinimum() + iterLeft * mup;
897  double mapRight = mapLeft + mup * iterCols;
898  double mapTop = extent.yMaximum() - iterTop * mup;
899  double mapBottom = mapTop - iterRows * mup;
900  QgsRectangle mapRect( mapLeft, mapBottom, mapRight, mapTop );
901 
902  QString outputFile = outputUrl + '/' + partFileName( fileIndex );
903 
904  //geotransform
905  double geoTransform[6];
906  geoTransform[0] = mapRect.xMinimum();
907  geoTransform[1] = mup;
908  geoTransform[2] = 0.0;
909  geoTransform[3] = mapRect.yMaximum();
910  geoTransform[4] = 0.0;
911  geoTransform[5] = -mup;
912 
913  // perhaps we need a separate createOptions for tiles ?
914 
915  QgsRasterDataProvider *destProvider = QgsRasterDataProvider::create( mOutputProviderKey, outputFile, mOutputFormat, nBands, type, iterCols, iterRows, geoTransform, crs, mCreateOptions );
916 
917  // TODO: return provider and report error
918  return destProvider;
919 }
920 
921 QgsRasterDataProvider *QgsRasterFileWriter::initOutput( int nCols, int nRows, const QgsCoordinateReferenceSystem &crs,
922  double *geoTransform, int nBands, Qgis::DataType type,
923  const QList<bool> &destHasNoDataValueList, const QList<double> &destNoDataValueList )
924 {
925  if ( mTiledMode )
926  {
927  createVRT( nCols, nRows, crs, geoTransform, type, destHasNoDataValueList, destNoDataValueList );
928  return nullptr;
929  }
930  else
931  {
932 #if 0
933  // TODO enable "use existing", has no effect for now, because using Create() in gdal provider
934  // should this belong in provider? should also test that source provider is gdal
935  if ( mBuildPyramidsFlag == -4 && mOutputProviderKey == "gdal" && mOutputFormat.toLower() == "gtiff" )
936  mCreateOptions << "COPY_SRC_OVERVIEWS=YES";
937 #endif
938 
939  QgsRasterDataProvider *destProvider = QgsRasterDataProvider::create( mOutputProviderKey, mOutputUrl, mOutputFormat, nBands, type, nCols, nRows, geoTransform, crs, mCreateOptions );
940 
941  if ( !destProvider )
942  {
943  QgsDebugMsg( "No provider created" );
944  }
945 
946  return destProvider;
947  }
948 }
949 
950 void QgsRasterFileWriter::globalOutputParameters( const QgsRectangle &extent, int nCols, int &nRows,
951  double *geoTransform, double &pixelSize )
952 {
953  pixelSize = extent.width() / nCols;
954 
955  //calculate nRows automatically for providers without exact resolution
956  if ( nRows < 0 )
957  {
958  nRows = static_cast< double >( nCols ) / extent.width() * extent.height() + 0.5; //NOLINT
959  }
960  geoTransform[0] = extent.xMinimum();
961  geoTransform[1] = pixelSize;
962  geoTransform[2] = 0.0;
963  geoTransform[3] = extent.yMaximum();
964  geoTransform[4] = 0.0;
965  geoTransform[5] = -( extent.height() / nRows );
966 }
967 
968 QString QgsRasterFileWriter::partFileName( int fileIndex )
969 {
970  // .tif for now
971  QFileInfo outputInfo( mOutputUrl );
972  return QStringLiteral( "%1.%2.tif" ).arg( outputInfo.fileName() ).arg( fileIndex );
973 }
974 
975 QString QgsRasterFileWriter::vrtFileName()
976 {
977  QFileInfo outputInfo( mOutputUrl );
978  return QStringLiteral( "%1.vrt" ).arg( outputInfo.fileName() );
979 }
980 
981 QString QgsRasterFileWriter::driverForExtension( const QString &extension )
982 {
983  QString ext = extension.trimmed();
984  if ( ext.isEmpty() )
985  return QString();
986 
987  if ( ext.startsWith( '.' ) )
988  ext.remove( 0, 1 );
989 
990  GDALAllRegister();
991  int const drvCount = GDALGetDriverCount();
992 
993  for ( int i = 0; i < drvCount; ++i )
994  {
995  GDALDriverH drv = GDALGetDriver( i );
996  if ( drv )
997  {
998  char **driverMetadata = GDALGetMetadata( drv, nullptr );
999  if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER, false ) )
1000  {
1001  QString drvName = GDALGetDriverShortName( drv );
1002  QStringList driverExtensions = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS, nullptr ) ).split( ' ' );
1003 
1004  Q_FOREACH ( const QString &driver, driverExtensions )
1005  {
1006  if ( driver.compare( ext, Qt::CaseInsensitive ) == 0 )
1007  return drvName;
1008  }
1009  }
1010  }
1011  }
1012  return QString();
1013 }
1014 
1015 QStringList QgsRasterFileWriter::extensionsForFormat( const QString &format )
1016 {
1017  GDALDriverH drv = GDALGetDriverByName( format.toLocal8Bit().data() );
1018  if ( drv )
1019  {
1020  char **driverMetadata = GDALGetMetadata( drv, nullptr );
1021  if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER, false ) )
1022  {
1023  return QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS, nullptr ) ).split( ' ' );
1024  }
1025  }
1026  return QStringList();
1027 }
1028 
1029 QString QgsRasterFileWriter::filterForDriver( const QString &driverName )
1030 {
1031  GDALDriverH drv = GDALGetDriverByName( driverName.toLocal8Bit().data() );
1032  if ( drv )
1033  {
1034  QString drvName = GDALGetDriverLongName( drv );
1035  QString extensionsString = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS, nullptr ) );
1036  if ( extensionsString.isEmpty() )
1037  {
1038  return QString();
1039  }
1040  QStringList extensions = extensionsString.split( ' ' );
1041  QString filter = drvName + " (";
1042  for ( const QString &ext : extensions )
1043  {
1044  filter.append( QStringLiteral( "*.%1 *.%2 " ).arg( ext.toLower(), ext.toUpper() ) );
1045  }
1046  filter = filter.trimmed().append( QStringLiteral( ")" ) );
1047  return filter;
1048  }
1049 
1050  return QString();
1051 }
1052 
1053 QList< QgsRasterFileWriter::FilterFormatDetails > QgsRasterFileWriter::supportedFiltersAndFormats( RasterFormatOptions options )
1054 {
1055  QList< FilterFormatDetails > results;
1056 
1057  GDALAllRegister();
1058  int const drvCount = GDALGetDriverCount();
1059 
1060  FilterFormatDetails tifFormat;
1061 
1062  for ( int i = 0; i < drvCount; ++i )
1063  {
1064  GDALDriverH drv = GDALGetDriver( i );
1065  if ( drv )
1066  {
1067  QString drvName = GDALGetDriverShortName( drv );
1068  char **driverMetadata = GDALGetMetadata( drv, nullptr );
1069  if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_CREATE, false ) && CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER, false ) )
1070  {
1071  QString filterString = filterForDriver( drvName );
1072  if ( filterString.isEmpty() )
1073  continue;
1074 
1075  FilterFormatDetails details;
1076  details.driverName = drvName;
1077  details.filterString = filterString;
1078 
1079  if ( options & SortRecommended )
1080  {
1081  if ( drvName == QLatin1String( "GTiff" ) )
1082  {
1083  tifFormat = details;
1084  continue;
1085  }
1086  }
1087 
1088  results << details;
1089  }
1090  }
1091  }
1092 
1093  std::sort( results.begin(), results.end(), []( const FilterFormatDetails & a, const FilterFormatDetails & b ) -> bool
1094  {
1095  return a.driverName < b.driverName;
1096  } );
1097 
1098  if ( options & SortRecommended )
1099  {
1100  if ( !tifFormat.filterString.isEmpty() )
1101  {
1102  results.insert( 0, tifFormat );
1103  }
1104  }
1105 
1106  return results;
1107 }
1108 
1109 QStringList QgsRasterFileWriter::supportedFormatExtensions( const RasterFormatOptions options )
1110 {
1111  const auto formats = supportedFiltersAndFormats( options );
1112  QStringList extensions;
1113 
1114  QRegularExpression rx( QStringLiteral( "\\*\\.([a-zA-Z0-9]*)" ) );
1115 
1116  for ( const FilterFormatDetails &format : formats )
1117  {
1118  QString ext = format.filterString;
1119  QRegularExpressionMatch match = rx.match( ext );
1120  if ( !match.hasMatch() )
1121  continue;
1122 
1123  QString matched = match.captured( 1 );
1124  extensions << matched;
1125  }
1126  return extensions;
1127 }
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: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:516
DataType
Raster data types.
Definition: qgis.h:91
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.
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
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.
Raster data container.
QgsCoordinateReferenceSystem sourceCrs() const
Get source CRS.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
virtual QList< QgsRasterPyramid > buildPyramidList(QList< int > overviewList=QList< int >())
Accessor for 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
QRgb color(int row, int column) const
Read a single color.
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
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:488
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.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:517
void setMaximumTileWidth(int w)
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: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
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: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.