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