QGIS API Documentation  3.12.1-BucureČ™ti (121cc00ff0)
qgsrasterlayer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrasterlayer.cpp - description
3  -------------------
4 begin : Sat Jun 22 2002
5 copyright : (C) 2003 by Tim Sutton, Steve Halasz and Gary E.Sherman
6 email : tim at linfiniti.com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 #include "qgsapplication.h"
19 #include "qgscolorrampshader.h"
21 #include "qgscoordinatetransform.h"
22 #include "qgsdatasourceuri.h"
23 #include "qgshuesaturationfilter.h"
25 #include "qgslogger.h"
26 #include "qgsmaplayerlegend.h"
27 #include "qgsmaptopixel.h"
28 #include "qgsmessagelog.h"
30 #include "qgspainting.h"
32 #include "qgspathresolver.h"
34 #include "qgsproviderregistry.h"
35 #include "qgsrasterdataprovider.h"
36 #include "qgsrasterdrawer.h"
37 #include "qgsrasteriterator.h"
38 #include "qgsrasterlayer.h"
39 #include "qgsrasterlayerrenderer.h"
40 #include "qgsrasterprojector.h"
41 #include "qgsrasterrange.h"
44 #include "qgsrastershader.h"
45 #include "qgsreadwritecontext.h"
46 #include "qgsrectangle.h"
47 #include "qgsrendercontext.h"
51 #include "qgssettings.h"
52 #include "qgssymbollayerutils.h"
53 #include "qgsgdalprovider.h"
56 
57 #include <cmath>
58 #include <cstdio>
59 #include <limits>
60 #include <typeinfo>
61 
62 #include <QApplication>
63 #include <QCursor>
64 #include <QDir>
65 #include <QDomElement>
66 #include <QDomNode>
67 #include <QFile>
68 #include <QFileInfo>
69 #include <QFont>
70 #include <QFontMetrics>
71 #include <QFrame>
72 #include <QImage>
73 #include <QLabel>
74 #include <QList>
75 #include <QMatrix>
76 #include <QMessageBox>
77 #include <QPainter>
78 #include <QPixmap>
79 #include <QRegExp>
80 #include <QSlider>
81 
82 #define ERR(message) QGS_ERROR_MESSAGE(message,"Raster layer")
83 
84 const double QgsRasterLayer::SAMPLE_SIZE = 250000;
85 
92 
99 
102  , QSTRING_NOT_SET( QStringLiteral( "Not Set" ) )
103  , TRSTRING_NOT_SET( tr( "Not Set" ) )
104 
105 {
106  init();
107  mValid = false;
108 }
109 
110 QgsRasterLayer::QgsRasterLayer( const QString &uri,
111  const QString &baseName,
112  const QString &providerKey,
113  const LayerOptions &options )
114  : QgsMapLayer( QgsMapLayerType::RasterLayer, baseName, uri )
115  // Constant that signals property not used.
116  , QSTRING_NOT_SET( QStringLiteral( "Not Set" ) )
117  , TRSTRING_NOT_SET( tr( "Not Set" ) )
118 {
120 
121  QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
122  setProviderType( providerKey );
123 
124  QgsDataProvider::ProviderOptions providerOptions { options.transformContext };
125 
126  setDataSource( uri, baseName, providerKey, providerOptions, options.loadDefaultStyle );
127 
128 } // QgsRasterLayer ctor
129 
131 {
132  emit willBeDeleted();
133 
134  mValid = false;
135  // Note: provider and other interfaces are owned and deleted by pipe
136 }
137 
139 {
141  if ( mDataProvider )
142  {
143  options.transformContext = mDataProvider->transformContext();
144  }
145  QgsRasterLayer *layer = new QgsRasterLayer( source(), name(), mProviderKey, options );
146  QgsMapLayer::clone( layer );
147 
148  // do not clone data provider which is the first element in pipe
149  for ( int i = 1; i < mPipe.size(); i++ )
150  {
151  if ( mPipe.at( i ) )
152  layer->pipe()->set( mPipe.at( i )->clone() );
153  }
154 
155  return layer;
156 }
157 
159 //
160 // Static Methods and members
161 //
163 
164 bool QgsRasterLayer::isValidRasterFileName( const QString &fileNameQString, QString &retErrMsg )
165 {
166  bool myIsValid = QgsGdalProvider::isValidRasterFileName( fileNameQString, retErrMsg );
167  return myIsValid;
168 }
169 
170 bool QgsRasterLayer::isValidRasterFileName( QString const &fileNameQString )
171 {
172  QString retErrMsg;
173  return isValidRasterFileName( fileNameQString, retErrMsg );
174 }
175 
176 QDateTime QgsRasterLayer::lastModified( QString const &name )
177 {
178  QgsDebugMsgLevel( "name=" + name, 4 );
179  QDateTime t;
180 
181  QFileInfo fi( name );
182 
183  // Is it file?
184  if ( !fi.exists() )
185  return t;
186 
187  t = fi.lastModified();
188 
189  QgsDebugMsgLevel( "last modified = " + t.toString(), 4 );
190 
191  return t;
192 }
193 
194 void QgsRasterLayer::setDataProvider( const QString &provider )
195 {
197 }
198 
199 // typedef for the QgsDataProvider class factory
200 typedef QgsDataProvider *classFactoryFunction_t( const QString *, const QgsDataProvider::ProviderOptions &options );
201 
203 //
204 // Non Static Public methods
205 //
207 
209 {
210  if ( !mDataProvider ) return 0;
211  return mDataProvider->bandCount();
212 }
213 
214 QString QgsRasterLayer::bandName( int bandNo ) const
215 {
216  if ( !mDataProvider ) return QString();
217  return mDataProvider->generateBandName( bandNo );
218 }
219 
220 void QgsRasterLayer::setRendererForDrawingStyle( QgsRaster::DrawingStyle drawingStyle )
221 {
222  setRenderer( QgsApplication::rasterRendererRegistry()->defaultRendererForDrawingStyle( drawingStyle, mDataProvider ) );
223 }
224 
226 {
227  return mDataProvider;
228 }
229 
231 {
232  return mDataProvider;
233 }
234 
236 {
237  if ( mDataProvider )
238  {
239  mDataProvider->reloadData();
240  }
241 }
242 
244 {
245  return new QgsRasterLayerRenderer( this, rendererContext );
246 }
247 
248 
249 void QgsRasterLayer::draw( QPainter *theQPainter,
250  QgsRasterViewPort *rasterViewPort,
251  const QgsMapToPixel *qgsMapToPixel )
252 {
253  QgsDebugMsgLevel( QStringLiteral( " 3 arguments" ), 4 );
254  QElapsedTimer time;
255  time.start();
256  //
257  //
258  // The goal here is to make as many decisions as possible early on (outside of the rendering loop)
259  // so that we can maximise performance of the rendering process. So now we check which drawing
260  // procedure to use :
261  //
262 
263  QgsRasterProjector *projector = mPipe.projector();
264 
265  // TODO add a method to interface to get provider and get provider
266  // params in QgsRasterProjector
267  if ( projector )
268  {
269  projector->setCrs( rasterViewPort->mSrcCRS, rasterViewPort->mDestCRS, rasterViewPort->mTransformContext );
270  }
271 
272  // Drawer to pipe?
273  QgsRasterIterator iterator( mPipe.last() );
274  QgsRasterDrawer drawer( &iterator );
275  drawer.draw( theQPainter, rasterViewPort, qgsMapToPixel );
276 
277  QgsDebugMsgLevel( QStringLiteral( "total raster draw time (ms): %1" ).arg( time.elapsed(), 5 ), 4 );
278 } //end of draw method
279 
281 {
282  QList< QPair< QString, QColor > > symbolList;
284  if ( renderer )
285  {
286  renderer->legendSymbologyItems( symbolList );
287  }
288  return symbolList;
289 }
290 
292 {
293  QgsLayerMetadataFormatter htmlFormatter( metadata() );
294  QString myMetadata = QStringLiteral( "<html><head></head>\n<body>\n" );
295 
296  // Begin Provider section
297  myMetadata += QStringLiteral( "<h1>" ) + tr( "Information from provider" ) + QStringLiteral( "</h1>\n<hr>\n" ) %
298  QStringLiteral( "<table class=\"list-view\">\n" ) %
299 
300  // name
301  QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Name" ) % QStringLiteral( "</td><td>" ) % name() % QStringLiteral( "</td></tr>\n" );
302 
303  // local path
304  QVariantMap uriComponents = QgsProviderRegistry::instance()->decodeUri( mProviderKey, publicSource() );
305  QString path;
306  if ( uriComponents.contains( QStringLiteral( "path" ) ) )
307  {
308  path = uriComponents[QStringLiteral( "path" )].toString();
309  if ( QFile::exists( path ) )
310  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Path" ) % QStringLiteral( "</td><td>%1" ).arg( QStringLiteral( "<a href=\"%1\">%2</a>" ).arg( QUrl::fromLocalFile( path ).toString(), QDir::toNativeSeparators( path ) ) ) + QStringLiteral( "</td></tr>\n" );
311  }
312  if ( uriComponents.contains( QStringLiteral( "url" ) ) )
313  {
314  const QString url = uriComponents[QStringLiteral( "url" )].toString();
315  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "URL" ) % QStringLiteral( "</td><td>%1" ).arg( QStringLiteral( "<a href=\"%1\">%2</a>" ).arg( QUrl( url ).toString(), url ) ) + QStringLiteral( "</td></tr>\n" );
316  }
317 
318  // data source
319  if ( publicSource() != path )
320  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Source" ) + QStringLiteral( "</td><td>%1" ).arg( publicSource() ) + QStringLiteral( "</td></tr>\n" );
321 
322  // EPSG
323  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "CRS" ) + QStringLiteral( "</td><td>" );
324  if ( crs().isValid() )
325  {
326  myMetadata += crs().userFriendlyIdentifier( QgsCoordinateReferenceSystem::FullString ) % QStringLiteral( " - " );
327  if ( crs().isGeographic() )
328  myMetadata += tr( "Geographic" );
329  else
330  myMetadata += tr( "Projected" );
331  }
332  myMetadata += QStringLiteral( "</td></tr>\n" ) %
333 
334  // Extent
335  QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Extent" ) % QStringLiteral( "</td><td>" ) % extent().toString() % QStringLiteral( "</td></tr>\n" ) %
336 
337  // unit
338  QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Unit" ) % QStringLiteral( "</td><td>" ) % QgsUnitTypes::toString( crs().mapUnits() ) % QStringLiteral( "</td></tr>\n" ) %
339 
340  // Raster Width
341  QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Width" ) % QStringLiteral( "</td><td>" );
342  if ( dataProvider()->capabilities() & QgsRasterDataProvider::Size )
343  myMetadata += QString::number( width() );
344  else
345  myMetadata += tr( "n/a" );
346  myMetadata += QStringLiteral( "</td></tr>\n" ) %
347 
348  // Raster height
349  QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Height" ) + QStringLiteral( "</td><td>" );
350  if ( dataProvider()->capabilities() & QgsRasterDataProvider::Size )
351  myMetadata += QString::number( height() );
352  else
353  myMetadata += tr( "n/a" );
354  myMetadata += QStringLiteral( "</td></tr>\n" ) %
355 
356  // Data type
357  QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Data type" ) % QStringLiteral( "</td><td>" );
358  // Just use the first band
359  switch ( mDataProvider->sourceDataType( 1 ) )
360  {
361  case Qgis::Byte:
362  myMetadata += tr( "Byte - Eight bit unsigned integer" );
363  break;
364  case Qgis::UInt16:
365  myMetadata += tr( "UInt16 - Sixteen bit unsigned integer " );
366  break;
367  case Qgis::Int16:
368  myMetadata += tr( "Int16 - Sixteen bit signed integer " );
369  break;
370  case Qgis::UInt32:
371  myMetadata += tr( "UInt32 - Thirty two bit unsigned integer " );
372  break;
373  case Qgis::Int32:
374  myMetadata += tr( "Int32 - Thirty two bit signed integer " );
375  break;
376  case Qgis::Float32:
377  myMetadata += tr( "Float32 - Thirty two bit floating point " );
378  break;
379  case Qgis::Float64:
380  myMetadata += tr( "Float64 - Sixty four bit floating point " );
381  break;
382  case Qgis::CInt16:
383  myMetadata += tr( "CInt16 - Complex Int16 " );
384  break;
385  case Qgis::CInt32:
386  myMetadata += tr( "CInt32 - Complex Int32 " );
387  break;
388  case Qgis::CFloat32:
389  myMetadata += tr( "CFloat32 - Complex Float32 " );
390  break;
391  case Qgis::CFloat64:
392  myMetadata += tr( "CFloat64 - Complex Float64 " );
393  break;
394  default:
395  myMetadata += tr( "Could not determine raster data type." );
396  }
397  myMetadata += QStringLiteral( "</td></tr>\n" ) %
398 
399  // Insert provider-specific (e.g. WMS-specific) metadata
400  mDataProvider->htmlMetadata() %
401 
402  // End Provider section
403  QStringLiteral( "</table>\n<br><br>" ) %
404 
405  // Identification section
406  QStringLiteral( "<h1>" ) % tr( "Identification" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
407  htmlFormatter.identificationSectionHtml() %
408  QStringLiteral( "<br><br>\n" ) %
409 
410  // extent section
411  QStringLiteral( "<h1>" ) % tr( "Extent" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
412  htmlFormatter.extentSectionHtml( ) %
413  QStringLiteral( "<br><br>\n" ) %
414 
415  // Start the Access section
416  QStringLiteral( "<h1>" ) % tr( "Access" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
417  htmlFormatter.accessSectionHtml( ) %
418  QStringLiteral( "<br><br>\n" ) %
419 
420  // Bands section
421  QStringLiteral( "</table>\n<br><br><h1>" ) % tr( "Bands" ) % QStringLiteral( "</h1>\n<hr>\n<table class=\"list-view\">\n" ) %
422 
423  // Band count
424  QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Band count" ) % QStringLiteral( "</td><td>" ) % QString::number( bandCount() ) % QStringLiteral( "</td></tr>\n" );
425 
426  // Band table
427  QStringLiteral( "</table>\n<br><table width=\"100%\" class=\"tabular-view\">\n" ) %
428  QStringLiteral( "<tr><th>" ) % tr( "Number" ) % QStringLiteral( "</th><th>" ) % tr( "Band" ) % QStringLiteral( "</th><th>" ) % tr( "No-Data" ) % QStringLiteral( "</th><th>" ) %
429  tr( "Min" ) % QStringLiteral( "</th><th>" ) % tr( "Max" ) % QStringLiteral( "</th></tr>\n" );
430 
431  QgsRasterDataProvider *provider = const_cast< QgsRasterDataProvider * >( mDataProvider );
432  for ( int i = 1; i <= bandCount(); i++ )
433  {
434  QString rowClass;
435  if ( i % 2 )
436  rowClass = QStringLiteral( "class=\"odd-row\"" );
437 
438  myMetadata += QStringLiteral( "<tr " ) % rowClass % QStringLiteral( "><td>" ) % QString::number( i ) % QStringLiteral( "</td><td>" ) % bandName( i ) % QStringLiteral( "</td><td>" );
439 
440  if ( dataProvider()->sourceHasNoDataValue( i ) )
441  myMetadata += QString::number( dataProvider()->sourceNoDataValue( i ) );
442  else
443  myMetadata += tr( "n/a" );
444  myMetadata += QStringLiteral( "</td>" );
445 
446  if ( provider->hasStatistics( i ) )
447  {
448  QgsRasterBandStats myRasterBandStats = provider->bandStatistics( i );
449  myMetadata += QStringLiteral( "<td>" ) % QString::number( myRasterBandStats.minimumValue, 'f', 10 ) % QStringLiteral( "</td>" ) %
450  QStringLiteral( "<td>" ) % QString::number( myRasterBandStats.maximumValue, 'f', 10 ) % QStringLiteral( "</td>" );
451  }
452  else
453  {
454  myMetadata += QStringLiteral( "<td>" ) % tr( "n/a" ) % QStringLiteral( "</td><td>" ) % tr( "n/a" ) % QStringLiteral( "</td>" );
455  }
456 
457  myMetadata += QStringLiteral( "</tr>\n" );
458  }
459 
460  //close previous bands table
461  myMetadata += QStringLiteral( "</table>\n<br><br>" ) %
462 
463  // Start the contacts section
464  QStringLiteral( "<h1>" ) % tr( "Contacts" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
465  htmlFormatter.contactsSectionHtml( ) %
466  QStringLiteral( "<br><br>\n" ) %
467 
468  // Start the links section
469  QStringLiteral( "<h1>" ) % tr( "References" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
470  htmlFormatter.linksSectionHtml( ) %
471  QStringLiteral( "<br><br>\n" ) %
472 
473  // Start the history section
474  QStringLiteral( "<h1>" ) % tr( "History" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
475  htmlFormatter.historySectionHtml( ) %
476  QStringLiteral( "<br><br>\n" ) %
477 
478  QStringLiteral( "\n</body>\n</html>\n" );
479  return myMetadata;
480 }
481 
482 QPixmap QgsRasterLayer::paletteAsPixmap( int bandNumber )
483 {
484  //TODO: This function should take dimensions
485  QgsDebugMsgLevel( QStringLiteral( "entered." ), 4 );
486 
487  // Only do this for the GDAL provider?
488  // Maybe WMS can do this differently using QImage::numColors and QImage::color()
489  if ( mDataProvider &&
490  mDataProvider->colorInterpretation( bandNumber ) == QgsRaster::PaletteIndex )
491  {
492  QgsDebugMsgLevel( QStringLiteral( "....found paletted image" ), 4 );
493  QgsColorRampShader myShader;
494  QList<QgsColorRampShader::ColorRampItem> myColorRampItemList = mDataProvider->colorTable( bandNumber );
495  if ( !myColorRampItemList.isEmpty() )
496  {
497  QgsDebugMsgLevel( QStringLiteral( "....got color ramp item list" ), 4 );
498  myShader.setColorRampItemList( myColorRampItemList );
500  // Draw image
501  int mySize = 100;
502  QPixmap myPalettePixmap( mySize, mySize );
503  QPainter myQPainter( &myPalettePixmap );
504 
505  QImage myQImage = QImage( mySize, mySize, QImage::Format_RGB32 );
506  myQImage.fill( 0 );
507  myPalettePixmap.fill();
508 
509  double myStep = ( static_cast< double >( myColorRampItemList.size() ) - 1 ) / static_cast< double >( mySize * mySize );
510  double myValue = 0.0;
511  for ( int myRow = 0; myRow < mySize; myRow++ )
512  {
513  QRgb *myLineBuffer = reinterpret_cast< QRgb * >( myQImage.scanLine( myRow ) );
514  for ( int myCol = 0; myCol < mySize; myCol++ )
515  {
516  myValue = myStep * static_cast< double >( myCol + myRow * mySize );
517  int c1, c2, c3, c4;
518  myShader.shade( myValue, &c1, &c2, &c3, &c4 );
519  myLineBuffer[ myCol ] = qRgba( c1, c2, c3, c4 );
520  }
521  }
522 
523  myQPainter.drawImage( 0, 0, myQImage );
524  return myPalettePixmap;
525  }
526  QPixmap myNullPixmap;
527  return myNullPixmap;
528  }
529  else
530  {
531  //invalid layer was requested
532  QPixmap myNullPixmap;
533  return myNullPixmap;
534  }
535 }
536 
538 {
539  return mProviderKey;
540 }
541 
543 {
544 // We return one raster pixel per map unit pixel
545 // One raster pixel can have several raster units...
546 
547 // We can only use one of the mGeoTransform[], so go with the
548 // horisontal one.
549 
550  if ( mDataProvider &&
551  mDataProvider->capabilities() & QgsRasterDataProvider::Size && !qgsDoubleNear( mDataProvider->xSize(), 0.0 ) )
552  {
553  return mDataProvider->extent().width() / mDataProvider->xSize();
554  }
555  return 1;
556 }
557 
559 {
560  if ( mDataProvider &&
561  mDataProvider->capabilities() & QgsRasterDataProvider::Size && !qgsDoubleNear( mDataProvider->ySize(), 0.0 ) )
562  {
563  return mDataProvider->extent().height() / mDataProvider->ySize();
564  }
565  return 1;
566 }
567 
568 void QgsRasterLayer::init()
569 {
570  mRasterType = QgsRasterLayer::GrayOrUndefined;
571 
573 
574  setRendererForDrawingStyle( QgsRaster::UndefinedDrawingStyle );
575 
576  //Initialize the last view port structure, should really be a class
577  mLastViewPort.mWidth = 0;
578  mLastViewPort.mHeight = 0;
579 }
580 
581 void QgsRasterLayer::setDataProvider( QString const &provider, const QgsDataProvider::ProviderOptions &options )
582 {
583  QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
584  mValid = false; // assume the layer is invalid until we determine otherwise
585 
586  mPipe.remove( mDataProvider ); // deletes if exists
587  mDataProvider = nullptr;
588 
589  // XXX should I check for and possibly delete any pre-existing providers?
590  // XXX How often will that scenario occur?
591 
592  mProviderKey = provider;
593  // set the layer name (uppercase first character)
594  if ( ! mLayerName.isEmpty() ) // XXX shouldn't this happen in parent?
595  {
596  setName( mLayerName );
597  }
598 
599  //mBandCount = 0;
600 
601  mDataProvider = qobject_cast< QgsRasterDataProvider * >( QgsProviderRegistry::instance()->createProvider( mProviderKey, mDataSource, options ) );
602  if ( !mDataProvider )
603  {
604  //QgsMessageLog::logMessage( tr( "Cannot instantiate the data provider" ), tr( "Raster" ) );
605  appendError( ERR( tr( "Cannot instantiate the '%1' data provider" ).arg( mProviderKey ) ) );
606  return;
607  }
608  QgsDebugMsgLevel( QStringLiteral( "Data provider created" ), 4 );
609  mDataProvider->setParent( this );
610 
611  // Set data provider into pipe even if not valid so that it is deleted with pipe (with layer)
612  mPipe.set( mDataProvider );
613  if ( !mDataProvider->isValid() )
614  {
615  setError( mDataProvider->error() );
616  appendError( ERR( tr( "Provider is not valid (provider: %1, URI: %2" ).arg( mProviderKey, mDataSource ) ) );
617  return;
618  }
619 
621  {
622  setMetadata( mDataProvider->layerMetadata() );
623  QgsDebugMsgLevel( QStringLiteral( "Set Data provider QgsLayerMetadata identifier[%1]" ).arg( metadata().identifier() ), 4 );
624  }
625 
626  if ( provider == QLatin1String( "gdal" ) )
627  {
628  // make sure that the /vsigzip or /vsizip is added to uri, if applicable
629  mDataSource = mDataProvider->dataSourceUri();
630  }
631 
632  // get the extent
633  QgsRectangle mbr = mDataProvider->extent();
634 
635  // show the extent
636  QgsDebugMsgLevel( "Extent of layer: " + mbr.toString(), 4 );
637  // store the extent
638  setExtent( mbr );
639 
640  // upper case the first letter of the layer name
641  QgsDebugMsgLevel( "mLayerName: " + name(), 4 );
642 
643  // set up the raster drawing style
644  // Do not set any 'sensible' style here, the style is set later
645 
646  // Setup source CRS
647  setCrs( QgsCoordinateReferenceSystem( mDataProvider->crs() ) );
648 
649  QgsDebugMsgLevel( "using wkt:\n" + crs().toWkt( QgsCoordinateReferenceSystem::WKT2_2018 ), 4 );
650 
651  //defaults - Needs to be set after the Contrast list has been build
652  //Try to read the default contrast enhancement from the config file
653 
654  //decide what type of layer this is...
655  //TODO Change this to look at the color interp and palette interp to decide which type of layer it is
656  QgsDebugMsgLevel( "bandCount = " + QString::number( mDataProvider->bandCount() ), 4 );
657  QgsDebugMsgLevel( "dataType = " + QString::number( mDataProvider->dataType( 1 ) ), 4 );
658  if ( ( mDataProvider->bandCount() > 1 ) )
659  {
660  // handle singleband gray with alpha
661  if ( mDataProvider->bandCount() == 2
662  && ( ( mDataProvider->colorInterpretation( 1 ) == QgsRaster::GrayIndex
663  && mDataProvider->colorInterpretation( 2 ) == QgsRaster::AlphaBand )
664  || ( mDataProvider->colorInterpretation( 1 ) == QgsRaster::AlphaBand
665  && mDataProvider->colorInterpretation( 2 ) == QgsRaster::GrayIndex ) ) )
666  {
667  mRasterType = GrayOrUndefined;
668  }
669  else
670  {
671  mRasterType = Multiband;
672  }
673  }
674  else if ( mDataProvider->dataType( 1 ) == Qgis::ARGB32
675  || mDataProvider->dataType( 1 ) == Qgis::ARGB32_Premultiplied )
676  {
677  mRasterType = ColorLayer;
678  }
679  else if ( mDataProvider->colorInterpretation( 1 ) == QgsRaster::PaletteIndex )
680  {
681  mRasterType = Palette;
682  }
683  else if ( mDataProvider->colorInterpretation( 1 ) == QgsRaster::ContinuousPalette )
684  {
685  mRasterType = Palette;
686  }
687  else
688  {
689  mRasterType = GrayOrUndefined;
690  }
691 
692  QgsDebugMsgLevel( "mRasterType = " + QString::number( mRasterType ), 4 );
693  if ( mRasterType == ColorLayer )
694  {
695  QgsDebugMsgLevel( "Setting drawing style to SingleBandColorDataStyle " + QString::number( QgsRaster::SingleBandColorDataStyle ), 4 );
696  setRendererForDrawingStyle( QgsRaster::SingleBandColorDataStyle );
697  }
698  else if ( mRasterType == Palette && mDataProvider->colorInterpretation( 1 ) == QgsRaster::PaletteIndex )
699  {
700  setRendererForDrawingStyle( QgsRaster::PalettedColor ); //sensible default
701  }
702  else if ( mRasterType == Palette && mDataProvider->colorInterpretation( 1 ) == QgsRaster::ContinuousPalette )
703  {
704  setRendererForDrawingStyle( QgsRaster::SingleBandPseudoColor );
705  // Load color table
706  QList<QgsColorRampShader::ColorRampItem> colorTable = mDataProvider->colorTable( 1 );
708  if ( r )
709  {
710  // TODO: this should go somewhere else
711  QgsRasterShader *shader = new QgsRasterShader();
712  QgsColorRampShader *colorRampShader = new QgsColorRampShader();
714  colorRampShader->setColorRampItemList( colorTable );
715  shader->setRasterShaderFunction( colorRampShader );
716  r->setShader( shader );
717  }
718  }
719  else if ( mRasterType == Multiband )
720  {
721  setRendererForDrawingStyle( QgsRaster::MultiBandColor ); //sensible default
722  }
723  else //GrayOrUndefined
724  {
725  setRendererForDrawingStyle( QgsRaster::SingleBandGray ); //sensible default
726  }
727 
728  // Auto set alpha band
729  for ( int bandNo = 1; bandNo <= mDataProvider->bandCount(); bandNo++ )
730  {
731  if ( mDataProvider->colorInterpretation( bandNo ) == QgsRaster::AlphaBand )
732  {
733  if ( mPipe.renderer() )
734  {
735  mPipe.renderer()->setAlphaBand( bandNo );
736  }
737  break;
738  }
739  }
740 
741  // brightness filter
743  mPipe.set( brightnessFilter );
744 
745  // hue/saturation filter
747  mPipe.set( hueSaturationFilter );
748 
749  // resampler (must be after renderer)
751  mPipe.set( resampleFilter );
752 
754  {
755  QgsSettings settings;
756  QString resampling = settings.value( QStringLiteral( "/Raster/defaultZoomedInResampling" ), QStringLiteral( "nearest neighbour" ) ).toString();
757  if ( resampling == QStringLiteral( "bilinear" ) )
758  {
759  resampleFilter->setZoomedInResampler( new QgsBilinearRasterResampler() );
760  }
761  else if ( resampling == QStringLiteral( "cubic" ) )
762  {
763  resampleFilter->setZoomedInResampler( new QgsCubicRasterResampler() );
764  }
765  resampling = settings.value( QStringLiteral( "/Raster/defaultZoomedOutResampling" ), QStringLiteral( "nearest neighbour" ) ).toString();
766  if ( resampling == QStringLiteral( "bilinear" ) )
767  {
768  resampleFilter->setZoomedOutResampler( new QgsBilinearRasterResampler() );
769  }
770  resampleFilter->setMaxOversampling( settings.value( QStringLiteral( "/Raster/defaultOversampling" ), 2.0 ).toDouble() );
771  }
772 
773  // projector (may be anywhere in pipe)
774  QgsRasterProjector *projector = new QgsRasterProjector;
775  mPipe.set( projector );
776 
777  // Set default identify format - use the richest format available
778  int capabilities = mDataProvider->capabilities();
780  if ( capabilities & QgsRasterInterface::IdentifyHtml )
781  {
782  // HTML is usually richest
783  identifyFormat = QgsRaster::IdentifyFormatHtml;
784  }
785  else if ( capabilities & QgsRasterInterface::IdentifyFeature )
786  {
787  identifyFormat = QgsRaster::IdentifyFormatFeature;
788  }
789  else if ( capabilities & QgsRasterInterface::IdentifyText )
790  {
791  identifyFormat = QgsRaster::IdentifyFormatText;
792  }
793  else if ( capabilities & QgsRasterInterface::IdentifyValue )
794  {
795  identifyFormat = QgsRaster::IdentifyFormatValue;
796  }
797  setCustomProperty( QStringLiteral( "identify/format" ), QgsRasterDataProvider::identifyFormatName( identifyFormat ) );
798 
799  // Store timestamp
800  // TODO move to provider
801  mLastModified = lastModified( mDataSource );
802 
803  // Do a passthrough for the status bar text
804  connect( mDataProvider, &QgsRasterDataProvider::statusChanged, this, &QgsRasterLayer::statusChanged );
805 
806  //mark the layer as valid
807  mValid = true;
808 
809  QgsDebugMsgLevel( QStringLiteral( "exiting." ), 4 );
810 }
811 
812 void QgsRasterLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag )
813 {
814  bool hadRenderer( renderer() );
815 
816  QDomImplementation domImplementation;
817  QDomDocumentType documentType;
818  QString errorMsg;
819 
820  // Store the original style
821  if ( hadRenderer && ! loadDefaultStyleFlag )
822  {
823  documentType = domImplementation.createDocumentType(
824  QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
825 
826  QDomDocument doc = QDomDocument( documentType );
827  QDomElement styleElem = doc.createElement( QStringLiteral( "qgis" ) );
828  styleElem.setAttribute( QStringLiteral( "version" ), Qgis::version() );
829  QgsReadWriteContext writeContext;
830  if ( ! writeSymbology( styleElem, doc, errorMsg, writeContext ) )
831  {
832  QgsDebugMsg( QStringLiteral( "Could not store symbology for layer %1: %2" )
833  .arg( name(),
834  errorMsg ) );
835  }
836  else
837  {
838  doc.appendChild( styleElem );
839 
840  mOriginalStyleDocument = doc;
841  mOriginalStyleElement = styleElem;
842  }
843  }
844 
845  if ( mDataProvider )
846  closeDataProvider();
847 
848  init();
849 
850  for ( int i = mPipe.size() - 1; i >= 0; --i )
851  {
852  mPipe.remove( i );
853  }
854 
855  mDataSource = dataSource;
856  mLayerName = baseName;
857 
858  setDataProvider( provider, options );
859 
860  if ( mValid )
861  {
862  // load default style
863  bool defaultLoadedFlag = false;
864  bool restoredStyle = false;
865  if ( loadDefaultStyleFlag )
866  {
867  loadDefaultStyle( defaultLoadedFlag );
868  }
869  else if ( !mOriginalStyleElement.isNull() ) // Restore the style
870  {
871  QgsReadWriteContext readContext;
872  if ( ! readSymbology( mOriginalStyleElement, errorMsg, readContext ) )
873  {
874  QgsDebugMsg( QStringLiteral( "Could not restore symbology for layer %1: %2" )
875  .arg( name() )
876  .arg( errorMsg ) );
877 
878  }
879  else
880  {
881  restoredStyle = true;
882  emit repaintRequested();
883  emit styleChanged();
884  emit rendererChanged();
885  }
886  }
887 
888  if ( !defaultLoadedFlag && !restoredStyle )
889  {
891  }
892  emit statusChanged( tr( "QgsRasterLayer created" ) );
893  }
894  emit dataSourceChanged();
895  emit dataChanged();
896 }
897 
898 void QgsRasterLayer::closeDataProvider()
899 {
900  mValid = false;
901  mPipe.remove( mDataProvider );
902  mDataProvider = nullptr;
903 }
904 
905 void QgsRasterLayer::computeMinMax( int band,
906  const QgsRasterMinMaxOrigin &mmo,
908  const QgsRectangle &extent,
909  int sampleSize,
910  double &min, double &max )
911 {
912 
913  min = std::numeric_limits<double>::quiet_NaN();
914  max = std::numeric_limits<double>::quiet_NaN();
915  if ( !mDataProvider )
916  return;
917 
918  if ( limits == QgsRasterMinMaxOrigin::MinMax )
919  {
920  QgsRasterBandStats myRasterBandStats = mDataProvider->bandStatistics( band, QgsRasterBandStats::Min | QgsRasterBandStats::Max, extent, sampleSize );
921  min = myRasterBandStats.minimumValue;
922  max = myRasterBandStats.maximumValue;
923  }
924  else if ( limits == QgsRasterMinMaxOrigin::StdDev )
925  {
926  QgsRasterBandStats myRasterBandStats = mDataProvider->bandStatistics( band, QgsRasterBandStats::Mean | QgsRasterBandStats::StdDev, extent, sampleSize );
927  min = myRasterBandStats.mean - ( mmo.stdDevFactor() * myRasterBandStats.stdDev );
928  max = myRasterBandStats.mean + ( mmo.stdDevFactor() * myRasterBandStats.stdDev );
929  }
930  else if ( limits == QgsRasterMinMaxOrigin::CumulativeCut )
931  {
932  const double myLower = mmo.cumulativeCutLower();
933  const double myUpper = mmo.cumulativeCutUpper();
934  QgsDebugMsgLevel( QStringLiteral( "myLower = %1 myUpper = %2" ).arg( myLower ).arg( myUpper ), 4 );
935  mDataProvider->cumulativeCut( band, myLower, myUpper, min, max, extent, sampleSize );
936  }
937  QgsDebugMsgLevel( QStringLiteral( "band = %1 min = %2 max = %3" ).arg( band ).arg( min ).arg( max ), 4 );
938 
939 }
940 
942 {
943  return mDataProvider ? mDataProvider->ignoreExtents() : false;
944 }
945 
947 {
948  setContrastEnhancement( algorithm,
949  limits,
950  extent,
951  sampleSize,
952  generateLookupTableFlag,
953  mPipe.renderer() );
954 }
955 
958  const QgsRectangle &extent,
959  int sampleSize,
960  bool generateLookupTableFlag,
961  QgsRasterRenderer *rasterRenderer )
962 {
963  QgsDebugMsgLevel( QStringLiteral( "theAlgorithm = %1 limits = %2 extent.isEmpty() = %3" ).arg( algorithm ).arg( limits ).arg( extent.isEmpty() ), 4 );
964  if ( !rasterRenderer || !mDataProvider )
965  {
966  return;
967  }
968 
969  QList<int> myBands;
970  QList<QgsContrastEnhancement *> myEnhancements;
971  QgsRasterMinMaxOrigin myMinMaxOrigin;
972  QgsRasterRenderer *myRasterRenderer = nullptr;
973  QgsSingleBandGrayRenderer *myGrayRenderer = nullptr;
974  QgsSingleBandPseudoColorRenderer *myPseudoColorRenderer = nullptr;
975  QgsMultiBandColorRenderer *myMultiBandRenderer = nullptr;
976  QString rendererType = rasterRenderer->type();
977  if ( rendererType == QLatin1String( "singlebandgray" ) )
978  {
979  myGrayRenderer = dynamic_cast<QgsSingleBandGrayRenderer *>( rasterRenderer );
980  if ( !myGrayRenderer )
981  {
982  return;
983  }
984  myBands << myGrayRenderer->grayBand();
985  myRasterRenderer = myGrayRenderer;
986  myMinMaxOrigin = myGrayRenderer->minMaxOrigin();
987  }
988  else if ( rendererType == QLatin1String( "multibandcolor" ) )
989  {
990  myMultiBandRenderer = dynamic_cast<QgsMultiBandColorRenderer *>( rasterRenderer );
991  if ( !myMultiBandRenderer )
992  {
993  return;
994  }
995  myBands << myMultiBandRenderer->redBand() << myMultiBandRenderer->greenBand() << myMultiBandRenderer->blueBand();
996  myRasterRenderer = myMultiBandRenderer;
997  myMinMaxOrigin = myMultiBandRenderer->minMaxOrigin();
998  }
999  else if ( rendererType == QLatin1String( "singlebandpseudocolor" ) )
1000  {
1001  myPseudoColorRenderer = dynamic_cast<QgsSingleBandPseudoColorRenderer *>( rasterRenderer );
1002  if ( !myPseudoColorRenderer )
1003  {
1004  return;
1005  }
1006  myBands << myPseudoColorRenderer->band();
1007  myRasterRenderer = myPseudoColorRenderer;
1008  myMinMaxOrigin = myPseudoColorRenderer->minMaxOrigin();
1009  }
1010  else
1011  {
1012  return;
1013  }
1014 
1015  const auto constMyBands = myBands;
1016  for ( int myBand : constMyBands )
1017  {
1018  if ( myBand != -1 )
1019  {
1020  Qgis::DataType myType = static_cast< Qgis::DataType >( mDataProvider->dataType( myBand ) );
1021  std::unique_ptr<QgsContrastEnhancement> myEnhancement( new QgsContrastEnhancement( static_cast< Qgis::DataType >( myType ) ) );
1022  myEnhancement->setContrastEnhancementAlgorithm( algorithm, generateLookupTableFlag );
1023 
1024  double min;
1025  double max;
1026  computeMinMax( myBand, myMinMaxOrigin, limits, extent, sampleSize, min, max );
1027 
1028  if ( rendererType == QLatin1String( "singlebandpseudocolor" ) )
1029  {
1030  myPseudoColorRenderer->setClassificationMin( min );
1031  myPseudoColorRenderer->setClassificationMax( max );
1032  if ( myPseudoColorRenderer->shader() )
1033  {
1034  QgsColorRampShader *colorRampShader = dynamic_cast<QgsColorRampShader *>( myPseudoColorRenderer->shader()->rasterShaderFunction() );
1035  if ( colorRampShader )
1036  {
1037  colorRampShader->classifyColorRamp( myPseudoColorRenderer->band(), extent, myPseudoColorRenderer->input() );
1038  }
1039  }
1040  }
1041  else
1042  {
1043  myEnhancement->setMinimumValue( min );
1044  myEnhancement->setMaximumValue( max );
1045  myEnhancements.append( myEnhancement.release() );
1046  }
1047  }
1048  else
1049  {
1050  myEnhancements.append( nullptr );
1051  }
1052  }
1053 
1054  if ( rendererType == QLatin1String( "singlebandgray" ) )
1055  {
1056  if ( myEnhancements.first() ) myGrayRenderer->setContrastEnhancement( myEnhancements.takeFirst() );
1057  }
1058  else if ( rendererType == QLatin1String( "multibandcolor" ) )
1059  {
1060  if ( myEnhancements.first() ) myMultiBandRenderer->setRedContrastEnhancement( myEnhancements.takeFirst() );
1061  if ( myEnhancements.first() ) myMultiBandRenderer->setGreenContrastEnhancement( myEnhancements.takeFirst() );
1062  if ( myEnhancements.first() ) myMultiBandRenderer->setBlueContrastEnhancement( myEnhancements.takeFirst() );
1063  }
1064 
1065  //delete all remaining unused enhancements
1066  qDeleteAll( myEnhancements );
1067 
1068  myMinMaxOrigin.setLimits( limits );
1069  if ( extent != QgsRectangle() &&
1070  myMinMaxOrigin.extent() == QgsRasterMinMaxOrigin::WholeRaster )
1071  {
1073  }
1074  if ( myRasterRenderer )
1075  {
1076  myRasterRenderer->setMinMaxOrigin( myMinMaxOrigin );
1077  }
1078 
1079  if ( rasterRenderer == renderer() )
1080  {
1081  emit repaintRequested();
1082  emit styleChanged();
1083  emit rendererChanged();
1084  }
1085 }
1086 
1088 {
1089  QgsSingleBandGrayRenderer *singleBandRenderer = nullptr;
1090  QgsMultiBandColorRenderer *multiBandRenderer = nullptr;
1091  const QgsContrastEnhancement *ce = nullptr;
1092  if ( ( singleBandRenderer = dynamic_cast<QgsSingleBandGrayRenderer *>( renderer() ) ) )
1093  {
1094  ce = singleBandRenderer->contrastEnhancement();
1095  }
1096  else if ( ( multiBandRenderer = dynamic_cast<QgsMultiBandColorRenderer *>( renderer() ) ) )
1097  {
1098  ce = multiBandRenderer->redContrastEnhancement();
1099  }
1100 
1101  if ( ce )
1102  {
1107  extent,
1108  SAMPLE_SIZE,
1109  true,
1110  renderer() );
1111  }
1112  else
1113  {
1116  if ( defaultContrastEnhancementSettings( myAlgorithm, myLimits ) )
1117  {
1119  myLimits,
1120  extent,
1121  SAMPLE_SIZE,
1122  true,
1123  renderer() );
1124  }
1125  }
1126 }
1127 
1129  const QgsRectangle &extent )
1130 {
1131  if ( !( mDataProvider &&
1132  mLastRectangleUsedByRefreshContrastEnhancementIfNeeded != extent &&
1133  rasterRenderer->minMaxOrigin().limits() != QgsRasterMinMaxOrigin::None &&
1134  rasterRenderer->minMaxOrigin().extent() == QgsRasterMinMaxOrigin::UpdatedCanvas ) )
1135  return;
1136 
1137  QgsSingleBandGrayRenderer *singleBandRenderer = nullptr;
1138  QgsMultiBandColorRenderer *multiBandRenderer = nullptr;
1139  QgsSingleBandPseudoColorRenderer *sbpcr = nullptr;
1140  const QgsContrastEnhancement *ce = nullptr;
1141  if ( ( singleBandRenderer = dynamic_cast<QgsSingleBandGrayRenderer *>( rasterRenderer ) ) )
1142  {
1143  ce = singleBandRenderer->contrastEnhancement();
1144  }
1145  else if ( ( multiBandRenderer = dynamic_cast<QgsMultiBandColorRenderer *>( rasterRenderer ) ) )
1146  {
1147  ce = multiBandRenderer->redContrastEnhancement();
1148  }
1149  else if ( ( sbpcr = dynamic_cast<QgsSingleBandPseudoColorRenderer *>( rasterRenderer ) ) )
1150  {
1151  mLastRectangleUsedByRefreshContrastEnhancementIfNeeded = extent;
1152  double min;
1153  double max;
1154  computeMinMax( sbpcr->band(),
1155  rasterRenderer->minMaxOrigin(),
1156  rasterRenderer->minMaxOrigin().limits(), extent,
1157  SAMPLE_SIZE, min, max );
1158  sbpcr->setClassificationMin( min );
1159  sbpcr->setClassificationMax( max );
1160 
1161  if ( sbpcr->shader() )
1162  {
1163  QgsColorRampShader *colorRampShader = dynamic_cast<QgsColorRampShader *>( sbpcr->shader()->rasterShaderFunction() );
1164  if ( colorRampShader )
1165  {
1166  colorRampShader->classifyColorRamp( sbpcr->band(), extent, rasterRenderer->input() );
1167  }
1168  }
1169 
1171  r->setClassificationMin( min );
1172  r->setClassificationMax( max );
1173 
1174  if ( r->shader() )
1175  {
1176  QgsColorRampShader *colorRampShader = dynamic_cast<QgsColorRampShader *>( r->shader()->rasterShaderFunction() );
1177  if ( colorRampShader )
1178  {
1179  colorRampShader->classifyColorRamp( sbpcr->band(), extent, rasterRenderer->input() );
1180  }
1181  }
1182 
1183  emit repaintRequested();
1184  emit styleChanged();
1185  emit rendererChanged();
1186  return;
1187  }
1188 
1189  if ( ce &&
1191  {
1192  mLastRectangleUsedByRefreshContrastEnhancementIfNeeded = extent;
1193 
1195  rasterRenderer->minMaxOrigin().limits(),
1196  extent,
1197  SAMPLE_SIZE,
1198  true,
1199  rasterRenderer );
1200 
1201  // Update main renderer so that the legends get updated
1202  if ( singleBandRenderer )
1203  static_cast<QgsSingleBandGrayRenderer *>( renderer() )->setContrastEnhancement( new QgsContrastEnhancement( * singleBandRenderer->contrastEnhancement() ) );
1204  else if ( multiBandRenderer )
1205  {
1206  if ( multiBandRenderer->redContrastEnhancement() )
1207  {
1208  static_cast<QgsMultiBandColorRenderer *>( renderer() )->setRedContrastEnhancement( new QgsContrastEnhancement( *multiBandRenderer->redContrastEnhancement() ) );
1209  }
1210  if ( multiBandRenderer->greenContrastEnhancement() )
1211  {
1212  static_cast<QgsMultiBandColorRenderer *>( renderer() )->setGreenContrastEnhancement( new QgsContrastEnhancement( *multiBandRenderer->greenContrastEnhancement() ) );
1213  }
1214  if ( multiBandRenderer->blueContrastEnhancement() )
1215  {
1216  static_cast<QgsMultiBandColorRenderer *>( renderer() )->setBlueContrastEnhancement( new QgsContrastEnhancement( *multiBandRenderer->blueContrastEnhancement() ) );
1217  }
1218  }
1219 
1220  emit styleChanged();
1221  emit rendererChanged();
1222  }
1223 }
1224 
1227  QgsRasterMinMaxOrigin::Limits &myLimits ) const
1228 {
1229  QgsSettings mySettings;
1230 
1231  QString key;
1232  QString defaultAlg;
1233  QString defaultLimits;
1234 
1235  // TODO: we should not test renderer class here, move it somehow to renderers
1236  if ( dynamic_cast<QgsSingleBandGrayRenderer *>( renderer() ) )
1237  {
1238  key = QStringLiteral( "singleBand" );
1241  defaultLimits = QgsRasterMinMaxOrigin::limitsString(
1243  }
1244  else if ( dynamic_cast<QgsMultiBandColorRenderer *>( renderer() ) )
1245  {
1246  if ( QgsRasterBlock::typeSize( dataProvider()->sourceDataType( 1 ) ) == 1 )
1247  {
1248  key = QStringLiteral( "multiBandSingleByte" );
1251  defaultLimits = QgsRasterMinMaxOrigin::limitsString(
1253  }
1254  else
1255  {
1256  key = QStringLiteral( "multiBandMultiByte" );
1259  defaultLimits = QgsRasterMinMaxOrigin::limitsString(
1261  }
1262  }
1263 
1264  if ( key.isEmpty() )
1265  {
1266  QgsDebugMsg( QStringLiteral( "No default contrast enhancement for this drawing style" ) );
1268  myLimits = QgsRasterMinMaxOrigin::limitsFromString( QString() );
1269  return false;
1270  }
1271  QgsDebugMsgLevel( "key = " + key, 4 );
1272 
1273  QString myAlgorithmString = mySettings.value( "/Raster/defaultContrastEnhancementAlgorithm/" + key, defaultAlg ).toString();
1274  QgsDebugMsgLevel( "myAlgorithmString = " + myAlgorithmString, 4 );
1275 
1276  myAlgorithm = QgsContrastEnhancement::contrastEnhancementAlgorithmFromString( myAlgorithmString );
1277 
1278  QString myLimitsString = mySettings.value( "/Raster/defaultContrastEnhancementLimits/" + key, defaultLimits ).toString();
1279  QgsDebugMsgLevel( "myLimitsString = " + myLimitsString, 4 );
1280  myLimits = QgsRasterMinMaxOrigin::limitsFromString( myLimitsString );
1281 
1282  return true;
1283 }
1284 
1286 {
1287  QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
1288 
1291  defaultContrastEnhancementSettings( myAlgorithm, myLimits );
1292 
1293  setContrastEnhancement( myAlgorithm, myLimits );
1294 }
1295 
1296 void QgsRasterLayer::setLayerOrder( QStringList const &layers )
1297 {
1298  QgsDebugMsgLevel( QStringLiteral( "entered." ), 4 );
1299 
1300  if ( mDataProvider )
1301  {
1302  QgsDebugMsgLevel( QStringLiteral( "About to mDataProvider->setLayerOrder(layers)." ), 4 );
1303  mDataProvider->setLayerOrder( layers );
1304  }
1305 
1306 }
1307 
1308 void QgsRasterLayer::setSubLayerVisibility( const QString &name, bool vis )
1309 {
1310 
1311  if ( mDataProvider )
1312  {
1313  QgsDebugMsgLevel( QStringLiteral( "About to mDataProvider->setSubLayerVisibility(name, vis)." ), 4 );
1314  mDataProvider->setSubLayerVisibility( name, vis );
1315  }
1316 
1317 }
1318 
1319 QDateTime QgsRasterLayer::timestamp() const
1320 {
1321  if ( !mDataProvider )
1322  return QDateTime();
1323  return mDataProvider->timestamp();
1324 }
1325 
1327 {
1328  if ( mPipe.renderer() )
1329  {
1330  if ( !mPipe.renderer()->accept( visitor ) )
1331  return false;
1332  }
1333  return true;
1334 }
1335 
1336 
1337 bool QgsRasterLayer::writeSld( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsStringMap &props ) const
1338 {
1339  Q_UNUSED( errorMessage )
1340 
1341  QgsStringMap localProps = QgsStringMap( props );
1342  if ( hasScaleBasedVisibility() )
1343  {
1344  // TODO: QgsSymbolLayerUtils::mergeScaleDependencies generate SE only and not SLD1.0
1346  }
1347 
1348  if ( isSpatial() ) // TODO: does it make sense this control?
1349  {
1350  // store constraints
1351  QDomElement constraintElem = doc.createElement( QStringLiteral( "sld:LayerFeatureConstraints" ) );
1352  node.appendChild( constraintElem );
1353 
1354  QDomElement featureTypeConstraintElem = doc.createElement( QStringLiteral( "sld:FeatureTypeConstraint" ) );
1355  constraintElem.appendChild( featureTypeConstraintElem );
1356 
1357  QDomElement userStyleElem = doc.createElement( QStringLiteral( "sld:UserStyle" ) );
1358  node.appendChild( userStyleElem );
1359 
1360  if ( !name().isEmpty() )
1361  {
1362  QDomElement nameElem = doc.createElement( QStringLiteral( "sld:Name" ) );
1363  nameElem.appendChild( doc.createTextNode( name() ) );
1364  userStyleElem.appendChild( nameElem );
1365  }
1366 
1367  if ( !abstract().isEmpty() )
1368  {
1369  QDomElement abstractElem = doc.createElement( QStringLiteral( "sld:Abstract" ) );
1370  abstractElem.appendChild( doc.createTextNode( abstract() ) );
1371  userStyleElem.appendChild( abstractElem );
1372  }
1373 
1374  if ( !title().isEmpty() )
1375  {
1376  QDomElement titleElem = doc.createElement( QStringLiteral( "sld:Title" ) );
1377  titleElem.appendChild( doc.createTextNode( title() ) );
1378  userStyleElem.appendChild( titleElem );
1379  }
1380 
1381  QDomElement featureTypeStyleElem = doc.createElement( QStringLiteral( "sld:FeatureTypeStyle" ) );
1382  userStyleElem.appendChild( featureTypeStyleElem );
1383 
1384 #if 0
1385  // TODO: Is there a way to fill it's value with the named style?
1386  // by default <sld:Name> under <sld:FeatureTypeStyle> can have 0 occurrences
1387  // the same happen for tags:
1388  // sld:Title
1389  // sld:Abstract
1390  // sld:FeatureTypeName
1391  // sld:SemanticTypeIdentifier
1392  QDomElement typeStyleNameElem = doc.createElement( QStringLiteral( "sld:Name" ) );
1393  featureTypeStyleElem.appendChild( typeStyleNameElem );
1394 #endif
1395 
1396  QDomElement typeStyleRuleElem = doc.createElement( QStringLiteral( "sld:Rule" ) );
1397  featureTypeStyleElem.appendChild( typeStyleRuleElem );
1398 
1399  // add ScaleDenominator tags
1400  if ( hasScaleBasedVisibility() )
1401  {
1402  // note that denominator is the inverted value of scale
1403  if ( maximumScale() != 0.0 )
1404  {
1405  QDomElement minScaleElem = doc.createElement( QStringLiteral( "sld:MinScaleDenominator" ) );
1406  minScaleElem.appendChild( doc.createTextNode( QString::number( maximumScale() ) ) );
1407  typeStyleRuleElem.appendChild( minScaleElem );
1408  }
1409 
1410  QDomElement maxScaleElem = doc.createElement( QStringLiteral( "sld:MaxScaleDenominator" ) );
1411  maxScaleElem.appendChild( doc.createTextNode( QString::number( minimumScale() ) ) );
1412  typeStyleRuleElem.appendChild( maxScaleElem );
1413  }
1414 
1415  // export renderer dependent tags
1416  mPipe.renderer()->toSld( doc, typeStyleRuleElem, localProps );
1417 
1418  // inject raster layer parameters in RasterSymbolizer tag because
1419  // they belongs to rasterlayer and not to the renderer => avoid to
1420  // pass many parameters value via localProps
1421  QDomNodeList elements = typeStyleRuleElem.elementsByTagName( QStringLiteral( "sld:RasterSymbolizer" ) );
1422  if ( elements.size() != 0 )
1423  {
1424  // there SHOULD be only one
1425  QDomElement rasterSymbolizerElem = elements.at( 0 ).toElement();
1426 
1427  // lamda helper used below to reduce code redundancy
1428  auto vendorOptionWriter = [&]( QString name, QString value )
1429  {
1430  QDomElement vendorOptionElem = doc.createElement( QStringLiteral( "sld:VendorOption" ) );
1431  vendorOptionElem.setAttribute( QStringLiteral( "name" ), name );
1432  vendorOptionElem.appendChild( doc.createTextNode( value ) );
1433  rasterSymbolizerElem.appendChild( vendorOptionElem );
1434  };
1435 
1436  // add greyScale rendering mode if set
1437  if ( hueSaturationFilter()->grayscaleMode() != QgsHueSaturationFilter::GrayscaleOff )
1438  {
1439  QString property;
1440  switch ( hueSaturationFilter()->grayscaleMode() )
1441  {
1443  property = QStringLiteral( "lightness" );
1444  break;
1446  property = QStringLiteral( "luminosity" );
1447  break;
1449  property = QStringLiteral( "average" );
1450  break;
1452  // added just to avoid travis fail
1453  break;
1454  }
1455  if ( !property.isEmpty() )
1456  vendorOptionWriter( QStringLiteral( "grayScale" ), property );
1457  }
1458 
1459  // add Hue, Saturation and Lighting values in props is Hue filter is set
1461  {
1462  vendorOptionWriter( QStringLiteral( "colorizeOn" ), QString::number( hueSaturationFilter()->colorizeOn() ) );
1463  vendorOptionWriter( QStringLiteral( "colorizeRed" ), QString::number( hueSaturationFilter()->colorizeColor().red() ) );
1464  vendorOptionWriter( QStringLiteral( "colorizeGreen" ), QString::number( hueSaturationFilter()->colorizeColor().green() ) );
1465  vendorOptionWriter( QStringLiteral( "colorizeBlue" ), QString::number( hueSaturationFilter()->colorizeColor().blue() ) );
1466  if ( hueSaturationFilter()->colorizeStrength() != 100.0 )
1467  vendorOptionWriter( QStringLiteral( "colorizeStrength" ), QString::number( hueSaturationFilter()->colorizeStrength() / 100.0 ) );
1468  vendorOptionWriter( QStringLiteral( "saturation" ), QString::number( hueSaturationFilter()->colorizeColor().saturationF() ) );
1469  }
1470  else
1471  {
1472  // saturation != 0 (default value)
1473  if ( hueSaturationFilter()->saturation() != 0 )
1474  {
1475  // normlize value [-100:100] -> [0:1]
1476  int s = hueSaturationFilter()->saturation();
1477  double sF = ( s - ( -100.0 ) ) / ( 100.0 - ( -100.0 ) );
1478  vendorOptionWriter( QStringLiteral( "saturation" ), QString::number( sF ) );
1479  }
1480  }
1481 
1482  // brightness != 0 (default value)
1483  if ( brightnessFilter()->brightness() != 0 )
1484  {
1485  // normalize value [-255:255] -> [0:1]
1486  int b = brightnessFilter()->brightness();
1487  double bF = ( b - ( -255.0 ) ) / ( 255.0 - ( -255.0 ) );
1488  vendorOptionWriter( QStringLiteral( "brightness" ), QString::number( bF ) );
1489  }
1490 
1491  // contrast != 0 (default value)
1492  if ( brightnessFilter()->contrast() != 0 )
1493  {
1494  // normlize value [-100:100] -> [0:1]
1495  int c = brightnessFilter()->contrast();
1496  double cF = ( c - ( -100.0 ) ) / ( 100.0 - ( -100.0 ) );
1497  vendorOptionWriter( QStringLiteral( "contrast" ), QString::number( cF ) );
1498  }
1499 
1500 #if 0
1501  // TODO: check if the below mapping formula make sense to map QGIS contrast with SLD gamma value
1502  //
1503  // add SLD1.0 ContrastEnhancement GammaValue = QGIS Contrast
1504  // SLD1.0 does only define 1 as neutral/center double value but does not define range.
1505  // because https://en.wikipedia.org/wiki/Gamma_correction assumed gamma is >0.
1506  // whilst QGIS has a -100/100 values centered in 0 => QGIS contrast value will be scaled in the
1507  // following way:
1508  // [-100,0] => [0,1] and [0,100] => [1,100]
1509  // an alternative could be scale [-100,100] => (0,2]
1510  //
1511  if ( newProps.contains( QStringLiteral( "contrast" ) ) )
1512  {
1513  double gamma;
1514  double contrast = newProps[ QStringLiteral( "contrast" ) ].toDouble();
1515  double percentage = ( contrast - ( -100.0 ) ) / ( 100.0 - ( -100.0 ) );
1516  if ( percentage <= 0.5 )
1517  {
1518  // stretch % to [0-1]
1519  gamma = percentage / 0.5;
1520  }
1521  else
1522  {
1523  gamma = contrast;
1524  }
1525 
1526  QDomElement globalContrastEnhancementElem = doc.createElement( QStringLiteral( "sld:ContrastEnhancement" ) );
1527  rasterSymolizerElem.appendChild( globalContrastEnhancementElem );
1528 
1529  QDomElement gammaValueElem = doc.createElement( QStringLiteral( "sld:GammaValue" ) );
1530  gammaValueElem.appendChild( doc.createTextNode( QString::number( gamma ) ) );
1531  globalContrastEnhancementElem.appendChild( gammaValueElem );
1532  }
1533 #endif
1534  }
1535  }
1536  return true;
1537 }
1538 
1539 
1541 {
1542  QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
1543  if ( !renderer )
1544  {
1545  return;
1546  }
1547 
1548  mPipe.set( renderer );
1549  emit rendererChanged();
1550  emit styleChanged();
1551 }
1552 
1553 void QgsRasterLayer::showStatusMessage( QString const &message )
1554 {
1555  // QgsDebugMsg(QString("entered with '%1'.").arg(theMessage));
1556 
1557  // Pass-through
1558  // TODO: See if we can connect signal-to-signal. This is a kludge according to the Qt doc.
1559  emit statusChanged( message );
1560 }
1561 
1563 {
1564  if ( mDataProvider )
1565  mDataProvider->setTransformContext( transformContext );
1566 }
1567 
1568 QStringList QgsRasterLayer::subLayers() const
1569 {
1570  if ( ! mDataProvider )
1571  return QStringList();
1572  return mDataProvider->subLayers();
1573 }
1574 
1575 // this function should be used when rendering with the MTR engine introduced in 2.3, as QPixmap is not thread safe (see bug #9626)
1576 // note: previewAsImage and previewAsPixmap should use a common low-level fct QgsRasterLayer::previewOnPaintDevice( QSize size, QColor bgColor, QPaintDevice &device )
1577 QImage QgsRasterLayer::previewAsImage( QSize size, const QColor &bgColor, QImage::Format format )
1578 {
1579  QImage image( size, format );
1580 
1581  if ( ! isValid( ) )
1582  return QImage();
1583 
1584  if ( image.format() == QImage::Format_Indexed8 )
1585  {
1586  image.setColor( 0, bgColor.rgba() );
1587  image.fill( 0 ); //defaults to white, set to transparent for rendering on a map
1588  }
1589  else
1590  {
1591  image.fill( bgColor );
1592  }
1593 
1594  QgsRasterViewPort *rasterViewPort = new QgsRasterViewPort();
1595 
1596  double mapUnitsPerPixel;
1597  double x = 0.0;
1598  double y = 0.0;
1599  QgsRectangle extent = mDataProvider->extent();
1600  if ( extent.width() / extent.height() >= static_cast< double >( image.width() ) / image.height() )
1601  {
1602  mapUnitsPerPixel = extent.width() / image.width();
1603  y = ( image.height() - extent.height() / mapUnitsPerPixel ) / 2;
1604  }
1605  else
1606  {
1607  mapUnitsPerPixel = extent.height() / image.height();
1608  x = ( image.width() - extent.width() / mapUnitsPerPixel ) / 2;
1609  }
1610 
1611  const double pixelWidth = extent.width() / mapUnitsPerPixel;
1612  const double pixelHeight = extent.height() / mapUnitsPerPixel;
1613 
1614  rasterViewPort->mTopLeftPoint = QgsPointXY( x, y );
1615  rasterViewPort->mBottomRightPoint = QgsPointXY( pixelWidth, pixelHeight );
1616  rasterViewPort->mWidth = image.width();
1617  rasterViewPort->mHeight = image.height();
1618 
1619  rasterViewPort->mDrawnExtent = extent;
1620  rasterViewPort->mSrcCRS = QgsCoordinateReferenceSystem(); // will be invalid
1621  rasterViewPort->mDestCRS = QgsCoordinateReferenceSystem(); // will be invalid
1622 
1623  QgsMapToPixel *mapToPixel = new QgsMapToPixel( mapUnitsPerPixel );
1624 
1625  QPainter *painter = new QPainter( &image );
1626  draw( painter, rasterViewPort, mapToPixel );
1627  delete rasterViewPort;
1628  delete mapToPixel;
1629 
1630  painter->end();
1631  delete painter;
1632 
1633  return image;
1634 }
1635 
1637 //
1638 // Protected methods
1639 //
1641 /*
1642  * \param QDomNode node that will contain the symbology definition for this layer.
1643  * \param errorMessage reference to string that will be updated with any error messages
1644  * \return true in case of success.
1645  */
1646 bool QgsRasterLayer::readSymbology( const QDomNode &layer_node, QString &errorMessage,
1647  QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
1648 {
1649  Q_UNUSED( errorMessage )
1650  // TODO: implement categories for raster layer
1651 
1652  QDomElement rasterRendererElem;
1653 
1654  QDomElement layerElement = layer_node.toElement();
1655  readCommonStyle( layerElement, context, categories );
1656 
1657  // pipe element was introduced in the end of 1.9 development when there were
1658  // already many project files in use so we support 1.9 backward compatibility
1659  // even it was never officially released -> use pipe element if present, otherwise
1660  // use layer node
1661  QDomNode pipeNode = layer_node.firstChildElement( QStringLiteral( "pipe" ) );
1662  if ( pipeNode.isNull() ) // old project
1663  {
1664  pipeNode = layer_node;
1665  }
1666 
1667  //rasterlayerproperties element there -> old format (1.8 and early 1.9)
1668  if ( !layer_node.firstChildElement( QStringLiteral( "rasterproperties" ) ).isNull() )
1669  {
1670  //copy node because layer_node is const
1671  QDomNode layerNodeCopy = layer_node.cloneNode();
1672  QDomDocument doc = layerNodeCopy.ownerDocument();
1673  QDomElement rasterPropertiesElem = layerNodeCopy.firstChildElement( QStringLiteral( "rasterproperties" ) );
1674  QgsProjectFileTransform::convertRasterProperties( doc, layerNodeCopy, rasterPropertiesElem,
1675  this );
1676  rasterRendererElem = layerNodeCopy.firstChildElement( QStringLiteral( "rasterrenderer" ) );
1677  QgsDebugMsgLevel( doc.toString(), 4 );
1678  }
1679  else
1680  {
1681  rasterRendererElem = pipeNode.firstChildElement( QStringLiteral( "rasterrenderer" ) );
1682  }
1683 
1684  if ( !rasterRendererElem.isNull() )
1685  {
1686  QString rendererType = rasterRendererElem.attribute( QStringLiteral( "type" ) );
1687  QgsRasterRendererRegistryEntry rendererEntry;
1688  if ( QgsApplication::rasterRendererRegistry()->rendererData( rendererType, rendererEntry ) )
1689  {
1690  QgsRasterRenderer *renderer = rendererEntry.rendererCreateFunction( rasterRendererElem, dataProvider() );
1691  mPipe.set( renderer );
1692  }
1693  }
1694 
1695  //brightness
1697  mPipe.set( brightnessFilter );
1698 
1699  //brightness coefficient
1700  QDomElement brightnessElem = pipeNode.firstChildElement( QStringLiteral( "brightnesscontrast" ) );
1701  if ( !brightnessElem.isNull() )
1702  {
1703  brightnessFilter->readXml( brightnessElem );
1704  }
1705 
1706  //hue/saturation
1708  mPipe.set( hueSaturationFilter );
1709 
1710  //saturation coefficient
1711  QDomElement hueSaturationElem = pipeNode.firstChildElement( QStringLiteral( "huesaturation" ) );
1712  if ( !hueSaturationElem.isNull() )
1713  {
1714  hueSaturationFilter->readXml( hueSaturationElem );
1715  }
1716 
1717  //resampler
1719  mPipe.set( resampleFilter );
1720 
1721  //max oversampling
1722  QDomElement resampleElem = pipeNode.firstChildElement( QStringLiteral( "rasterresampler" ) );
1723  if ( !resampleElem.isNull() )
1724  {
1725  resampleFilter->readXml( resampleElem );
1726  }
1727 
1728  // get and set the blend mode if it exists
1729  QDomNode blendModeNode = layer_node.namedItem( QStringLiteral( "blendMode" ) );
1730  if ( !blendModeNode.isNull() )
1731  {
1732  QDomElement e = blendModeNode.toElement();
1733  setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( e.text().toInt() ) ) );
1734  }
1735 
1736  readCustomProperties( layer_node );
1737 
1738  return true;
1739 }
1740 
1741 bool QgsRasterLayer::readStyle( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
1742 {
1743  return readSymbology( node, errorMessage, context, categories );
1744 }
1745 
1746 bool QgsRasterLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
1747 {
1748  QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
1749  // Make sure to read the file first so stats etc are initialized properly!
1750 
1751  //process provider key
1752  QDomNode pkeyNode = layer_node.namedItem( QStringLiteral( "provider" ) );
1753 
1754  if ( pkeyNode.isNull() )
1755  {
1756  mProviderKey = QStringLiteral( "gdal" );
1757  }
1758  else
1759  {
1760  QDomElement pkeyElt = pkeyNode.toElement();
1761  mProviderKey = pkeyElt.text();
1762  if ( mProviderKey.isEmpty() )
1763  {
1764  mProviderKey = QStringLiteral( "gdal" );
1765  }
1766  }
1767 
1768  // Open the raster source based on provider and datasource
1769 
1770  // Go down the raster-data-provider paradigm
1771 
1772  // Collect provider-specific information
1773 
1774  QDomNode rpNode = layer_node.namedItem( QStringLiteral( "rasterproperties" ) );
1775 
1776  if ( mProviderKey == QLatin1String( "wms" ) )
1777  {
1778  // >>> BACKWARD COMPATIBILITY < 1.9
1779  // The old WMS URI format does not contain all the information, we add them here.
1780  if ( !mDataSource.contains( QLatin1String( "crs=" ) ) && !mDataSource.contains( QLatin1String( "format=" ) ) )
1781  {
1782  QgsDebugMsgLevel( QStringLiteral( "Old WMS URI format detected -> adding params" ), 4 );
1783  QgsDataSourceUri uri;
1784  uri.setEncodedUri( mDataSource );
1785  QDomElement layerElement = rpNode.firstChildElement( QStringLiteral( "wmsSublayer" ) );
1786  while ( !layerElement.isNull() )
1787  {
1788  // TODO: sublayer visibility - post-0.8 release timeframe
1789 
1790  // collect name for the sublayer
1791  uri.setParam( QStringLiteral( "layers" ), layerElement.namedItem( QStringLiteral( "name" ) ).toElement().text() );
1792 
1793  // collect style for the sublayer
1794  uri.setParam( QStringLiteral( "styles" ), layerElement.namedItem( QStringLiteral( "style" ) ).toElement().text() );
1795 
1796  layerElement = layerElement.nextSiblingElement( QStringLiteral( "wmsSublayer" ) );
1797  }
1798 
1799  // Collect format
1800  uri.setParam( QStringLiteral( "format" ), rpNode.namedItem( QStringLiteral( "wmsFormat" ) ).toElement().text() );
1801 
1802  // WMS CRS URL param should not be mixed with that assigned to the layer.
1803  // In the old WMS URI version there was no CRS and layer crs().authid() was used.
1804  uri.setParam( QStringLiteral( "crs" ), crs().authid() );
1805  mDataSource = uri.encodedUri();
1806  }
1807  // <<< BACKWARD COMPATIBILITY < 1.9
1808  }
1809 
1811  {
1812  QgsDataProvider::ProviderOptions providerOptions { context.transformContext() };
1813  setDataProvider( mProviderKey, providerOptions );
1814  }
1815 
1816  mOriginalStyleElement = layer_node.namedItem( QStringLiteral( "originalStyle" ) ).firstChildElement();
1817  if ( mOriginalStyleElement.isNull() )
1818  mOriginalStyleElement = layer_node.toElement();
1819  mOriginalStyleDocument = layer_node.ownerDocument();
1820 
1821  if ( ! mDataProvider )
1822  {
1823  if ( !( mReadFlags & QgsMapLayer::FlagDontResolveLayers ) )
1824  {
1825  QgsDebugMsg( QStringLiteral( "Raster data provider could not be created for %1" ).arg( mDataSource ) );
1826  }
1827  return false;
1828  }
1829 
1830  QString error;
1831  bool res = readSymbology( layer_node, error, context );
1832 
1833  // old wms settings we need to correct
1834  if ( res && mProviderKey == QLatin1String( "wms" ) && ( !renderer() || renderer()->type() != QLatin1String( "singlebandcolordata" ) ) )
1835  {
1836  setRendererForDrawingStyle( QgsRaster::SingleBandColorDataStyle );
1837  }
1838 
1839  // Check timestamp
1840  // This was probably introduced to reload completely raster if data changed and
1841  // reset completely symbology to reflect new data type etc. It creates however
1842  // problems, because user defined symbology is complete lost if data file time
1843  // changed (the content may be the same). See also 6900.
1844 #if 0
1845  QDomNode stampNode = layer_node.namedItem( "timestamp" );
1846  if ( !stampNode.isNull() )
1847  {
1848  QDateTime stamp = QDateTime::fromString( stampNode.toElement().text(), Qt::ISODate );
1849  // TODO: very bad, we have to load twice!!! Make QgsDataProvider::timestamp() static?
1850  if ( stamp < mDataProvider->dataTimestamp() )
1851  {
1852  QgsDebugMsgLevel( QStringLiteral( "data changed, reload provider" ), 3 );
1853  closeDataProvider();
1854  init();
1856  if ( !mValid ) return false;
1857  }
1858  }
1859 #endif
1860 
1861  // Load user no data value
1862  QDomElement noDataElement = layer_node.firstChildElement( QStringLiteral( "noData" ) );
1863 
1864  QDomNodeList noDataBandList = noDataElement.elementsByTagName( QStringLiteral( "noDataList" ) );
1865 
1866  for ( int i = 0; i < noDataBandList.size(); ++i )
1867  {
1868  QDomElement bandElement = noDataBandList.at( i ).toElement();
1869  bool ok;
1870  int bandNo = bandElement.attribute( QStringLiteral( "bandNo" ) ).toInt( &ok );
1871  QgsDebugMsgLevel( QStringLiteral( "bandNo = %1" ).arg( bandNo ), 4 );
1872  if ( ok && ( bandNo > 0 ) && ( bandNo <= mDataProvider->bandCount() ) )
1873  {
1874  mDataProvider->setUseSourceNoDataValue( bandNo, bandElement.attribute( QStringLiteral( "useSrcNoData" ) ).toInt() );
1875  QgsRasterRangeList myNoDataRangeList;
1876 
1877  QDomNodeList rangeList = bandElement.elementsByTagName( QStringLiteral( "noDataRange" ) );
1878 
1879  myNoDataRangeList.reserve( rangeList.size() );
1880  for ( int j = 0; j < rangeList.size(); ++j )
1881  {
1882  QDomElement rangeElement = rangeList.at( j ).toElement();
1883  QgsRasterRange myNoDataRange( rangeElement.attribute( QStringLiteral( "min" ) ).toDouble(),
1884  rangeElement.attribute( QStringLiteral( "max" ) ).toDouble() );
1885  QgsDebugMsgLevel( QStringLiteral( "min = %1 %2" ).arg( rangeElement.attribute( "min" ) ).arg( myNoDataRange.min() ), 4 );
1886  myNoDataRangeList << myNoDataRange;
1887  }
1888  mDataProvider->setUserNoDataValue( bandNo, myNoDataRangeList );
1889  }
1890  }
1891 
1892  readStyleManager( layer_node );
1893 
1894  return res;
1895 }
1896 
1897 bool QgsRasterLayer::writeSymbology( QDomNode &layer_node, QDomDocument &document, QString &errorMessage,
1898  const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1899 {
1900  Q_UNUSED( errorMessage )
1901  // TODO: implement categories for raster layer
1902 
1903  QDomElement layerElement = layer_node.toElement();
1904  writeCommonStyle( layerElement, document, context, categories );
1905 
1906  // Store pipe members (except provider) into pipe element, in future, it will be
1907  // possible to add custom filters into the pipe
1908  QDomElement pipeElement = document.createElement( QStringLiteral( "pipe" ) );
1909 
1910  for ( int i = 1; i < mPipe.size(); i++ )
1911  {
1912  QgsRasterInterface *interface = mPipe.at( i );
1913  if ( !interface ) continue;
1914  interface->writeXml( document, pipeElement );
1915  }
1916 
1917  layer_node.appendChild( pipeElement );
1918 
1919  if ( !isValid() && !mOriginalStyleElement.isNull() )
1920  {
1921  QDomElement originalStyleElement = document.createElement( QStringLiteral( "originalStyle" ) );
1922  originalStyleElement.appendChild( mOriginalStyleElement );
1923  layer_node.appendChild( originalStyleElement );
1924  }
1925 
1926  // add blend mode node
1927  QDomElement blendModeElement = document.createElement( QStringLiteral( "blendMode" ) );
1928  QDomText blendModeText = document.createTextNode( QString::number( QgsPainting::getBlendModeEnum( blendMode() ) ) );
1929  blendModeElement.appendChild( blendModeText );
1930  layer_node.appendChild( blendModeElement );
1931  return true;
1932 }
1933 
1934 bool QgsRasterLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage,
1935  const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1936 {
1937  return writeSymbology( node, doc, errorMessage, context, categories );
1938 } // bool QgsRasterLayer::writeSymbology
1939 
1940 /*
1941  * virtual
1942  * \note Called by QgsMapLayer::writeXml().
1943  */
1944 bool QgsRasterLayer::writeXml( QDomNode &layer_node,
1945  QDomDocument &document,
1946  const QgsReadWriteContext &context ) const
1947 {
1948  // first get the layer element so that we can append the type attribute
1949 
1950  QDomElement mapLayerNode = layer_node.toElement();
1951 
1952  if ( mapLayerNode.isNull() || "maplayer" != mapLayerNode.nodeName() )
1953  {
1954  QgsMessageLog::logMessage( tr( "<maplayer> not found." ), tr( "Raster" ) );
1955  return false;
1956  }
1957 
1958  mapLayerNode.setAttribute( QStringLiteral( "type" ), QStringLiteral( "raster" ) );
1959 
1960  // add provider node
1961 
1962  QDomElement provider = document.createElement( QStringLiteral( "provider" ) );
1963  QDomText providerText = document.createTextNode( mProviderKey );
1964  provider.appendChild( providerText );
1965  layer_node.appendChild( provider );
1966 
1967  // User no data
1968  QDomElement noData = document.createElement( QStringLiteral( "noData" ) );
1969 
1970  for ( int bandNo = 1; bandNo <= mDataProvider->bandCount(); bandNo++ )
1971  {
1972  QDomElement noDataRangeList = document.createElement( QStringLiteral( "noDataList" ) );
1973  noDataRangeList.setAttribute( QStringLiteral( "bandNo" ), bandNo );
1974  noDataRangeList.setAttribute( QStringLiteral( "useSrcNoData" ), mDataProvider->useSourceNoDataValue( bandNo ) );
1975 
1976  const auto constUserNoDataValues = mDataProvider->userNoDataValues( bandNo );
1977  for ( QgsRasterRange range : constUserNoDataValues )
1978  {
1979  QDomElement noDataRange = document.createElement( QStringLiteral( "noDataRange" ) );
1980 
1981  noDataRange.setAttribute( QStringLiteral( "min" ), QgsRasterBlock::printValue( range.min() ) );
1982  noDataRange.setAttribute( QStringLiteral( "max" ), QgsRasterBlock::printValue( range.max() ) );
1983  noDataRangeList.appendChild( noDataRange );
1984  }
1985 
1986  noData.appendChild( noDataRangeList );
1987 
1988  }
1989  if ( noData.hasChildNodes() )
1990  {
1991  layer_node.appendChild( noData );
1992  }
1993 
1994  writeStyleManager( layer_node, document );
1995 
1996  //write out the symbology
1997  QString errorMsg;
1998  return writeSymbology( layer_node, document, errorMsg, context );
1999 }
2000 
2001 // TODO: this should ideally go to gdal provider (together with most of encodedSource() + decodedSource())
2002 static bool _parseGpkgColons( const QString &src, QString &filename, QString &tablename )
2003 {
2004  // GDAL accepts the following input format: GPKG:filename:table
2005  // (GDAL won't accept quoted filename)
2006 
2007  QStringList lst = src.split( ':' );
2008  if ( lst.count() != 3 && lst.count() != 4 )
2009  return false;
2010 
2011  tablename = lst.last();
2012  if ( lst.count() == 3 )
2013  {
2014  filename = lst[1];
2015  return true;
2016  }
2017  else if ( lst.count() == 4 && lst[1].count() == 1 && ( lst[2][0] == '/' || lst[2][0] == '\\' ) )
2018  {
2019  // a bit of handling to make sure that filename C:\hello.gpkg is parsed correctly
2020  filename = lst[1] + ":" + lst[2];
2021  return true;
2022  }
2023  return false;
2024 }
2025 
2026 
2027 QString QgsRasterLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
2028 {
2029  QString src( source );
2030  bool handled = false;
2031 
2032  // Update path for subdataset
2033  if ( providerType() == QLatin1String( "gdal" ) )
2034  {
2035  if ( src.startsWith( QLatin1String( "NETCDF:" ) ) )
2036  {
2037  // NETCDF:filename:variable
2038  // filename can be quoted with " as it can contain colons
2039  QRegExp r( "NETCDF:(.+):([^:]+)" );
2040  if ( r.exactMatch( src ) )
2041  {
2042  QString filename = r.cap( 1 );
2043  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
2044  filename = filename.mid( 1, filename.length() - 2 );
2045  src = "NETCDF:\"" + context.pathResolver().writePath( filename ) + "\":" + r.cap( 2 );
2046  handled = true;
2047  }
2048  }
2049  else if ( src.startsWith( QLatin1String( "GPKG:" ) ) )
2050  {
2051  // GPKG:filename:table
2052  QString filename, tablename;
2053  if ( _parseGpkgColons( src, filename, tablename ) )
2054  {
2055  filename = context.pathResolver().writePath( filename );
2056  src = QStringLiteral( "GPKG:%1:%2" ).arg( filename, tablename );
2057  handled = true;
2058  }
2059  }
2060  else if ( src.startsWith( QLatin1String( "HDF4_SDS:" ) ) )
2061  {
2062  // HDF4_SDS:subdataset_type:file_name:subdataset_index
2063  // filename can be quoted with " as it can contain colons
2064  QRegExp r( "HDF4_SDS:([^:]+):(.+):([^:]+)" );
2065  if ( r.exactMatch( src ) )
2066  {
2067  QString filename = r.cap( 2 );
2068  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
2069  filename = filename.mid( 1, filename.length() - 2 );
2070  src = "HDF4_SDS:" + r.cap( 1 ) + ":\"" + context.pathResolver().writePath( filename ) + "\":" + r.cap( 3 );
2071  handled = true;
2072  }
2073  }
2074  else if ( src.startsWith( QLatin1String( "HDF5:" ) ) )
2075  {
2076  // HDF5:file_name:subdataset
2077  // filename can be quoted with " as it can contain colons
2078  QRegExp r( "HDF5:(.+):([^:]+)" );
2079  if ( r.exactMatch( src ) )
2080  {
2081  QString filename = r.cap( 1 );
2082  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
2083  filename = filename.mid( 1, filename.length() - 2 );
2084  src = "HDF5:\"" + context.pathResolver().writePath( filename ) + "\":" + r.cap( 2 );
2085  handled = true;
2086  }
2087  }
2088  else if ( src.contains( QRegExp( "^(NITF_IM|RADARSAT_2_CALIB):" ) ) )
2089  {
2090  // NITF_IM:0:filename
2091  // RADARSAT_2_CALIB:?:filename
2092  QRegExp r( "([^:]+):([^:]+):(.+)" );
2093  if ( r.exactMatch( src ) )
2094  {
2095  src = r.cap( 1 ) + ':' + r.cap( 2 ) + ':' + context.pathResolver().writePath( r.cap( 3 ) );
2096  handled = true;
2097  }
2098  }
2099  }
2100  else if ( providerType() == "wms" )
2101  {
2102  // handle relative paths to XYZ tiles
2103  QgsDataSourceUri uri;
2104  uri.setEncodedUri( src );
2105  QUrl srcUrl( uri.param( QStringLiteral( "url" ) ) );
2106  if ( srcUrl.isLocalFile() )
2107  {
2108  // relative path will become "file:./x.txt"
2109  QString relSrcUrl = context.pathResolver().writePath( srcUrl.toLocalFile() );
2110  uri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
2111  uri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( relSrcUrl ).toString() );
2112  src = uri.encodedUri();
2113  handled = true;
2114  }
2115  }
2116 
2117  if ( !handled )
2118  src = context.pathResolver().writePath( src );
2119 
2120  return src;
2121 }
2122 
2123 QString QgsRasterLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
2124 {
2125  QString src( source );
2126 
2127  if ( provider == QLatin1String( "wms" ) )
2128  {
2129  // >>> BACKWARD COMPATIBILITY < 1.9
2130  // For project file backward compatibility we must support old format:
2131  // 1. mode: <url>
2132  // example: http://example.org/wms?
2133  // 2. mode: tiled=<width>;<height>;<resolution>;<resolution>...,ignoreUrl=GetMap;GetFeatureInfo,featureCount=<count>,username=<name>,password=<password>,url=<url>
2134  // example: tiled=256;256;0.703;0.351,url=http://example.org/tilecache?
2135  // example: featureCount=10,http://example.org/wms?
2136  // example: ignoreUrl=GetMap;GetFeatureInfo,username=cimrman,password=jara,url=http://example.org/wms?
2137  // This is modified version of old QgsWmsProvider::parseUri
2138  // The new format has always params crs,format,layers,styles and that params
2139  // should not appear in old format url -> use them to identify version
2140  // XYZ tile layers do not need to contain crs,format params, but they have type=xyz
2141  if ( !src.contains( QLatin1String( "type=" ) ) &&
2142  !src.contains( QLatin1String( "crs=" ) ) && !src.contains( QLatin1String( "format=" ) ) )
2143  {
2144  QgsDebugMsgLevel( QStringLiteral( "Old WMS URI format detected -> converting to new format" ), 2 );
2145  QgsDataSourceUri uri;
2146  if ( !src.startsWith( QLatin1String( "http:" ) ) )
2147  {
2148  QStringList parts = src.split( ',' );
2149  QStringListIterator iter( parts );
2150  while ( iter.hasNext() )
2151  {
2152  QString item = iter.next();
2153  if ( item.startsWith( QLatin1String( "username=" ) ) )
2154  {
2155  uri.setUsername( item.mid( 9 ) );
2156  }
2157  else if ( item.startsWith( QLatin1String( "password=" ) ) )
2158  {
2159  uri.setPassword( item.mid( 9 ) );
2160  }
2161  else if ( item.startsWith( QLatin1String( "tiled=" ) ) )
2162  {
2163  // in < 1.9 tiled= may apper in to variants:
2164  // tiled=width;height - non tiled mode, specifies max width and max height
2165  // tiled=width;height;resolutions-1;resolution2;... - tile mode
2166 
2167  QStringList params = item.mid( 6 ).split( ';' );
2168 
2169  if ( params.size() == 2 ) // non tiled mode
2170  {
2171  uri.setParam( QStringLiteral( "maxWidth" ), params.takeFirst() );
2172  uri.setParam( QStringLiteral( "maxHeight" ), params.takeFirst() );
2173  }
2174  else if ( params.size() > 2 ) // tiled mode
2175  {
2176  // resolutions are no more needed and size limit is not used for tiles
2177  // we have to tell to the provider however that it is tiled
2178  uri.setParam( QStringLiteral( "tileMatrixSet" ), QString() );
2179  }
2180  }
2181  else if ( item.startsWith( QLatin1String( "featureCount=" ) ) )
2182  {
2183  uri.setParam( QStringLiteral( "featureCount" ), item.mid( 13 ) );
2184  }
2185  else if ( item.startsWith( QLatin1String( "url=" ) ) )
2186  {
2187  uri.setParam( QStringLiteral( "url" ), item.mid( 4 ) );
2188  }
2189  else if ( item.startsWith( QLatin1String( "ignoreUrl=" ) ) )
2190  {
2191  uri.setParam( QStringLiteral( "ignoreUrl" ), item.mid( 10 ).split( ';' ) );
2192  }
2193  }
2194  }
2195  else
2196  {
2197  uri.setParam( QStringLiteral( "url" ), src );
2198  }
2199  src = uri.encodedUri();
2200  // At this point, the URI is obviously incomplete, we add additional params
2201  // in QgsRasterLayer::readXml
2202  }
2203  // <<< BACKWARD COMPATIBILITY < 1.9
2204 
2205  // handle relative paths to XYZ tiles
2206  QgsDataSourceUri uri;
2207  uri.setEncodedUri( src );
2208  QUrl srcUrl( uri.param( QStringLiteral( "url" ) ) );
2209  if ( srcUrl.isLocalFile() ) // file-based URL? convert to relative path
2210  {
2211  QString absSrcUrl = context.pathResolver().readPath( srcUrl.toLocalFile() );
2212  uri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
2213  uri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( absSrcUrl ).toString() );
2214  src = uri.encodedUri();
2215  }
2216 
2217  }
2218  else
2219  {
2220  bool handled = false;
2221 
2222  if ( provider == QLatin1String( "gdal" ) )
2223  {
2224  if ( src.startsWith( QLatin1String( "NETCDF:" ) ) )
2225  {
2226  // NETCDF:filename:variable
2227  // filename can be quoted with " as it can contain colons
2228  QRegExp r( "NETCDF:(.+):([^:]+)" );
2229  if ( r.exactMatch( src ) )
2230  {
2231  QString filename = r.cap( 1 );
2232  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
2233  filename = filename.mid( 1, filename.length() - 2 );
2234  src = "NETCDF:\"" + context.pathResolver().readPath( filename ) + "\":" + r.cap( 2 );
2235  handled = true;
2236  }
2237  }
2238  else if ( src.startsWith( QLatin1String( "GPKG:" ) ) )
2239  {
2240  // GPKG:filename:table
2241  QString filename, tablename;
2242  if ( _parseGpkgColons( src, filename, tablename ) )
2243  {
2244  filename = context.pathResolver().readPath( filename );
2245  src = QStringLiteral( "GPKG:%1:%2" ).arg( filename, tablename );
2246  handled = true;
2247  }
2248  }
2249  else if ( src.startsWith( QLatin1String( "HDF4_SDS:" ) ) )
2250  {
2251  // HDF4_SDS:subdataset_type:file_name:subdataset_index
2252  // filename can be quoted with " as it can contain colons
2253  QRegExp r( "HDF4_SDS:([^:]+):(.+):([^:]+)" );
2254  if ( r.exactMatch( src ) )
2255  {
2256  QString filename = r.cap( 2 );
2257  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
2258  filename = filename.mid( 1, filename.length() - 2 );
2259  src = "HDF4_SDS:" + r.cap( 1 ) + ":\"" + context.pathResolver().readPath( filename ) + "\":" + r.cap( 3 );
2260  handled = true;
2261  }
2262  }
2263  else if ( src.startsWith( QLatin1String( "HDF5:" ) ) )
2264  {
2265  // HDF5:file_name:subdataset
2266  // filename can be quoted with " as it can contain colons
2267  QRegExp r( "HDF5:(.+):([^:]+)" );
2268  if ( r.exactMatch( src ) )
2269  {
2270  QString filename = r.cap( 1 );
2271  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
2272  filename = filename.mid( 1, filename.length() - 2 );
2273  src = "HDF5:\"" + context.pathResolver().readPath( filename ) + "\":" + r.cap( 2 );
2274  handled = true;
2275  }
2276  }
2277  else if ( src.contains( QRegExp( "^(NITF_IM|RADARSAT_2_CALIB):" ) ) )
2278  {
2279  // NITF_IM:0:filename
2280  // RADARSAT_2_CALIB:?:filename
2281  QRegExp r( "([^:]+):([^:]+):(.+)" );
2282  if ( r.exactMatch( src ) )
2283  {
2284  src = r.cap( 1 ) + ':' + r.cap( 2 ) + ':' + context.pathResolver().readPath( r.cap( 3 ) );
2285  handled = true;
2286  }
2287  }
2288  }
2289 
2290  if ( !handled )
2291  src = context.pathResolver().readPath( src );
2292  }
2293 
2294  return src;
2295 }
2296 
2298 {
2299  if ( !mDataProvider ) return 0;
2300  return mDataProvider->xSize();
2301 }
2302 
2304 {
2305  if ( !mDataProvider ) return 0;
2306  return mDataProvider->ySize();
2307 }
2308 
2310 //
2311 // Private methods
2312 //
2314 bool QgsRasterLayer::update()
2315 {
2316  QgsDebugMsgLevel( QStringLiteral( "entered." ), 4 );
2317  // Check if data changed
2318  if ( mDataProvider && mDataProvider->dataTimestamp() > mDataProvider->timestamp() )
2319  {
2320  QgsDebugMsgLevel( QStringLiteral( "reload data" ), 4 );
2321  closeDataProvider();
2322  init();
2323  QgsDataProvider::ProviderOptions providerOptions;
2324  setDataProvider( mProviderKey, providerOptions );
2325  emit dataChanged();
2326  }
2327  return mValid;
2328 }
static void mergeScaleDependencies(double mScaleMinDenom, double mScaleMaxDenom, QgsStringMap &props)
Merges the local scale limits, if any, with the ones already in the map, if any.
QgsDataProvider * classFactoryFunction_t(const QString *, const QgsDataProvider::ProviderOptions &options)
QString param(const QString &key) const
Returns a generic parameter value corresponding to the specified key.
static void convertRasterProperties(QDomDocument &doc, QDomNode &parentNode, QDomElement &rasterPropertiesElem, QgsRasterLayer *rlayer)
int width() const
Returns the width of the (unclipped) raster.
QgsRasterMinMaxOrigin::Limits limits() const
Returns the raster limits.
bool shade(double value, int *returnRedValue, int *returnGreenValue, int *returnBlueValue, int *returnAlphaValue) const override
Generates and new RGB value based on one input value.
virtual int bandCount() const =0
Gets number of bands.
QgsRasterMinMaxOrigin::Extent extent() const
Returns the raster extent.
virtual void setSubLayerVisibility(const QString &name, bool vis)
Set the visibility of the given sublayer name.
The class is used as a container of context for various read/write operations on other objects...
#define ERR(message)
QString extentSectionHtml(const bool showSpatialExtent=true) const
Formats the "Extents" section according to a metadata object (extent and temporal).
IdentifyFormat
Definition: qgsraster.h:57
A rectangle specified with double values.
Definition: qgsrectangle.h:41
Base class for all map layer types.
Definition: qgsmaplayer.h:79
Cubic Raster Resampler.
Thirty two bit signed integer (qint32)
Definition: qgis.h:108
Interface for all raster shaders.
void setColorRampItemList(const QList< QgsColorRampShader::ColorRampItem > &list)
Sets a custom colormap.
QgsRasterLayer * clone() const override
Returns a new instance equivalent to this one.
QStringList subLayers() const override
Returns the sublayers of this layer.
static QString printValue(double value)
Print double value with all necessary significant digits.
void refreshContrastEnhancement(const QgsRectangle &extent)
Refresh contrast enhancement with new extent.
virtual void setUseSourceNoDataValue(int bandNo, bool use)
Sets the source nodata value usage.
void setProviderType(const QString &providerType)
Sets the providerType (provider key)
virtual QgsMapLayer * clone() const =0
Returns a new instance equivalent to this one except for the id which is still unique.
QString contactsSectionHtml() const
Formats the "Contacts" section according to a metadata object.
QString historySectionHtml() const
Formats the "History" section according to a metadata object.
void setDataSource(const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag=false) override
Updates the data source of the layer.
const QgsContrastEnhancement * blueContrastEnhancement() const
QgsMapLayerType type() const
Returns the type of the layer.
static Q_INVOKABLE QString toString(QgsUnitTypes::DistanceUnit unit)
Returns a translated string representing a distance unit.
Iterator for sequentially processing raster cells.
QString htmlMetadata() const override
Obtain a formatted HTML string containing assorted metadata for this layer.
static const QgsContrastEnhancement::ContrastEnhancementAlgorithm MULTIPLE_BAND_MULTI_BYTE_ENHANCEMENT_ALGORITHM
Default enhancement algorithm for multiple band raster of type different from Byte.
int bandCount() const
Returns the number of bands in this layer.
virtual void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props=QgsStringMap()) const
Used from subclasses to create SLD Rule elements following SLD v1.0 specs.
void setUsername(const QString &username)
Sets the username for the URI.
bool readStyle(const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) override
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
virtual bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
QgsHueSaturationFilter * hueSaturationFilter() const
Returns the raster&#39;s hue/saturation filter.
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
DrawingStyle
This enumerator describes the different kinds of drawing we can do.
Definition: qgsraster.h:89
A ramp shader will color a raster pixel based on a list of values ranges in a ramp.
qgssize mHeight
Distance in map units from bottom edge to top edge for the part of the raster that is to be rendered...
virtual QList< QgsColorRampShader::ColorRampItem > colorTable(int bandNo) const
virtual QgsError error() const
Gets current status error.
QgsRasterRenderer * renderer() const
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setRenderer(QgsRasterRenderer *renderer)
Sets the raster&#39;s renderer.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
virtual QgsError error() const
Gets current status error.
Represents a raster layer.
bool mShouldValidateCrs
true if the layer&#39;s CRS should be validated and invalid CRSes are not permitted.
Definition: qgsmaplayer.h:1559
void setLayerOrder(const QStringList &layers) override
Reorders the previously selected sublayers of this layer from bottom to top.
double rasterUnitsPerPixelX() const
Returns the number of raster units per each raster pixel in X axis.
QString mProviderKey
Data provider key (name of the data provider)
Definition: qgsmaplayer.h:1547
QString accessSectionHtml() const
Formats the "Access" section according to a metadata object.
void willBeDeleted()
Emitted in the destructor when the layer is about to be deleted, but it is still in a perfectly valid...
QgsRasterPipe * pipe()
Returns the raster pipe.
bool writeXml(QDomNode &layer_node, QDomDocument &doc, const QgsReadWriteContext &context) const override
Called by writeLayerXML(), used by children to write state specific to them to project files...
A class to represent a 2D point.
Definition: qgspointxy.h:43
virtual bool ignoreExtents() const
Returns true if the extents reported by the data provider are not reliable and it&#39;s possible that the...
void setDefaultContrastEnhancement()
Sets the default contrast enhancement.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:315
QString linksSectionHtml() const
Formats the "Links" section according to a metadata object.
void showStatusMessage(const QString &message)
virtual QgsRasterInterface * input() const
Current input.
QgsRasterProjector * projector() const
Q_INVOKABLE void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for layer.
virtual QString type() const
Thirty two bit unsigned integer (quint32)
Definition: qgis.h:107
void readCustomProperties(const QDomNode &layerNode, const QString &keyStartsWith=QString())
Read custom properties from project file.
static QgsPainting::BlendMode getBlendModeEnum(QPainter::CompositionMode blendMode)
Returns a BlendMode corresponding to a QPainter::CompositionMode.
Definition: qgspainting.cpp:80
DataType
Raster data types.
Definition: qgis.h:101
QgsRasterInterface * last() const
double maximumValue
The maximum cell value in the raster band.
static Limits limitsFromString(const QString &limits)
Deserialize Limits.
const QgsContrastEnhancement * contrastEnhancement() const
virtual int ySize() const
bool readXml(const QDomNode &layer_node, QgsReadWriteContext &context) override
Called by readLayerXML(), used by children to read state specific to them from project files...
virtual void reloadData()
Reloads the data from the source by calling reloadProviderData() implemented by providers with data c...
virtual const QgsLayerMetadata & metadata() const
Returns a reference to the layer&#39;s metadata store.
double rasterUnitsPerPixelY() const
Returns the number of raster units per each raster pixel in Y axis.
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...
static QDateTime lastModified(const QString &name)
Returns time stamp for given file name.
static QPainter::CompositionMode getCompositionMode(QgsPainting::BlendMode blendMode)
Returns a QPainter::CompositionMode corresponding to a BlendMode.
Definition: qgspainting.cpp:20
Raster values range container.
QVariantMap decodeUri(const QString &providerKey, const QString &uri)
Breaks a provider data source URI into its component paths (e.g.
Resample filter pipe for rasters.
Abstract base class for spatial data provider implementations.
const QgsRasterMinMaxOrigin & minMaxOrigin() const
Returns const reference to origin of min/max values.
QgsRasterRenderer * renderer() const
Returns the raster&#39;s renderer.
int height() const
Returns the height of the (unclipped) raster.
static const double SAMPLE_SIZE
Default sample size (number of pixels) for estimated statistics/histogram calculation.
Thirty two bit floating point (float)
Definition: qgis.h:109
bool isValid() const
Returns the status of the layer.
An interface for classes which can visit style entity (e.g.
Implementation of threaded rendering for raster layers.
Full definition – possibly a very lengthy string, e.g. with no truncation of custom WKT definitions...
void setBlendMode(QPainter::CompositionMode blendMode)
Set the blending mode used for rendering a layer.
QgsRasterShader * shader()
Returns the raster shader.
virtual void cumulativeCut(int bandNo, double lowerCount, double upperCount, double &lowerValue, double &upperValue, const QgsRectangle &extent=QgsRectangle(), int sampleSize=0)
Find values for cumulative pixel count cut.
QPixmap paletteAsPixmap(int bandNumber=1)
Returns a 100x100 pixmap of the color palette.
void readXml(const QDomElement &filterElem) override
Sets base class members from xml. Usually called from create() methods of subclasses.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:694
Sixteen bit signed integer (qint16)
Definition: qgis.h:106
QDateTime timestamp() const override
Time stamp of data source in the moment when data/metadata were loaded by provider.
Complex Int16.
Definition: qgis.h:111
QString mLayerName
Name of the layer - used for display.
Definition: qgsmaplayer.h:1504
void setShader(QgsRasterShader *shader)
Takes ownership of the shader.
void styleChanged()
Signal emitted whenever a change affects the layer&#39;s style.
void setGreenContrastEnhancement(QgsContrastEnhancement *ce)
Takes ownership.
void statusChanged(const QString &) const
Emit a message to be displayed on status bar, usually used by network providers (WMS,WCS)
Sixty four bit floating point (double)
Definition: qgis.h:110
Current extent of the canvas (at the time of computation) is used to compute statistics.
static QString identifyFormatName(QgsRaster::IdentifyFormat format)
virtual QgsRectangle extent() const
Returns the extent of the layer.
void setExtent(QgsRasterMinMaxOrigin::Extent extent)
Sets the extent.
QgsCoordinateReferenceSystem mDestCRS
Target coordinate system.
virtual QgsLayerMetadata layerMetadata() const
Returns layer metadata collected from the provider&#39;s source.
QgsDataProvider * createProvider(const QString &providerKey, const QString &dataSource, const QgsDataProvider::ProviderOptions &options=QgsDataProvider::ProviderOptions())
Creates a new instance of a provider.
QgsBrightnessContrastFilter * brightnessFilter() const
Returns the raster&#39;s brightness/contrast filter.
Provider benefits from resampling and should apply user default resampling settings (since QGIS 3...
QDateTime timestamp() const override
Time stamp of data source in the moment when data/metadata were loaded by provider.
void statusChanged(const QString &status)
Emit a signal with status (e.g. to be caught by QgisApp and display a msg on status bar) ...
double cumulativeCutLower() const
Returns the lower bound of cumulative cut method (between 0 and 1).
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition: qgis.h:116
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:37
static const QgsRasterMinMaxOrigin::Limits MULTIPLE_BAND_SINGLE_BYTE_MIN_MAX_LIMITS
Default enhancement limits for multiple band raster of type Byte.
The drawing pipe for raster layers.
double stdDev
The standard deviation of the cell values.
Paletted (see associated color table)
Definition: qgsraster.h:39
void setContrastEnhancement(QgsContrastEnhancement::ContrastEnhancementAlgorithm algorithm, QgsRasterMinMaxOrigin::Limits limits=QgsRasterMinMaxOrigin::MinMax, const QgsRectangle &extent=QgsRectangle(), int sampleSize=QgsRasterLayer::SAMPLE_SIZE, bool generateLookupTableFlag=true)
Set contrast enhancement algorithm.
void setColorRampType(QgsColorRampShader::Type colorRampType)
Sets the color ramp type.
Alpha (0=transparent, 255=opaque)
Definition: qgsraster.h:43
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
This class describes the origin of min/max values.
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 bool isValidRasterFileName(const QString &fileNameQString, QString &retError)
This helper checks to see whether the file name appears to be a valid raster file name...
double mean
The mean cell value for the band. NO_DATA values are excluded.
static QString version()
Version string.
Definition: qgis.cpp:276
Continuous palette, QGIS addition, GRASS.
Definition: qgsraster.h:54
bool writeSld(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsStringMap &props=QgsStringMap()) const
Writes the symbology of the layer into the document provided in SLD 1.0.0 format. ...
QgsCoordinateTransformContext transformContext() const
Returns data provider coordinate transform context.
void writeCommonStyle(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const
Write style data common to all layer types.
void readStyleManager(const QDomNode &layerNode)
Read style manager&#39;s configuration (if any). To be called by subclasses.
void setRedContrastEnhancement(QgsContrastEnhancement *ce)
Takes ownership.
int removeParam(const QString &key)
Removes a generic parameter by key.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
bool isEmpty() const
Returns true if the rectangle is empty.
Definition: qgsrectangle.h:426
virtual void setMetadata(const QgsLayerMetadata &metadata)
Sets the layer&#39;s metadata store.
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer&#39;s spatial reference system.
QgsPointXY mBottomRightPoint
Coordinate (in output device coordinate system) of bottom right corner of the part of the raster that...
virtual int capabilities() const
Returns a bitmask containing the supported capabilities.
QgsRectangle extent() const override=0
Returns the extent of the layer.
virtual bool isValid() const =0
Returns true if this is a valid layer.
virtual QgsCoordinateReferenceSystem crs() const =0
Returns the coordinate system for the data source.
static const QgsContrastEnhancement::ContrastEnhancementAlgorithm SINGLE_BAND_ENHANCEMENT_ALGORITHM
Default enhancement algorithm for single band raster.
bool loadDefaultStyle
Sets to true if the default layer style should be loaded.
QgsRasterInterface * at(int idx) const
QString providerType() const
[ data provider interface ] Which provider is being used for this Raster Layer?
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:202
QgsRasterShaderFunction * rasterShaderFunction()
virtual void setExtent(const QgsRectangle &rect)
Sets the extent.
Complex Float32.
Definition: qgis.h:113
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
virtual QString dataSourceUri(bool expandAuthConfig=false) const
Gets the data source specification.
double cumulativeCutUpper() const
Returns the upper bound of cumulative cut method (between 0 and 1).
QString bandName(int bandNoInt) const
Returns the name of a band given its number.
Constantly updated extent of the canvas is used to compute statistics.
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
Don&#39;t resolve layer paths or create data providers for layers.
Definition: qgsmaplayer.h:542
virtual bool hasStatistics(int bandNo, int stats=QgsRasterBandStats::All, const QgsRectangle &extent=QgsRectangle(), int sampleSize=0)
Returns true if histogram is available (cached, already calculated).
void setEncodedUri(const QByteArray &uri)
Sets the complete encoded uri.
Raster renderer pipe for single band pseudocolor.
void setRasterShaderFunction(QgsRasterShaderFunction *function)
A public method that allows the user to set their own shader function.
Range is [ mean - stdDevFactor() * stddev, mean + stdDevFactor() * stddev ].
static QString contrastEnhancementAlgorithmString(ContrastEnhancementAlgorithm algorithm)
Returns a string to serialize ContrastEnhancementAlgorithm.
QgsCoordinateReferenceSystem crs() const
Returns the layer&#39;s spatial reference system.
bool defaultContrastEnhancementSettings(QgsContrastEnhancement::ContrastEnhancementAlgorithm &myAlgorithm, QgsRasterMinMaxOrigin::Limits &myLimits) const
Returns default contrast enhancement settings for that type of raster.
void dataSourceChanged()
Emitted whenever the layer&#39;s data source has been changed.
void draw(QPainter *theQPainter, QgsRasterViewPort *myRasterViewPort, const QgsMapToPixel *qgsMapToPixel=nullptr)
This is an overloaded version of the draw() function that is called by both draw() and thumbnailAsPix...
QString publicSource() const
Gets a version of the internal layer definition that has sensitive bits removed (for example...
Raster renderer pipe for single band gray.
Complex Int32.
Definition: qgis.h:112
static int typeSize(int dataType)
void setParam(const QString &key, const QString &value)
Sets a generic parameter value on the URI.
QgsMapLayerRenderer * createMapRenderer(QgsRenderContext &rendererContext) override
Returns new instance of QgsMapLayerRenderer that will be used for rendering of given context...
Sixteen bit unsigned integer (quint16)
Definition: qgis.h:105
virtual void setLayerOrder(const QStringList &layers)
Reorder the list of layer names to be rendered by this provider (in order from bottom to top) ...
QgsCoordinateTransformContext transformContext() const
Returns the layer data provider coordinate transform context or a default transform context if the la...
QString decodedSource(const QString &source, const QString &provider, const QgsReadWriteContext &context) const override
Called by readLayerXML(), used by derived classes to decode provider&#39;s specific data source from proj...
virtual void setTransformContext(const QgsCoordinateTransformContext &transformContext) override
Sets the coordinate transform context to transformContext.
QString userFriendlyIdentifier(IdentifierType type=MediumString) const
Returns a user friendly identifier for the CRS.
void rendererChanged()
Signal emitted when renderer is changed.
double minimumScale() const
Returns the minimum map scale (i.e.
Contains information about the context in which a coordinate transform is executed.
void setAlphaBand(int band)
double maximumScale() const
Returns the maximum map scale (i.e.
bool mValid
Indicates if the layer is valid and can be drawn.
Definition: qgsmaplayer.h:1498
bool writeStyle(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) const override
void setName(const QString &name)
Set the display name of the layer.
Q_DECL_DEPRECATED void setDataProvider(const QString &provider)
Set the data provider.
Range is [ min + cumulativeCutLower() * (max - min), min + cumulativeCutUpper() * (max - min) ]...
Base class for processing filters like renderers, reprojector, resampler etc.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into allowing algorithms to be written in pure substantial changes are required in order to port existing x Processing algorithms for QGIS x The most significant changes are outlined not GeoAlgorithm For algorithms which operate on features one by consider subclassing the QgsProcessingFeatureBasedAlgorithm class This class allows much of the boilerplate code for looping over features from a vector layer to be bypassed and instead requires implementation of a processFeature method Ensure that your algorithm(or algorithm 's parent class) implements the new pure virtual createInstance(self) call
static const QgsRasterMinMaxOrigin::Limits SINGLE_BAND_MIN_MAX_LIMITS
Default enhancement limits for single band raster.
static QString limitsString(Limits limits)
Returns a string to serialize Limits.
void setSubLayerVisibility(const QString &name, bool vis) override
Set the visibility of the given sublayer name.
virtual QString htmlMetadata()=0
Returns metadata in a format suitable for feeding directly into a subset of the GUI raster properties...
QString title() const
Returns the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:280
int size() const
static ContrastEnhancementAlgorithm contrastEnhancementAlgorithmFromString(const QString &contrastEnhancementString)
Deserialize ContrastEnhancementAlgorithm.
void classifyColorRamp(int classes=0, int band=-1, const QgsRectangle &extent=QgsRectangle(), QgsRasterInterface *input=nullptr)
Classify color ramp shader.
Full WKT2 string, conforming to ISO 19162:2018 / OGC 18-010, with all possible nodes and new keyword ...
void repaintRequested(bool deferredUpdate=false)
By emitting this signal the layer tells that either appearance or content have been changed and any v...
void setMinMaxOrigin(const QgsRasterMinMaxOrigin &origin)
Sets origin of min/max values.
QString identificationSectionHtml() const
Formats the "Identification" section according to a metadata object.
Limits
This enumerator describes the limits used to compute min/max values.
QgsCoordinateReferenceSystem mSrcCRS
Source coordinate system.
void setLimits(QgsRasterMinMaxOrigin::Limits limits)
Sets the limits.
void writeStyleManager(QDomNode &layerNode, QDomDocument &doc) const
Write style manager&#39;s configuration (if exists). To be called by subclasses.
QgsRasterProjector implements approximate projection support for it calculates grid of points in sour...
bool writeSymbology(QDomNode &, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) const override
bool set(QgsRasterInterface *interface)
Insert a new known interface in default place or replace interface of the same role if it already exi...
Registry for raster renderer entries.
QgsCoordinateTransformContext transformContext() const
Returns data provider coordinate transform context.
bool skipCrsValidation
Controls whether the layer is allowed to have an invalid/unknown CRS.
virtual QgsRasterBandStats bandStatistics(int bandNo, int stats=QgsRasterBandStats::All, const QgsRectangle &extent=QgsRectangle(), int sampleSize=0, QgsRasterBlockFeedback *feedback=nullptr)
Returns the band statistics.
QList< QPair< QString, QColor > > QgsLegendColorList
QImage previewAsImage(QSize size, const QColor &bgColor=Qt::white, QImage::Format format=QImage::Format_ARGB32_Premultiplied)
Draws a preview of the rasterlayer into a QImage.
void setContrastEnhancement(QgsContrastEnhancement *ce)
Takes ownership.
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
ContrastEnhancementAlgorithm
This enumerator describes the types of contrast enhancement algorithms that can be used...
virtual QString loadDefaultStyle(bool &resultFlag)
Retrieve the default style for this layer if one exists (either as a .qml file on disk or as a record...
Contains information about the context of a rendering operation.
Setting options for creating vector data providers.
QString name() const
Returns the display name of the layer.
static QgsMapLayerLegend * defaultRasterLegend(QgsRasterLayer *rl)
Create new legend implementation for raster layer.
const QgsContrastEnhancement * redContrastEnhancement() const
const QgsContrastEnhancement * greenContrastEnhancement() const
void setZoomedInResampler(QgsRasterResampler *r)
Sets resampler for zoomed in scales. Takes ownership of the object.
QgsRasterResampleFilter * resampleFilter() const
Returns the raster&#39;s resample filter.
bool remove(int idx)
Remove and delete interface at given index if possible.
QList< QgsRasterRange > QgsRasterRangeList
QString mDataSource
Data source description string, varies by layer type.
Definition: qgsmaplayer.h:1501
virtual void setTransformContext(const QgsCoordinateTransformContext &transformContext)
Sets data coordinate transform context to transformContext.
QgsCoordinateTransformContext mTransformContext
Coordinate transform context.
QString source() const
Returns the source for the layer.
bool readSymbology(const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) override
virtual QgsRasterInterface * clone() const =0
Clone itself, create deep copy.
Whole raster is used to compute statistics.
bool hasScaleBasedVisibility() const
Returns whether scale based visibility is enabled for the layer.
void setPassword(const QString &password)
Sets the password for the URI.
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified symbology visitor, causing it to visit all symbols associated with the layer...
QByteArray encodedUri() const
Returns the complete encoded URI as a byte array.
Brightness/contrast filter pipe for rasters.
Bilinear Raster Resampler.
qgssize mWidth
Width, number of columns to be rendered.
This class represents a coordinate reference system (CRS).
Color and saturation filter pipe for rasters.
void setBlueContrastEnhancement(QgsContrastEnhancement *ce)
Takes ownership.
Provider can read layer metadata from data store. Since QGIS 3.0. See QgsDataProvider::layerMetadata(...
ContrastEnhancementAlgorithm contrastEnhancementAlgorithm() const
void setZoomedOutResampler(QgsRasterResampler *r)
Sets resampler for zoomed out scales. Takes ownership of the object.
bool ignoreExtents() const
If the ignoreExtent flag is set, the layer will also render outside the bounding box reported by the ...
Greyscale.
Definition: qgsraster.h:38
QStringList subLayers() const override
Returns the sublayers of this layer - useful for providers that manage their own layers, such as WMS.
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
double minimumValue
The minimum cell value in the raster band.
Class for metadata formatter.
Renderer for multiband images with the color components.
bool isSpatial() const override
Returns true if the layer is considered a spatial layer, ie it has some form of geometry associated w...
void dataChanged()
Data of layer changed.
void appendError(const QgsErrorMessage &error)
Add error message.
Definition: qgsmaplayer.h:1490
virtual QgsRasterRangeList userNoDataValues(int bandNo) const
Returns a list of user no data value ranges.
Base class for utility classes that encapsulate information necessary for rendering of map layers...
Interpolates the color between two class breaks linearly.
Manipulates raster pixel values so that they enhanceContrast or clip into a specified numerical range...
QString encodedSource(const QString &source, const QgsReadWriteContext &context) const override
Called by writeLayerXML(), used by derived classes to encode provider&#39;s specific data source to proje...
void readXml(const QDomElement &filterElem) override
Sets base class members from xml. Usually called from create() methods of subclasses.
QgsMapLayerType
Types of layers that can be added to a map.
Definition: qgsmaplayer.h:66
void refreshRendererIfNeeded(QgsRasterRenderer *rasterRenderer, const QgsRectangle &extent)
Refresh renderer with new extent, if needed.
~QgsRasterLayer() override
This class provides details of the viewable area that a raster will be rendered into.
QDateTime dataTimestamp() const override
Current time stamp of data source.
virtual bool useSourceNoDataValue(int bandNo) const
Returns the source nodata value usage.
Assigns the color of the higher class for every pixel between two class breaks.
QgsCoordinateTransformContext transformContext
Coordinate transform context.
virtual void legendSymbologyItems(QList< QPair< QString, QColor > > &symbolItems) const
Gets symbology items if provided by renderer.
virtual QString generateBandName(int bandNumber) const
helper function to create zero padded band names
void reload() override
Synchronises with changes in the datasource.
void setLegend(QgsMapLayerLegend *legend)
Assign a legend controller to the map layer.
Class for storing the component parts of a RDBMS data source URI (e.g.
virtual void setUserNoDataValue(int bandNo, const QgsRasterRangeList &noData)
Complex Float64.
Definition: qgis.h:114
QgsLegendColorList legendSymbologyItems() const
Returns a list with classification items (Text and color)
virtual QgsRasterDataProvider::ProviderCapabilities providerCapabilities() const
Returns flags containing the supported capabilities of the data provider.
void readXml(const QDomElement &filterElem) override
Sets base class members from xml. Usually called from create() methods of subclasses.
double stdDevFactor() const
Returns the factor f so that the min/max range is [ mean - f * stddev , mean + f * stddev ]...
virtual int xSize() const
Gets raster size.
static QgsRasterRendererRegistry * rasterRendererRegistry()
Returns the application&#39;s raster renderer registry, used for managing raster layer renderers...
Raster renderer pipe that applies colors to a raster.
QgsRasterRendererCreateFunc rendererCreateFunction
static const QgsContrastEnhancement::ContrastEnhancementAlgorithm MULTIPLE_BAND_SINGLE_BYTE_ENHANCEMENT_ALGORITHM
Default enhancement algorithm for multiple band raster of type Byte.
void setError(const QgsError &error)
Sets error message.
Definition: qgsmaplayer.h:1492
Eight bit unsigned integer (quint8)
Definition: qgis.h:104
Qgis::DataType dataType(int bandNo) const override=0
Returns data type for the band specified by number.
Setting options for loading raster layers.
static const QgsRasterMinMaxOrigin::Limits MULTIPLE_BAND_MULTI_BYTE_MIN_MAX_LIMITS
Default enhancement limits for multiple band raster of type different from Byte.
int band() const
Returns the band used by the renderer.
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition: qgis.h:115
void readCommonStyle(const QDomElement &layerElement, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories)
Read style data common to all layer types.
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:209
Q_DECL_DEPRECATED void setCrs(const QgsCoordinateReferenceSystem &srcCRS, const QgsCoordinateReferenceSystem &destCRS, int srcDatumTransform=-1, int destDatumTransform=-1)
Sets the source and destination CRS.
virtual int colorInterpretation(int bandNo) const
Returns data type for the band specified by number.
QgsRectangle mDrawnExtent
Intersection of current map extent and layer extent.
QgsMapLayer::ReadFlags mReadFlags
Read flags. It&#39;s up to the subclass to respect these when restoring state from XML.
Definition: qgsmaplayer.h:1552
Base class for raster data providers.
QgsPointXY mTopLeftPoint
Coordinate (in output device coordinate system) of top left corner of the part of the raster that is ...
QgsRasterLayer()
Constructor. Provider is not set.