QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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 #include <QTime>
82 
83 #define ERR(message) QGS_ERROR_MESSAGE(message,"Raster layer")
84 
85 const double QgsRasterLayer::SAMPLE_SIZE = 250000;
86 
93 
100 
103  , QSTRING_NOT_SET( QStringLiteral( "Not Set" ) )
104  , TRSTRING_NOT_SET( tr( "Not Set" ) )
105 
106 {
107  init();
108  mValid = false;
109 }
110 
111 QgsRasterLayer::QgsRasterLayer( const QString &uri,
112  const QString &baseName,
113  const QString &providerKey,
114  const LayerOptions &options )
115  : QgsMapLayer( QgsMapLayerType::RasterLayer, baseName, uri )
116  // Constant that signals property not used.
117  , QSTRING_NOT_SET( QStringLiteral( "Not Set" ) )
118  , TRSTRING_NOT_SET( tr( "Not Set" ) )
119 {
121 
122  QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
123  setProviderType( providerKey );
124 
125  QgsDataProvider::ProviderOptions providerOptions { options.transformContext };
126 
127  setDataSource( uri, baseName, providerKey, providerOptions, options.loadDefaultStyle );
128 
129 } // QgsRasterLayer ctor
130 
132 {
133  emit willBeDeleted();
134 
135  mValid = false;
136  // Note: provider and other interfaces are owned and deleted by pipe
137 }
138 
140 {
142  if ( mDataProvider )
143  {
144  options.transformContext = mDataProvider->transformContext();
145  }
146  QgsRasterLayer *layer = new QgsRasterLayer( source(), name(), mProviderKey, options );
147  QgsMapLayer::clone( layer );
148 
149  // do not clone data provider which is the first element in pipe
150  for ( int i = 1; i < mPipe.size(); i++ )
151  {
152  if ( mPipe.at( i ) )
153  layer->pipe()->set( mPipe.at( i )->clone() );
154  }
155 
156  return layer;
157 }
158 
160 //
161 // Static Methods and members
162 //
164 
165 bool QgsRasterLayer::isValidRasterFileName( const QString &fileNameQString, QString &retErrMsg )
166 {
167  bool myIsValid = QgsGdalProvider::isValidRasterFileName( fileNameQString, retErrMsg );
168  return myIsValid;
169 }
170 
171 bool QgsRasterLayer::isValidRasterFileName( QString const &fileNameQString )
172 {
173  QString retErrMsg;
174  return isValidRasterFileName( fileNameQString, retErrMsg );
175 }
176 
177 QDateTime QgsRasterLayer::lastModified( QString const &name )
178 {
179  QgsDebugMsgLevel( "name=" + name, 4 );
180  QDateTime t;
181 
182  QFileInfo fi( name );
183 
184  // Is it file?
185  if ( !fi.exists() )
186  return t;
187 
188  t = fi.lastModified();
189 
190  QgsDebugMsgLevel( "last modified = " + t.toString(), 4 );
191 
192  return t;
193 }
194 
195 void QgsRasterLayer::setDataProvider( const QString &provider )
196 {
198 }
199 
200 // typedef for the QgsDataProvider class factory
201 typedef QgsDataProvider *classFactoryFunction_t( const QString *, const QgsDataProvider::ProviderOptions &options );
202 
204 //
205 // Non Static Public methods
206 //
208 
210 {
211  if ( !mDataProvider ) return 0;
212  return mDataProvider->bandCount();
213 }
214 
215 QString QgsRasterLayer::bandName( int bandNo ) const
216 {
217  return dataProvider()->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  QTime 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>\n<body>\n" );
295 
296  // Begin Provider section
297  myMetadata += QStringLiteral( "<h1>" ) + tr( "Information from provider" ) + QStringLiteral( "</h1>\n<hr>\n" );
298  myMetadata += QLatin1String( "<table class=\"list-view\">\n" );
299 
300  // name
301  myMetadata += 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  // data source
323  if ( publicSource() != path )
324  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Source" ) + QStringLiteral( "</td><td>%1" ).arg( publicSource() ) + QStringLiteral( "</td></tr>\n" );
325 
326  // EPSG
327  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "CRS" ) + QStringLiteral( "</td><td>" );
328  if ( crs().isValid() )
329  {
330  myMetadata += crs().authid() + QStringLiteral( " - " );
331  myMetadata += crs().description() + QStringLiteral( " - " );
332  if ( crs().isGeographic() )
333  myMetadata += tr( "Geographic" );
334  else
335  myMetadata += tr( "Projected" );
336  }
337  myMetadata += QLatin1String( "</td></tr>\n" );
338 
339  // Extent
340  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Extent" ) + QStringLiteral( "</td><td>" ) + extent().toString() + QStringLiteral( "</td></tr>\n" );
341 
342  // unit
343  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Unit" ) + QStringLiteral( "</td><td>" ) + QgsUnitTypes::toString( crs().mapUnits() ) + QStringLiteral( "</td></tr>\n" );
344 
345  // Raster Width
346  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Width" ) + QStringLiteral( "</td><td>" );
347  if ( dataProvider()->capabilities() & QgsRasterDataProvider::Size )
348  myMetadata += QString::number( width() );
349  else
350  myMetadata += tr( "n/a" );
351  myMetadata += QLatin1String( "</td></tr>\n" );
352 
353  // Raster height
354  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Height" ) + QStringLiteral( "</td><td>" );
355  if ( dataProvider()->capabilities() & QgsRasterDataProvider::Size )
356  myMetadata += QString::number( height() );
357  else
358  myMetadata += tr( "n/a" );
359  myMetadata += QLatin1String( "</td></tr>\n" );
360 
361  // Data type
362  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Data type" ) + QStringLiteral( "</td><td>" );
363  // Just use the first band
364  switch ( mDataProvider->sourceDataType( 1 ) )
365  {
366  case Qgis::Byte:
367  myMetadata += tr( "Byte - Eight bit unsigned integer" );
368  break;
369  case Qgis::UInt16:
370  myMetadata += tr( "UInt16 - Sixteen bit unsigned integer " );
371  break;
372  case Qgis::Int16:
373  myMetadata += tr( "Int16 - Sixteen bit signed integer " );
374  break;
375  case Qgis::UInt32:
376  myMetadata += tr( "UInt32 - Thirty two bit unsigned integer " );
377  break;
378  case Qgis::Int32:
379  myMetadata += tr( "Int32 - Thirty two bit signed integer " );
380  break;
381  case Qgis::Float32:
382  myMetadata += tr( "Float32 - Thirty two bit floating point " );
383  break;
384  case Qgis::Float64:
385  myMetadata += tr( "Float64 - Sixty four bit floating point " );
386  break;
387  case Qgis::CInt16:
388  myMetadata += tr( "CInt16 - Complex Int16 " );
389  break;
390  case Qgis::CInt32:
391  myMetadata += tr( "CInt32 - Complex Int32 " );
392  break;
393  case Qgis::CFloat32:
394  myMetadata += tr( "CFloat32 - Complex Float32 " );
395  break;
396  case Qgis::CFloat64:
397  myMetadata += tr( "CFloat64 - Complex Float64 " );
398  break;
399  default:
400  myMetadata += tr( "Could not determine raster data type." );
401  }
402  myMetadata += QLatin1String( "</td></tr>\n" );
403 
404  // Insert provider-specific (e.g. WMS-specific) metadata
405  myMetadata += mDataProvider->htmlMetadata();
406 
407  // End Provider section
408  myMetadata += QLatin1String( "</table>\n<br><br>" );
409 
410  // Identification section
411  myMetadata += QStringLiteral( "<h1>" ) + tr( "Identification" ) + QStringLiteral( "</h1>\n<hr>\n" );
412  myMetadata += htmlFormatter.identificationSectionHtml();
413  myMetadata += QLatin1String( "<br><br>\n" );
414 
415  // extent section
416  myMetadata += QStringLiteral( "<h1>" ) + tr( "Extent" ) + QStringLiteral( "</h1>\n<hr>\n" );
417  myMetadata += htmlFormatter.extentSectionHtml( );
418  myMetadata += QLatin1String( "<br><br>\n" );
419 
420  // Start the Access section
421  myMetadata += QStringLiteral( "<h1>" ) + tr( "Access" ) + QStringLiteral( "</h1>\n<hr>\n" );
422  myMetadata += htmlFormatter.accessSectionHtml( );
423  myMetadata += QLatin1String( "<br><br>\n" );
424 
425  // Bands section
426  myMetadata += QStringLiteral( "</table>\n<br><br><h1>" ) + tr( "Bands" ) + QStringLiteral( "</h1>\n<hr>\n<table class=\"list-view\">\n" );
427 
428  // Band count
429  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Band count" ) + QStringLiteral( "</td><td>" ) + QString::number( bandCount() ) + QStringLiteral( "</td></tr>\n" );
430 
431  // Band table
432  myMetadata += QLatin1String( "</table>\n<br><table width=\"100%\" class=\"tabular-view\">\n" );
433  myMetadata += QLatin1String( "<tr><th>" ) + tr( "Number" ) + QLatin1String( "</th><th>" ) + tr( "Band" ) + QLatin1String( "</th><th>" ) + tr( "No-Data" ) + QLatin1String( "</th><th>" ) + tr( "Min" ) + QLatin1String( "</th><th>" ) + tr( "Max" ) + QLatin1String( "</th></tr>\n" );
434 
435  QgsRasterDataProvider *provider = const_cast< QgsRasterDataProvider * >( mDataProvider );
436  for ( int i = 1; i <= bandCount(); i++ )
437  {
438  QString rowClass;
439  if ( i % 2 )
440  rowClass = QStringLiteral( "class=\"odd-row\"" );
441  myMetadata += QLatin1String( "<tr " ) + rowClass + QLatin1String( "><td>" ) + QString::number( i ) + QLatin1String( "</td><td>" ) + bandName( i ) + QLatin1String( "</td><td>" );
442 
443  if ( dataProvider()->sourceHasNoDataValue( i ) )
444  myMetadata += QString::number( dataProvider()->sourceNoDataValue( i ) );
445  else
446  myMetadata += tr( "n/a" );
447  myMetadata += QLatin1String( "</td>" );
448 
449  if ( provider->hasStatistics( i ) )
450  {
451  QgsRasterBandStats myRasterBandStats = provider->bandStatistics( i );
452  myMetadata += QLatin1String( "<td>" ) + QString::number( myRasterBandStats.minimumValue, 'f', 10 ) + QLatin1String( "</td>" );
453  myMetadata += QLatin1String( "<td>" ) + QString::number( myRasterBandStats.maximumValue, 'f', 10 ) + QLatin1String( "</td>" );
454  }
455  else
456  {
457  myMetadata += QLatin1String( "<td>" ) + tr( "n/a" ) + QLatin1String( "</td><td>" ) + tr( "n/a" ) + QLatin1String( "</td>" );
458  }
459 
460  myMetadata += QLatin1String( "</tr>\n" );
461  }
462 
463  //close previous bands table
464  myMetadata += QLatin1String( "</table>\n<br><br>" );
465 
466  // Start the contacts section
467  myMetadata += QStringLiteral( "<h1>" ) + tr( "Contacts" ) + QStringLiteral( "</h1>\n<hr>\n" );
468  myMetadata += htmlFormatter.contactsSectionHtml( );
469  myMetadata += QLatin1String( "<br><br>\n" );
470 
471  // Start the links section
472  myMetadata += QStringLiteral( "<h1>" ) + tr( "References" ) + QStringLiteral( "</h1>\n<hr>\n" );
473  myMetadata += htmlFormatter.linksSectionHtml( );
474  myMetadata += QLatin1String( "<br><br>\n" );
475 
476  // Start the history section
477  myMetadata += QStringLiteral( "<h1>" ) + tr( "History" ) + QStringLiteral( "</h1>\n<hr>\n" );
478  myMetadata += htmlFormatter.historySectionHtml( );
479  myMetadata += QLatin1String( "<br><br>\n" );
480 
481  myMetadata += QStringLiteral( "\n</body>\n</html>\n" );
482  return myMetadata;
483 }
484 
485 QPixmap QgsRasterLayer::paletteAsPixmap( int bandNumber )
486 {
487  //TODO: This function should take dimensions
488  QgsDebugMsgLevel( QStringLiteral( "entered." ), 4 );
489 
490  // Only do this for the GDAL provider?
491  // Maybe WMS can do this differently using QImage::numColors and QImage::color()
492  if ( mDataProvider->colorInterpretation( bandNumber ) == QgsRaster::PaletteIndex )
493  {
494  QgsDebugMsgLevel( QStringLiteral( "....found paletted image" ), 4 );
495  QgsColorRampShader myShader;
496  QList<QgsColorRampShader::ColorRampItem> myColorRampItemList = mDataProvider->colorTable( bandNumber );
497  if ( !myColorRampItemList.isEmpty() )
498  {
499  QgsDebugMsgLevel( QStringLiteral( "....got color ramp item list" ), 4 );
500  myShader.setColorRampItemList( myColorRampItemList );
502  // Draw image
503  int mySize = 100;
504  QPixmap myPalettePixmap( mySize, mySize );
505  QPainter myQPainter( &myPalettePixmap );
506 
507  QImage myQImage = QImage( mySize, mySize, QImage::Format_RGB32 );
508  myQImage.fill( 0 );
509  myPalettePixmap.fill();
510 
511  double myStep = ( static_cast< double >( myColorRampItemList.size() ) - 1 ) / static_cast< double >( mySize * mySize );
512  double myValue = 0.0;
513  for ( int myRow = 0; myRow < mySize; myRow++ )
514  {
515  QRgb *myLineBuffer = reinterpret_cast< QRgb * >( myQImage.scanLine( myRow ) );
516  for ( int myCol = 0; myCol < mySize; myCol++ )
517  {
518  myValue = myStep * static_cast< double >( myCol + myRow * mySize );
519  int c1, c2, c3, c4;
520  myShader.shade( myValue, &c1, &c2, &c3, &c4 );
521  myLineBuffer[ myCol ] = qRgba( c1, c2, c3, c4 );
522  }
523  }
524 
525  myQPainter.drawImage( 0, 0, myQImage );
526  return myPalettePixmap;
527  }
528  QPixmap myNullPixmap;
529  return myNullPixmap;
530  }
531  else
532  {
533  //invalid layer was requested
534  QPixmap myNullPixmap;
535  return myNullPixmap;
536  }
537 }
538 
540 {
541  return mProviderKey;
542 }
543 
545 {
546 // We return one raster pixel per map unit pixel
547 // One raster pixel can have several raster units...
548 
549 // We can only use one of the mGeoTransform[], so go with the
550 // horisontal one.
551 
552  if ( mDataProvider->capabilities() & QgsRasterDataProvider::Size && !qgsDoubleNear( mDataProvider->xSize(), 0.0 ) )
553  {
554  return mDataProvider->extent().width() / mDataProvider->xSize();
555  }
556  return 1;
557 }
558 
560 {
561  if ( 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(), 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::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 
916  if ( limits == QgsRasterMinMaxOrigin::MinMax )
917  {
918  QgsRasterBandStats myRasterBandStats = mDataProvider->bandStatistics( band, QgsRasterBandStats::Min | QgsRasterBandStats::Max, extent, sampleSize );
919  min = myRasterBandStats.minimumValue;
920  max = myRasterBandStats.maximumValue;
921  }
922  else if ( limits == QgsRasterMinMaxOrigin::StdDev )
923  {
924  QgsRasterBandStats myRasterBandStats = mDataProvider->bandStatistics( band, QgsRasterBandStats::Mean | QgsRasterBandStats::StdDev, extent, sampleSize );
925  min = myRasterBandStats.mean - ( mmo.stdDevFactor() * myRasterBandStats.stdDev );
926  max = myRasterBandStats.mean + ( mmo.stdDevFactor() * myRasterBandStats.stdDev );
927  }
928  else if ( limits == QgsRasterMinMaxOrigin::CumulativeCut )
929  {
930  const double myLower = mmo.cumulativeCutLower();
931  const double myUpper = mmo.cumulativeCutUpper();
932  QgsDebugMsgLevel( QStringLiteral( "myLower = %1 myUpper = %2" ).arg( myLower ).arg( myUpper ), 4 );
933  mDataProvider->cumulativeCut( band, myLower, myUpper, min, max, extent, sampleSize );
934  }
935  QgsDebugMsgLevel( QStringLiteral( "band = %1 min = %2 max = %3" ).arg( band ).arg( min ).arg( max ), 4 );
936 
937 }
938 
940 {
941  return mDataProvider ? mDataProvider->ignoreExtents() : false;
942 }
943 
945 {
946  setContrastEnhancement( algorithm,
947  limits,
948  extent,
949  sampleSize,
950  generateLookupTableFlag,
951  mPipe.renderer() );
952 }
953 
956  const QgsRectangle &extent,
957  int sampleSize,
958  bool generateLookupTableFlag,
959  QgsRasterRenderer *rasterRenderer )
960 {
961  QgsDebugMsgLevel( QStringLiteral( "theAlgorithm = %1 limits = %2 extent.isEmpty() = %3" ).arg( algorithm ).arg( limits ).arg( extent.isEmpty() ), 4 );
962  if ( !rasterRenderer || !mDataProvider )
963  {
964  return;
965  }
966 
967  QList<int> myBands;
968  QList<QgsContrastEnhancement *> myEnhancements;
969  QgsRasterMinMaxOrigin myMinMaxOrigin;
970  QgsRasterRenderer *myRasterRenderer = nullptr;
971  QgsSingleBandGrayRenderer *myGrayRenderer = nullptr;
972  QgsSingleBandPseudoColorRenderer *myPseudoColorRenderer = nullptr;
973  QgsMultiBandColorRenderer *myMultiBandRenderer = nullptr;
974  QString rendererType = rasterRenderer->type();
975  if ( rendererType == QLatin1String( "singlebandgray" ) )
976  {
977  myGrayRenderer = dynamic_cast<QgsSingleBandGrayRenderer *>( rasterRenderer );
978  if ( !myGrayRenderer )
979  {
980  return;
981  }
982  myBands << myGrayRenderer->grayBand();
983  myRasterRenderer = myGrayRenderer;
984  myMinMaxOrigin = myGrayRenderer->minMaxOrigin();
985  }
986  else if ( rendererType == QLatin1String( "multibandcolor" ) )
987  {
988  myMultiBandRenderer = dynamic_cast<QgsMultiBandColorRenderer *>( rasterRenderer );
989  if ( !myMultiBandRenderer )
990  {
991  return;
992  }
993  myBands << myMultiBandRenderer->redBand() << myMultiBandRenderer->greenBand() << myMultiBandRenderer->blueBand();
994  myRasterRenderer = myMultiBandRenderer;
995  myMinMaxOrigin = myMultiBandRenderer->minMaxOrigin();
996  }
997  else if ( rendererType == QLatin1String( "singlebandpseudocolor" ) )
998  {
999  myPseudoColorRenderer = dynamic_cast<QgsSingleBandPseudoColorRenderer *>( rasterRenderer );
1000  if ( !myPseudoColorRenderer )
1001  {
1002  return;
1003  }
1004  myBands << myPseudoColorRenderer->band();
1005  myRasterRenderer = myPseudoColorRenderer;
1006  myMinMaxOrigin = myPseudoColorRenderer->minMaxOrigin();
1007  }
1008  else
1009  {
1010  return;
1011  }
1012 
1013  const auto constMyBands = myBands;
1014  for ( int myBand : constMyBands )
1015  {
1016  if ( myBand != -1 )
1017  {
1018  Qgis::DataType myType = static_cast< Qgis::DataType >( mDataProvider->dataType( myBand ) );
1019  std::unique_ptr<QgsContrastEnhancement> myEnhancement( new QgsContrastEnhancement( static_cast< Qgis::DataType >( myType ) ) );
1020  myEnhancement->setContrastEnhancementAlgorithm( algorithm, generateLookupTableFlag );
1021 
1022  double min;
1023  double max;
1024  computeMinMax( myBand, myMinMaxOrigin, limits, extent, sampleSize, min, max );
1025 
1026  if ( rendererType == QLatin1String( "singlebandpseudocolor" ) )
1027  {
1028  myPseudoColorRenderer->setClassificationMin( min );
1029  myPseudoColorRenderer->setClassificationMax( max );
1030  if ( myPseudoColorRenderer->shader() )
1031  {
1032  QgsColorRampShader *colorRampShader = dynamic_cast<QgsColorRampShader *>( myPseudoColorRenderer->shader()->rasterShaderFunction() );
1033  if ( colorRampShader )
1034  {
1035  colorRampShader->classifyColorRamp( myPseudoColorRenderer->band(), extent, myPseudoColorRenderer->input() );
1036  }
1037  }
1038  }
1039  else
1040  {
1041  myEnhancement->setMinimumValue( min );
1042  myEnhancement->setMaximumValue( max );
1043  myEnhancements.append( myEnhancement.release() );
1044  }
1045  }
1046  else
1047  {
1048  myEnhancements.append( nullptr );
1049  }
1050  }
1051 
1052  if ( rendererType == QLatin1String( "singlebandgray" ) )
1053  {
1054  if ( myEnhancements.first() ) myGrayRenderer->setContrastEnhancement( myEnhancements.takeFirst() );
1055  }
1056  else if ( rendererType == QLatin1String( "multibandcolor" ) )
1057  {
1058  if ( myEnhancements.first() ) myMultiBandRenderer->setRedContrastEnhancement( myEnhancements.takeFirst() );
1059  if ( myEnhancements.first() ) myMultiBandRenderer->setGreenContrastEnhancement( myEnhancements.takeFirst() );
1060  if ( myEnhancements.first() ) myMultiBandRenderer->setBlueContrastEnhancement( myEnhancements.takeFirst() );
1061  }
1062 
1063  //delete all remaining unused enhancements
1064  qDeleteAll( myEnhancements );
1065 
1066  myMinMaxOrigin.setLimits( limits );
1067  if ( extent != QgsRectangle() &&
1068  myMinMaxOrigin.extent() == QgsRasterMinMaxOrigin::WholeRaster )
1069  {
1071  }
1072  if ( myRasterRenderer )
1073  {
1074  myRasterRenderer->setMinMaxOrigin( myMinMaxOrigin );
1075  }
1076 
1077  if ( rasterRenderer == renderer() )
1078  {
1079  emit repaintRequested();
1080  emit styleChanged();
1081  emit rendererChanged();
1082  }
1083 }
1084 
1086 {
1087  QgsSingleBandGrayRenderer *singleBandRenderer = nullptr;
1088  QgsMultiBandColorRenderer *multiBandRenderer = nullptr;
1089  const QgsContrastEnhancement *ce = nullptr;
1090  if ( ( singleBandRenderer = dynamic_cast<QgsSingleBandGrayRenderer *>( renderer() ) ) )
1091  {
1092  ce = singleBandRenderer->contrastEnhancement();
1093  }
1094  else if ( ( multiBandRenderer = dynamic_cast<QgsMultiBandColorRenderer *>( renderer() ) ) )
1095  {
1096  ce = multiBandRenderer->redContrastEnhancement();
1097  }
1098 
1099  if ( ce )
1100  {
1105  extent,
1106  SAMPLE_SIZE,
1107  true,
1108  renderer() );
1109  }
1110  else
1111  {
1114  if ( defaultContrastEnhancementSettings( myAlgorithm, myLimits ) )
1115  {
1117  myLimits,
1118  extent,
1119  SAMPLE_SIZE,
1120  true,
1121  renderer() );
1122  }
1123  }
1124 }
1125 
1127  const QgsRectangle &extent )
1128 {
1129  if ( !( mDataProvider &&
1130  mLastRectangleUsedByRefreshContrastEnhancementIfNeeded != extent &&
1131  rasterRenderer->minMaxOrigin().limits() != QgsRasterMinMaxOrigin::None &&
1132  rasterRenderer->minMaxOrigin().extent() == QgsRasterMinMaxOrigin::UpdatedCanvas ) )
1133  return;
1134 
1135  QgsSingleBandGrayRenderer *singleBandRenderer = nullptr;
1136  QgsMultiBandColorRenderer *multiBandRenderer = nullptr;
1137  QgsSingleBandPseudoColorRenderer *sbpcr = nullptr;
1138  const QgsContrastEnhancement *ce = nullptr;
1139  if ( ( singleBandRenderer = dynamic_cast<QgsSingleBandGrayRenderer *>( rasterRenderer ) ) )
1140  {
1141  ce = singleBandRenderer->contrastEnhancement();
1142  }
1143  else if ( ( multiBandRenderer = dynamic_cast<QgsMultiBandColorRenderer *>( rasterRenderer ) ) )
1144  {
1145  ce = multiBandRenderer->redContrastEnhancement();
1146  }
1147  else if ( ( sbpcr = dynamic_cast<QgsSingleBandPseudoColorRenderer *>( rasterRenderer ) ) )
1148  {
1149  mLastRectangleUsedByRefreshContrastEnhancementIfNeeded = extent;
1150  double min;
1151  double max;
1152  computeMinMax( sbpcr->band(),
1153  rasterRenderer->minMaxOrigin(),
1154  rasterRenderer->minMaxOrigin().limits(), extent,
1155  SAMPLE_SIZE, min, max );
1156  sbpcr->setClassificationMin( min );
1157  sbpcr->setClassificationMax( max );
1158 
1159  if ( sbpcr->shader() )
1160  {
1161  QgsColorRampShader *colorRampShader = dynamic_cast<QgsColorRampShader *>( sbpcr->shader()->rasterShaderFunction() );
1162  if ( colorRampShader )
1163  {
1164  colorRampShader->classifyColorRamp( sbpcr->band(), extent, rasterRenderer->input() );
1165  }
1166  }
1167 
1169  r->setClassificationMin( min );
1170  r->setClassificationMax( max );
1171 
1172  if ( r->shader() )
1173  {
1174  QgsColorRampShader *colorRampShader = dynamic_cast<QgsColorRampShader *>( r->shader()->rasterShaderFunction() );
1175  if ( colorRampShader )
1176  {
1177  colorRampShader->classifyColorRamp( sbpcr->band(), extent, rasterRenderer->input() );
1178  }
1179  }
1180 
1181  emit repaintRequested();
1182  emit styleChanged();
1183  emit rendererChanged();
1184  return;
1185  }
1186 
1187  if ( ce &&
1189  {
1190  mLastRectangleUsedByRefreshContrastEnhancementIfNeeded = extent;
1191 
1193  rasterRenderer->minMaxOrigin().limits(),
1194  extent,
1195  SAMPLE_SIZE,
1196  true,
1197  rasterRenderer );
1198 
1199  // Update main renderer so that the legends get updated
1200  if ( singleBandRenderer )
1201  static_cast<QgsSingleBandGrayRenderer *>( renderer() )->setContrastEnhancement( new QgsContrastEnhancement( * singleBandRenderer->contrastEnhancement() ) );
1202  else if ( multiBandRenderer )
1203  {
1204  if ( multiBandRenderer->redContrastEnhancement() )
1205  {
1206  static_cast<QgsMultiBandColorRenderer *>( renderer() )->setRedContrastEnhancement( new QgsContrastEnhancement( *multiBandRenderer->redContrastEnhancement() ) );
1207  }
1208  if ( multiBandRenderer->greenContrastEnhancement() )
1209  {
1210  static_cast<QgsMultiBandColorRenderer *>( renderer() )->setGreenContrastEnhancement( new QgsContrastEnhancement( *multiBandRenderer->greenContrastEnhancement() ) );
1211  }
1212  if ( multiBandRenderer->blueContrastEnhancement() )
1213  {
1214  static_cast<QgsMultiBandColorRenderer *>( renderer() )->setBlueContrastEnhancement( new QgsContrastEnhancement( *multiBandRenderer->blueContrastEnhancement() ) );
1215  }
1216  }
1217 
1218  emit styleChanged();
1219  emit rendererChanged();
1220  }
1221 }
1222 
1225  QgsRasterMinMaxOrigin::Limits &myLimits ) const
1226 {
1227  QgsSettings mySettings;
1228 
1229  QString key;
1230  QString defaultAlg;
1231  QString defaultLimits;
1232 
1233  // TODO: we should not test renderer class here, move it somehow to renderers
1234  if ( dynamic_cast<QgsSingleBandGrayRenderer *>( renderer() ) )
1235  {
1236  key = QStringLiteral( "singleBand" );
1239  defaultLimits = QgsRasterMinMaxOrigin::limitsString(
1241  }
1242  else if ( dynamic_cast<QgsMultiBandColorRenderer *>( renderer() ) )
1243  {
1244  if ( QgsRasterBlock::typeSize( dataProvider()->sourceDataType( 1 ) ) == 1 )
1245  {
1246  key = QStringLiteral( "multiBandSingleByte" );
1249  defaultLimits = QgsRasterMinMaxOrigin::limitsString(
1251  }
1252  else
1253  {
1254  key = QStringLiteral( "multiBandMultiByte" );
1257  defaultLimits = QgsRasterMinMaxOrigin::limitsString(
1259  }
1260  }
1261 
1262  if ( key.isEmpty() )
1263  {
1264  QgsDebugMsg( QStringLiteral( "No default contrast enhancement for this drawing style" ) );
1266  myLimits = QgsRasterMinMaxOrigin::limitsFromString( QString() );
1267  return false;
1268  }
1269  QgsDebugMsgLevel( "key = " + key, 4 );
1270 
1271  QString myAlgorithmString = mySettings.value( "/Raster/defaultContrastEnhancementAlgorithm/" + key, defaultAlg ).toString();
1272  QgsDebugMsgLevel( "myAlgorithmString = " + myAlgorithmString, 4 );
1273 
1274  myAlgorithm = QgsContrastEnhancement::contrastEnhancementAlgorithmFromString( myAlgorithmString );
1275 
1276  QString myLimitsString = mySettings.value( "/Raster/defaultContrastEnhancementLimits/" + key, defaultLimits ).toString();
1277  QgsDebugMsgLevel( "myLimitsString = " + myLimitsString, 4 );
1278  myLimits = QgsRasterMinMaxOrigin::limitsFromString( myLimitsString );
1279 
1280  return true;
1281 }
1282 
1284 {
1285  QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
1286 
1289  defaultContrastEnhancementSettings( myAlgorithm, myLimits );
1290 
1291  setContrastEnhancement( myAlgorithm, myLimits );
1292 }
1293 
1294 void QgsRasterLayer::setLayerOrder( QStringList const &layers )
1295 {
1296  QgsDebugMsgLevel( QStringLiteral( "entered." ), 4 );
1297 
1298  if ( mDataProvider )
1299  {
1300  QgsDebugMsgLevel( QStringLiteral( "About to mDataProvider->setLayerOrder(layers)." ), 4 );
1301  mDataProvider->setLayerOrder( layers );
1302  }
1303 
1304 }
1305 
1306 void QgsRasterLayer::setSubLayerVisibility( const QString &name, bool vis )
1307 {
1308 
1309  if ( mDataProvider )
1310  {
1311  QgsDebugMsgLevel( QStringLiteral( "About to mDataProvider->setSubLayerVisibility(name, vis)." ), 4 );
1312  mDataProvider->setSubLayerVisibility( name, vis );
1313  }
1314 
1315 }
1316 
1317 QDateTime QgsRasterLayer::timestamp() const
1318 {
1319  return mDataProvider->timestamp();
1320 }
1321 
1323 {
1324  if ( mPipe.renderer() )
1325  {
1326  if ( !mPipe.renderer()->accept( visitor ) )
1327  return false;
1328  }
1329  return true;
1330 }
1331 
1332 
1333 bool QgsRasterLayer::writeSld( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsStringMap &props ) const
1334 {
1335  Q_UNUSED( errorMessage )
1336 
1337  QgsStringMap localProps = QgsStringMap( props );
1338  if ( hasScaleBasedVisibility() )
1339  {
1340  // TODO: QgsSymbolLayerUtils::mergeScaleDependencies generate SE only and not SLD1.0
1342  }
1343 
1344  if ( isSpatial() ) // TODO: does it make sense this control?
1345  {
1346  // store constraints
1347  QDomElement constraintElem = doc.createElement( QStringLiteral( "sld:LayerFeatureConstraints" ) );
1348  node.appendChild( constraintElem );
1349 
1350  QDomElement featureTypeConstraintElem = doc.createElement( QStringLiteral( "sld:FeatureTypeConstraint" ) );
1351  constraintElem.appendChild( featureTypeConstraintElem );
1352 
1353  QDomElement userStyleElem = doc.createElement( QStringLiteral( "sld:UserStyle" ) );
1354  node.appendChild( userStyleElem );
1355 
1356  if ( !name().isEmpty() )
1357  {
1358  QDomElement nameElem = doc.createElement( QStringLiteral( "sld:Name" ) );
1359  nameElem.appendChild( doc.createTextNode( name() ) );
1360  userStyleElem.appendChild( nameElem );
1361  }
1362 
1363  if ( !abstract().isEmpty() )
1364  {
1365  QDomElement abstractElem = doc.createElement( QStringLiteral( "sld:Abstract" ) );
1366  abstractElem.appendChild( doc.createTextNode( abstract() ) );
1367  userStyleElem.appendChild( abstractElem );
1368  }
1369 
1370  if ( !title().isEmpty() )
1371  {
1372  QDomElement titleElem = doc.createElement( QStringLiteral( "sld:Title" ) );
1373  titleElem.appendChild( doc.createTextNode( title() ) );
1374  userStyleElem.appendChild( titleElem );
1375  }
1376 
1377  QDomElement featureTypeStyleElem = doc.createElement( QStringLiteral( "sld:FeatureTypeStyle" ) );
1378  userStyleElem.appendChild( featureTypeStyleElem );
1379 
1380 #if 0
1381  // TODO: Is there a way to fill it's value with the named style?
1382  // by default <sld:Name> under <sld:FeatureTypeStyle> can have 0 occurrences
1383  // the same happen for tags:
1384  // sld:Title
1385  // sld:Abstract
1386  // sld:FeatureTypeName
1387  // sld:SemanticTypeIdentifier
1388  QDomElement typeStyleNameElem = doc.createElement( QStringLiteral( "sld:Name" ) );
1389  featureTypeStyleElem.appendChild( typeStyleNameElem );
1390 #endif
1391 
1392  QDomElement typeStyleRuleElem = doc.createElement( QStringLiteral( "sld:Rule" ) );
1393  featureTypeStyleElem.appendChild( typeStyleRuleElem );
1394 
1395  // add ScaleDenominator tags
1396  if ( hasScaleBasedVisibility() )
1397  {
1398  // note that denominator is the inverted value of scale
1399  if ( maximumScale() != 0.0 )
1400  {
1401  QDomElement minScaleElem = doc.createElement( QStringLiteral( "sld:MinScaleDenominator" ) );
1402  minScaleElem.appendChild( doc.createTextNode( QString::number( maximumScale() ) ) );
1403  typeStyleRuleElem.appendChild( minScaleElem );
1404  }
1405 
1406  QDomElement maxScaleElem = doc.createElement( QStringLiteral( "sld:MaxScaleDenominator" ) );
1407  maxScaleElem.appendChild( doc.createTextNode( QString::number( minimumScale() ) ) );
1408  typeStyleRuleElem.appendChild( maxScaleElem );
1409  }
1410 
1411  // export renderer dependent tags
1412  mPipe.renderer()->toSld( doc, typeStyleRuleElem, localProps );
1413 
1414  // inject raster layer parameters in RasterSymbolizer tag because
1415  // they belongs to rasterlayer and not to the renderer => avoid to
1416  // pass many parameters value via localProps
1417  QDomNodeList elements = typeStyleRuleElem.elementsByTagName( QStringLiteral( "sld:RasterSymbolizer" ) );
1418  if ( elements.size() != 0 )
1419  {
1420  // there SHOULD be only one
1421  QDomElement rasterSymbolizerElem = elements.at( 0 ).toElement();
1422 
1423  // lamda helper used below to reduce code redundancy
1424  auto vendorOptionWriter = [&]( QString name, QString value )
1425  {
1426  QDomElement vendorOptionElem = doc.createElement( QStringLiteral( "sld:VendorOption" ) );
1427  vendorOptionElem.setAttribute( QStringLiteral( "name" ), name );
1428  vendorOptionElem.appendChild( doc.createTextNode( value ) );
1429  rasterSymbolizerElem.appendChild( vendorOptionElem );
1430  };
1431 
1432  // add greyScale rendering mode if set
1433  if ( hueSaturationFilter()->grayscaleMode() != QgsHueSaturationFilter::GrayscaleOff )
1434  {
1435  QString property;
1436  switch ( hueSaturationFilter()->grayscaleMode() )
1437  {
1439  property = QStringLiteral( "lightness" );
1440  break;
1442  property = QStringLiteral( "luminosity" );
1443  break;
1445  property = QStringLiteral( "average" );
1446  break;
1448  // added just to avoid travis fail
1449  break;
1450  }
1451  if ( !property.isEmpty() )
1452  vendorOptionWriter( QStringLiteral( "grayScale" ), property );
1453  }
1454 
1455  // add Hue, Saturation and Lighting values in props is Hue filter is set
1457  {
1458  vendorOptionWriter( QStringLiteral( "colorizeOn" ), QString::number( hueSaturationFilter()->colorizeOn() ) );
1459  vendorOptionWriter( QStringLiteral( "colorizeRed" ), QString::number( hueSaturationFilter()->colorizeColor().red() ) );
1460  vendorOptionWriter( QStringLiteral( "colorizeGreen" ), QString::number( hueSaturationFilter()->colorizeColor().green() ) );
1461  vendorOptionWriter( QStringLiteral( "colorizeBlue" ), QString::number( hueSaturationFilter()->colorizeColor().blue() ) );
1462  if ( hueSaturationFilter()->colorizeStrength() != 100.0 )
1463  vendorOptionWriter( QStringLiteral( "colorizeStrength" ), QString::number( hueSaturationFilter()->colorizeStrength() / 100.0 ) );
1464  vendorOptionWriter( QStringLiteral( "saturation" ), QString::number( hueSaturationFilter()->colorizeColor().saturationF() ) );
1465  }
1466  else
1467  {
1468  // saturation != 0 (default value)
1469  if ( hueSaturationFilter()->saturation() != 0 )
1470  {
1471  // normlize value [-100:100] -> [0:1]
1472  int s = hueSaturationFilter()->saturation();
1473  double sF = ( s - ( -100.0 ) ) / ( 100.0 - ( -100.0 ) );
1474  vendorOptionWriter( QStringLiteral( "saturation" ), QString::number( sF ) );
1475  }
1476  }
1477 
1478  // brightness != 0 (default value)
1479  if ( brightnessFilter()->brightness() != 0 )
1480  {
1481  // normalize value [-255:255] -> [0:1]
1482  int b = brightnessFilter()->brightness();
1483  double bF = ( b - ( -255.0 ) ) / ( 255.0 - ( -255.0 ) );
1484  vendorOptionWriter( QStringLiteral( "brightness" ), QString::number( bF ) );
1485  }
1486 
1487  // contrast != 0 (default value)
1488  if ( brightnessFilter()->contrast() != 0 )
1489  {
1490  // normlize value [-100:100] -> [0:1]
1491  int c = brightnessFilter()->contrast();
1492  double cF = ( c - ( -100.0 ) ) / ( 100.0 - ( -100.0 ) );
1493  vendorOptionWriter( QStringLiteral( "contrast" ), QString::number( cF ) );
1494  }
1495 
1496 #if 0
1497  // TODO: check if the below mapping formula make sense to map QGIS contrast with SLD gamma value
1498  //
1499  // add SLD1.0 ContrastEnhancement GammaValue = QGIS Contrast
1500  // SLD1.0 does only define 1 as neutral/center double value but does not define range.
1501  // because https://en.wikipedia.org/wiki/Gamma_correction assumed gamma is >0.
1502  // whilst QGIS has a -100/100 values centered in 0 => QGIS contrast value will be scaled in the
1503  // following way:
1504  // [-100,0] => [0,1] and [0,100] => [1,100]
1505  // an alternative could be scale [-100,100] => (0,2]
1506  //
1507  if ( newProps.contains( QStringLiteral( "contrast" ) ) )
1508  {
1509  double gamma;
1510  double contrast = newProps[ QStringLiteral( "contrast" ) ].toDouble();
1511  double percentage = ( contrast - ( -100.0 ) ) / ( 100.0 - ( -100.0 ) );
1512  if ( percentage <= 0.5 )
1513  {
1514  // stretch % to [0-1]
1515  gamma = percentage / 0.5;
1516  }
1517  else
1518  {
1519  gamma = contrast;
1520  }
1521 
1522  QDomElement globalContrastEnhancementElem = doc.createElement( QStringLiteral( "sld:ContrastEnhancement" ) );
1523  rasterSymolizerElem.appendChild( globalContrastEnhancementElem );
1524 
1525  QDomElement gammaValueElem = doc.createElement( QStringLiteral( "sld:GammaValue" ) );
1526  gammaValueElem.appendChild( doc.createTextNode( QString::number( gamma ) ) );
1527  globalContrastEnhancementElem.appendChild( gammaValueElem );
1528  }
1529 #endif
1530  }
1531  }
1532  return true;
1533 }
1534 
1535 
1537 {
1538  QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
1539  if ( !renderer )
1540  {
1541  return;
1542  }
1543 
1544  mPipe.set( renderer );
1545  emit rendererChanged();
1546  emit styleChanged();
1547 }
1548 
1549 void QgsRasterLayer::showStatusMessage( QString const &message )
1550 {
1551  // QgsDebugMsg(QString("entered with '%1'.").arg(theMessage));
1552 
1553  // Pass-through
1554  // TODO: See if we can connect signal-to-signal. This is a kludge according to the Qt doc.
1555  emit statusChanged( message );
1556 }
1557 
1559 {
1560  if ( mDataProvider )
1561  mDataProvider->setTransformContext( transformContext );
1562 }
1563 
1564 QStringList QgsRasterLayer::subLayers() const
1565 {
1566  return mDataProvider->subLayers();
1567 }
1568 
1569 // this function should be used when rendering with the MTR engine introduced in 2.3, as QPixmap is not thread safe (see bug #9626)
1570 // note: previewAsImage and previewAsPixmap should use a common low-level fct QgsRasterLayer::previewOnPaintDevice( QSize size, QColor bgColor, QPaintDevice &device )
1571 QImage QgsRasterLayer::previewAsImage( QSize size, const QColor &bgColor, QImage::Format format )
1572 {
1573  QImage image( size, format );
1574 
1575  if ( ! isValid( ) )
1576  return QImage();
1577 
1578  if ( image.format() == QImage::Format_Indexed8 )
1579  {
1580  image.setColor( 0, bgColor.rgba() );
1581  image.fill( 0 ); //defaults to white, set to transparent for rendering on a map
1582  }
1583  else
1584  {
1585  image.fill( bgColor );
1586  }
1587 
1588  QgsRasterViewPort *rasterViewPort = new QgsRasterViewPort();
1589 
1590  double mapUnitsPerPixel;
1591  double x = 0.0;
1592  double y = 0.0;
1593  QgsRectangle extent = mDataProvider->extent();
1594  if ( extent.width() / extent.height() >= static_cast< double >( image.width() ) / image.height() )
1595  {
1596  mapUnitsPerPixel = extent.width() / image.width();
1597  y = ( image.height() - extent.height() / mapUnitsPerPixel ) / 2;
1598  }
1599  else
1600  {
1601  mapUnitsPerPixel = extent.height() / image.height();
1602  x = ( image.width() - extent.width() / mapUnitsPerPixel ) / 2;
1603  }
1604 
1605  const double pixelWidth = extent.width() / mapUnitsPerPixel;
1606  const double pixelHeight = extent.height() / mapUnitsPerPixel;
1607 
1608  rasterViewPort->mTopLeftPoint = QgsPointXY( x, y );
1609  rasterViewPort->mBottomRightPoint = QgsPointXY( pixelWidth, pixelHeight );
1610  rasterViewPort->mWidth = image.width();
1611  rasterViewPort->mHeight = image.height();
1612 
1613  rasterViewPort->mDrawnExtent = extent;
1614  rasterViewPort->mSrcCRS = QgsCoordinateReferenceSystem(); // will be invalid
1615  rasterViewPort->mDestCRS = QgsCoordinateReferenceSystem(); // will be invalid
1616 
1617  QgsMapToPixel *mapToPixel = new QgsMapToPixel( mapUnitsPerPixel );
1618 
1619  QPainter *painter = new QPainter( &image );
1620  draw( painter, rasterViewPort, mapToPixel );
1621  delete rasterViewPort;
1622  delete mapToPixel;
1623 
1624  painter->end();
1625  delete painter;
1626 
1627  return image;
1628 }
1629 
1631 //
1632 // Protected methods
1633 //
1635 /*
1636  * \param QDomNode node that will contain the symbology definition for this layer.
1637  * \param errorMessage reference to string that will be updated with any error messages
1638  * \return true in case of success.
1639  */
1640 bool QgsRasterLayer::readSymbology( const QDomNode &layer_node, QString &errorMessage,
1641  QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
1642 {
1643  Q_UNUSED( errorMessage )
1644  // TODO: implement categories for raster layer
1645 
1646  QDomElement rasterRendererElem;
1647 
1648  QDomElement layerElement = layer_node.toElement();
1649  readCommonStyle( layerElement, context, categories );
1650 
1651  // pipe element was introduced in the end of 1.9 development when there were
1652  // already many project files in use so we support 1.9 backward compatibility
1653  // even it was never officially released -> use pipe element if present, otherwise
1654  // use layer node
1655  QDomNode pipeNode = layer_node.firstChildElement( QStringLiteral( "pipe" ) );
1656  if ( pipeNode.isNull() ) // old project
1657  {
1658  pipeNode = layer_node;
1659  }
1660 
1661  //rasterlayerproperties element there -> old format (1.8 and early 1.9)
1662  if ( !layer_node.firstChildElement( QStringLiteral( "rasterproperties" ) ).isNull() )
1663  {
1664  //copy node because layer_node is const
1665  QDomNode layerNodeCopy = layer_node.cloneNode();
1666  QDomDocument doc = layerNodeCopy.ownerDocument();
1667  QDomElement rasterPropertiesElem = layerNodeCopy.firstChildElement( QStringLiteral( "rasterproperties" ) );
1668  QgsProjectFileTransform::convertRasterProperties( doc, layerNodeCopy, rasterPropertiesElem,
1669  this );
1670  rasterRendererElem = layerNodeCopy.firstChildElement( QStringLiteral( "rasterrenderer" ) );
1671  QgsDebugMsgLevel( doc.toString(), 4 );
1672  }
1673  else
1674  {
1675  rasterRendererElem = pipeNode.firstChildElement( QStringLiteral( "rasterrenderer" ) );
1676  }
1677 
1678  if ( !rasterRendererElem.isNull() )
1679  {
1680  QString rendererType = rasterRendererElem.attribute( QStringLiteral( "type" ) );
1681  QgsRasterRendererRegistryEntry rendererEntry;
1682  if ( QgsApplication::rasterRendererRegistry()->rendererData( rendererType, rendererEntry ) )
1683  {
1684  QgsRasterRenderer *renderer = rendererEntry.rendererCreateFunction( rasterRendererElem, dataProvider() );
1685  mPipe.set( renderer );
1686  }
1687  }
1688 
1689  //brightness
1691  mPipe.set( brightnessFilter );
1692 
1693  //brightness coefficient
1694  QDomElement brightnessElem = pipeNode.firstChildElement( QStringLiteral( "brightnesscontrast" ) );
1695  if ( !brightnessElem.isNull() )
1696  {
1697  brightnessFilter->readXml( brightnessElem );
1698  }
1699 
1700  //hue/saturation
1702  mPipe.set( hueSaturationFilter );
1703 
1704  //saturation coefficient
1705  QDomElement hueSaturationElem = pipeNode.firstChildElement( QStringLiteral( "huesaturation" ) );
1706  if ( !hueSaturationElem.isNull() )
1707  {
1708  hueSaturationFilter->readXml( hueSaturationElem );
1709  }
1710 
1711  //resampler
1713  mPipe.set( resampleFilter );
1714 
1715  //max oversampling
1716  QDomElement resampleElem = pipeNode.firstChildElement( QStringLiteral( "rasterresampler" ) );
1717  if ( !resampleElem.isNull() )
1718  {
1719  resampleFilter->readXml( resampleElem );
1720  }
1721 
1722  // get and set the blend mode if it exists
1723  QDomNode blendModeNode = layer_node.namedItem( QStringLiteral( "blendMode" ) );
1724  if ( !blendModeNode.isNull() )
1725  {
1726  QDomElement e = blendModeNode.toElement();
1727  setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( e.text().toInt() ) ) );
1728  }
1729 
1730  readCustomProperties( layer_node );
1731 
1732  return true;
1733 }
1734 
1735 bool QgsRasterLayer::readStyle( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
1736 {
1737  return readSymbology( node, errorMessage, context, categories );
1738 }
1739 
1740 bool QgsRasterLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
1741 {
1742  QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
1743  // Make sure to read the file first so stats etc are initialized properly!
1744 
1745  //process provider key
1746  QDomNode pkeyNode = layer_node.namedItem( QStringLiteral( "provider" ) );
1747 
1748  if ( pkeyNode.isNull() )
1749  {
1750  mProviderKey = QStringLiteral( "gdal" );
1751  }
1752  else
1753  {
1754  QDomElement pkeyElt = pkeyNode.toElement();
1755  mProviderKey = pkeyElt.text();
1756  if ( mProviderKey.isEmpty() )
1757  {
1758  mProviderKey = QStringLiteral( "gdal" );
1759  }
1760  }
1761 
1762  // Open the raster source based on provider and datasource
1763 
1764  // Go down the raster-data-provider paradigm
1765 
1766  // Collect provider-specific information
1767 
1768  QDomNode rpNode = layer_node.namedItem( QStringLiteral( "rasterproperties" ) );
1769 
1770  if ( mProviderKey == QLatin1String( "wms" ) )
1771  {
1772  // >>> BACKWARD COMPATIBILITY < 1.9
1773  // The old WMS URI format does not contain all the information, we add them here.
1774  if ( !mDataSource.contains( QLatin1String( "crs=" ) ) && !mDataSource.contains( QLatin1String( "format=" ) ) )
1775  {
1776  QgsDebugMsgLevel( QStringLiteral( "Old WMS URI format detected -> adding params" ), 4 );
1777  QgsDataSourceUri uri;
1778  uri.setEncodedUri( mDataSource );
1779  QDomElement layerElement = rpNode.firstChildElement( QStringLiteral( "wmsSublayer" ) );
1780  while ( !layerElement.isNull() )
1781  {
1782  // TODO: sublayer visibility - post-0.8 release timeframe
1783 
1784  // collect name for the sublayer
1785  uri.setParam( QStringLiteral( "layers" ), layerElement.namedItem( QStringLiteral( "name" ) ).toElement().text() );
1786 
1787  // collect style for the sublayer
1788  uri.setParam( QStringLiteral( "styles" ), layerElement.namedItem( QStringLiteral( "style" ) ).toElement().text() );
1789 
1790  layerElement = layerElement.nextSiblingElement( QStringLiteral( "wmsSublayer" ) );
1791  }
1792 
1793  // Collect format
1794  QDomNode formatNode = rpNode.namedItem( QStringLiteral( "wmsFormat" ) );
1795  uri.setParam( QStringLiteral( "format" ), rpNode.namedItem( QStringLiteral( "wmsFormat" ) ).toElement().text() );
1796 
1797  // WMS CRS URL param should not be mixed with that assigned to the layer.
1798  // In the old WMS URI version there was no CRS and layer crs().authid() was used.
1799  uri.setParam( QStringLiteral( "crs" ), crs().authid() );
1800  mDataSource = uri.encodedUri();
1801  }
1802  // <<< BACKWARD COMPATIBILITY < 1.9
1803  }
1804 
1806  {
1807  QgsDataProvider::ProviderOptions providerOptions { context.transformContext() };
1808  setDataProvider( mProviderKey, providerOptions );
1809  }
1810 
1811  mOriginalStyleElement = layer_node.namedItem( QStringLiteral( "originalStyle" ) ).firstChildElement();
1812  if ( mOriginalStyleElement.isNull() )
1813  mOriginalStyleElement = layer_node.toElement();
1814  mOriginalStyleDocument = layer_node.ownerDocument();
1815 
1816  if ( ! mDataProvider )
1817  {
1818  if ( !( mReadFlags & QgsMapLayer::FlagDontResolveLayers ) )
1819  {
1820  QgsDebugMsg( QStringLiteral( "Raster data provider could not be created for %1" ).arg( mDataSource ) );
1821  }
1822  return false;
1823  }
1824 
1825  QString error;
1826  bool res = readSymbology( layer_node, error, context );
1827 
1828  // old wms settings we need to correct
1829  if ( res && mProviderKey == QLatin1String( "wms" ) && ( !renderer() || renderer()->type() != QLatin1String( "singlebandcolordata" ) ) )
1830  {
1831  setRendererForDrawingStyle( QgsRaster::SingleBandColorDataStyle );
1832  }
1833 
1834  // Check timestamp
1835  // This was probably introduced to reload completely raster if data changed and
1836  // reset completely symbology to reflect new data type etc. It creates however
1837  // problems, because user defined symbology is complete lost if data file time
1838  // changed (the content may be the same). See also 6900.
1839 #if 0
1840  QDomNode stampNode = layer_node.namedItem( "timestamp" );
1841  if ( !stampNode.isNull() )
1842  {
1843  QDateTime stamp = QDateTime::fromString( stampNode.toElement().text(), Qt::ISODate );
1844  // TODO: very bad, we have to load twice!!! Make QgsDataProvider::timestamp() static?
1845  if ( stamp < mDataProvider->dataTimestamp() )
1846  {
1847  QgsDebugMsg( QStringLiteral( "data changed, reload provider" ) );
1848  closeDataProvider();
1849  init();
1851  if ( !mValid ) return false;
1852  }
1853  }
1854 #endif
1855 
1856  // Load user no data value
1857  QDomElement noDataElement = layer_node.firstChildElement( QStringLiteral( "noData" ) );
1858 
1859  QDomNodeList noDataBandList = noDataElement.elementsByTagName( QStringLiteral( "noDataList" ) );
1860 
1861  for ( int i = 0; i < noDataBandList.size(); ++i )
1862  {
1863  QDomElement bandElement = noDataBandList.at( i ).toElement();
1864  bool ok;
1865  int bandNo = bandElement.attribute( QStringLiteral( "bandNo" ) ).toInt( &ok );
1866  QgsDebugMsgLevel( QStringLiteral( "bandNo = %1" ).arg( bandNo ), 4 );
1867  if ( ok && ( bandNo > 0 ) && ( bandNo <= mDataProvider->bandCount() ) )
1868  {
1869  mDataProvider->setUseSourceNoDataValue( bandNo, bandElement.attribute( QStringLiteral( "useSrcNoData" ) ).toInt() );
1870  QgsRasterRangeList myNoDataRangeList;
1871 
1872  QDomNodeList rangeList = bandElement.elementsByTagName( QStringLiteral( "noDataRange" ) );
1873 
1874  myNoDataRangeList.reserve( rangeList.size() );
1875  for ( int j = 0; j < rangeList.size(); ++j )
1876  {
1877  QDomElement rangeElement = rangeList.at( j ).toElement();
1878  QgsRasterRange myNoDataRange( rangeElement.attribute( QStringLiteral( "min" ) ).toDouble(),
1879  rangeElement.attribute( QStringLiteral( "max" ) ).toDouble() );
1880  QgsDebugMsgLevel( QStringLiteral( "min = %1 %2" ).arg( rangeElement.attribute( "min" ) ).arg( myNoDataRange.min() ), 4 );
1881  myNoDataRangeList << myNoDataRange;
1882  }
1883  mDataProvider->setUserNoDataValue( bandNo, myNoDataRangeList );
1884  }
1885  }
1886 
1887  readStyleManager( layer_node );
1888 
1889  return res;
1890 }
1891 
1892 bool QgsRasterLayer::writeSymbology( QDomNode &layer_node, QDomDocument &document, QString &errorMessage,
1893  const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1894 {
1895  Q_UNUSED( errorMessage )
1896  // TODO: implement categories for raster layer
1897 
1898  QDomElement layerElement = layer_node.toElement();
1899  writeCommonStyle( layerElement, document, context, categories );
1900 
1901  // Store pipe members (except provider) into pipe element, in future, it will be
1902  // possible to add custom filters into the pipe
1903  QDomElement pipeElement = document.createElement( QStringLiteral( "pipe" ) );
1904 
1905  for ( int i = 1; i < mPipe.size(); i++ )
1906  {
1907  QgsRasterInterface *interface = mPipe.at( i );
1908  if ( !interface ) continue;
1909  interface->writeXml( document, pipeElement );
1910  }
1911 
1912  layer_node.appendChild( pipeElement );
1913 
1914  if ( !isValid() && !mOriginalStyleElement.isNull() )
1915  {
1916  QDomElement originalStyleElement = document.createElement( QStringLiteral( "originalStyle" ) );
1917  originalStyleElement.appendChild( mOriginalStyleElement );
1918  layer_node.appendChild( originalStyleElement );
1919  }
1920 
1921  // add blend mode node
1922  QDomElement blendModeElement = document.createElement( QStringLiteral( "blendMode" ) );
1923  QDomText blendModeText = document.createTextNode( QString::number( QgsPainting::getBlendModeEnum( blendMode() ) ) );
1924  blendModeElement.appendChild( blendModeText );
1925  layer_node.appendChild( blendModeElement );
1926  return true;
1927 }
1928 
1929 bool QgsRasterLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage,
1930  const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1931 {
1932  return writeSymbology( node, doc, errorMessage, context, categories );
1933 } // bool QgsRasterLayer::writeSymbology
1934 
1935 /*
1936  * virtual
1937  * \note Called by QgsMapLayer::writeXml().
1938  */
1939 bool QgsRasterLayer::writeXml( QDomNode &layer_node,
1940  QDomDocument &document,
1941  const QgsReadWriteContext &context ) const
1942 {
1943  // first get the layer element so that we can append the type attribute
1944 
1945  QDomElement mapLayerNode = layer_node.toElement();
1946 
1947  if ( mapLayerNode.isNull() || "maplayer" != mapLayerNode.nodeName() )
1948  {
1949  QgsMessageLog::logMessage( tr( "<maplayer> not found." ), tr( "Raster" ) );
1950  return false;
1951  }
1952 
1953  mapLayerNode.setAttribute( QStringLiteral( "type" ), QStringLiteral( "raster" ) );
1954 
1955  // add provider node
1956 
1957  QDomElement provider = document.createElement( QStringLiteral( "provider" ) );
1958  QDomText providerText = document.createTextNode( mProviderKey );
1959  provider.appendChild( providerText );
1960  layer_node.appendChild( provider );
1961 
1962  // User no data
1963  QDomElement noData = document.createElement( QStringLiteral( "noData" ) );
1964 
1965  for ( int bandNo = 1; bandNo <= mDataProvider->bandCount(); bandNo++ )
1966  {
1967  QDomElement noDataRangeList = document.createElement( QStringLiteral( "noDataList" ) );
1968  noDataRangeList.setAttribute( QStringLiteral( "bandNo" ), bandNo );
1969  noDataRangeList.setAttribute( QStringLiteral( "useSrcNoData" ), mDataProvider->useSourceNoDataValue( bandNo ) );
1970 
1971  const auto constUserNoDataValues = mDataProvider->userNoDataValues( bandNo );
1972  for ( QgsRasterRange range : constUserNoDataValues )
1973  {
1974  QDomElement noDataRange = document.createElement( QStringLiteral( "noDataRange" ) );
1975 
1976  noDataRange.setAttribute( QStringLiteral( "min" ), QgsRasterBlock::printValue( range.min() ) );
1977  noDataRange.setAttribute( QStringLiteral( "max" ), QgsRasterBlock::printValue( range.max() ) );
1978  noDataRangeList.appendChild( noDataRange );
1979  }
1980 
1981  noData.appendChild( noDataRangeList );
1982 
1983  }
1984  if ( noData.hasChildNodes() )
1985  {
1986  layer_node.appendChild( noData );
1987  }
1988 
1989  writeStyleManager( layer_node, document );
1990 
1991  //write out the symbology
1992  QString errorMsg;
1993  return writeSymbology( layer_node, document, errorMsg, context );
1994 }
1995 
1996 // TODO: this should ideally go to gdal provider (together with most of encodedSource() + decodedSource())
1997 static bool _parseGpkgColons( const QString &src, QString &filename, QString &tablename )
1998 {
1999  // GDAL accepts the following input format: GPKG:filename:table
2000  // (GDAL won't accept quoted filename)
2001 
2002  QStringList lst = src.split( ':' );
2003  if ( lst.count() != 3 && lst.count() != 4 )
2004  return false;
2005 
2006  tablename = lst.last();
2007  if ( lst.count() == 3 )
2008  {
2009  filename = lst[1];
2010  return true;
2011  }
2012  else if ( lst.count() == 4 && lst[1].count() == 1 && ( lst[2][0] == '/' || lst[2][0] == '\\' ) )
2013  {
2014  // a bit of handling to make sure that filename C:\hello.gpkg is parsed correctly
2015  filename = lst[1] + ":" + lst[2];
2016  return true;
2017  }
2018  return false;
2019 }
2020 
2021 
2022 QString QgsRasterLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
2023 {
2024  QString src( source );
2025  bool handled = false;
2026 
2027  // Update path for subdataset
2028  if ( providerType() == QLatin1String( "gdal" ) )
2029  {
2030  if ( src.startsWith( QLatin1String( "NETCDF:" ) ) )
2031  {
2032  // NETCDF:filename:variable
2033  // filename can be quoted with " as it can contain colons
2034  QRegExp r( "NETCDF:(.+):([^:]+)" );
2035  if ( r.exactMatch( src ) )
2036  {
2037  QString filename = r.cap( 1 );
2038  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
2039  filename = filename.mid( 1, filename.length() - 2 );
2040  src = "NETCDF:\"" + context.pathResolver().writePath( filename ) + "\":" + r.cap( 2 );
2041  handled = true;
2042  }
2043  }
2044  else if ( src.startsWith( QLatin1String( "GPKG:" ) ) )
2045  {
2046  // GPKG:filename:table
2047  QString filename, tablename;
2048  if ( _parseGpkgColons( src, filename, tablename ) )
2049  {
2050  filename = context.pathResolver().writePath( filename );
2051  src = QStringLiteral( "GPKG:%1:%2" ).arg( filename, tablename );
2052  handled = true;
2053  }
2054  }
2055  else if ( src.startsWith( QLatin1String( "HDF4_SDS:" ) ) )
2056  {
2057  // HDF4_SDS:subdataset_type:file_name:subdataset_index
2058  // filename can be quoted with " as it can contain colons
2059  QRegExp r( "HDF4_SDS:([^:]+):(.+):([^:]+)" );
2060  if ( r.exactMatch( src ) )
2061  {
2062  QString filename = r.cap( 2 );
2063  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
2064  filename = filename.mid( 1, filename.length() - 2 );
2065  src = "HDF4_SDS:" + r.cap( 1 ) + ":\"" + context.pathResolver().writePath( filename ) + "\":" + r.cap( 3 );
2066  handled = true;
2067  }
2068  }
2069  else if ( src.startsWith( QLatin1String( "HDF5:" ) ) )
2070  {
2071  // HDF5:file_name:subdataset
2072  // filename can be quoted with " as it can contain colons
2073  QRegExp r( "HDF5:(.+):([^:]+)" );
2074  if ( r.exactMatch( src ) )
2075  {
2076  QString filename = r.cap( 1 );
2077  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
2078  filename = filename.mid( 1, filename.length() - 2 );
2079  src = "HDF5:\"" + context.pathResolver().writePath( filename ) + "\":" + r.cap( 2 );
2080  handled = true;
2081  }
2082  }
2083  else if ( src.contains( QRegExp( "^(NITF_IM|RADARSAT_2_CALIB):" ) ) )
2084  {
2085  // NITF_IM:0:filename
2086  // RADARSAT_2_CALIB:?:filename
2087  QRegExp r( "([^:]+):([^:]+):(.+)" );
2088  if ( r.exactMatch( src ) )
2089  {
2090  src = r.cap( 1 ) + ':' + r.cap( 2 ) + ':' + context.pathResolver().writePath( r.cap( 3 ) );
2091  handled = true;
2092  }
2093  }
2094  }
2095  else if ( providerType() == "wms" )
2096  {
2097  // handle relative paths to XYZ tiles
2098  QgsDataSourceUri uri;
2099  uri.setEncodedUri( src );
2100  QUrl srcUrl( uri.param( QStringLiteral( "url" ) ) );
2101  if ( srcUrl.isLocalFile() )
2102  {
2103  // relative path will become "file:./x.txt"
2104  QString relSrcUrl = context.pathResolver().writePath( srcUrl.toLocalFile() );
2105  uri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
2106  uri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( relSrcUrl ).toString() );
2107  src = uri.encodedUri();
2108  handled = true;
2109  }
2110  }
2111 
2112  if ( !handled )
2113  src = context.pathResolver().writePath( src );
2114 
2115  return src;
2116 }
2117 
2118 QString QgsRasterLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
2119 {
2120  QString src( source );
2121 
2122  if ( provider == QLatin1String( "wms" ) )
2123  {
2124  // >>> BACKWARD COMPATIBILITY < 1.9
2125  // For project file backward compatibility we must support old format:
2126  // 1. mode: <url>
2127  // example: http://example.org/wms?
2128  // 2. mode: tiled=<width>;<height>;<resolution>;<resolution>...,ignoreUrl=GetMap;GetFeatureInfo,featureCount=<count>,username=<name>,password=<password>,url=<url>
2129  // example: tiled=256;256;0.703;0.351,url=http://example.org/tilecache?
2130  // example: featureCount=10,http://example.org/wms?
2131  // example: ignoreUrl=GetMap;GetFeatureInfo,username=cimrman,password=jara,url=http://example.org/wms?
2132  // This is modified version of old QgsWmsProvider::parseUri
2133  // The new format has always params crs,format,layers,styles and that params
2134  // should not appear in old format url -> use them to identify version
2135  // XYZ tile layers do not need to contain crs,format params, but they have type=xyz
2136  if ( !src.contains( QLatin1String( "type=" ) ) &&
2137  !src.contains( QLatin1String( "crs=" ) ) && !src.contains( QLatin1String( "format=" ) ) )
2138  {
2139  QgsDebugMsg( QStringLiteral( "Old WMS URI format detected -> converting to new format" ) );
2140  QgsDataSourceUri uri;
2141  if ( !src.startsWith( QLatin1String( "http:" ) ) )
2142  {
2143  QStringList parts = src.split( ',' );
2144  QStringListIterator iter( parts );
2145  while ( iter.hasNext() )
2146  {
2147  QString item = iter.next();
2148  if ( item.startsWith( QLatin1String( "username=" ) ) )
2149  {
2150  uri.setParam( QStringLiteral( "username" ), item.mid( 9 ) );
2151  }
2152  else if ( item.startsWith( QLatin1String( "password=" ) ) )
2153  {
2154  uri.setParam( QStringLiteral( "password" ), item.mid( 9 ) );
2155  }
2156  else if ( item.startsWith( QLatin1String( "tiled=" ) ) )
2157  {
2158  // in < 1.9 tiled= may apper in to variants:
2159  // tiled=width;height - non tiled mode, specifies max width and max height
2160  // tiled=width;height;resolutions-1;resolution2;... - tile mode
2161 
2162  QStringList params = item.mid( 6 ).split( ';' );
2163 
2164  if ( params.size() == 2 ) // non tiled mode
2165  {
2166  uri.setParam( QStringLiteral( "maxWidth" ), params.takeFirst() );
2167  uri.setParam( QStringLiteral( "maxHeight" ), params.takeFirst() );
2168  }
2169  else if ( params.size() > 2 ) // tiled mode
2170  {
2171  // resolutions are no more needed and size limit is not used for tiles
2172  // we have to tell to the provider however that it is tiled
2173  uri.setParam( QStringLiteral( "tileMatrixSet" ), QString() );
2174  }
2175  }
2176  else if ( item.startsWith( QLatin1String( "featureCount=" ) ) )
2177  {
2178  uri.setParam( QStringLiteral( "featureCount" ), item.mid( 13 ) );
2179  }
2180  else if ( item.startsWith( QLatin1String( "url=" ) ) )
2181  {
2182  uri.setParam( QStringLiteral( "url" ), item.mid( 4 ) );
2183  }
2184  else if ( item.startsWith( QLatin1String( "ignoreUrl=" ) ) )
2185  {
2186  uri.setParam( QStringLiteral( "ignoreUrl" ), item.mid( 10 ).split( ';' ) );
2187  }
2188  }
2189  }
2190  else
2191  {
2192  uri.setParam( QStringLiteral( "url" ), src );
2193  }
2194  src = uri.encodedUri();
2195  // At this point, the URI is obviously incomplete, we add additional params
2196  // in QgsRasterLayer::readXml
2197  }
2198  // <<< BACKWARD COMPATIBILITY < 1.9
2199 
2200  // handle relative paths to XYZ tiles
2201  QgsDataSourceUri uri;
2202  uri.setEncodedUri( src );
2203  QUrl srcUrl( uri.param( QStringLiteral( "url" ) ) );
2204  if ( srcUrl.isLocalFile() ) // file-based URL? convert to relative path
2205  {
2206  QString absSrcUrl = context.pathResolver().readPath( srcUrl.toLocalFile() );
2207  uri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
2208  uri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( absSrcUrl ).toString() );
2209  src = uri.encodedUri();
2210  }
2211 
2212  }
2213  else
2214  {
2215  bool handled = false;
2216 
2217  if ( provider == QLatin1String( "gdal" ) )
2218  {
2219  if ( src.startsWith( QLatin1String( "NETCDF:" ) ) )
2220  {
2221  // NETCDF:filename:variable
2222  // filename can be quoted with " as it can contain colons
2223  QRegExp r( "NETCDF:(.+):([^:]+)" );
2224  if ( r.exactMatch( src ) )
2225  {
2226  QString filename = r.cap( 1 );
2227  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
2228  filename = filename.mid( 1, filename.length() - 2 );
2229  src = "NETCDF:\"" + context.pathResolver().readPath( filename ) + "\":" + r.cap( 2 );
2230  handled = true;
2231  }
2232  }
2233  else if ( src.startsWith( QLatin1String( "GPKG:" ) ) )
2234  {
2235  // GPKG:filename:table
2236  QString filename, tablename;
2237  if ( _parseGpkgColons( src, filename, tablename ) )
2238  {
2239  filename = context.pathResolver().readPath( filename );
2240  src = QStringLiteral( "GPKG:%1:%2" ).arg( filename, tablename );
2241  handled = true;
2242  }
2243  }
2244  else if ( src.startsWith( QLatin1String( "HDF4_SDS:" ) ) )
2245  {
2246  // HDF4_SDS:subdataset_type:file_name:subdataset_index
2247  // filename can be quoted with " as it can contain colons
2248  QRegExp r( "HDF4_SDS:([^:]+):(.+):([^:]+)" );
2249  if ( r.exactMatch( src ) )
2250  {
2251  QString filename = r.cap( 2 );
2252  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
2253  filename = filename.mid( 1, filename.length() - 2 );
2254  src = "HDF4_SDS:" + r.cap( 1 ) + ":\"" + context.pathResolver().readPath( filename ) + "\":" + r.cap( 3 );
2255  handled = true;
2256  }
2257  }
2258  else if ( src.startsWith( QLatin1String( "HDF5:" ) ) )
2259  {
2260  // HDF5:file_name:subdataset
2261  // filename can be quoted with " as it can contain colons
2262  QRegExp r( "HDF5:(.+):([^:]+)" );
2263  if ( r.exactMatch( src ) )
2264  {
2265  QString filename = r.cap( 1 );
2266  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
2267  filename = filename.mid( 1, filename.length() - 2 );
2268  src = "HDF5:\"" + context.pathResolver().readPath( filename ) + "\":" + r.cap( 2 );
2269  handled = true;
2270  }
2271  }
2272  else if ( src.contains( QRegExp( "^(NITF_IM|RADARSAT_2_CALIB):" ) ) )
2273  {
2274  // NITF_IM:0:filename
2275  // RADARSAT_2_CALIB:?:filename
2276  QRegExp r( "([^:]+):([^:]+):(.+)" );
2277  if ( r.exactMatch( src ) )
2278  {
2279  src = r.cap( 1 ) + ':' + r.cap( 2 ) + ':' + context.pathResolver().readPath( r.cap( 3 ) );
2280  handled = true;
2281  }
2282  }
2283  }
2284 
2285  if ( !handled )
2286  src = context.pathResolver().readPath( src );
2287  }
2288 
2289  return src;
2290 }
2291 
2293 {
2294  if ( !mDataProvider ) return 0;
2295  return mDataProvider->xSize();
2296 }
2297 
2299 {
2300  if ( !mDataProvider ) return 0;
2301  return mDataProvider->ySize();
2302 }
2303 
2305 //
2306 // Private methods
2307 //
2309 bool QgsRasterLayer::update()
2310 {
2311  QgsDebugMsgLevel( QStringLiteral( "entered." ), 4 );
2312  // Check if data changed
2313  if ( mDataProvider->dataTimestamp() > mDataProvider->timestamp() )
2314  {
2315  QgsDebugMsgLevel( QStringLiteral( "reload data" ), 4 );
2316  closeDataProvider();
2317  init();
2318  QgsDataProvider::ProviderOptions providerOptions;
2319  setDataProvider( mProviderKey, providerOptions );
2320  emit dataChanged();
2321  }
2322  return mValid;
2323 }
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:87
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 const QString QGIS_VERSION
Version string.
Definition: qgis.h:52
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.
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.
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.
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
bool mShouldValidateCrs
true if the layer&#39;s CRS should be validated and invalid CRSes are not permitted.
Definition: qgsmaplayer.h:1541
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:1529
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:280
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
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:86
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:80
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
int mWidth
Width, number of columns to be rendered.
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 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:88
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.
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:612
Sixteen bit signed integer (qint16)
Definition: qgis.h:85
QDateTime timestamp() const override
Time stamp of data source in the moment when data/metadata were loaded by provider.
Complex Int16.
Definition: qgis.h:90
QString mLayerName
Name of the layer - used for display.
Definition: qgsmaplayer.h:1486
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:89
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:95
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.
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:92
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:531
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.
QString description() const
Returns the descriptive name of the CRS, e.g., "WGS 84" or "GDA 94 / Vicgrid94".
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:91
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:84
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.
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:1480
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:279
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.
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:1483
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.
virtual void reloadData()
Reloads the data from the source.
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.
int mHeight
Distance in map units from bottom edge to top edge for the part of the raster that is to be rendered...
Brightness/contrast filter pipe for rasters.
Bilinear Raster Resampler.
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:1472
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:93
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:1474
QString authid() const
Returns the authority identifier for the CRS.
Eight bit unsigned integer (quint8)
Definition: qgis.h:83
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:94
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:1534
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.