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