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