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