25#include <QDomDocument>
31using namespace Qt::StringLiterals;
41 , mRedContrastEnhancement( redEnhancement )
42 , mGreenContrastEnhancement( greenEnhancement )
43 , mBlueContrastEnhancement( blueEnhancement )
54 if ( mRedContrastEnhancement )
58 if ( mGreenContrastEnhancement )
62 if ( mBlueContrastEnhancement )
77 if ( ce == mRedContrastEnhancement.get() )
80 mRedContrastEnhancement.reset( ce );
85 return mGreenContrastEnhancement.get();
90 if ( ce == mGreenContrastEnhancement.get() )
93 mGreenContrastEnhancement.reset( ce );
98 return mBlueContrastEnhancement.get();
103 if ( ce == mBlueContrastEnhancement.get() )
106 mBlueContrastEnhancement.reset( ce );
117 const int redBand = elem.attribute( u
"redBand"_s, u
"-1"_s ).toInt();
118 const int greenBand = elem.attribute( u
"greenBand"_s, u
"-1"_s ).toInt();
119 const int blueBand = elem.attribute( u
"blueBand"_s, u
"-1"_s ).toInt();
123 const QDomElement redContrastElem = elem.firstChildElement( u
"redContrastEnhancement"_s );
124 if ( !redContrastElem.isNull() )
132 const QDomElement greenContrastElem = elem.firstChildElement( u
"greenContrastEnhancement"_s );
133 if ( !greenContrastElem.isNull() )
141 const QDomElement blueContrastElem = elem.firstChildElement( u
"blueContrastEnhancement"_s );
142 if ( !blueContrastElem.isNull() )
158 auto outputBlock = std::make_unique<QgsRasterBlock>();
161 return outputBlock.release();
166 && mRedBand > 0 && mGreenBand > 0 && mBlueBand > 0
174 if ( mGreenBand > 0 )
186 return outputBlock.release();
194 QMap<int, QgsRasterBlock *> bandBlocks;
196 QList<int>::const_iterator bandIt = bands.constBegin();
197 for ( ; bandIt != bands.constEnd(); ++bandIt )
199 bandBlocks.insert( *bandIt, defaultPointer );
207 bandIt = bands.constBegin();
208 for ( ; bandIt != bands.constEnd(); ++bandIt )
210 bandBlocks[*bandIt] =
mInput->block( *bandIt,
extent, width, height, feedback );
211 if ( !bandBlocks[*bandIt] )
216 for ( ; bandIt != bands.constBegin(); --bandIt )
218 delete bandBlocks[*bandIt];
220 return outputBlock.release();
226 redBlock = bandBlocks[mRedBand];
228 if ( mGreenBand > 0 )
230 greenBlock = bandBlocks[mGreenBand];
234 blueBlock = bandBlocks[mBlueBand];
243 for (
int i = 0; i < bandBlocks.size(); i++ )
245 delete bandBlocks.value( i );
247 return outputBlock.release();
250 QRgb *outputBlockColorData = outputBlock->colorData();
254 const quint8 *redData =
nullptr, *greenData =
nullptr, *blueData =
nullptr;
279 hasEnhancement = mRedContrastEnhancement || mGreenContrastEnhancement || mBlueContrastEnhancement;
281 if ( hasEnhancement )
286 for (
qgssize i = 0; i < count; i++ )
296 outputBlock->setColor( i, myDefaultColor );
300 outputBlockColorData[i] = qRgb( redData[i], greenData[i], blueData[i] );
305 bool redIsNoData =
false;
306 bool greenIsNoData =
false;
307 bool blueIsNoData =
false;
317 if ( !redIsNoData && !greenIsNoData )
324 outputBlock->setColor( i, myDefaultColor );
328 outputBlockColorData[i] = qRgb( redVal, greenVal, blueVal );
334 bool isNoData =
false;
342 if ( !isNoData && mGreenBand > 0 )
346 if ( !isNoData && mBlueBand > 0 )
352 outputBlock->setColor( i, myDefaultColor );
357 if ( ( mRedContrastEnhancement && !mRedContrastEnhancement->isValueInDisplayableRange( redVal ) )
358 || ( mGreenContrastEnhancement && !mGreenContrastEnhancement->isValueInDisplayableRange( redVal ) )
359 || ( mBlueContrastEnhancement && !mBlueContrastEnhancement->isValueInDisplayableRange( redVal ) ) )
361 outputBlock->setColor( i, myDefaultColor );
366 if ( mRedContrastEnhancement )
368 redVal = mRedContrastEnhancement->enhanceContrast( redVal );
370 if ( mGreenContrastEnhancement )
372 greenVal = mGreenContrastEnhancement->enhanceContrast( greenVal );
374 if ( mBlueContrastEnhancement )
376 blueVal = mBlueContrastEnhancement->enhanceContrast( blueVal );
387 const double alpha = alphaBlock->
value( i );
390 outputBlock->setColor( i, myDefaultColor );
395 currentOpacity *= alpha / 255.0;
401 outputBlock->setColor( i, qRgba( redVal, greenVal, blueVal, 255 ) );
405 outputBlock->setColor( i, qRgba( currentOpacity * redVal, currentOpacity * greenVal, currentOpacity * blueVal, currentOpacity * 255 ) );
410 QMap<int, QgsRasterBlock *>::const_iterator bandDelIt = bandBlocks.constBegin();
411 for ( ; bandDelIt != bandBlocks.constEnd(); ++bandDelIt )
413 delete bandDelIt.value();
416 return outputBlock.release();
421 return mRedContrastEnhancement.get();
426 if ( parentElem.isNull() )
431 QDomElement rasterRendererElem = doc.createElement( u
"rasterrenderer"_s );
433 rasterRendererElem.setAttribute( u
"redBand"_s, mRedBand );
434 rasterRendererElem.setAttribute( u
"greenBand"_s, mGreenBand );
435 rasterRendererElem.setAttribute( u
"blueBand"_s, mBlueBand );
438 if ( mRedContrastEnhancement )
440 QDomElement redContrastElem = doc.createElement( u
"redContrastEnhancement"_s );
441 mRedContrastEnhancement->writeXml( doc, redContrastElem );
442 rasterRendererElem.appendChild( redContrastElem );
444 if ( mGreenContrastEnhancement )
446 QDomElement greenContrastElem = doc.createElement( u
"greenContrastEnhancement"_s );
447 mGreenContrastEnhancement->writeXml( doc, greenContrastElem );
448 rasterRendererElem.appendChild( greenContrastElem );
450 if ( mBlueContrastEnhancement )
452 QDomElement blueContrastElem = doc.createElement( u
"blueContrastEnhancement"_s );
453 mBlueContrastEnhancement->writeXml( doc, blueContrastElem );
454 rasterRendererElem.appendChild( blueContrastElem );
456 parentElem.appendChild( rasterRendererElem );
462 if ( mRedBand != -1 )
464 bandList << mRedBand;
466 if ( mGreenBand != -1 )
468 bandList << mGreenBand;
470 if ( mBlueBand != -1 )
472 bandList << mBlueBand;
479 QList<QgsLayerTreeModelLegendNode *> res;
480 if ( mRedBand != -1 )
484 if ( mGreenBand != -1 )
488 if ( mBlueBand != -1 )
500 toSld( doc, element, context );
518 bool isDefaultCombination =
true;
519 QList<int> defaultBandCombination( { 1, 2, 3 } );
521 isDefaultCombination = isDefaultCombination && (
usesBands() == defaultBandCombination );
522 isDefaultCombination = isDefaultCombination && (
528 if ( isDefaultCombination )
531 isDefaultCombination = isDefaultCombination && (
532 ( mRedContrastEnhancement->minimumValue() == statRed.
minimumValue &&
533 mRedContrastEnhancement->maximumValue() == statRed.
maximumValue )
536 if ( isDefaultCombination )
539 isDefaultCombination = isDefaultCombination && (
540 ( mGreenContrastEnhancement->minimumValue() == statGreen.
minimumValue &&
541 mGreenContrastEnhancement->maximumValue() == statGreen.
maximumValue )
544 if ( isDefaultCombination )
547 isDefaultCombination = isDefaultCombination && (
548 ( mBlueContrastEnhancement->minimumValue() == statBlue.
minimumValue &&
549 mBlueContrastEnhancement->maximumValue() == statBlue.
maximumValue )
552 if ( isDefaultCombination )
557 QDomNodeList elements = element.elementsByTagName( u
"sld:RasterSymbolizer"_s );
558 if ( elements.size() == 0 )
562 QDomElement rasterSymbolizerElem = elements.at( 0 ).toElement();
567 QDomElement channelSelectionElem = doc.createElement( u
"sld:ChannelSelection"_s );
568 elements = rasterSymbolizerElem.elementsByTagName( u
"sld:Opacity"_s );
569 if ( elements.size() != 0 )
571 rasterSymbolizerElem.insertAfter( channelSelectionElem, elements.at( 0 ) );
575 elements = rasterSymbolizerElem.elementsByTagName( u
"sld:Geometry"_s );
576 if ( elements.size() != 0 )
578 rasterSymbolizerElem.insertAfter( channelSelectionElem, elements.at( 0 ) );
582 rasterSymbolizerElem.insertBefore( channelSelectionElem, rasterSymbolizerElem.firstChild() );
587 static QStringList tags { u
"sld:RedChannel"_s, u
"sld:GreenChannel"_s, u
"sld:BlueChannel"_s };
589 QList<QgsContrastEnhancement *> contrastEnhancements;
590 contrastEnhancements.append( mRedContrastEnhancement.get() );
591 contrastEnhancements.append( mGreenContrastEnhancement.get() );
592 contrastEnhancements.append( mBlueContrastEnhancement.get() );
595 QList<int>::const_iterator bandIt = bands.constBegin();
596 for (
int tagCounter = 0 ; bandIt != bands.constEnd(); ++bandIt, ++tagCounter )
601 QDomElement channelElem = doc.createElement( tags[ tagCounter ] );
602 channelSelectionElem.appendChild( channelElem );
605 QDomElement sourceChannelNameElem = doc.createElement( u
"sld:SourceChannelName"_s );
606 sourceChannelNameElem.appendChild( doc.createTextNode( QString::number( *bandIt ) ) );
607 channelElem.appendChild( sourceChannelNameElem );
612 if ( contrastEnhancements[ tagCounter ] )
614 QDomElement contrastEnhancementElem = doc.createElement( u
"sld:ContrastEnhancement"_s );
615 contrastEnhancements[ tagCounter ]->toSld( doc, contrastEnhancementElem );
616 channelElem.appendChild( contrastEnhancementElem );
629 bool refreshed =
false;
630 if ( min.size() >= 3 && max.size() >= 3 )
635 !std::isnan( min[0] ) && !std::isnan( max[0] ) )
637 mRedContrastEnhancement->setMinimumValue( min[0] );
638 mRedContrastEnhancement->setMaximumValue( max[0] );
643 !std::isnan( min[1] ) && !std::isnan( max[1] ) )
645 mGreenContrastEnhancement->setMinimumValue( min[1] );
646 mGreenContrastEnhancement->setMaximumValue( max[1] );
651 !std::isnan( min[2] ) && !std::isnan( max[2] ) )
653 mBlueContrastEnhancement->setMinimumValue( min[2] );
654 mBlueContrastEnhancement->setMaximumValue( max[2] );
QFlags< RasterRendererFlag > RasterRendererFlags
Flags which control behavior of raster renderers.
@ InternalLayerOpacityHandling
The renderer internally handles the raster layer's opacity, so the default layer level opacity handli...
DataType
Raster data types.
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
@ Byte
Eight bit unsigned integer (quint8).
Handles contrast enhancement and clipping.
@ StretchToMinimumMaximum
Linear histogram.
@ NoEnhancement
Default color scaling algorithm, no scaling is applied.
Layer tree node points to a map layer.
bool refresh(const QgsRectangle &extent, const QList< double > &min, const QList< double > &max, bool forceRefresh=false) override
Refreshes the renderer according to the min and max values associated with the extent.
QgsMultiBandColorRenderer(QgsRasterInterface *input, int redBand, int greenBand, int blueBand, QgsContrastEnhancement *redEnhancement=nullptr, QgsContrastEnhancement *greenEnhancement=nullptr, QgsContrastEnhancement *blueEnhancement=nullptr)
Constructor for QgsMultiBandColorRenderer.
const QgsContrastEnhancement * greenContrastEnhancement() const
Returns the contrast enhancement to use for the green channel.
QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
Q_DECL_DEPRECATED void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props=QVariantMap()) const override
Used from subclasses to create SLD Rule elements following SLD v1.0 specs.
Qgis::RasterRendererFlags flags() const override
Returns flags which dictate renderer behavior.
int blueBand() const
Returns the band number for the blue channel.
~QgsMultiBandColorRenderer() override
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.
QList< int > usesBands() const override
Returns a list of band numbers used by the renderer.
QgsMultiBandColorRenderer * clone() const override
Clone itself, create deep copy.
void setBlueContrastEnhancement(QgsContrastEnhancement *ce)
Sets the contrast enhancement to use for the blue channel.
static QgsRasterRenderer * create(const QDomElement &elem, QgsRasterInterface *input)
void setRedContrastEnhancement(QgsContrastEnhancement *ce)
Sets the contrast enhancement to use for the red channel.
void writeXml(QDomDocument &doc, QDomElement &parentElem) const override
Write base class members to xml.
const QgsContrastEnhancement * redContrastEnhancement() const
Returns the contrast enhancement to use for the red channel.
int redBand() const
Returns the band number for the red channel.
QList< QgsLayerTreeModelLegendNode * > createLegendNodes(QgsLayerTreeLayer *nodeLayer) override
Creates a set of legend nodes representing the renderer.
int greenBand() const
Returns the band number for the green channel.
The RasterBandStats struct is a container for statistics about a single raster band.
double minimumValue
The minimum cell value in the raster band.
double maximumValue
The maximum cell value in the raster band.
Feedback object tailored for raster block reading.
double value(int row, int column) const
Read a single value if type of block is numeric.
double valueAndNoData(int row, int column, bool &isNoData) const
Reads a single value from the pixel at row and column, if type of block is numeric.
bool isNoData(int row, int column) const
Checks if value at position is no data.
Qgis::DataType dataType() const
Returns data type.
const quint8 * byteData() const
Gives direct access to the raster block data.
QgsRasterInterface(QgsRasterInterface *input=nullptr)
Q_DECL_DEPRECATED QgsRasterBandStats bandStatistics(int bandNo, int stats, const QgsRectangle &extent=QgsRectangle(), int sampleSize=0, QgsRasterBlockFeedback *feedback=nullptr)
Returns the band statistics.
QString displayBandName(int bandNumber) const
Generates a friendly, descriptive name for the specified bandNumber.
QgsRasterInterface * mInput
virtual QgsRectangle extent() const
Gets the extent of the interface.
virtual QgsRasterInterface * input() const
Current input.
QgsRasterRenderer(QgsRasterInterface *input=nullptr, const QString &type=QString())
Constructor for QgsRasterRenderer.
double mOpacity
Global alpha value (0-1).
int mAlphaBand
Read alpha value from band.
QgsRectangle mLastRectangleUsedByRefreshContrastEnhancementIfNeeded
To save computations and possible infinite cycle of notifications.
QRgb renderColorForNodataPixel() const
Returns the color for the renderer to use to represent nodata pixels.
std::unique_ptr< QgsRasterTransparency > mRasterTransparency
Raster transparency per color or value. Overwrites global alpha value.
void _writeXml(QDomDocument &doc, QDomElement &rasterRendererElem) const
Write upper class info into rasterrenderer element (called by writeXml method of subclasses).
bool usesTransparency() const
void copyCommonProperties(const QgsRasterRenderer *other, bool copyMinMaxOrigin=true)
Copies common properties like opacity / transparency data from other renderer.
bool needsRefresh(const QgsRectangle &extent) const
Checks if the renderer needs to be refreshed according to extent.
virtual Q_DECL_DEPRECATED void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props=QVariantMap()) const
Used from subclasses to create SLD Rule elements following SLD v1.0 specs.
void readXml(const QDomElement &rendererElem) override
Sets base class members from xml. Usually called from create() methods of subclasses.
Implementation of legend node interface for displaying raster legend entries.
A rectangle specified with double values.
Holds SLD export options and other information related to SLD export of a QGIS layer style.
void setExtraProperties(const QVariantMap &properties)
Sets the open ended set of properties that can drive/inform the SLD encoding.
unsigned long long qgssize
Qgssize is used instead of size_t, because size_t is stdlib type, unknown by SIP, and it would be har...
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
#define QgsDebugError(str)