QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
qgsrasterlayer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsrasterlayer.cpp - description
3 -------------------
4begin : Sat Jun 22 2002
5copyright : (C) 2003 by Tim Sutton, Steve Halasz and Gary E.Sherman
6email : 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"
22#include "qgsdatasourceuri.h"
25#include "qgslogger.h"
26#include "qgsmaplayerlegend.h"
27#include "qgsmaplayerutils.h"
28#include "qgsmaptopixel.h"
29#include "qgsmessagelog.h"
31#include "qgspainting.h"
33#include "qgspathresolver.h"
35#include "qgsproviderregistry.h"
37#include "qgsrasterdrawer.h"
38#include "qgsrasteriterator.h"
39#include "qgsrasterlayer.h"
41#include "qgsrasterprojector.h"
42#include "qgsrasterrange.h"
45#include "qgsrastershader.h"
46#include "qgsreadwritecontext.h"
47#include "qgsxmlutils.h"
48#include "qgsrectangle.h"
49#include "qgsrendercontext.h"
53#include "qgssettings.h"
54#include "qgssymbollayerutils.h"
55#include "qgsgdalprovider.h"
59#include "qgsruntimeprofiler.h"
60#include "qgsmaplayerfactory.h"
61#include "qgsrasterpipe.h"
64
65#include <cmath>
66#include <cstdio>
67#include <limits>
68#include <typeinfo>
69
70#include <QApplication>
71#include <QCursor>
72#include <QDir>
73#include <QDomElement>
74#include <QDomNode>
75#include <QFile>
76#include <QFileInfo>
77#include <QFont>
78#include <QFontMetrics>
79#include <QFrame>
80#include <QImage>
81#include <QLabel>
82#include <QList>
83#include <QPainter>
84#include <QPixmap>
85#include <QRegularExpression>
86#include <QSlider>
87#include <QUrl>
88
89#define ERR(message) QGS_ERROR_MESSAGE(message,"Raster layer")
90
91const double QgsRasterLayer::SAMPLE_SIZE = 250000;
92
99
106
109 , QSTRING_NOT_SET( QStringLiteral( "Not Set" ) )
110 , TRSTRING_NOT_SET( tr( "Not Set" ) )
111 , mTemporalProperties( new QgsRasterLayerTemporalProperties( this ) )
112 , mElevationProperties( new QgsRasterLayerElevationProperties( this ) )
113 , mPipe( std::make_unique< QgsRasterPipe >() )
114{
115 init();
116 setValid( false );
117}
118
120 const QString &baseName,
121 const QString &providerKey,
122 const LayerOptions &options )
123 : QgsMapLayer( QgsMapLayerType::RasterLayer, baseName, uri )
124 // Constant that signals property not used.
125 , QSTRING_NOT_SET( QStringLiteral( "Not Set" ) )
126 , TRSTRING_NOT_SET( tr( "Not Set" ) )
127 , mTemporalProperties( new QgsRasterLayerTemporalProperties( this ) )
128 , mElevationProperties( new QgsRasterLayerElevationProperties( this ) )
129 , mPipe( std::make_unique< QgsRasterPipe >() )
130{
132
133 QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
134 setProviderType( providerKey );
135
136 const QgsDataProvider::ProviderOptions providerOptions { options.transformContext };
137 QgsDataProvider::ReadFlags providerFlags = QgsDataProvider::ReadFlags();
138 if ( options.loadDefaultStyle )
139 {
141 }
142 setDataSource( uri, baseName, providerKey, providerOptions, providerFlags );
143
144 if ( isValid() )
145 {
146 mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( mDataProvider->temporalCapabilities() );
147 }
148
149} // QgsRasterLayer ctor
150
152{
153 emit willBeDeleted();
154
155 setValid( false );
156 // Note: provider and other interfaces are owned and deleted by pipe
157}
158
160{
162 if ( mDataProvider )
163 {
164 options.transformContext = mDataProvider->transformContext();
165 }
166 QgsRasterLayer *layer = new QgsRasterLayer( source(), name(), mProviderKey, options );
167 QgsMapLayer::clone( layer );
168 layer->mElevationProperties = mElevationProperties->clone();
169 layer->mElevationProperties->setParent( layer );
170
171 // do not clone data provider which is the first element in pipe
172 for ( int i = 1; i < mPipe->size(); i++ )
173 {
174 if ( mPipe->at( i ) )
175 layer->pipe()->set( mPipe->at( i )->clone() );
176 }
177 layer->pipe()->setDataDefinedProperties( mPipe->dataDefinedProperties() );
178
179 return layer;
180}
181
183{
184 if ( !mElevationProperties->isEnabled() )
185 return nullptr;
186
187 return new QgsRasterLayerProfileGenerator( this, request );
188}
189
191//
192// Static Methods and members
193//
195
196bool QgsRasterLayer::isValidRasterFileName( const QString &fileNameQString, QString &retErrMsg )
197{
198 const bool myIsValid = QgsGdalProvider::isValidRasterFileName( fileNameQString, retErrMsg );
199 return myIsValid;
200}
201
202bool QgsRasterLayer::isValidRasterFileName( QString const &fileNameQString )
203{
204 QString retErrMsg;
205 return isValidRasterFileName( fileNameQString, retErrMsg );
206}
207
208QDateTime QgsRasterLayer::lastModified( QString const &name )
209{
210 QgsDebugMsgLevel( "name=" + name, 4 );
211 QDateTime t;
212
213 const QFileInfo fi( name );
214
215 // Is it file?
216 if ( !fi.exists() )
217 return t;
218
219 t = fi.lastModified();
220
221 QgsDebugMsgLevel( "last modified = " + t.toString(), 4 );
222
223 return t;
224}
225
226void QgsRasterLayer::setDataProvider( const QString &provider )
227{
229}
230
231// typedef for the QgsDataProvider class factory
233
235//
236// Non Static Public methods
237//
239
241{
242 if ( !mDataProvider ) return 0;
243 return mDataProvider->bandCount();
244}
245
246QString QgsRasterLayer::bandName( int bandNo ) const
247{
248 if ( !mDataProvider ) return QString();
249 return mDataProvider->generateBandName( bandNo );
250}
251
252void QgsRasterLayer::setRendererForDrawingStyle( QgsRaster::DrawingStyle drawingStyle )
253{
254 setRenderer( QgsApplication::rasterRendererRegistry()->defaultRendererForDrawingStyle( drawingStyle, mDataProvider ) );
255}
256
258{
259 return mDataProvider;
260}
261
263{
264 return mDataProvider;
265}
266
268{
269 if ( mDataProvider )
270 {
271 mDataProvider->reloadData();
272 }
273}
274
276{
277 return new QgsRasterLayerRenderer( this, rendererContext );
278}
279
280
281void QgsRasterLayer::draw( QPainter *theQPainter,
282 QgsRasterViewPort *rasterViewPort,
283 const QgsMapToPixel *qgsMapToPixel )
284{
285 QgsDebugMsgLevel( QStringLiteral( " 3 arguments" ), 4 );
286 QElapsedTimer time;
287 time.start();
288 //
289 //
290 // The goal here is to make as many decisions as possible early on (outside of the rendering loop)
291 // so that we can maximise performance of the rendering process. So now we check which drawing
292 // procedure to use :
293 //
294
295 QgsRasterProjector *projector = mPipe->projector();
296 bool restoreOldResamplingStage = false;
297 const Qgis::RasterResamplingStage oldResamplingState = resamplingStage();
298 // TODO add a method to interface to get provider and get provider
299 // params in QgsRasterProjector
300
301 if ( projector )
302 {
303 // Force provider resampling if reprojection is needed
304 if ( mDataProvider != nullptr &&
306 rasterViewPort->mSrcCRS != rasterViewPort->mDestCRS &&
307 oldResamplingState != Qgis::RasterResamplingStage::Provider )
308 {
309 restoreOldResamplingStage = true;
311 }
312 projector->setCrs( rasterViewPort->mSrcCRS, rasterViewPort->mDestCRS, rasterViewPort->mTransformContext );
313 }
314
315 // Drawer to pipe?
316 QgsRasterIterator iterator( mPipe->last() );
317 QgsRasterDrawer drawer( &iterator );
318 drawer.draw( theQPainter, rasterViewPort, qgsMapToPixel );
319
320 if ( restoreOldResamplingStage )
321 {
322 setResamplingStage( oldResamplingState );
323 }
324
325 QgsDebugMsgLevel( QStringLiteral( "total raster draw time (ms): %1" ).arg( time.elapsed(), 5 ), 4 );
326}
327
329{
330 QgsRasterRenderer *renderer = mPipe->renderer();
331 return renderer ? renderer->legendSymbologyItems() : QList< QPair< QString, QColor > >();;
332}
333
335{
336 if ( !mDataProvider )
337 return QString();
338
339 const QgsLayerMetadataFormatter htmlFormatter( metadata() );
340 QString myMetadata = QStringLiteral( "<html><head></head>\n<body>\n" );
341
342 myMetadata += generalHtmlMetadata();
343
344 // Begin Provider section
345 myMetadata += QStringLiteral( "<h1>" ) + tr( "Information from provider" ) + QStringLiteral( "</h1>\n<hr>\n" ) + QStringLiteral( "<table class=\"list-view\">\n" );
346
347 myMetadata += QStringLiteral( "\n" ) %
348 // Extent
349 QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Extent" ) % QStringLiteral( "</td><td>" ) % extent().toString() % QStringLiteral( "</td></tr>\n" ) %
350
351 // Raster Width
352 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 += QStringLiteral( "</td></tr>\n" ) %
358
359 // Raster height
360 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 += QStringLiteral( "</td></tr>\n" ) %
366
367 // Data type
368 QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Data type" ) % QStringLiteral( "</td><td>" );
369 // Just use the first band
370 switch ( mDataProvider->sourceDataType( 1 ) )
371 {
373 myMetadata += tr( "Byte - Eight bit unsigned integer" );
374 break;
376 myMetadata += tr( "UInt16 - Sixteen bit unsigned integer " );
377 break;
379 myMetadata += tr( "Int16 - Sixteen bit signed integer " );
380 break;
382 myMetadata += tr( "UInt32 - Thirty two bit unsigned integer " );
383 break;
385 myMetadata += tr( "Int32 - Thirty two bit signed integer " );
386 break;
388 myMetadata += tr( "Float32 - Thirty two bit floating point " );
389 break;
391 myMetadata += tr( "Float64 - Sixty four bit floating point " );
392 break;
394 myMetadata += tr( "CInt16 - Complex Int16 " );
395 break;
397 myMetadata += tr( "CInt32 - Complex Int32 " );
398 break;
400 myMetadata += tr( "CFloat32 - Complex Float32 " );
401 break;
403 myMetadata += tr( "CFloat64 - Complex Float64 " );
404 break;
405 default:
406 myMetadata += tr( "Could not determine raster data type." );
407 }
408 myMetadata += QStringLiteral( "</td></tr>\n" ) %
409
410 // Insert provider-specific (e.g. WMS-specific) metadata
411 mDataProvider->htmlMetadata() %
412
413 // End Provider section
414 QStringLiteral( "</table>\n<br><br>" );
415
416 // CRS
417 myMetadata += crsHtmlMetadata();
418
419 // Identification section
420 myMetadata += QStringLiteral( "<h1>" ) % tr( "Identification" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
421 htmlFormatter.identificationSectionHtml() %
422 QStringLiteral( "<br><br>\n" ) %
423
424 // extent section
425 QStringLiteral( "<h1>" ) % tr( "Extent" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
426 htmlFormatter.extentSectionHtml( ) %
427 QStringLiteral( "<br><br>\n" ) %
428
429 // Start the Access section
430 QStringLiteral( "<h1>" ) % tr( "Access" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
431 htmlFormatter.accessSectionHtml( ) %
432 QStringLiteral( "<br><br>\n" ) %
433
434 // Bands section
435 QStringLiteral( "</table>\n<br><br><h1>" ) % tr( "Bands" ) % QStringLiteral( "</h1>\n<hr>\n<table class=\"list-view\">\n" ) %
436
437 // Band count
438 QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Band count" ) % QStringLiteral( "</td><td>" ) % QString::number( bandCount() ) % QStringLiteral( "</td></tr>\n" );
439
440 // Band table
441 myMetadata += QStringLiteral( "</table>\n<br><table width=\"100%\" class=\"tabular-view\">\n" ) %
442 QStringLiteral( "<tr><th>" ) % tr( "Number" ) % QStringLiteral( "</th><th>" ) % tr( "Band" ) % QStringLiteral( "</th><th>" ) % tr( "No-Data" ) % QStringLiteral( "</th><th>" ) %
443 tr( "Min" ) % QStringLiteral( "</th><th>" ) % tr( "Max" ) % QStringLiteral( "</th></tr>\n" );
444
445 QgsRasterDataProvider *provider = const_cast< QgsRasterDataProvider * >( mDataProvider );
446 for ( int i = 1; i <= bandCount(); i++ )
447 {
448 QString rowClass;
449 if ( i % 2 )
450 rowClass = QStringLiteral( "class=\"odd-row\"" );
451
452 myMetadata += QStringLiteral( "<tr " ) % rowClass % QStringLiteral( "><td>" ) % QString::number( i ) % QStringLiteral( "</td><td>" ) % bandName( i ) % QStringLiteral( "</td><td>" );
453
454 if ( dataProvider()->sourceHasNoDataValue( i ) )
455 myMetadata += QString::number( dataProvider()->sourceNoDataValue( i ) );
456 else
457 myMetadata += tr( "n/a" );
458 myMetadata += QLatin1String( "</td>" );
459
461 {
462 const QgsRasterBandStats myRasterBandStats = provider->bandStatistics( i, QgsRasterBandStats::Min | QgsRasterBandStats::Max, provider->extent(), SAMPLE_SIZE );
463 myMetadata += QStringLiteral( "<td>" ) % QString::number( myRasterBandStats.minimumValue, 'f', 10 ) % QStringLiteral( "</td>" ) %
464 QStringLiteral( "<td>" ) % QString::number( myRasterBandStats.maximumValue, 'f', 10 ) % QStringLiteral( "</td>" );
465 }
466 else
467 {
468 myMetadata += QStringLiteral( "<td>" ) % tr( "n/a" ) % QStringLiteral( "</td><td>" ) % tr( "n/a" ) % QStringLiteral( "</td>" );
469 }
470
471 myMetadata += QLatin1String( "</tr>\n" );
472 }
473
474 //close previous bands table
475 myMetadata += QStringLiteral( "</table>\n<br><br>" ) %
476
477 // Start the contacts section
478 QStringLiteral( "<h1>" ) % tr( "Contacts" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
479 htmlFormatter.contactsSectionHtml( ) %
480 QStringLiteral( "<br><br>\n" ) %
481
482 // Start the links section
483 QStringLiteral( "<h1>" ) % tr( "References" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
484 htmlFormatter.linksSectionHtml( ) %
485 QStringLiteral( "<br><br>\n" ) %
486
487 // Start the history section
488 QStringLiteral( "<h1>" ) % tr( "History" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
489 htmlFormatter.historySectionHtml( ) %
490 QStringLiteral( "<br><br>\n" ) %
491
492 QStringLiteral( "\n</body>\n</html>\n" );
493 return myMetadata;
494}
495
496Qgis::MapLayerProperties QgsRasterLayer::properties() const
497{
498 Qgis::MapLayerProperties res;
499 if ( mDataProvider && ( mDataProvider->flags() & Qgis::DataProviderFlag::IsBasemapSource ) )
500 {
502 }
503 return res;
504}
505
506QPixmap QgsRasterLayer::paletteAsPixmap( int bandNumber )
507{
508 //TODO: This function should take dimensions
509 QgsDebugMsgLevel( QStringLiteral( "entered." ), 4 );
510
511 // Only do this for the GDAL provider?
512 // Maybe WMS can do this differently using QImage::numColors and QImage::color()
513 if ( mDataProvider &&
514 mDataProvider->colorInterpretation( bandNumber ) == QgsRaster::PaletteIndex )
515 {
516 QgsDebugMsgLevel( QStringLiteral( "....found paletted image" ), 4 );
517 QgsColorRampShader myShader;
518 const QList<QgsColorRampShader::ColorRampItem> myColorRampItemList = mDataProvider->colorTable( bandNumber );
519 if ( !myColorRampItemList.isEmpty() )
520 {
521 QgsDebugMsgLevel( QStringLiteral( "....got color ramp item list" ), 4 );
522 myShader.setColorRampItemList( myColorRampItemList );
524 // Draw image
525 const int mySize = 100;
526 QPixmap myPalettePixmap( mySize, mySize );
527 QPainter myQPainter( &myPalettePixmap );
528
529 QImage myQImage = QImage( mySize, mySize, QImage::Format_RGB32 );
530 myQImage.fill( 0 );
531 myPalettePixmap.fill();
532
533 const double myStep = ( static_cast< double >( myColorRampItemList.size() ) - 1 ) / static_cast< double >( mySize * mySize );
534 double myValue = 0.0;
535 for ( int myRow = 0; myRow < mySize; myRow++ )
536 {
537 QRgb *myLineBuffer = reinterpret_cast< QRgb * >( myQImage.scanLine( myRow ) );
538 for ( int myCol = 0; myCol < mySize; myCol++ )
539 {
540 myValue = myStep * static_cast< double >( myCol + myRow * mySize );
541 int c1, c2, c3, c4;
542 myShader.shade( myValue, &c1, &c2, &c3, &c4 );
543 myLineBuffer[ myCol ] = qRgba( c1, c2, c3, c4 );
544 }
545 }
546
547 myQPainter.drawImage( 0, 0, myQImage );
548 return myPalettePixmap;
549 }
550 const QPixmap myNullPixmap;
551 return myNullPixmap;
552 }
553 else
554 {
555 //invalid layer was requested
556 const QPixmap myNullPixmap;
557 return myNullPixmap;
558 }
559}
560
562{
563 return mProviderKey;
564}
565
567{
568// We return one raster pixel per map unit pixel
569// One raster pixel can have several raster units...
570
571// We can only use one of the mGeoTransform[], so go with the
572// horisontal one.
573
574 if ( mDataProvider &&
575 mDataProvider->capabilities() & QgsRasterDataProvider::Size && !qgsDoubleNear( mDataProvider->xSize(), 0.0 ) )
576 {
577 return mDataProvider->extent().width() / mDataProvider->xSize();
578 }
579 return 1;
580}
581
583{
584 if ( mDataProvider &&
585 mDataProvider->capabilities() & QgsRasterDataProvider::Size && !qgsDoubleNear( mDataProvider->ySize(), 0.0 ) )
586 {
587 return mDataProvider->extent().height() / mDataProvider->ySize();
588 }
589 return 1;
590}
591
592void QgsRasterLayer::setOpacity( double opacity )
593{
594 if ( !mPipe->renderer() || mPipe->renderer()->opacity() == opacity )
595 return;
596
597 mPipe->renderer()->setOpacity( opacity );
598 emit opacityChanged( opacity );
600}
601
603{
604 return mPipe->renderer() ? mPipe->renderer()->opacity() : 1.0;
605}
606
607void QgsRasterLayer::init()
608{
610
611 whileBlocking( this )->setLegend( QgsMapLayerLegend::defaultRasterLegend( this ) );
612
613 setRendererForDrawingStyle( QgsRaster::UndefinedDrawingStyle );
614
615 //Initialize the last view port structure, should really be a class
616 mLastViewPort.mWidth = 0;
617 mLastViewPort.mHeight = 0;
618}
619
620void QgsRasterLayer::setDataProvider( QString const &provider, const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
621{
622 QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
623 setValid( false ); // assume the layer is invalid until we determine otherwise
624
625 // deletes pipe elements (including data provider)
626 mPipe = std::make_unique< QgsRasterPipe >();
627 mDataProvider = nullptr;
628
629 // XXX should I check for and possibly delete any pre-existing providers?
630 // XXX How often will that scenario occur?
631
632 mProviderKey = provider;
633 // set the layer name (uppercase first character)
634 if ( ! mLayerName.isEmpty() ) // XXX shouldn't this happen in parent?
635 {
637 }
638
639 //mBandCount = 0;
640
641 std::unique_ptr< QgsScopedRuntimeProfile > profile;
642 if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
643 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Create %1 provider" ).arg( provider ), QStringLiteral( "projectload" ) );
644
645 mDataProvider = qobject_cast< QgsRasterDataProvider * >( QgsProviderRegistry::instance()->createProvider( mProviderKey, mDataSource, options, flags ) );
646 if ( !mDataProvider )
647 {
648 //QgsMessageLog::logMessage( tr( "Cannot instantiate the data provider" ), tr( "Raster" ) );
649 appendError( ERR( tr( "Cannot instantiate the '%1' data provider" ).arg( mProviderKey ) ) );
650 return;
651 }
652 QgsDebugMsgLevel( QStringLiteral( "Data provider created" ), 4 );
653 mDataProvider->setParent( this );
654
655 // Set data provider into pipe even if not valid so that it is deleted with pipe (with layer)
656 mPipe->set( mDataProvider );
657 if ( !mDataProvider->isValid() )
658 {
659 setError( mDataProvider->error() );
660 appendError( ERR( tr( "Provider is not valid (provider: %1, URI: %2" ).arg( mProviderKey, mDataSource ) ) );
661 return;
662 }
663
665 {
666 setMetadata( mDataProvider->layerMetadata() );
667 QgsDebugMsgLevel( QStringLiteral( "Set Data provider QgsLayerMetadata identifier[%1]" ).arg( metadata().identifier() ), 4 );
668 }
669
670 if ( provider == QLatin1String( "gdal" ) )
671 {
672 // make sure that the /vsigzip or /vsizip is added to uri, if applicable
673 mDataSource = mDataProvider->dataSourceUri();
674 }
675
677 {
678 // get the extent
679 const QgsRectangle mbr = mDataProvider->extent();
680
681 // store the extent
682 setExtent( mbr );
683 }
684
685 // upper case the first letter of the layer name
686 QgsDebugMsgLevel( "mLayerName: " + name(), 4 );
687
688 // set up the raster drawing style
689 // Do not set any 'sensible' style here, the style is set later
690
691 // Setup source CRS
692 setCrs( QgsCoordinateReferenceSystem( mDataProvider->crs() ) );
693
694 QgsDebugMsgLevel( "using wkt:\n" + crs().toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED ), 4 );
695
696 //defaults - Needs to be set after the Contrast list has been build
697 //Try to read the default contrast enhancement from the config file
698
699 //decide what type of layer this is...
700 //TODO Change this to look at the color interp and palette interp to decide which type of layer it is
701 QgsDebugMsgLevel( "bandCount = " + QString::number( mDataProvider->bandCount() ), 4 );
702 QgsDebugMsgLevel( "dataType = " + qgsEnumValueToKey< Qgis::DataType >( mDataProvider->dataType( 1 ) ), 4 );
703 if ( ( mDataProvider->bandCount() > 1 ) )
704 {
705 // handle singleband gray with alpha
706 if ( mDataProvider->bandCount() == 2
707 && ( ( mDataProvider->colorInterpretation( 1 ) == QgsRaster::GrayIndex
708 && mDataProvider->colorInterpretation( 2 ) == QgsRaster::AlphaBand )
709 || ( mDataProvider->colorInterpretation( 1 ) == QgsRaster::AlphaBand
710 && mDataProvider->colorInterpretation( 2 ) == QgsRaster::GrayIndex ) ) )
711 {
712 mRasterType = GrayOrUndefined;
713 }
714 else
715 {
716 mRasterType = Multiband;
717 }
718 }
719 else if ( mDataProvider->dataType( 1 ) == Qgis::DataType::ARGB32
720 || mDataProvider->dataType( 1 ) == Qgis::DataType::ARGB32_Premultiplied )
721 {
722 mRasterType = ColorLayer;
723 }
724 else if ( mDataProvider->colorInterpretation( 1 ) == QgsRaster::PaletteIndex )
725 {
726 mRasterType = Palette;
727 }
728 else if ( mDataProvider->colorInterpretation( 1 ) == QgsRaster::ContinuousPalette )
729 {
730 mRasterType = Palette;
731 }
732 else
733 {
734 mRasterType = GrayOrUndefined;
735 }
736
737 QgsDebugMsgLevel( "mRasterType = " + QString::number( mRasterType ), 4 );
738 if ( mRasterType == ColorLayer )
739 {
740 QgsDebugMsgLevel( "Setting drawing style to SingleBandColorDataStyle " + QString::number( QgsRaster::SingleBandColorDataStyle ), 4 );
741 setRendererForDrawingStyle( QgsRaster::SingleBandColorDataStyle );
742 }
743 else if ( mRasterType == Palette && mDataProvider->colorInterpretation( 1 ) == QgsRaster::PaletteIndex )
744 {
745 setRendererForDrawingStyle( QgsRaster::PalettedColor ); //sensible default
746 }
747 else if ( mRasterType == Palette && mDataProvider->colorInterpretation( 1 ) == QgsRaster::ContinuousPalette )
748 {
749 setRendererForDrawingStyle( QgsRaster::SingleBandPseudoColor );
750 // Load color table
751 const QList<QgsColorRampShader::ColorRampItem> colorTable = mDataProvider->colorTable( 1 );
753 if ( r )
754 {
755 // TODO: this should go somewhere else
756 QgsRasterShader *shader = new QgsRasterShader();
757 QgsColorRampShader *colorRampShader = new QgsColorRampShader();
759 colorRampShader->setColorRampItemList( colorTable );
760 shader->setRasterShaderFunction( colorRampShader );
761 r->setShader( shader );
762 }
763 }
764 else if ( mRasterType == Multiband )
765 {
766 setRendererForDrawingStyle( QgsRaster::MultiBandColor ); //sensible default
767 }
768 else //GrayOrUndefined
769 {
770 setRendererForDrawingStyle( QgsRaster::SingleBandGray ); //sensible default
771 }
772
773 // Auto set alpha band
774 for ( int bandNo = 1; bandNo <= mDataProvider->bandCount(); bandNo++ )
775 {
776 if ( mDataProvider->colorInterpretation( bandNo ) == QgsRaster::AlphaBand )
777 {
778 if ( auto *lRenderer = mPipe->renderer() )
779 {
780 lRenderer->setAlphaBand( bandNo );
781 }
782 break;
783 }
784 }
785
786 // brightness filter
788 mPipe->set( brightnessFilter );
789
790 // hue/saturation filter
792 mPipe->set( hueSaturationFilter );
793
794 // resampler (must be after renderer)
796 mPipe->set( resampleFilter );
797
799 {
800 const QgsSettings settings;
801 QString resampling = settings.value( QStringLiteral( "/Raster/defaultZoomedInResampling" ), QStringLiteral( "nearest neighbour" ) ).toString();
802 if ( resampling == QLatin1String( "bilinear" ) )
803 {
806 }
807 else if ( resampling == QLatin1String( "cubic" ) )
808 {
811 }
812 resampling = settings.value( QStringLiteral( "/Raster/defaultZoomedOutResampling" ), QStringLiteral( "nearest neighbour" ) ).toString();
813 if ( resampling == QLatin1String( "bilinear" ) )
814 {
817 }
818
819 const double maxOversampling = settings.value( QStringLiteral( "/Raster/defaultOversampling" ), 2.0 ).toDouble();
820 resampleFilter->setMaxOversampling( maxOversampling );
821 mDataProvider->setMaxOversampling( maxOversampling );
822
824 settings.value( QStringLiteral( "/Raster/defaultEarlyResampling" ), false ).toBool() )
825 {
827 }
828 else
829 {
831 }
832 }
833
834 // projector (may be anywhere in pipe)
835 QgsRasterProjector *projector = new QgsRasterProjector;
836 mPipe->set( projector );
837
838 // Set default identify format - use the richest format available
839 const int capabilities = mDataProvider->capabilities();
841 if ( capabilities & QgsRasterInterface::IdentifyHtml )
842 {
843 // HTML is usually richest
844 identifyFormat = QgsRaster::IdentifyFormatHtml;
845 }
846 else if ( capabilities & QgsRasterInterface::IdentifyFeature )
847 {
848 identifyFormat = QgsRaster::IdentifyFormatFeature;
849 }
850 else if ( capabilities & QgsRasterInterface::IdentifyText )
851 {
852 identifyFormat = QgsRaster::IdentifyFormatText;
853 }
854 else if ( capabilities & QgsRasterInterface::IdentifyValue )
855 {
856 identifyFormat = QgsRaster::IdentifyFormatValue;
857 }
858 setCustomProperty( QStringLiteral( "identify/format" ), QgsRasterDataProvider::identifyFormatName( identifyFormat ) );
859
860 // Store timestamp
861 // TODO move to provider
862 mLastModified = lastModified( mDataSource );
863
864 // Do a passthrough for the status bar text
866
867 //mark the layer as valid
868 setValid( true );
869
870 if ( mDataProvider->supportsSubsetString() )
871 connect( this, &QgsRasterLayer::subsetStringChanged, this, &QgsMapLayer::configChanged, Qt::UniqueConnection );
872 else
874
875
876 QgsDebugMsgLevel( QStringLiteral( "exiting." ), 4 );
877
878}
879
880void QgsRasterLayer::setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider,
881 const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
882{
883 const bool hadRenderer( renderer() );
884
885 QDomImplementation domImplementation;
886 QDomDocumentType documentType;
887 QString errorMsg;
888
889 bool loadDefaultStyleFlag = false;
891 {
892 loadDefaultStyleFlag = true;
893 }
894
895 // Store the original style
896 if ( hadRenderer && ! loadDefaultStyleFlag )
897 {
898 documentType = domImplementation.createDocumentType(
899 QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
900
901 QDomDocument doc = QDomDocument( documentType );
902 QDomElement styleElem = doc.createElement( QStringLiteral( "qgis" ) );
903 styleElem.setAttribute( QStringLiteral( "version" ), Qgis::version() );
904 const QgsReadWriteContext writeContext;
905 if ( ! writeSymbology( styleElem, doc, errorMsg, writeContext ) )
906 {
907 QgsDebugMsg( QStringLiteral( "Could not store symbology for layer %1: %2" )
908 .arg( name(),
909 errorMsg ) );
910 }
911 else
912 {
913 doc.appendChild( styleElem );
914
915 mOriginalStyleDocument = doc;
916 mOriginalStyleElement = styleElem;
917 }
918 }
919
920 if ( mDataProvider )
921 closeDataProvider();
922
923 init();
924
925 for ( int i = mPipe->size() - 1; i >= 0; --i )
926 {
927 mPipe->remove( i );
928 }
929
930 mDataSource = dataSource;
931 mLayerName = baseName;
932
933 setDataProvider( provider, options, flags );
934
935 if ( mDataProvider )
936 mDataProvider->setDataSourceUri( mDataSource );
937
938 if ( isValid() )
939 {
940 // load default style
941 bool defaultLoadedFlag = false;
942 bool restoredStyle = false;
943 if ( loadDefaultStyleFlag )
944 {
945 loadDefaultStyle( defaultLoadedFlag );
946 }
947 else if ( !mOriginalStyleElement.isNull() ) // Restore the style
948 {
949 QgsReadWriteContext readContext;
950 if ( ! readSymbology( mOriginalStyleElement, errorMsg, readContext ) )
951 {
952 QgsDebugMsg( QStringLiteral( "Could not restore symbology for layer %1: %2" )
953 .arg( name() )
954 .arg( errorMsg ) );
955
956 }
957 else
958 {
959 restoredStyle = true;
960 emit repaintRequested();
962 emit rendererChanged();
963 }
964 }
965
966 if ( !defaultLoadedFlag && !restoredStyle )
967 {
969 }
970 }
971}
972
973void QgsRasterLayer::closeDataProvider()
974{
975 setValid( false );
976 mPipe->remove( mDataProvider );
977 mDataProvider = nullptr;
978}
979
980void QgsRasterLayer::computeMinMax( int band,
981 const QgsRasterMinMaxOrigin &mmo,
983 const QgsRectangle &extent,
984 int sampleSize,
985 double &min, double &max )
986{
987
988 min = std::numeric_limits<double>::quiet_NaN();
989 max = std::numeric_limits<double>::quiet_NaN();
990 if ( !mDataProvider )
991 return;
992
993 if ( limits == QgsRasterMinMaxOrigin::MinMax )
994 {
995 QgsRasterBandStats myRasterBandStats = mDataProvider->bandStatistics( band, QgsRasterBandStats::Min | QgsRasterBandStats::Max, extent, sampleSize );
996 // Check if statistics were actually gathered, None means a failure
997 if ( myRasterBandStats.statsGathered == QgsRasterBandStats::Stats::None )
998 {
999 // Best guess we can do
1000 switch ( mDataProvider->dataType( band ) )
1001 {
1003 {
1004 myRasterBandStats.minimumValue = 0;
1005 myRasterBandStats.maximumValue = 255;
1006 break;
1007 }
1009 {
1010 myRasterBandStats.minimumValue = 0;
1011 myRasterBandStats.maximumValue = std::numeric_limits<uint16_t>::max();
1012 break;
1013 }
1015 {
1016 myRasterBandStats.minimumValue = 0;
1017 myRasterBandStats.maximumValue = std::numeric_limits<uint32_t>::max();
1018 break;
1019 }
1022 {
1023 myRasterBandStats.minimumValue = std::numeric_limits<int16_t>::lowest();
1024 myRasterBandStats.maximumValue = std::numeric_limits<int16_t>::max();
1025 break;
1026 }
1029 {
1030 myRasterBandStats.minimumValue = std::numeric_limits<int32_t>::lowest();
1031 myRasterBandStats.maximumValue = std::numeric_limits<int32_t>::max();
1032 break;
1033 }
1036 {
1037 myRasterBandStats.minimumValue = std::numeric_limits<float_t>::lowest();
1038 myRasterBandStats.maximumValue = std::numeric_limits<float_t>::max();
1039 break;
1040 }
1043 {
1044 myRasterBandStats.minimumValue = std::numeric_limits<double_t>::lowest();
1045 myRasterBandStats.maximumValue = std::numeric_limits<double_t>::max();
1046 break;
1047 }
1051 {
1052 // Nothing to guess
1053 break;
1054 }
1055 }
1056 }
1057 min = myRasterBandStats.minimumValue;
1058 max = myRasterBandStats.maximumValue;
1059 }
1060 else if ( limits == QgsRasterMinMaxOrigin::StdDev )
1061 {
1062 const QgsRasterBandStats myRasterBandStats = mDataProvider->bandStatistics( band, QgsRasterBandStats::Mean | QgsRasterBandStats::StdDev, extent, sampleSize );
1063 min = myRasterBandStats.mean - ( mmo.stdDevFactor() * myRasterBandStats.stdDev );
1064 max = myRasterBandStats.mean + ( mmo.stdDevFactor() * myRasterBandStats.stdDev );
1065 }
1066 else if ( limits == QgsRasterMinMaxOrigin::CumulativeCut )
1067 {
1068 const double myLower = mmo.cumulativeCutLower();
1069 const double myUpper = mmo.cumulativeCutUpper();
1070 QgsDebugMsgLevel( QStringLiteral( "myLower = %1 myUpper = %2" ).arg( myLower ).arg( myUpper ), 4 );
1071 mDataProvider->cumulativeCut( band, myLower, myUpper, min, max, extent, sampleSize );
1072 }
1073 QgsDebugMsgLevel( QStringLiteral( "band = %1 min = %2 max = %3" ).arg( band ).arg( min ).arg( max ), 4 );
1074
1075}
1076
1078{
1079 return mDataProvider ? mDataProvider->ignoreExtents() : false;
1080}
1081
1083{
1084 return mTemporalProperties;
1085}
1086
1088{
1089 return mElevationProperties;
1090}
1091
1093{
1095 limits,
1096 extent,
1097 sampleSize,
1098 generateLookupTableFlag,
1099 mPipe->renderer() );
1100}
1101
1104 const QgsRectangle &extent,
1105 int sampleSize,
1106 bool generateLookupTableFlag,
1107 QgsRasterRenderer *rasterRenderer )
1108{
1109 QgsDebugMsgLevel( QStringLiteral( "theAlgorithm = %1 limits = %2 extent.isEmpty() = %3" ).arg( algorithm ).arg( limits ).arg( extent.isEmpty() ), 4 );
1110 if ( !rasterRenderer || !mDataProvider )
1111 {
1112 return;
1113 }
1114
1115 QList<int> myBands;
1116 QList<QgsContrastEnhancement *> myEnhancements;
1117 QgsRasterMinMaxOrigin myMinMaxOrigin;
1118 QgsRasterRenderer *myRasterRenderer = nullptr;
1119 QgsSingleBandGrayRenderer *myGrayRenderer = nullptr;
1120 QgsSingleBandPseudoColorRenderer *myPseudoColorRenderer = nullptr;
1121 QgsMultiBandColorRenderer *myMultiBandRenderer = nullptr;
1122 const QString rendererType = rasterRenderer->type();
1123 if ( rendererType == QLatin1String( "singlebandgray" ) )
1124 {
1125 myGrayRenderer = dynamic_cast<QgsSingleBandGrayRenderer *>( rasterRenderer );
1126 if ( !myGrayRenderer )
1127 {
1128 return;
1129 }
1130 myBands << myGrayRenderer->grayBand();
1131 myRasterRenderer = myGrayRenderer;
1132 myMinMaxOrigin = myGrayRenderer->minMaxOrigin();
1133 }
1134 else if ( rendererType == QLatin1String( "multibandcolor" ) )
1135 {
1136 myMultiBandRenderer = dynamic_cast<QgsMultiBandColorRenderer *>( rasterRenderer );
1137 if ( !myMultiBandRenderer )
1138 {
1139 return;
1140 }
1141 myBands << myMultiBandRenderer->redBand() << myMultiBandRenderer->greenBand() << myMultiBandRenderer->blueBand();
1142 myRasterRenderer = myMultiBandRenderer;
1143 myMinMaxOrigin = myMultiBandRenderer->minMaxOrigin();
1144 }
1145 else if ( rendererType == QLatin1String( "singlebandpseudocolor" ) )
1146 {
1147 myPseudoColorRenderer = dynamic_cast<QgsSingleBandPseudoColorRenderer *>( rasterRenderer );
1148 if ( !myPseudoColorRenderer )
1149 {
1150 return;
1151 }
1152 myBands << myPseudoColorRenderer->band();
1153 myRasterRenderer = myPseudoColorRenderer;
1154 myMinMaxOrigin = myPseudoColorRenderer->minMaxOrigin();
1155 }
1156 else
1157 {
1158 return;
1159 }
1160
1161 const auto constMyBands = myBands;
1162 for ( const int myBand : constMyBands )
1163 {
1164 if ( myBand != -1 )
1165 {
1166 const Qgis::DataType myType = static_cast< Qgis::DataType >( mDataProvider->dataType( myBand ) );
1167 std::unique_ptr<QgsContrastEnhancement> myEnhancement( new QgsContrastEnhancement( static_cast< Qgis::DataType >( myType ) ) );
1168 myEnhancement->setContrastEnhancementAlgorithm( algorithm, generateLookupTableFlag );
1169
1170 double min;
1171 double max;
1172 computeMinMax( myBand, myMinMaxOrigin, limits, extent, sampleSize, min, max );
1173
1174 if ( rendererType == QLatin1String( "singlebandpseudocolor" ) )
1175 {
1176 myPseudoColorRenderer->setClassificationMin( min );
1177 myPseudoColorRenderer->setClassificationMax( max );
1178 if ( myPseudoColorRenderer->shader() )
1179 {
1180 QgsColorRampShader *colorRampShader = dynamic_cast<QgsColorRampShader *>( myPseudoColorRenderer->shader()->rasterShaderFunction() );
1181 if ( colorRampShader )
1182 {
1183 colorRampShader->classifyColorRamp( myPseudoColorRenderer->band(), extent, myPseudoColorRenderer->input() );
1184 }
1185 }
1186 }
1187 else
1188 {
1189 myEnhancement->setMinimumValue( min );
1190 myEnhancement->setMaximumValue( max );
1191 myEnhancements.append( myEnhancement.release() );
1192 }
1193 }
1194 else
1195 {
1196 myEnhancements.append( nullptr );
1197 }
1198 }
1199
1200 if ( rendererType == QLatin1String( "singlebandgray" ) )
1201 {
1202 if ( myEnhancements.first() ) myGrayRenderer->setContrastEnhancement( myEnhancements.takeFirst() );
1203 }
1204 else if ( rendererType == QLatin1String( "multibandcolor" ) )
1205 {
1206 if ( myEnhancements.first() ) myMultiBandRenderer->setRedContrastEnhancement( myEnhancements.takeFirst() );
1207 if ( myEnhancements.first() ) myMultiBandRenderer->setGreenContrastEnhancement( myEnhancements.takeFirst() );
1208 if ( myEnhancements.first() ) myMultiBandRenderer->setBlueContrastEnhancement( myEnhancements.takeFirst() );
1209 }
1210
1211 //delete all remaining unused enhancements
1212 qDeleteAll( myEnhancements );
1213
1214 myMinMaxOrigin.setLimits( limits );
1215 if ( extent != QgsRectangle() &&
1216 myMinMaxOrigin.extent() == QgsRasterMinMaxOrigin::WholeRaster )
1217 {
1219 }
1220 if ( myRasterRenderer )
1221 {
1222 myRasterRenderer->setMinMaxOrigin( myMinMaxOrigin );
1223 }
1224
1225 if ( rasterRenderer == renderer() )
1226 {
1227 emit repaintRequested();
1229 emit rendererChanged();
1230 }
1231}
1232
1234{
1235 QgsSingleBandGrayRenderer *singleBandRenderer = nullptr;
1236 QgsMultiBandColorRenderer *multiBandRenderer = nullptr;
1237 const QgsContrastEnhancement *ce = nullptr;
1238 if ( ( singleBandRenderer = dynamic_cast<QgsSingleBandGrayRenderer *>( renderer() ) ) )
1239 {
1240 ce = singleBandRenderer->contrastEnhancement();
1241 }
1242 else if ( ( multiBandRenderer = dynamic_cast<QgsMultiBandColorRenderer *>( renderer() ) ) )
1243 {
1244 ce = multiBandRenderer->redContrastEnhancement();
1245 }
1246
1247 if ( ce )
1248 {
1251 renderer()->minMaxOrigin().limits() == QgsRasterMinMaxOrigin::None ?
1252 QgsRasterMinMaxOrigin::MinMax : renderer()->minMaxOrigin().limits(),
1253 extent,
1255 true,
1256 renderer() );
1257 }
1258 else
1259 {
1262 if ( defaultContrastEnhancementSettings( myAlgorithm, myLimits ) )
1263 {
1265 myLimits,
1266 extent,
1268 true,
1269 renderer() );
1270 }
1271 }
1272}
1273
1275 const QgsRectangle &extent )
1276{
1277 if ( mDataProvider &&
1278 mLastRectangleUsedByRefreshContrastEnhancementIfNeeded != extent &&
1279 rasterRenderer->minMaxOrigin().limits() != QgsRasterMinMaxOrigin::None &&
1281 {
1282 refreshRenderer( rasterRenderer, extent );
1283 }
1284}
1285
1286void QgsRasterLayer::refreshRenderer( QgsRasterRenderer *rasterRenderer, const QgsRectangle &extent )
1287{
1288 if ( mDataProvider )
1289 {
1290 QgsSingleBandGrayRenderer *singleBandRenderer = nullptr;
1291 QgsMultiBandColorRenderer *multiBandRenderer = nullptr;
1292 QgsSingleBandPseudoColorRenderer *sbpcr = nullptr;
1293 const QgsContrastEnhancement *ce = nullptr;
1294 if ( ( singleBandRenderer = dynamic_cast<QgsSingleBandGrayRenderer *>( rasterRenderer ) ) )
1295 {
1296 ce = singleBandRenderer->contrastEnhancement();
1297 }
1298 else if ( ( multiBandRenderer = dynamic_cast<QgsMultiBandColorRenderer *>( rasterRenderer ) ) )
1299 {
1300 ce = multiBandRenderer->redContrastEnhancement();
1301 }
1302 else if ( ( sbpcr = dynamic_cast<QgsSingleBandPseudoColorRenderer *>( rasterRenderer ) ) )
1303 {
1304 mLastRectangleUsedByRefreshContrastEnhancementIfNeeded = extent;
1305 double min;
1306 double max;
1307 computeMinMax( sbpcr->band(),
1308 rasterRenderer->minMaxOrigin(),
1309 rasterRenderer->minMaxOrigin().limits(), extent,
1310 SAMPLE_SIZE, min, max );
1311 sbpcr->setClassificationMin( min );
1312 sbpcr->setClassificationMax( max );
1313
1314 if ( sbpcr->shader() )
1315 {
1316 QgsColorRampShader *colorRampShader = dynamic_cast<QgsColorRampShader *>( sbpcr->shader()->rasterShaderFunction() );
1317 if ( colorRampShader )
1318 {
1319 colorRampShader->classifyColorRamp( sbpcr->band(), extent, rasterRenderer->input() );
1320 }
1321 }
1322
1324 r->setClassificationMin( min );
1325 r->setClassificationMax( max );
1326
1327 if ( r->shader() )
1328 {
1329 QgsColorRampShader *colorRampShader = dynamic_cast<QgsColorRampShader *>( r->shader()->rasterShaderFunction() );
1330 if ( colorRampShader )
1331 {
1332 colorRampShader->classifyColorRamp( sbpcr->band(), extent, rasterRenderer->input() );
1333 }
1334 }
1335
1336 emit repaintRequested();
1338 emit rendererChanged();
1339 return;
1340 }
1341
1342 if ( ce &&
1344 {
1345 mLastRectangleUsedByRefreshContrastEnhancementIfNeeded = extent;
1346
1348 rasterRenderer->minMaxOrigin().limits(),
1349 extent,
1351 true,
1352 rasterRenderer );
1353
1354 // Update main renderer so that the legends get updated
1355 if ( singleBandRenderer )
1356 static_cast<QgsSingleBandGrayRenderer *>( renderer() )->setContrastEnhancement( new QgsContrastEnhancement( * singleBandRenderer->contrastEnhancement() ) );
1357 else if ( multiBandRenderer )
1358 {
1359 if ( multiBandRenderer->redContrastEnhancement() )
1360 {
1361 static_cast<QgsMultiBandColorRenderer *>( renderer() )->setRedContrastEnhancement( new QgsContrastEnhancement( *multiBandRenderer->redContrastEnhancement() ) );
1362 }
1363 if ( multiBandRenderer->greenContrastEnhancement() )
1364 {
1365 static_cast<QgsMultiBandColorRenderer *>( renderer() )->setGreenContrastEnhancement( new QgsContrastEnhancement( *multiBandRenderer->greenContrastEnhancement() ) );
1366 }
1367 if ( multiBandRenderer->blueContrastEnhancement() )
1368 {
1369 static_cast<QgsMultiBandColorRenderer *>( renderer() )->setBlueContrastEnhancement( new QgsContrastEnhancement( *multiBandRenderer->blueContrastEnhancement() ) );
1370 }
1371 }
1372
1374 emit rendererChanged();
1375 }
1376 }
1377}
1378
1380{
1381 if ( !isValid() || !mDataProvider )
1382 {
1383 QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer or null mDataProvider" ), 3 );
1384 return customProperty( QStringLiteral( "storedSubsetString" ) ).toString();
1385 }
1386 if ( !mDataProvider->supportsSubsetString() )
1387 {
1388 return QString();
1389 }
1390 return mDataProvider->subsetString();
1391}
1392
1393bool QgsRasterLayer::setSubsetString( const QString &subset )
1394{
1395 if ( !isValid() || !mDataProvider )
1396 {
1397 QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer or null mDataProvider or while editing" ), 3 );
1398 setCustomProperty( QStringLiteral( "storedSubsetString" ), subset );
1399 return false;
1400 }
1401
1402 if ( !mDataProvider->supportsSubsetString() )
1403 {
1404 return false;
1405 }
1406
1407 if ( subset == mDataProvider->subsetString() )
1408 return true;
1409
1410 const bool res = mDataProvider->setSubsetString( subset );
1411
1412 // get the updated data source string from the provider
1413 mDataSource = mDataProvider->dataSourceUri();
1414
1415 if ( res )
1416 {
1417 setExtent( mDataProvider->extent() );
1418 refreshRenderer( renderer(), extent() );
1419 emit subsetStringChanged();
1420 }
1421
1422 return res;
1423}
1424
1427 QgsRasterMinMaxOrigin::Limits &myLimits ) const
1428{
1429 const QgsSettings mySettings;
1430
1431 QString key;
1432 QString defaultAlg;
1433 QString defaultLimits;
1434
1435 // TODO: we should not test renderer class here, move it somehow to renderers
1436 if ( dynamic_cast<QgsSingleBandGrayRenderer *>( renderer() ) )
1437 {
1438 key = QStringLiteral( "singleBand" );
1443 }
1444 else if ( dynamic_cast<QgsMultiBandColorRenderer *>( renderer() ) )
1445 {
1446 if ( QgsRasterBlock::typeSize( dataProvider()->sourceDataType( 1 ) ) == 1 )
1447 {
1448 key = QStringLiteral( "multiBandSingleByte" );
1453 }
1454 else
1455 {
1456 key = QStringLiteral( "multiBandMultiByte" );
1461 }
1462 }
1463
1464 if ( key.isEmpty() )
1465 {
1466 QgsDebugMsgLevel( QStringLiteral( "No default contrast enhancement for this drawing style" ), 2 );
1468 myLimits = QgsRasterMinMaxOrigin::limitsFromString( QString() );
1469 return false;
1470 }
1471 QgsDebugMsgLevel( "key = " + key, 4 );
1472
1473 const QString myAlgorithmString = mySettings.value( "/Raster/defaultContrastEnhancementAlgorithm/" + key, defaultAlg ).toString();
1474 QgsDebugMsgLevel( "myAlgorithmString = " + myAlgorithmString, 4 );
1475
1476 myAlgorithm = QgsContrastEnhancement::contrastEnhancementAlgorithmFromString( myAlgorithmString );
1477
1478 const QString myLimitsString = mySettings.value( "/Raster/defaultContrastEnhancementLimits/" + key, defaultLimits ).toString();
1479 QgsDebugMsgLevel( "myLimitsString = " + myLimitsString, 4 );
1480 myLimits = QgsRasterMinMaxOrigin::limitsFromString( myLimitsString );
1481
1482 return true;
1483}
1484
1486{
1487 QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
1488
1491 defaultContrastEnhancementSettings( myAlgorithm, myLimits );
1492
1493 setContrastEnhancement( myAlgorithm, myLimits );
1494}
1495
1496void QgsRasterLayer::setLayerOrder( QStringList const &layers )
1497{
1498 QgsDebugMsgLevel( QStringLiteral( "entered." ), 4 );
1499
1500 if ( mDataProvider )
1501 {
1502 QgsDebugMsgLevel( QStringLiteral( "About to mDataProvider->setLayerOrder(layers)." ), 4 );
1503 mDataProvider->setLayerOrder( layers );
1504 }
1505
1506}
1507
1508void QgsRasterLayer::setSubLayerVisibility( const QString &name, bool vis )
1509{
1510
1511 if ( mDataProvider )
1512 {
1513 QgsDebugMsgLevel( QStringLiteral( "About to mDataProvider->setSubLayerVisibility(name, vis)." ), 4 );
1514 mDataProvider->setSubLayerVisibility( name, vis );
1515 }
1516
1517}
1518
1520{
1521 if ( !mDataProvider )
1522 return QDateTime();
1523 return mDataProvider->timestamp();
1524}
1525
1527{
1528 if ( auto *lRenderer = mPipe->renderer() )
1529 {
1530 if ( !lRenderer->accept( visitor ) )
1531 return false;
1532 }
1533 return true;
1534}
1535
1536
1537bool QgsRasterLayer::writeSld( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QVariantMap &props ) const
1538{
1539 Q_UNUSED( errorMessage )
1540
1541 QVariantMap localProps = QVariantMap( props );
1543 {
1544 // TODO: QgsSymbolLayerUtils::mergeScaleDependencies generate SE only and not SLD1.0
1546 }
1547
1548 if ( isSpatial() ) // TODO: does it make sense this control?
1549 {
1550 // store constraints
1551 QDomElement constraintElem = doc.createElement( QStringLiteral( "sld:LayerFeatureConstraints" ) );
1552 node.appendChild( constraintElem );
1553
1554 const QDomElement featureTypeConstraintElem = doc.createElement( QStringLiteral( "sld:FeatureTypeConstraint" ) );
1555 constraintElem.appendChild( featureTypeConstraintElem );
1556
1557 QDomElement userStyleElem = doc.createElement( QStringLiteral( "sld:UserStyle" ) );
1558 node.appendChild( userStyleElem );
1559
1560 if ( !name().isEmpty() )
1561 {
1562 QDomElement nameElem = doc.createElement( QStringLiteral( "sld:Name" ) );
1563 nameElem.appendChild( doc.createTextNode( name() ) );
1564 userStyleElem.appendChild( nameElem );
1565 }
1566
1567 if ( !abstract().isEmpty() )
1568 {
1569 QDomElement abstractElem = doc.createElement( QStringLiteral( "sld:Abstract" ) );
1570 abstractElem.appendChild( doc.createTextNode( abstract() ) );
1571 userStyleElem.appendChild( abstractElem );
1572 }
1573
1574 if ( !title().isEmpty() )
1575 {
1576 QDomElement titleElem = doc.createElement( QStringLiteral( "sld:Title" ) );
1577 titleElem.appendChild( doc.createTextNode( title() ) );
1578 userStyleElem.appendChild( titleElem );
1579 }
1580
1581 QDomElement featureTypeStyleElem = doc.createElement( QStringLiteral( "sld:FeatureTypeStyle" ) );
1582 userStyleElem.appendChild( featureTypeStyleElem );
1583
1584#if 0
1585 // TODO: Is there a way to fill it's value with the named style?
1586 // by default <sld:Name> under <sld:FeatureTypeStyle> can have 0 occurrences
1587 // the same happen for tags:
1588 // sld:Title
1589 // sld:Abstract
1590 // sld:FeatureTypeName
1591 // sld:SemanticTypeIdentifier
1592 QDomElement typeStyleNameElem = doc.createElement( QStringLiteral( "sld:Name" ) );
1593 featureTypeStyleElem.appendChild( typeStyleNameElem );
1594#endif
1595
1596 QDomElement typeStyleRuleElem = doc.createElement( QStringLiteral( "sld:Rule" ) );
1597 featureTypeStyleElem.appendChild( typeStyleRuleElem );
1598
1599 // add ScaleDenominator tags
1601 {
1602 // note that denominator is the inverted value of scale
1603 if ( maximumScale() != 0.0 )
1604 {
1605 QDomElement minScaleElem = doc.createElement( QStringLiteral( "sld:MinScaleDenominator" ) );
1606 minScaleElem.appendChild( doc.createTextNode( QString::number( maximumScale() ) ) );
1607 typeStyleRuleElem.appendChild( minScaleElem );
1608 }
1609
1610 QDomElement maxScaleElem = doc.createElement( QStringLiteral( "sld:MaxScaleDenominator" ) );
1611 maxScaleElem.appendChild( doc.createTextNode( QString::number( minimumScale() ) ) );
1612 typeStyleRuleElem.appendChild( maxScaleElem );
1613 }
1614
1615 // export renderer dependent tags
1616 mPipe->renderer()->toSld( doc, typeStyleRuleElem, localProps );
1617
1618 // inject raster layer parameters in RasterSymbolizer tag because
1619 // they belongs to rasterlayer and not to the renderer => avoid to
1620 // pass many parameters value via localProps
1621 const QDomNodeList elements = typeStyleRuleElem.elementsByTagName( QStringLiteral( "sld:RasterSymbolizer" ) );
1622 if ( elements.size() != 0 )
1623 {
1624 // there SHOULD be only one
1625 QDomElement rasterSymbolizerElem = elements.at( 0 ).toElement();
1626
1627 // lamda helper used below to reduce code redundancy
1628 auto vendorOptionWriter = [&]( QString name, QString value )
1629 {
1630 QDomElement vendorOptionElem = doc.createElement( QStringLiteral( "sld:VendorOption" ) );
1631 vendorOptionElem.setAttribute( QStringLiteral( "name" ), name );
1632 vendorOptionElem.appendChild( doc.createTextNode( value ) );
1633 rasterSymbolizerElem.appendChild( vendorOptionElem );
1634 };
1635
1637 {
1638 vendorOptionWriter( QStringLiteral( "invertColors" ), QString::number( 1 ) );
1639 }
1640
1641 // add greyScale rendering mode if set
1643 {
1644 QString property;
1645 switch ( hueSaturationFilter()->grayscaleMode() )
1646 {
1648 property = QStringLiteral( "lightness" );
1649 break;
1651 property = QStringLiteral( "luminosity" );
1652 break;
1654 property = QStringLiteral( "average" );
1655 break;
1657 // added just to avoid travis fail
1658 break;
1659 }
1660 if ( !property.isEmpty() )
1661 vendorOptionWriter( QStringLiteral( "grayScale" ), property );
1662 }
1663
1664 // add Hue, Saturation and Lighting values in props is Hue filter is set
1665 if ( hueSaturationFilter() && hueSaturationFilter()->colorizeOn() )
1666 {
1667 vendorOptionWriter( QStringLiteral( "colorizeOn" ), QString::number( hueSaturationFilter()->colorizeOn() ) );
1668 vendorOptionWriter( QStringLiteral( "colorizeRed" ), QString::number( hueSaturationFilter()->colorizeColor().red() ) );
1669 vendorOptionWriter( QStringLiteral( "colorizeGreen" ), QString::number( hueSaturationFilter()->colorizeColor().green() ) );
1670 vendorOptionWriter( QStringLiteral( "colorizeBlue" ), QString::number( hueSaturationFilter()->colorizeColor().blue() ) );
1671 if ( hueSaturationFilter()->colorizeStrength() != 100.0 )
1672 vendorOptionWriter( QStringLiteral( "colorizeStrength" ), QString::number( hueSaturationFilter()->colorizeStrength() / 100.0 ) );
1673 vendorOptionWriter( QStringLiteral( "saturation" ), QString::number( hueSaturationFilter()->colorizeColor().saturationF() ) );
1674 }
1675 else
1676 {
1677 // saturation != 0 (default value)
1678 if ( hueSaturationFilter()->saturation() != 0 )
1679 {
1680 // normlize value [-100:100] -> [0:1]
1681 const int s = hueSaturationFilter()->saturation();
1682 const double sF = ( s - ( -100.0 ) ) / ( 100.0 - ( -100.0 ) );
1683 vendorOptionWriter( QStringLiteral( "saturation" ), QString::number( sF ) );
1684 }
1685 }
1686
1687 // brightness != 0 (default value)
1688 if ( brightnessFilter()->brightness() != 0 )
1689 {
1690 // normalize value [-255:255] -> [0:1]
1691 const int b = brightnessFilter()->brightness();
1692 const double bF = ( b - ( -255.0 ) ) / ( 255.0 - ( -255.0 ) );
1693 vendorOptionWriter( QStringLiteral( "brightness" ), QString::number( bF ) );
1694 }
1695
1696 // contrast != 0 (default value)
1697 if ( brightnessFilter()->contrast() != 0 )
1698 {
1699 // normlize value [-100:100] -> [0:1]
1700 const int c = brightnessFilter()->contrast();
1701 const double cF = ( c - ( -100.0 ) ) / ( 100.0 - ( -100.0 ) );
1702 vendorOptionWriter( QStringLiteral( "contrast" ), QString::number( cF ) );
1703 }
1704
1705#if 0
1706 // TODO: check if the below mapping formula make sense to map QGIS contrast with SLD gamma value
1707 //
1708 // add SLD1.0 ContrastEnhancement GammaValue = QGIS Contrast
1709 // SLD1.0 does only define 1 as neutral/center double value but does not define range.
1710 // because https://en.wikipedia.org/wiki/Gamma_correction assumed gamma is >0.
1711 // whilst QGIS has a -100/100 values centered in 0 => QGIS contrast value will be scaled in the
1712 // following way:
1713 // [-100,0] => [0,1] and [0,100] => [1,100]
1714 // an alternative could be scale [-100,100] => (0,2]
1715 //
1716 if ( newProps.contains( QStringLiteral( "contrast" ) ) )
1717 {
1718 double gamma;
1719 double contrast = newProps[ QStringLiteral( "contrast" ) ].toDouble();
1720 double percentage = ( contrast - ( -100.0 ) ) / ( 100.0 - ( -100.0 ) );
1721 if ( percentage <= 0.5 )
1722 {
1723 // stretch % to [0-1]
1724 gamma = percentage / 0.5;
1725 }
1726 else
1727 {
1728 gamma = contrast;
1729 }
1730
1731 QDomElement globalContrastEnhancementElem = doc.createElement( QStringLiteral( "sld:ContrastEnhancement" ) );
1732 rasterSymolizerElem.appendChild( globalContrastEnhancementElem );
1733
1734 QDomElement gammaValueElem = doc.createElement( QStringLiteral( "sld:GammaValue" ) );
1735 gammaValueElem.appendChild( doc.createTextNode( QString::number( gamma ) ) );
1736 globalContrastEnhancementElem.appendChild( gammaValueElem );
1737 }
1738#endif
1739 }
1740 }
1741 return true;
1742}
1743
1744
1746{
1747 QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
1748 if ( !renderer )
1749 {
1750 return;
1751 }
1752
1753 mPipe->set( renderer );
1754 emit rendererChanged();
1756}
1757
1759{
1760 return mPipe->renderer();
1761}
1762
1764{
1765 return mPipe->resampleFilter();
1766}
1767
1769{
1770 return mPipe->brightnessFilter();
1771}
1772
1774{
1775 return mPipe->hueSaturationFilter();
1776}
1777
1778void QgsRasterLayer::showStatusMessage( QString const &message )
1779{
1780 // QgsDebugMsg(QString("entered with '%1'.").arg(theMessage));
1781
1782 // Pass-through
1783 // TODO: See if we can connect signal-to-signal. This is a kludge according to the Qt doc.
1784 emit statusChanged( message );
1785}
1786
1788{
1789 if ( mDataProvider )
1790 mDataProvider->setTransformContext( transformContext );
1792}
1793
1794QStringList QgsRasterLayer::subLayers() const
1795{
1796 if ( ! mDataProvider )
1797 return QStringList();
1798 return mDataProvider->subLayers();
1799}
1800
1801// this function should be used when rendering with the MTR engine introduced in 2.3, as QPixmap is not thread safe (see bug #9626)
1802// note: previewAsImage and previewAsPixmap should use a common low-level fct QgsRasterLayer::previewOnPaintDevice( QSize size, QColor bgColor, QPaintDevice &device )
1803QImage QgsRasterLayer::previewAsImage( QSize size, const QColor &bgColor, QImage::Format format )
1804{
1805 QImage image( size, format );
1806
1807 if ( ! isValid( ) )
1808 return QImage();
1809
1810 if ( image.format() == QImage::Format_Indexed8 )
1811 {
1812 image.setColor( 0, bgColor.rgba() );
1813 image.fill( 0 ); //defaults to white, set to transparent for rendering on a map
1814 }
1815 else
1816 {
1817 image.fill( bgColor );
1818 }
1819
1820 QgsRasterViewPort *rasterViewPort = new QgsRasterViewPort();
1821
1822 double mapUnitsPerPixel;
1823 double x = 0.0;
1824 double y = 0.0;
1825 const QgsRectangle extent = mDataProvider->extent();
1826 if ( extent.width() / extent.height() >= static_cast< double >( image.width() ) / image.height() )
1827 {
1828 mapUnitsPerPixel = extent.width() / image.width();
1829 y = ( image.height() - extent.height() / mapUnitsPerPixel ) / 2;
1830 }
1831 else
1832 {
1833 mapUnitsPerPixel = extent.height() / image.height();
1834 x = ( image.width() - extent.width() / mapUnitsPerPixel ) / 2;
1835 }
1836
1837 const double pixelWidth = extent.width() / mapUnitsPerPixel;
1838 const double pixelHeight = extent.height() / mapUnitsPerPixel;
1839
1840 rasterViewPort->mTopLeftPoint = QgsPointXY( x, y );
1841 rasterViewPort->mBottomRightPoint = QgsPointXY( pixelWidth, pixelHeight );
1842 rasterViewPort->mWidth = image.width();
1843 rasterViewPort->mHeight = image.height();
1844
1845 rasterViewPort->mDrawnExtent = extent;
1846 rasterViewPort->mSrcCRS = QgsCoordinateReferenceSystem(); // will be invalid
1847 rasterViewPort->mDestCRS = QgsCoordinateReferenceSystem(); // will be invalid
1848
1849 QgsMapToPixel *mapToPixel = new QgsMapToPixel( mapUnitsPerPixel );
1850
1851 QPainter *painter = new QPainter( &image );
1852 draw( painter, rasterViewPort, mapToPixel );
1853 delete rasterViewPort;
1854 delete mapToPixel;
1855
1856 painter->end();
1857 delete painter;
1858
1859 return image;
1860}
1861
1863//
1864// Protected methods
1865//
1867/*
1868 * \param QDomNode node that will contain the symbology definition for this layer.
1869 * \param errorMessage reference to string that will be updated with any error messages
1870 * \return TRUE in case of success.
1871 */
1872bool QgsRasterLayer::readSymbology( const QDomNode &layer_node, QString &errorMessage,
1873 QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
1874{
1875 Q_UNUSED( errorMessage )
1876 // TODO: implement categories for raster layer
1877
1878 QDomElement rasterRendererElem;
1879
1880 const QDomElement layerElement = layer_node.toElement();
1881 readCommonStyle( layerElement, context, categories );
1882
1883 // pipe element was introduced in the end of 1.9 development when there were
1884 // already many project files in use so we support 1.9 backward compatibility
1885 // even it was never officially released -> use pipe element if present, otherwise
1886 // use layer node
1887 QDomNode pipeNode = layer_node.firstChildElement( QStringLiteral( "pipe" ) );
1888 if ( pipeNode.isNull() ) // old project
1889 {
1890 pipeNode = layer_node;
1891 }
1892
1893 //rasterlayerproperties element there -> old format (1.8 and early 1.9)
1894 if ( !layer_node.firstChildElement( QStringLiteral( "rasterproperties" ) ).isNull() )
1895 {
1896 //copy node because layer_node is const
1897 QDomNode layerNodeCopy = layer_node.cloneNode();
1898 QDomDocument doc = layerNodeCopy.ownerDocument();
1899 QDomElement rasterPropertiesElem = layerNodeCopy.firstChildElement( QStringLiteral( "rasterproperties" ) );
1900 QgsProjectFileTransform::convertRasterProperties( doc, layerNodeCopy, rasterPropertiesElem,
1901 this );
1902 rasterRendererElem = layerNodeCopy.firstChildElement( QStringLiteral( "rasterrenderer" ) );
1903 QgsDebugMsgLevel( doc.toString(), 4 );
1904 }
1905 else
1906 {
1907 rasterRendererElem = pipeNode.firstChildElement( QStringLiteral( "rasterrenderer" ) );
1908 }
1909
1910 if ( !rasterRendererElem.isNull() )
1911 {
1912 const QString rendererType = rasterRendererElem.attribute( QStringLiteral( "type" ) );
1913 QgsRasterRendererRegistryEntry rendererEntry;
1914 if ( QgsApplication::rasterRendererRegistry()->rendererData( rendererType, rendererEntry ) )
1915 {
1916 QgsRasterRenderer *renderer = rendererEntry.rendererCreateFunction( rasterRendererElem, dataProvider() );
1917 mPipe->set( renderer );
1918 }
1919 }
1920
1921 //brightness
1923 mPipe->set( brightnessFilter );
1924
1925 //brightness coefficient
1926 const QDomElement brightnessElem = pipeNode.firstChildElement( QStringLiteral( "brightnesscontrast" ) );
1927 if ( !brightnessElem.isNull() )
1928 {
1929 brightnessFilter->readXml( brightnessElem );
1930 }
1931
1932 //hue/saturation
1934 mPipe->set( hueSaturationFilter );
1935
1936 //saturation coefficient
1937 const QDomElement hueSaturationElem = pipeNode.firstChildElement( QStringLiteral( "huesaturation" ) );
1938 if ( !hueSaturationElem.isNull() )
1939 {
1940 hueSaturationFilter->readXml( hueSaturationElem );
1941 }
1942
1943 //resampler
1945 mPipe->set( resampleFilter );
1946
1947 //max oversampling
1948 const QDomElement resampleElem = pipeNode.firstChildElement( QStringLiteral( "rasterresampler" ) );
1949 if ( !resampleElem.isNull() )
1950 {
1951 resampleFilter->readXml( resampleElem );
1952 }
1953
1954 //provider
1955 if ( mDataProvider )
1956 {
1957 const QDomElement providerElem = pipeNode.firstChildElement( QStringLiteral( "provider" ) );
1958 if ( !providerElem.isNull() )
1959 {
1960 mDataProvider->readXml( providerElem );
1961 }
1962 }
1963
1964 // Resampling stage
1965 const QDomNode resamplingStageElement = pipeNode.namedItem( QStringLiteral( "resamplingStage" ) );
1966 if ( !resamplingStageElement.isNull() )
1967 {
1968 const QDomElement e = resamplingStageElement.toElement();
1969 if ( e.text() == QLatin1String( "provider" ) )
1971 else if ( e.text() == QLatin1String( "resamplingFilter" ) )
1973 }
1974
1975 // get and set the blend mode if it exists
1976 const QDomNode blendModeNode = layer_node.namedItem( QStringLiteral( "blendMode" ) );
1977 if ( !blendModeNode.isNull() )
1978 {
1979 const QDomElement e = blendModeNode.toElement();
1980 setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( e.text().toInt() ) ) );
1981 }
1982
1983 const QDomElement elemDataDefinedProperties = layer_node.firstChildElement( QStringLiteral( "pipe-data-defined-properties" ) );
1984 if ( !elemDataDefinedProperties.isNull() )
1985 mPipe->dataDefinedProperties().readXml( elemDataDefinedProperties, QgsRasterPipe::propertyDefinitions() );
1986
1987 readCustomProperties( layer_node );
1988
1989 emit rendererChanged();
1991
1992 return true;
1993}
1994
1995bool QgsRasterLayer::readStyle( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
1996{
1997 return readSymbology( node, errorMessage, context, categories );
1998}
1999
2000bool QgsRasterLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
2001{
2002 QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
2003 // Make sure to read the file first so stats etc are initialized properly!
2004
2005 //process provider key
2006 const QDomNode pkeyNode = layer_node.namedItem( QStringLiteral( "provider" ) );
2007
2008 if ( pkeyNode.isNull() )
2009 {
2010 mProviderKey = QStringLiteral( "gdal" );
2011 }
2012 else
2013 {
2014 const QDomElement pkeyElt = pkeyNode.toElement();
2015 mProviderKey = pkeyElt.text();
2016 if ( mProviderKey.isEmpty() )
2017 {
2018 mProviderKey = QStringLiteral( "gdal" );
2019 }
2020 }
2021
2022 // Open the raster source based on provider and datasource
2023
2024 // Go down the raster-data-provider paradigm
2025
2026 // Collect provider-specific information
2027
2028 const QDomNode rpNode = layer_node.namedItem( QStringLiteral( "rasterproperties" ) );
2029
2030 if ( mProviderKey == QLatin1String( "wms" ) )
2031 {
2032 // >>> BACKWARD COMPATIBILITY < 1.9
2033 // The old WMS URI format does not contain all the information, we add them here.
2034 if ( !mDataSource.contains( QLatin1String( "crs=" ) ) && !mDataSource.contains( QLatin1String( "format=" ) ) )
2035 {
2036 QgsDebugMsgLevel( QStringLiteral( "Old WMS URI format detected -> adding params" ), 4 );
2037 QgsDataSourceUri uri;
2039 QDomElement layerElement = rpNode.firstChildElement( QStringLiteral( "wmsSublayer" ) );
2040 while ( !layerElement.isNull() )
2041 {
2042 // TODO: sublayer visibility - post-0.8 release timeframe
2043
2044 // collect name for the sublayer
2045 uri.setParam( QStringLiteral( "layers" ), layerElement.namedItem( QStringLiteral( "name" ) ).toElement().text() );
2046
2047 // collect style for the sublayer
2048 uri.setParam( QStringLiteral( "styles" ), layerElement.namedItem( QStringLiteral( "style" ) ).toElement().text() );
2049
2050 layerElement = layerElement.nextSiblingElement( QStringLiteral( "wmsSublayer" ) );
2051 }
2052
2053 // Collect format
2054 uri.setParam( QStringLiteral( "format" ), rpNode.namedItem( QStringLiteral( "wmsFormat" ) ).toElement().text() );
2055
2056 // WMS CRS URL param should not be mixed with that assigned to the layer.
2057 // In the old WMS URI version there was no CRS and layer crs().authid() was used.
2058 uri.setParam( QStringLiteral( "crs" ), crs().authid() );
2059 mDataSource = uri.encodedUri();
2060 }
2061 // <<< BACKWARD COMPATIBILITY < 1.9
2062 }
2063
2065 {
2066 const QgsDataProvider::ProviderOptions providerOptions { context.transformContext() };
2067 QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags();
2069 {
2071 }
2073 {
2075 }
2076 // read extent
2078 {
2079 const QDomNode extentNode = layer_node.namedItem( QStringLiteral( "extent" ) );
2080 if ( !extentNode.isNull() )
2081 {
2082 // get the extent
2083 const QgsRectangle mbr = QgsXmlUtils::readRectangle( extentNode.toElement() );
2084
2085 // store the extent
2086 setExtent( mbr );
2087
2088 // skip get extent
2090 }
2091 }
2092 setDataProvider( mProviderKey, providerOptions, flags );
2093 }
2094
2095 mOriginalStyleElement = layer_node.namedItem( QStringLiteral( "originalStyle" ) ).firstChildElement();
2096 if ( mOriginalStyleElement.isNull() )
2097 mOriginalStyleElement = layer_node.toElement();
2098 mOriginalStyleDocument = layer_node.ownerDocument();
2099
2100 if ( ! mDataProvider )
2101 {
2103 {
2104 QgsDebugMsg( QStringLiteral( "Raster data provider could not be created for %1" ).arg( mDataSource ) );
2105 }
2106 return false;
2107 }
2108
2109 QString error;
2110 const bool res = readSymbology( layer_node, error, context );
2111
2112 // old wms settings we need to correct
2113 if ( res && mProviderKey == QLatin1String( "wms" ) && ( !renderer() || renderer()->type() != QLatin1String( "singlebandcolordata" ) ) )
2114 {
2115 setRendererForDrawingStyle( QgsRaster::SingleBandColorDataStyle );
2116 }
2117
2118 // Check timestamp
2119 // This was probably introduced to reload completely raster if data changed and
2120 // reset completely symbology to reflect new data type etc. It creates however
2121 // problems, because user defined symbology is complete lost if data file time
2122 // changed (the content may be the same). See also 6900.
2123#if 0
2124 QDomNode stampNode = layer_node.namedItem( "timestamp" );
2125 if ( !stampNode.isNull() )
2126 {
2127 QDateTime stamp = QDateTime::fromString( stampNode.toElement().text(), Qt::ISODate );
2128 // TODO: very bad, we have to load twice!!! Make QgsDataProvider::timestamp() static?
2129 if ( stamp < mDataProvider->dataTimestamp() )
2130 {
2131 QgsDebugMsgLevel( QStringLiteral( "data changed, reload provider" ), 3 );
2132 closeDataProvider();
2133 init();
2135 if ( !isValid() ) return false;
2136 }
2137 }
2138#endif
2139
2140 // Load user no data value
2141 const QDomElement noDataElement = layer_node.firstChildElement( QStringLiteral( "noData" ) );
2142
2143 const QDomNodeList noDataBandList = noDataElement.elementsByTagName( QStringLiteral( "noDataList" ) );
2144
2145 for ( int i = 0; i < noDataBandList.size(); ++i )
2146 {
2147 const QDomElement bandElement = noDataBandList.at( i ).toElement();
2148 bool ok;
2149 const int bandNo = bandElement.attribute( QStringLiteral( "bandNo" ) ).toInt( &ok );
2150 QgsDebugMsgLevel( QStringLiteral( "bandNo = %1" ).arg( bandNo ), 4 );
2151 if ( ok && ( bandNo > 0 ) && ( bandNo <= mDataProvider->bandCount() ) )
2152 {
2153 mDataProvider->setUseSourceNoDataValue( bandNo, bandElement.attribute( QStringLiteral( "useSrcNoData" ) ).toInt() );
2154 QgsRasterRangeList myNoDataRangeList;
2155
2156 const QDomNodeList rangeList = bandElement.elementsByTagName( QStringLiteral( "noDataRange" ) );
2157
2158 myNoDataRangeList.reserve( rangeList.size() );
2159 for ( int j = 0; j < rangeList.size(); ++j )
2160 {
2161 const QDomElement rangeElement = rangeList.at( j ).toElement();
2162 const QgsRasterRange myNoDataRange( rangeElement.attribute( QStringLiteral( "min" ) ).toDouble(),
2163 rangeElement.attribute( QStringLiteral( "max" ) ).toDouble() );
2164 QgsDebugMsgLevel( QStringLiteral( "min = %1 %2" ).arg( rangeElement.attribute( "min" ) ).arg( myNoDataRange.min() ), 4 );
2165 myNoDataRangeList << myNoDataRange;
2166 }
2167 mDataProvider->setUserNoDataValue( bandNo, myNoDataRangeList );
2168 }
2169 }
2170
2171 readStyleManager( layer_node );
2172
2173 return res;
2174}
2175
2176bool QgsRasterLayer::writeSymbology( QDomNode &layer_node, QDomDocument &document, QString &errorMessage,
2177 const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
2178{
2179 Q_UNUSED( errorMessage )
2180 // TODO: implement categories for raster layer
2181
2182 QDomElement layerElement = layer_node.toElement();
2183 writeCommonStyle( layerElement, document, context, categories );
2184
2185 // Store pipe members into pipe element, in future, it will be
2186 // possible to add custom filters into the pipe
2187 QDomElement pipeElement = document.createElement( QStringLiteral( "pipe" ) );
2188
2189 for ( int i = 0; i < mPipe->size(); i++ )
2190 {
2191 QgsRasterInterface *interface = mPipe->at( i );
2192 if ( !interface ) continue;
2193 interface->writeXml( document, pipeElement );
2194 }
2195
2196 QDomElement elemDataDefinedProperties = document.createElement( QStringLiteral( "pipe-data-defined-properties" ) );
2197 mPipe->dataDefinedProperties().writeXml( elemDataDefinedProperties, QgsRasterPipe::propertyDefinitions() );
2198 layer_node.appendChild( elemDataDefinedProperties );
2199
2200 QDomElement resamplingStageElement = document.createElement( QStringLiteral( "resamplingStage" ) );
2201 const QDomText resamplingStageText = document.createTextNode( resamplingStage() == Qgis::RasterResamplingStage::Provider ? QStringLiteral( "provider" ) : QStringLiteral( "resamplingFilter" ) );
2202 resamplingStageElement.appendChild( resamplingStageText );
2203 pipeElement.appendChild( resamplingStageElement );
2204
2205 layer_node.appendChild( pipeElement );
2206
2207 if ( !isValid() && !mOriginalStyleElement.isNull() )
2208 {
2209 QDomElement originalStyleElement = document.createElement( QStringLiteral( "originalStyle" ) );
2210 originalStyleElement.appendChild( mOriginalStyleElement );
2211 layer_node.appendChild( originalStyleElement );
2212 }
2213
2214 // add blend mode node
2215 QDomElement blendModeElement = document.createElement( QStringLiteral( "blendMode" ) );
2216 const QDomText blendModeText = document.createTextNode( QString::number( QgsPainting::getBlendModeEnum( blendMode() ) ) );
2217 blendModeElement.appendChild( blendModeText );
2218 layer_node.appendChild( blendModeElement );
2219
2220 return true;
2221}
2222
2223bool QgsRasterLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage,
2224 const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
2225{
2226 return writeSymbology( node, doc, errorMessage, context, categories );
2227} // bool QgsRasterLayer::writeSymbology
2228
2229/*
2230 * virtual
2231 * \note Called by QgsMapLayer::writeXml().
2232 */
2233bool QgsRasterLayer::writeXml( QDomNode &layer_node,
2234 QDomDocument &document,
2235 const QgsReadWriteContext &context ) const
2236{
2237 if ( !mDataProvider )
2238 return false;
2239
2240 // first get the layer element so that we can append the type attribute
2241
2242 QDomElement mapLayerNode = layer_node.toElement();
2243
2244 if ( mapLayerNode.isNull() || "maplayer" != mapLayerNode.nodeName() )
2245 {
2246 QgsMessageLog::logMessage( tr( "<maplayer> not found." ), tr( "Raster" ) );
2247 return false;
2248 }
2249
2250 mapLayerNode.setAttribute( QStringLiteral( "type" ), QgsMapLayerFactory::typeToString( QgsMapLayerType::RasterLayer ) );
2251
2252 // add provider node
2253
2254 QDomElement provider = document.createElement( QStringLiteral( "provider" ) );
2255 const QDomText providerText = document.createTextNode( mProviderKey );
2256 provider.appendChild( providerText );
2257 layer_node.appendChild( provider );
2258
2259 // User no data
2260 QDomElement noData = document.createElement( QStringLiteral( "noData" ) );
2261
2262 for ( int bandNo = 1; bandNo <= mDataProvider->bandCount(); bandNo++ )
2263 {
2264 QDomElement noDataRangeList = document.createElement( QStringLiteral( "noDataList" ) );
2265 noDataRangeList.setAttribute( QStringLiteral( "bandNo" ), bandNo );
2266 noDataRangeList.setAttribute( QStringLiteral( "useSrcNoData" ), mDataProvider->useSourceNoDataValue( bandNo ) );
2267
2268 const auto constUserNoDataValues = mDataProvider->userNoDataValues( bandNo );
2269 for ( const QgsRasterRange &range : constUserNoDataValues )
2270 {
2271 QDomElement noDataRange = document.createElement( QStringLiteral( "noDataRange" ) );
2272
2273 noDataRange.setAttribute( QStringLiteral( "min" ), QgsRasterBlock::printValue( range.min() ) );
2274 noDataRange.setAttribute( QStringLiteral( "max" ), QgsRasterBlock::printValue( range.max() ) );
2275 noDataRangeList.appendChild( noDataRange );
2276 }
2277
2278 noData.appendChild( noDataRangeList );
2279
2280 }
2281 if ( noData.hasChildNodes() )
2282 {
2283 layer_node.appendChild( noData );
2284 }
2285
2286 writeStyleManager( layer_node, document );
2287
2288 serverProperties()->writeXml( layer_node, document );
2289
2290 //write out the symbology
2291 QString errorMsg;
2292 return writeSymbology( layer_node, document, errorMsg, context );
2293}
2294
2295// TODO: this should ideally go to gdal provider (together with most of encodedSource() + decodedSource())
2296static bool _parseGpkgColons( const QString &src, QString &filename, QString &tablename )
2297{
2298 // GDAL accepts the following input format: GPKG:filename:table
2299 // (GDAL won't accept quoted filename)
2300
2301 QStringList lst = src.split( ':' );
2302 if ( lst.count() != 3 && lst.count() != 4 )
2303 return false;
2304
2305 tablename = lst.last();
2306 if ( lst.count() == 3 )
2307 {
2308 filename = lst[1];
2309 return true;
2310 }
2311 else if ( lst.count() == 4 && lst[1].count() == 1 && ( lst[2][0] == '/' || lst[2][0] == '\\' ) )
2312 {
2313 // a bit of handling to make sure that filename C:\hello.gpkg is parsed correctly
2314 filename = lst[1] + ":" + lst[2];
2315 return true;
2316 }
2317 return false;
2318}
2319
2320
2321QString QgsRasterLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
2322{
2323 QString src( source );
2324 bool handled = false;
2325
2326 // Update path for subdataset
2327 if ( providerType() == QLatin1String( "gdal" ) )
2328 {
2329 if ( src.startsWith( QLatin1String( "NETCDF:" ) ) )
2330 {
2331 // NETCDF:filename:variable
2332 // filename can be quoted with " as it can contain colons
2333 const QRegularExpression netcdfEncodedRegExp( QRegularExpression::anchoredPattern( "NETCDF:(.+):([^:]+)" ) );
2334 const QRegularExpressionMatch match = netcdfEncodedRegExp.match( src );
2335 if ( match.hasMatch() )
2336 {
2337 QString filename = match.captured( 1 );
2338 if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
2339 filename = filename.mid( 1, filename.length() - 2 );
2340 src = "NETCDF:\"" + context.pathResolver().writePath( filename ) + "\":" + match.captured( 2 );
2341 handled = true;
2342 }
2343 }
2344 else if ( src.startsWith( QLatin1String( "GPKG:" ) ) )
2345 {
2346 // GPKG:filename:table
2347 QString filename, tablename;
2348 if ( _parseGpkgColons( src, filename, tablename ) )
2349 {
2350 filename = context.pathResolver().writePath( filename );
2351 src = QStringLiteral( "GPKG:%1:%2" ).arg( filename, tablename );
2352 handled = true;
2353 }
2354 }
2355 else if ( src.startsWith( QLatin1String( "HDF4_SDS:" ) ) )
2356 {
2357 // HDF4_SDS:subdataset_type:file_name:subdataset_index
2358 // filename can be quoted with " as it can contain colons
2359 const QRegularExpression hdf4EncodedRegExp( QRegularExpression::anchoredPattern( "HDF4_SDS:([^:]+):(.+):([^:]+)" ) );
2360 const QRegularExpressionMatch match = hdf4EncodedRegExp.match( src );
2361 if ( match.hasMatch() )
2362 {
2363 QString filename = match.captured( 2 );
2364 if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
2365 filename = filename.mid( 1, filename.length() - 2 );
2366 src = "HDF4_SDS:" + match.captured( 1 ) + ":\"" + context.pathResolver().writePath( filename ) + "\":" + match.captured( 3 );
2367 handled = true;
2368 }
2369 }
2370 else if ( src.startsWith( QLatin1String( "HDF5:" ) ) )
2371 {
2372 // HDF5:file_name:subdataset
2373 // filename can be quoted with " as it can contain colons
2374 const QRegularExpression hdf5EncodedRegExp( QRegularExpression::anchoredPattern( "HDF5:(.+):([^:]+)" ) );
2375 const QRegularExpressionMatch match = hdf5EncodedRegExp.match( src );
2376 if ( match.hasMatch() )
2377 {
2378 QString filename = match.captured( 1 );
2379 if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
2380 filename = filename.mid( 1, filename.length() - 2 );
2381 src = "HDF5:\"" + context.pathResolver().writePath( filename ) + "\":" + match.captured( 2 );
2382 handled = true;
2383 }
2384 }
2385 else if ( src.contains( QRegularExpression( "^(NITF_IM|RADARSAT_2_CALIB):" ) ) )
2386 {
2387 // NITF_IM:0:filename
2388 // RADARSAT_2_CALIB:?:filename
2389 const QRegularExpression nitfRadarsatEncodedRegExp( QRegularExpression::anchoredPattern( "([^:]+):([^:]+):(.+)" ) );
2390 const QRegularExpressionMatch match = nitfRadarsatEncodedRegExp.match( src );
2391 if ( match.hasMatch() )
2392 {
2393 src = match.captured( 1 ) + ':' + match.captured( 2 ) + ':' + context.pathResolver().writePath( match.captured( 3 ) );
2394 handled = true;
2395 }
2396 }
2397 }
2398 else if ( providerType() == "wms" )
2399 {
2400 // handle relative paths to XYZ tiles
2401 QgsDataSourceUri uri;
2402 uri.setEncodedUri( src );
2403 const QUrl srcUrl( uri.param( QStringLiteral( "url" ) ) );
2404 if ( srcUrl.isLocalFile() )
2405 {
2406 // relative path will become "file:./x.txt"
2407 const QString relSrcUrl = context.pathResolver().writePath( srcUrl.toLocalFile() );
2408 uri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
2409 uri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( relSrcUrl ).toString() );
2410 src = uri.encodedUri();
2411 handled = true;
2412 }
2413 }
2414 else if ( providerType() == "virtualraster" )
2415 {
2416
2418
2419 for ( auto &it : decodedVirtualParams.rInputLayers )
2420 {
2421 it.uri = context.pathResolver().writePath( it.uri );
2422 }
2423 src = QgsRasterDataProvider::encodeVirtualRasterProviderUri( decodedVirtualParams ) ;
2424 }
2425
2426 if ( !handled )
2427 src = context.pathResolver().writePath( src );
2428
2429 return src;
2430}
2431
2432QString QgsRasterLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
2433{
2434 QString src( source );
2435
2436 if ( provider == QLatin1String( "wms" ) )
2437 {
2438 // >>> BACKWARD COMPATIBILITY < 1.9
2439 // For project file backward compatibility we must support old format:
2440 // 1. mode: <url>
2441 // example: http://example.org/wms?
2442 // 2. mode: tiled=<width>;<height>;<resolution>;<resolution>...,ignoreUrl=GetMap;GetFeatureInfo,featureCount=<count>,username=<name>,password=<password>,url=<url>
2443 // example: tiled=256;256;0.703;0.351,url=http://example.org/tilecache?
2444 // example: featureCount=10,http://example.org/wms?
2445 // example: ignoreUrl=GetMap;GetFeatureInfo,username=cimrman,password=jara,url=http://example.org/wms?
2446 // This is modified version of old QgsWmsProvider::parseUri
2447 // The new format has always params crs,format,layers,styles and that params
2448 // should not appear in old format url -> use them to identify version
2449 // XYZ tile layers do not need to contain crs,format params, but they have type=xyz
2450 if ( !src.contains( QLatin1String( "type=" ) ) &&
2451 !src.contains( QLatin1String( "crs=" ) ) && !src.contains( QLatin1String( "format=" ) ) )
2452 {
2453 QgsDebugMsgLevel( QStringLiteral( "Old WMS URI format detected -> converting to new format" ), 2 );
2454 QgsDataSourceUri uri;
2455 if ( !src.startsWith( QLatin1String( "http:" ) ) )
2456 {
2457 const QStringList parts = src.split( ',' );
2458 QStringListIterator iter( parts );
2459 while ( iter.hasNext() )
2460 {
2461 const QString item = iter.next();
2462 if ( item.startsWith( QLatin1String( "username=" ) ) )
2463 {
2464 uri.setUsername( item.mid( 9 ) );
2465 }
2466 else if ( item.startsWith( QLatin1String( "password=" ) ) )
2467 {
2468 uri.setPassword( item.mid( 9 ) );
2469 }
2470 else if ( item.startsWith( QLatin1String( "tiled=" ) ) )
2471 {
2472 // in < 1.9 tiled= may apper in to variants:
2473 // tiled=width;height - non tiled mode, specifies max width and max height
2474 // tiled=width;height;resolutions-1;resolution2;... - tile mode
2475
2476 QStringList params = item.mid( 6 ).split( ';' );
2477
2478 if ( params.size() == 2 ) // non tiled mode
2479 {
2480 uri.setParam( QStringLiteral( "maxWidth" ), params.takeFirst() );
2481 uri.setParam( QStringLiteral( "maxHeight" ), params.takeFirst() );
2482 }
2483 else if ( params.size() > 2 ) // tiled mode
2484 {
2485 // resolutions are no more needed and size limit is not used for tiles
2486 // we have to tell to the provider however that it is tiled
2487 uri.setParam( QStringLiteral( "tileMatrixSet" ), QString() );
2488 }
2489 }
2490 else if ( item.startsWith( QLatin1String( "featureCount=" ) ) )
2491 {
2492 uri.setParam( QStringLiteral( "featureCount" ), item.mid( 13 ) );
2493 }
2494 else if ( item.startsWith( QLatin1String( "url=" ) ) )
2495 {
2496 uri.setParam( QStringLiteral( "url" ), item.mid( 4 ) );
2497 }
2498 else if ( item.startsWith( QLatin1String( "ignoreUrl=" ) ) )
2499 {
2500 uri.setParam( QStringLiteral( "ignoreUrl" ), item.mid( 10 ).split( ';' ) );
2501 }
2502 }
2503 }
2504 else
2505 {
2506 uri.setParam( QStringLiteral( "url" ), src );
2507 }
2508 src = uri.encodedUri();
2509 // At this point, the URI is obviously incomplete, we add additional params
2510 // in QgsRasterLayer::readXml
2511 }
2512 // <<< BACKWARD COMPATIBILITY < 1.9
2513
2514 // handle relative paths to XYZ tiles
2515 QgsDataSourceUri uri;
2516 uri.setEncodedUri( src );
2517 const QUrl srcUrl( uri.param( QStringLiteral( "url" ) ) );
2518 if ( srcUrl.isLocalFile() ) // file-based URL? convert to relative path
2519 {
2520 const QString absSrcUrl = context.pathResolver().readPath( srcUrl.toLocalFile() );
2521 uri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
2522 uri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( absSrcUrl ).toString() );
2523 src = uri.encodedUri();
2524 }
2525
2526 }
2527 else
2528 {
2529 bool handled = false;
2530
2531 if ( provider == QLatin1String( "gdal" ) )
2532 {
2533 if ( src.startsWith( QLatin1String( "NETCDF:" ) ) )
2534 {
2535 // NETCDF:filename:variable
2536 // filename can be quoted with " as it can contain colons
2537 const QRegularExpression netcdfDecodedRegExp( QRegularExpression::anchoredPattern( "NETCDF:(.+):([^:]+)" ) );
2538 const QRegularExpressionMatch match = netcdfDecodedRegExp.match( src );
2539 if ( match.hasMatch() )
2540 {
2541 QString filename = match.captured( 1 );
2542 if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
2543 filename = filename.mid( 1, filename.length() - 2 );
2544 src = "NETCDF:\"" + context.pathResolver().readPath( filename ) + "\":" + match.captured( 2 );
2545 handled = true;
2546 }
2547 }
2548 else if ( src.startsWith( QLatin1String( "GPKG:" ) ) )
2549 {
2550 // GPKG:filename:table
2551 QString filename, tablename;
2552 if ( _parseGpkgColons( src, filename, tablename ) )
2553 {
2554 filename = context.pathResolver().readPath( filename );
2555 src = QStringLiteral( "GPKG:%1:%2" ).arg( filename, tablename );
2556 handled = true;
2557 }
2558 }
2559 else if ( src.startsWith( QLatin1String( "HDF4_SDS:" ) ) )
2560 {
2561 // HDF4_SDS:subdataset_type:file_name:subdataset_index
2562 // filename can be quoted with " as it can contain colons
2563 const QRegularExpression hdf4DecodedRegExp( QRegularExpression::anchoredPattern( "HDF4_SDS:([^:]+):(.+):([^:]+)" ) );
2564 const QRegularExpressionMatch match = hdf4DecodedRegExp.match( src );
2565 if ( match.hasMatch() )
2566 {
2567 QString filename = match.captured( 2 );
2568 if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
2569 filename = filename.mid( 1, filename.length() - 2 );
2570 src = "HDF4_SDS:" + match.captured( 1 ) + ":\"" + context.pathResolver().readPath( filename ) + "\":" + match.captured( 3 );
2571 handled = true;
2572 }
2573 }
2574 else if ( src.startsWith( QLatin1String( "HDF5:" ) ) )
2575 {
2576 // HDF5:file_name:subdataset
2577 // filename can be quoted with " as it can contain colons
2578 const QRegularExpression hdf5DecodedRegExp( QRegularExpression::anchoredPattern( "HDF5:(.+):([^:]+)" ) );
2579 const QRegularExpressionMatch match = hdf5DecodedRegExp.match( src );
2580 if ( match.hasMatch() )
2581 {
2582 QString filename = match.captured( 1 );
2583 if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
2584 filename = filename.mid( 1, filename.length() - 2 );
2585 src = "HDF5:\"" + context.pathResolver().readPath( filename ) + "\":" + match.captured( 2 );
2586 handled = true;
2587 }
2588 }
2589 else if ( src.contains( QRegularExpression( "^(NITF_IM|RADARSAT_2_CALIB):" ) ) )
2590 {
2591 // NITF_IM:0:filename
2592 // RADARSAT_2_CALIB:?:filename
2593 const QRegularExpression niftRadarsatDecodedRegExp( QRegularExpression::anchoredPattern( "([^:]+):([^:]+):(.+)" ) );
2594 const QRegularExpressionMatch match = niftRadarsatDecodedRegExp.match( src );
2595 if ( match.hasMatch() )
2596 {
2597 src = match.captured( 1 ) + ':' + match.captured( 2 ) + ':' + context.pathResolver().readPath( match.captured( 3 ) );
2598 handled = true;
2599 }
2600 }
2601 }
2602
2603 if ( provider == QLatin1String( "virtualraster" ) )
2604 {
2606
2607 for ( auto &it : decodedVirtualParams.rInputLayers )
2608 {
2609 it.uri = context.pathResolver().readPath( it.uri );
2610 }
2611 src = QgsRasterDataProvider::encodeVirtualRasterProviderUri( decodedVirtualParams ) ;
2612 handled = true;
2613 }
2614
2615 if ( !handled )
2616 src = context.pathResolver().readPath( src );
2617 }
2618
2619 return src;
2620}
2621
2623{
2624 if ( !mDataProvider ) return 0;
2625 return mDataProvider->xSize();
2626}
2627
2629{
2630 if ( !mDataProvider ) return 0;
2631 return mDataProvider->ySize();
2632}
2633
2635{
2636 mPipe->setResamplingStage( stage );
2637}
2638
2640{
2641 return mPipe->resamplingStage();
2642}
2643
2645//
2646// Private methods
2647//
2649bool QgsRasterLayer::update()
2650{
2651 QgsDebugMsgLevel( QStringLiteral( "entered." ), 4 );
2652 // Check if data changed
2653 if ( mDataProvider && mDataProvider->dataTimestamp() > mDataProvider->timestamp() )
2654 {
2655 QgsDebugMsgLevel( QStringLiteral( "reload data" ), 4 );
2656 closeDataProvider();
2657 init();
2658 const QgsDataProvider::ProviderOptions providerOptions;
2659 QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags();
2661 {
2663 }
2664 setDataProvider( mProviderKey, providerOptions, flags );
2665 emit dataChanged();
2666 }
2667 return isValid();
2668}
static QString version()
Version string.
Definition: qgis.cpp:277
@ IsBasemapLayer
Layer is considered a 'basemap' layer, and certain properties of the layer should be ignored when cal...
RasterResamplingStage
Stage at which raster resampling occurs.
Definition: qgis.h:721
@ Provider
Resampling occurs in Provider.
@ ResampleFilter
Resampling occurs in ResamplingFilter.
@ IsBasemapSource
Associated source should be considered a 'basemap' layer. See Qgis::MapLayerProperty::IsBasemapLayer.
DataType
Raster data types.
Definition: qgis.h:129
@ CInt32
Complex Int32.
@ Float32
Thirty two bit floating point (float)
@ CFloat64
Complex Float64.
@ Int16
Sixteen bit signed integer (qint16)
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
@ UInt16
Sixteen bit unsigned integer (quint16)
@ Byte
Eight bit unsigned integer (quint8)
@ UnknownDataType
Unknown or unspecified type.
@ ARGB32
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
@ Int32
Thirty two bit signed integer (qint32)
@ Float64
Sixty four bit floating point (double)
@ CFloat32
Complex Float32.
@ CInt16
Complex Int16.
@ UInt32
Thirty two bit unsigned integer (quint32)
Abstract base class for objects which generate elevation profiles.
static QgsRasterRendererRegistry * rasterRendererRegistry()
Returns the application's raster renderer registry, used for managing raster layer renderers.
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
Bilinear Raster Resampler.
Brightness/contrast and gamma correction filter pipe for rasters.
int contrast() const
Returns current contrast level.
int brightness() const
Returns current brightness level.
void readXml(const QDomElement &filterElem) override
Sets base class members from xml. Usually called from create() methods of subclasses.
A ramp shader will color a raster pixel based on a list of values ranges in a ramp.
bool shade(double value, int *returnRedValue, int *returnGreenValue, int *returnBlueValue, int *returnAlphaValue) const override
Generates and new RGB value based on one input value.
@ Interpolated
Interpolates the color between two class breaks linearly.
@ Discrete
Assigns the color of the higher class for every pixel between two class breaks.
void classifyColorRamp(int classes=0, int band=-1, const QgsRectangle &extent=QgsRectangle(), QgsRasterInterface *input=nullptr)
Classify color ramp shader.
void setColorRampItemList(const QList< QgsColorRampShader::ColorRampItem > &list)
Sets a custom colormap.
void setColorRampType(QgsColorRampShader::Type colorRampType)
Sets the color ramp type.
Manipulates raster or point cloud pixel values so that they enhanceContrast or clip into a specified ...
ContrastEnhancementAlgorithm
This enumerator describes the types of contrast enhancement algorithms that can be used.
@ StretchToMinimumMaximum
Linear histogram.
@ NoEnhancement
Default color scaling algorithm, no scaling is applied.
static QString contrastEnhancementAlgorithmString(ContrastEnhancementAlgorithm algorithm)
Returns a string to serialize ContrastEnhancementAlgorithm.
static ContrastEnhancementAlgorithm contrastEnhancementAlgorithmFromString(const QString &contrastEnhancementString)
Deserialize ContrastEnhancementAlgorithm.
ContrastEnhancementAlgorithm contrastEnhancementAlgorithm() const
This class represents a coordinate reference system (CRS).
@ WKT_PREFERRED
Preferred format, matching the most recent WKT ISO standard. Currently an alias to WKT2_2019,...
Contains information about the context in which a coordinate transform is executed.
Cubic Raster Resampler.
Abstract base class for spatial data provider implementations.
virtual void setLayerOrder(const QStringList &layers)
Reorder the list of layer names to be rendered by this provider (in order from bottom to top)
@ FlagLoadDefaultStyle
Reset the layer's style to the default for the datasource.
@ FlagTrustDataSource
Trust datasource config (primary key unicity, geometry type and srid, etc). Improves provider load ti...
@ ForceReadOnly
Open layer in a read-only mode (since QGIS 3.28)
@ SkipGetExtent
Skip the extent from provider.
QgsCoordinateTransformContext transformContext() const
Returns data provider coordinate transform context.
virtual Qgis::DataProviderFlags flags() const
Returns the generic data provider flags.
virtual QgsCoordinateReferenceSystem crs() const =0
Returns the coordinate system for the data source.
virtual QString subsetString() const
Returns the subset definition string (typically sql) currently in use by the layer and used by the pr...
virtual QgsLayerMetadata layerMetadata() const
Returns layer metadata collected from the provider's source.
virtual bool isValid() const =0
Returns true if this is a valid layer.
virtual void setDataSourceUri(const QString &uri)
Set the data source specification.
virtual QgsError error() const
Gets current status error.
virtual bool supportsSubsetString() const
Returns true if the provider supports setting of subset strings.
virtual QString dataSourceUri(bool expandAuthConfig=false) const
Gets the data source specification.
virtual bool setSubsetString(const QString &subset, bool updateFeatureCount=true)
Set the subset string used to create a subset of features in the layer.
virtual void reloadData()
Reloads the data from the source for providers with data caches to synchronize, changes in the data s...
virtual void setSubLayerVisibility(const QString &name, bool vis)
Set the visibility of the given sublayer name.
virtual void setTransformContext(const QgsCoordinateTransformContext &transformContext)
Sets data coordinate transform context to transformContext.
Class for storing the component parts of a RDBMS data source URI (e.g.
QByteArray encodedUri() const
Returns the complete encoded URI as a byte array.
int removeParam(const QString &key)
Removes a generic parameter by key.
void setEncodedUri(const QByteArray &uri)
Sets the complete encoded uri.
void setUsername(const QString &username)
Sets the username for the URI.
QString param(const QString &key) const
Returns a generic parameter value corresponding to the specified key.
void setParam(const QString &key, const QString &value)
Sets a generic parameter value on the URI.
void setPassword(const QString &password)
Sets the password for the URI.
Color and saturation filter pipe for rasters.
bool invertColors() const
Returns true if the filter inverts colors.
void readXml(const QDomElement &filterElem) override
Sets base class members from xml. Usually called from create() methods of subclasses.
Class for metadata formatter.
QString linksSectionHtml() const
Formats the "Links" section according to a metadata object.
QString extentSectionHtml(const bool showSpatialExtent=true) const
Formats the "Extents" section according to a metadata object (extent and temporal).
QString contactsSectionHtml() const
Formats the "Contacts" section according to a metadata object.
QString identificationSectionHtml() const
Formats the "Identification" section according to a metadata object.
QString historySectionHtml() const
Formats the "History" section according to a metadata object.
QString accessSectionHtml() const
Formats the "Access" section according to a metadata object.
Base class for storage of map layer elevation properties.
static QString typeToString(QgsMapLayerType type)
Converts a map layer type to a string value.
static QgsMapLayerLegend * defaultRasterLegend(QgsRasterLayer *rl)
Create new legend implementation for raster layer.
Base class for utility classes that encapsulate information necessary for rendering of map layers.
void writeXml(QDomNode &layer_node, QDomDocument &document) const
Saves server properties to xml under the layer node.
Base class for storage of map layer temporal properties.
Base class for all map layer types.
Definition: qgsmaplayer.h:73
QString name
Definition: qgsmaplayer.h:76
void readStyleManager(const QDomNode &layerNode)
Read style manager's configuration (if any). To be called by subclasses.
void setError(const QgsError &error)
Sets error message.
Definition: qgsmaplayer.h:1928
void writeStyleManager(QDomNode &layerNode, QDomDocument &doc) const
Write style manager's configuration (if exists). To be called by subclasses.
virtual QgsRectangle extent() const
Returns the extent of the layer.
QString source() const
Returns the source for the layer.
Q_INVOKABLE QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
void setBlendMode(QPainter::CompositionMode blendMode)
Set the blending mode used for rendering a layer.
QgsMapLayerType type
Definition: qgsmaplayer.h:80
void configChanged()
Emitted whenever the configuration is changed.
QgsMapLayer::LayerFlags flags() const
Returns the flags for this layer.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:79
QgsMapLayerServerProperties * serverProperties()
Returns QGIS Server Properties for the map layer.
Definition: qgsmaplayer.h:426
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...
QString mLayerName
Name of the layer - used for display.
Definition: qgsmaplayer.h:1945
QString crsHtmlMetadata() const
Returns a HTML fragment containing the layer's CRS metadata, for use in the htmlMetadata() method.
QgsLayerMetadata metadata
Definition: qgsmaplayer.h:78
QString abstract() const
Returns the abstract of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:326
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
void statusChanged(const QString &status)
Emit a signal with status (e.g. to be caught by QgisApp and display a msg on status bar)
void readCustomProperties(const QDomNode &layerNode, const QString &keyStartsWith=QString())
Read custom properties from project file.
virtual void setMetadata(const QgsLayerMetadata &metadata)
Sets the layer's metadata store.
Q_INVOKABLE void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for layer.
QString mProviderKey
Data provider key (name of the data provider)
Definition: qgsmaplayer.h:1983
QgsCoordinateTransformContext transformContext() const
Returns the layer data provider coordinate transform context or a default transform context if the la...
void rendererChanged()
Signal emitted when renderer is changed.
QString title() const
Returns the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:310
virtual QgsError error() const
Gets current status error.
bool hasScaleBasedVisibility() const
Returns whether scale based visibility is enabled for the layer.
void opacityChanged(double opacity)
Emitted when the layer's opacity is changed, where opacity is a value between 0 (transparent) and 1 (...
void emitStyleChanged()
Triggers an emission of the styleChanged() signal.
void dataChanged()
Data of layer changed.
void willBeDeleted()
Emitted in the destructor when the layer is about to be deleted, but it is still in a perfectly valid...
virtual QgsMapLayer * clone() const =0
Returns a new instance equivalent to this one except for the id which is still unique.
void setName(const QString &name)
Set the display name of the layer.
virtual void setExtent(const QgsRectangle &rect)
Sets the extent.
bool isValid
Definition: qgsmaplayer.h:81
void appendError(const QgsErrorMessage &error)
Add error message.
Definition: qgsmaplayer.h:1926
QString mDataSource
Data source description string, varies by layer type.
Definition: qgsmaplayer.h:1942
@ FlagReadExtentFromXml
Read extent from xml and skip get extent from provider.
Definition: qgsmaplayer.h:642
@ FlagTrustLayerMetadata
Trust layer metadata. Improves layer load time by skipping expensive checks like primary key unicity,...
Definition: qgsmaplayer.h:641
@ FlagForceReadOnly
Force open as read only.
Definition: qgsmaplayer.h:643
@ FlagDontResolveLayers
Don't resolve layer paths or create data providers for layers.
Definition: qgsmaplayer.h:640
void setValid(bool valid)
Sets whether layer is valid or not.
void readCommonStyle(const QDomElement &layerElement, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories)
Read style data common to all layer types.
QgsMapLayer::ReadFlags mReadFlags
Read flags. It's up to the subclass to respect these when restoring state from XML.
Definition: qgsmaplayer.h:1988
void setDataSource(const QString &dataSource, const QString &baseName, const QString &provider, bool loadDefaultStyleFlag=false)
Updates the data source of the layer.
double minimumScale() const
Returns the minimum map scale (i.e.
void repaintRequested(bool deferredUpdate=false)
By emitting this signal the layer tells that either appearance or content have been changed and any v...
void setProviderType(const QString &providerType)
Sets the providerType (provider key)
QString generalHtmlMetadata() const
Returns an HTML fragment containing general metadata information, for use in the htmlMetadata() metho...
void writeCommonStyle(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const
Write style data common to all layer types.
double maximumScale() const
Returns the maximum map scale (i.e.
void invalidateWgs84Extent()
Invalidates the WGS84 extent.
bool mShouldValidateCrs
true if the layer's CRS should be validated and invalid CRSes are not permitted.
Definition: qgsmaplayer.h:1995
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:39
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Renderer for multiband images with the color components.
const QgsContrastEnhancement * greenContrastEnhancement() const
Returns the contrast enhancement to use for the green channel.
const QgsContrastEnhancement * blueContrastEnhancement() const
Returns the contrast enhancement to use for the blue channel.
void setGreenContrastEnhancement(QgsContrastEnhancement *ce)
Sets the contrast enhancement to use for the green channel.
void setBlueContrastEnhancement(QgsContrastEnhancement *ce)
Sets the contrast enhancement to use for the blue channel.
void setRedContrastEnhancement(QgsContrastEnhancement *ce)
Sets the contrast enhancement to use for the red channel.
const QgsContrastEnhancement * redContrastEnhancement() const
Returns the contrast enhancement to use for the red channel.
static QgsPainting::BlendMode getBlendModeEnum(QPainter::CompositionMode blendMode)
Returns a BlendMode corresponding to a QPainter::CompositionMode.
Definition: qgspainting.cpp:80
static QPainter::CompositionMode getCompositionMode(QgsPainting::BlendMode blendMode)
Returns a QPainter::CompositionMode corresponding to a BlendMode.
Definition: qgspainting.cpp:20
BlendMode
Blending modes enum defining the available composition modes that can be used when rendering a layer.
Definition: qgspainting.h:37
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
A class to represent a 2D point.
Definition: qgspointxy.h:59
Encapsulates properties and constraints relating to fetching elevation profiles from different source...
static void convertRasterProperties(QDomDocument &doc, QDomNode &parentNode, QDomElement &rasterPropertiesElem, QgsRasterLayer *rlayer)
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
The RasterBandStats struct is a container for statistics about a single raster band.
int statsGathered
Collected statistics.
double mean
The mean cell value for the band. NO_DATA values are excluded.
double stdDev
The standard deviation of the cell values.
double minimumValue
The minimum cell value in the raster band.
double maximumValue
The maximum cell value in the raster band.
static int typeSize(Qgis::DataType dataType) SIP_HOLDGIL
Returns the size in bytes for the specified dataType.
static QString printValue(double value)
Print double value with all necessary significant digits.
Base class for raster data providers.
static QString encodeVirtualRasterProviderUri(const VirtualRasterParameters &parts)
Encodes the URI starting from the struct .
virtual bool useSourceNoDataValue(int bandNo) const
Returns the source nodata value usage.
static QgsRasterDataProvider::VirtualRasterParameters decodeVirtualRasterProviderUri(const QString &uri, bool *ok=nullptr)
Decodes the URI returning a struct with all the parameters for QgsVirtualRasterProvider class.
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...
virtual void setUseSourceNoDataValue(int bandNo, bool use)
Sets the source nodata value usage.
void readXml(const QDomElement &filterElem) override
Sets base class members from xml. Usually called from create() methods of subclasses.
virtual QgsRasterDataProvider::ProviderCapabilities providerCapabilities() const
Returns flags containing the supported capabilities of the data provider.
QDateTime timestamp() const override
Time stamp of data source in the moment when data/metadata were loaded by provider.
QgsRectangle extent() const override=0
Returns the extent of the layer.
virtual bool ignoreExtents() const
Returns true if the extents reported by the data provider are not reliable and it's possible that the...
virtual bool setMaxOversampling(double factor)
Sets maximum oversampling factor for zoomed-out operations.
Qgis::DataType dataType(int bandNo) const override=0
Returns data type for the band specified by number.
QStringList subLayers() const override
Returns the sublayers of this layer - useful for providers that manage their own layers,...
static QString identifyFormatName(QgsRaster::IdentifyFormat format)
@ ReadLayerMetadata
Provider can read layer metadata from data store. Since QGIS 3.0. See QgsDataProvider::layerMetadata(...
@ ProviderHintBenefitsFromResampling
Provider benefits from resampling and should apply user default resampling settings (since QGIS 3....
@ ProviderHintCanPerformProviderResampling
Provider can perform resampling (to be opposed to post rendering resampling) (since QGIS 3....
QDateTime dataTimestamp() const override
Current time stamp of data source.
virtual QString htmlMetadata()=0
Returns metadata in a format suitable for feeding directly into a subset of the GUI raster properties...
virtual QList< QgsColorRampShader::ColorRampItem > colorTable(int bandNo) const
virtual int colorInterpretation(int bandNo) const
Returns data type for the band specified by number.
void statusChanged(const QString &) const
Emit a message to be displayed on status bar, usually used by network providers (WMS,...
virtual QgsRasterRangeList userNoDataValues(int bandNo) const
Returns a list of user no data value ranges.
virtual bool setZoomedInResamplingMethod(ResamplingMethod method)
Set resampling method to apply for zoomed-in operations.
QgsRasterDataProviderTemporalCapabilities * temporalCapabilities() override
Returns the provider's temporal capabilities.
@ Bilinear
Bilinear (2x2 kernel) resampling.
@ Cubic
Cubic Convolution Approximation (4x4 kernel) resampling.
virtual void setUserNoDataValue(int bandNo, const QgsRasterRangeList &noData)
virtual bool setZoomedOutResamplingMethod(ResamplingMethod method)
Set resampling method to apply for zoomed-out operations.
The drawing pipe for raster layers.
void draw(QPainter *p, QgsRasterViewPort *viewPort, const QgsMapToPixel *qgsMapToPixel, QgsRasterBlockFeedback *feedback=nullptr)
Draws raster data.
Base class for processing filters like renderers, reprojector, resampler etc.
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.
@ IdentifyValue
Numerical values.
@ IdentifyFeature
WMS GML -> feature.
@ Size
Original data source size (and thus resolution) is known, it is not always available,...
virtual int xSize() const
Gets raster size.
virtual QString generateBandName(int bandNumber) const
helper function to create zero padded band names
virtual int bandCount() const =0
Gets number of bands.
virtual QgsRasterBandStats bandStatistics(int bandNo, int stats=QgsRasterBandStats::All, const QgsRectangle &extent=QgsRectangle(), int sampleSize=0, QgsRasterBlockFeedback *feedback=nullptr)
Returns the band statistics.
virtual bool hasStatistics(int bandNo, int stats=QgsRasterBandStats::All, const QgsRectangle &extent=QgsRectangle(), int sampleSize=0)
Returns true if histogram is available (cached, already calculated).
virtual int capabilities() const
Returns a bitmask containing the supported capabilities.
virtual int ySize() const
virtual QgsRasterInterface * input() const
Current input.
Iterator for sequentially processing raster cells.
Raster layer specific subclass of QgsMapLayerElevationProperties.
bool isEnabled() const
Returns true if the elevation properties are enabled, i.e.
QgsRasterLayerElevationProperties * clone() const override
Creates a clone of the properties.
Implementation of QgsAbstractProfileGenerator for raster layers.
Implementation of threaded rendering for raster layers.
Implementation of map layer temporal properties for raster layers.
void setDefaultsFromDataProviderTemporalCapabilities(const QgsDataProviderTemporalCapabilities *capabilities) override
Sets the layers temporal settings to appropriate defaults based on a provider's temporal capabilities...
Represents a raster layer.
QString htmlMetadata() const override
Obtain a formatted HTML string containing assorted metadata for this layer.
bool defaultContrastEnhancementSettings(QgsContrastEnhancement::ContrastEnhancementAlgorithm &myAlgorithm, QgsRasterMinMaxOrigin::Limits &myLimits) const
Returns default contrast enhancement settings for that type of raster.
void subsetStringChanged()
Emitted when the layer's subset string has changed.
Qgis::MapLayerProperties properties() const override
Returns the map layer properties of this layer.
QString encodedSource(const QString &source, const QgsReadWriteContext &context) const override
Called by writeLayerXML(), used by derived classes to encode provider's specific data source to proje...
Q_DECL_DEPRECATED QgsLegendColorList legendSymbologyItems() const
Returns a list with classification items (Text and color).
QgsMapLayerRenderer * createMapRenderer(QgsRenderContext &rendererContext) override
Returns new instance of QgsMapLayerRenderer that will be used for rendering of given context.
void showStatusMessage(const QString &message)
virtual bool setSubsetString(const QString &subset)
Sets the string (typically sql) used to define a subset of the layer.
QgsRasterResampleFilter * resampleFilter() const
Returns the raster's resample filter.
bool writeSymbology(QDomNode &, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) const override
QgsRasterLayer * clone() const override
Returns a new instance equivalent to this one.
void setResamplingStage(Qgis::RasterResamplingStage stage)
Select which stage of the pipe should apply resampling.
Qgis::RasterResamplingStage resamplingStage() const
Returns which stage of the pipe should apply resampling.
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 refreshContrastEnhancement(const QgsRectangle &extent)
Refresh contrast enhancement with new extent.
int height() const
Returns the height of the (unclipped) raster.
void setOpacity(double opacity) FINAL
Sets the opacity for the layer, where opacity is a value between 0 (totally transparent) and 1....
Q_DECL_DEPRECATED void setDataProvider(const QString &provider)
Set the data provider.
static const QgsContrastEnhancement::ContrastEnhancementAlgorithm MULTIPLE_BAND_SINGLE_BYTE_ENHANCEMENT_ALGORITHM
Default enhancement algorithm for multiple band raster of type Byte.
int bandCount() const
Returns the number of bands in this layer.
void refreshRendererIfNeeded(QgsRasterRenderer *rasterRenderer, const QgsRectangle &extent)
Refresh renderer with new extent, if needed.
QgsMapLayerTemporalProperties * temporalProperties() override
Returns the layer's temporal properties.
QgsRasterPipe * pipe()
Returns the raster pipe.
bool ignoreExtents() const
If the ignoreExtent flag is set, the layer will also render outside the bounding box reported by the ...
QString decodedSource(const QString &source, const QString &provider, const QgsReadWriteContext &context) const override
Called by readLayerXML(), used by derived classes to decode provider's specific data source from proj...
void setSubLayerVisibility(const QString &name, bool vis) override
Set the visibility of the given sublayer name.
virtual QString subsetString() const
Returns the string (typically sql) used to define a subset of the layer.
static const QgsRasterMinMaxOrigin::Limits SINGLE_BAND_MIN_MAX_LIMITS
Default enhancement limits for single band raster.
QgsAbstractProfileGenerator * createProfileGenerator(const QgsProfileRequest &request) override
Given a profile request, returns a new profile generator ready for generating elevation profiles.
QgsBrightnessContrastFilter * brightnessFilter() const
Returns the raster's brightness/contrast filter.
static const QgsRasterMinMaxOrigin::Limits MULTIPLE_BAND_MULTI_BYTE_MIN_MAX_LIMITS
Default enhancement limits for multiple band raster of type different from Byte.
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.
bool writeStyle(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) const override
double opacity() const FINAL
Returns the opacity for the layer, where opacity is a value between 0 (totally transparent) and 1....
double rasterUnitsPerPixelX() const
Returns the number of raster units per each raster pixel in X axis.
void reload() override
Synchronises with changes in the datasource.
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified symbology visitor, causing it to visit all symbols associated with the layer.
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.
QStringList subLayers() const override
Returns the sublayers of this layer.
void setDefaultContrastEnhancement()
Sets the default contrast enhancement.
QgsRasterRenderer * renderer() const
Returns the raster's renderer.
static const double SAMPLE_SIZE
Default sample size (number of pixels) for estimated statistics/histogram calculation.
static const QgsRasterMinMaxOrigin::Limits MULTIPLE_BAND_SINGLE_BYTE_MIN_MAX_LIMITS
Default enhancement limits for multiple band raster of type Byte.
static const QgsContrastEnhancement::ContrastEnhancementAlgorithm MULTIPLE_BAND_MULTI_BYTE_ENHANCEMENT_ALGORITHM
Default enhancement algorithm for multiple band raster of type different from Byte.
bool readXml(const QDomNode &layer_node, QgsReadWriteContext &context) override
Called by readLayerXML(), used by children to read state specific to them from project files.
QString bandName(int bandNoInt) const
Returns the name of a band given its number.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
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.
bool isSpatial() const override
Returns true if the layer is considered a spatial layer, ie it has some form of geometry associated w...
double rasterUnitsPerPixelY() const
Returns the number of raster units per each raster pixel in Y axis.
QString providerType() const
[ data provider interface ] Which provider is being used for this Raster Layer?
int width() const
Returns the width of the (unclipped) raster.
QgsMapLayerElevationProperties * elevationProperties() override
Returns the layer's elevation properties.
bool readSymbology(const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) override
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...
bool writeSld(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QVariantMap &props=QVariantMap()) const
Writes the symbology of the layer into the document provided in SLD 1.0.0 format.
static QDateTime lastModified(const QString &name)
Returns time stamp for given file name.
static const QgsContrastEnhancement::ContrastEnhancementAlgorithm SINGLE_BAND_ENHANCEMENT_ALGORITHM
Default enhancement algorithm for single band raster.
~QgsRasterLayer() override
QDateTime timestamp() const override
Time stamp of data source in the moment when data/metadata were loaded by provider.
virtual void setTransformContext(const QgsCoordinateTransformContext &transformContext) override
Sets the coordinate transform context to transformContext.
void setRenderer(QgsRasterRenderer *renderer)
Sets the raster's renderer.
QgsRasterLayer()
Constructor. Provider is not set.
void setLayerOrder(const QStringList &layers) override
Reorders the previously selected sublayers of this layer from bottom to top.
QgsHueSaturationFilter * hueSaturationFilter() const
Returns the raster's hue/saturation filter.
bool readStyle(const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) override
QPixmap paletteAsPixmap(int bandNumber=1)
Returns a 100x100 pixmap of the color palette.
This class describes the origin of min/max values.
void setExtent(QgsRasterMinMaxOrigin::Extent extent)
Sets the extent.
static QString limitsString(Limits limits)
Returns a string to serialize Limits.
double cumulativeCutLower() const
Returns the lower bound of cumulative cut method (between 0 and 1).
QgsRasterMinMaxOrigin::Limits limits() const
Returns the raster limits.
double stdDevFactor() const
Returns the factor f so that the min/max range is [ mean - f * stddev , mean + f * stddev ].
void setLimits(QgsRasterMinMaxOrigin::Limits limits)
Sets the limits.
@ UpdatedCanvas
Constantly updated extent of the canvas is used to compute statistics.
@ CurrentCanvas
Current extent of the canvas (at the time of computation) is used to compute statistics.
@ WholeRaster
Whole raster is used to compute statistics.
double cumulativeCutUpper() const
Returns the upper bound of cumulative cut method (between 0 and 1).
Limits
This enumerator describes the limits used to compute min/max values.
@ StdDev
Range is [ mean - stdDevFactor() * stddev, mean + stdDevFactor() * stddev ].
@ MinMax
Real min-max values.
@ CumulativeCut
Range is [ min + cumulativeCutLower() * (max - min), min + cumulativeCutUpper() * (max - min) ].
static Limits limitsFromString(const QString &limits)
Deserialize Limits.
QgsRasterMinMaxOrigin::Extent extent() const
Returns the raster extent.
Contains a pipeline of raster interfaces for sequential raster processing.
Definition: qgsrasterpipe.h:50
bool set(QgsRasterInterface *interface)
Inserts a new known interface in default place or replace interface of the same role if it already ex...
static QgsPropertiesDefinition propertyDefinitions()
Returns the definitions for data defined properties available for use in raster pipes.
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the pipe's property collection, used for data defined overrides.
QgsRasterProjector implements approximate projection support for it calculates grid of points in sour...
Q_DECL_DEPRECATED void setCrs(const QgsCoordinateReferenceSystem &srcCRS, const QgsCoordinateReferenceSystem &destCRS, int srcDatumTransform=-1, int destDatumTransform=-1)
Sets the source and destination CRS.
Raster values range container.
double min() const
Returns the minimum value for the range.
Raster renderer pipe that applies colors to a raster.
virtual QString type() const
Returns a unique string representation of the renderer type.
void setMinMaxOrigin(const QgsRasterMinMaxOrigin &origin)
Sets origin of min/max values.
const QgsRasterMinMaxOrigin & minMaxOrigin() const
Returns const reference to origin of min/max values.
virtual QList< QPair< QString, QColor > > legendSymbologyItems() const
Returns symbology items if provided by renderer.
Resample filter pipe for rasters.
void setZoomedOutResampler(QgsRasterResampler *r)
Sets resampler for zoomed out scales. Takes ownership of the object.
void readXml(const QDomElement &filterElem) override
Sets base class members from xml. Usually called from create() methods of subclasses.
void setZoomedInResampler(QgsRasterResampler *r)
Sets resampler for zoomed in scales. Takes ownership of the object.
Interface for all raster shaders.
void setRasterShaderFunction(QgsRasterShaderFunction *function)
A public method that allows the user to set their own shader function.
QgsRasterShaderFunction * rasterShaderFunction()
IdentifyFormat
Definition: qgsraster.h:58
@ IdentifyFormatFeature
Definition: qgsraster.h:63
@ IdentifyFormatValue
Definition: qgsraster.h:60
@ IdentifyFormatText
Definition: qgsraster.h:61
@ IdentifyFormatUndefined
Definition: qgsraster.h:59
@ IdentifyFormatHtml
Definition: qgsraster.h:62
@ PaletteIndex
Paletted (see associated color table)
Definition: qgsraster.h:39
@ AlphaBand
Alpha (0=transparent, 255=opaque)
Definition: qgsraster.h:43
@ GrayIndex
Greyscale.
Definition: qgsraster.h:38
@ ContinuousPalette
Continuous palette, QGIS addition, GRASS.
Definition: qgsraster.h:54
DrawingStyle
This enumerator describes the different kinds of drawing we can do.
Definition: qgsraster.h:90
@ SingleBandColorDataStyle
Definition: qgsraster.h:101
@ MultiBandColor
Definition: qgsraster.h:100
@ PalettedColor
Definition: qgsraster.h:94
@ SingleBandPseudoColor
Definition: qgsraster.h:93
@ SingleBandGray
Definition: qgsraster.h:92
@ UndefinedDrawingStyle
Definition: qgsraster.h:91
The class is used as a container of context for various read/write operations on other objects.
QgsCoordinateTransformContext transformContext() const
Returns data provider coordinate transform context.
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:230
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
bool isEmpty() const
Returns true if the rectangle is empty.
Definition: qgsrectangle.h:469
Contains information about the context of a rendering operation.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Raster renderer pipe for single band gray.
const QgsContrastEnhancement * contrastEnhancement() const
void setContrastEnhancement(QgsContrastEnhancement *ce)
Takes ownership.
Raster renderer pipe for single band pseudocolor.
int band() const
Returns the band used by the renderer.
void setShader(QgsRasterShader *shader)
Takes ownership of the shader.
QgsRasterShader * shader()
Returns the raster shader.
An interface for classes which can visit style entity (e.g.
static void mergeScaleDependencies(double mScaleMinDenom, double mScaleMaxDenom, QVariantMap &props)
Merges the local scale limits, if any, with the ones already in the map, if any.
static QgsRectangle readRectangle(const QDomElement &element)
Definition: qgsxmlutils.cpp:39
QgsMapLayerType
Types of layers that can be added to a map.
Definition: qgis.h:47
@ RasterLayer
Raster layer.
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
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
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:2527
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:2453
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
#define ERR(message)
QgsDataProvider * classFactoryFunction_t(const QString *, const QgsDataProvider::ProviderOptions &options)
QList< QPair< QString, QColor > > QgsLegendColorList
QList< QgsRasterRange > QgsRasterRangeList
Setting options for creating vector data providers.
Struct that stores the information about the parameters that should be given to the QgsVirtualRasterP...
QList< QgsRasterDataProvider::VirtualRasterInputLayers > rInputLayers
Setting options for loading raster layers.
bool skipCrsValidation
Controls whether the layer is allowed to have an invalid/unknown CRS.
bool loadDefaultStyle
Sets to true if the default layer style should be loaded.
QgsCoordinateTransformContext transformContext
Coordinate transform context.
Registry for raster renderer entries.
QgsRasterRendererCreateFunc rendererCreateFunction
This class provides details of the viewable area that a raster will be rendered into.
qgssize mHeight
Height, number of rows to be rendered.
QgsCoordinateReferenceSystem mDestCRS
Target coordinate system.
QgsPointXY mBottomRightPoint
Coordinate (in output device coordinate system) of bottom right corner of the part of the raster that...
QgsPointXY mTopLeftPoint
Coordinate (in output device coordinate system) of top left corner of the part of the raster that is ...
QgsCoordinateReferenceSystem mSrcCRS
Source coordinate system.
QgsRectangle mDrawnExtent
Intersection of current map extent and layer extent.
QgsCoordinateTransformContext mTransformContext
Coordinate transform context.
qgssize mWidth
Width, number of columns to be rendered.