25#include <QDomDocument>
31using namespace Qt::StringLiterals;
40 , mRedContrastEnhancement( redEnhancement )
41 , mGreenContrastEnhancement( greenEnhancement )
42 , mBlueContrastEnhancement( blueEnhancement )
52 if ( mRedContrastEnhancement )
56 if ( mGreenContrastEnhancement )
60 if ( mBlueContrastEnhancement )
75 if ( ce == mRedContrastEnhancement.get() )
78 mRedContrastEnhancement.reset( ce );
83 return mGreenContrastEnhancement.get();
88 if ( ce == mGreenContrastEnhancement.get() )
91 mGreenContrastEnhancement.reset( ce );
96 return mBlueContrastEnhancement.get();
101 if ( ce == mBlueContrastEnhancement.get() )
104 mBlueContrastEnhancement.reset( ce );
115 const int redBand = elem.attribute( u
"redBand"_s, u
"-1"_s ).toInt();
116 const int greenBand = elem.attribute( u
"greenBand"_s, u
"-1"_s ).toInt();
117 const int blueBand = elem.attribute( u
"blueBand"_s, u
"-1"_s ).toInt();
121 const QDomElement redContrastElem = elem.firstChildElement( u
"redContrastEnhancement"_s );
122 if ( !redContrastElem.isNull() )
129 const QDomElement greenContrastElem = elem.firstChildElement( u
"greenContrastEnhancement"_s );
130 if ( !greenContrastElem.isNull() )
137 const QDomElement blueContrastElem = elem.firstChildElement( u
"blueContrastEnhancement"_s );
138 if ( !blueContrastElem.isNull() )
152 auto outputBlock = std::make_unique<QgsRasterBlock>();
155 return outputBlock.release();
166 if ( mGreenBand > 0 )
178 return outputBlock.release();
186 QMap<int, QgsRasterBlock *> bandBlocks;
188 QList<int>::const_iterator bandIt = bands.constBegin();
189 for ( ; bandIt != bands.constEnd(); ++bandIt )
191 bandBlocks.insert( *bandIt, defaultPointer );
199 bandIt = bands.constBegin();
200 for ( ; bandIt != bands.constEnd(); ++bandIt )
202 bandBlocks[*bandIt] =
mInput->block( *bandIt,
extent, width, height, feedback );
203 if ( !bandBlocks[*bandIt] )
208 for ( ; bandIt != bands.constBegin(); --bandIt )
210 delete bandBlocks[*bandIt];
212 return outputBlock.release();
218 redBlock = bandBlocks[mRedBand];
220 if ( mGreenBand > 0 )
222 greenBlock = bandBlocks[mGreenBand];
226 blueBlock = bandBlocks[mBlueBand];
235 for (
int i = 0; i < bandBlocks.size(); i++ )
237 delete bandBlocks.value( i );
239 return outputBlock.release();
242 QRgb *outputBlockColorData = outputBlock->colorData();
245 const bool hasByteRgb
247 const quint8 *redData =
nullptr, *greenData =
nullptr, *blueData =
nullptr;
271 hasEnhancement = mRedContrastEnhancement || mGreenContrastEnhancement || mBlueContrastEnhancement;
273 if ( hasEnhancement )
278 for (
qgssize i = 0; i < count; i++ )
286 outputBlock->setColor( i, myDefaultColor );
290 outputBlockColorData[i] = qRgb( redData[i], greenData[i], blueData[i] );
295 bool redIsNoData =
false;
296 bool greenIsNoData =
false;
297 bool blueIsNoData =
false;
307 if ( !redIsNoData && !greenIsNoData )
310 if ( redIsNoData || greenIsNoData || blueIsNoData )
312 outputBlock->setColor( i, myDefaultColor );
316 outputBlockColorData[i] = qRgb( redVal, greenVal, blueVal );
322 bool isNoData =
false;
330 if ( !isNoData && mGreenBand > 0 )
334 if ( !isNoData && mBlueBand > 0 )
340 outputBlock->setColor( i, myDefaultColor );
345 if ( ( mRedContrastEnhancement && !mRedContrastEnhancement->isValueInDisplayableRange( redVal ) )
346 || ( mGreenContrastEnhancement && !mGreenContrastEnhancement->isValueInDisplayableRange( redVal ) )
347 || ( mBlueContrastEnhancement && !mBlueContrastEnhancement->isValueInDisplayableRange( redVal ) ) )
349 outputBlock->setColor( i, myDefaultColor );
354 if ( mRedContrastEnhancement )
356 redVal = mRedContrastEnhancement->enhanceContrast( redVal );
358 if ( mGreenContrastEnhancement )
360 greenVal = mGreenContrastEnhancement->enhanceContrast( greenVal );
362 if ( mBlueContrastEnhancement )
364 blueVal = mBlueContrastEnhancement->enhanceContrast( blueVal );
375 const double alpha = alphaBlock->
value( i );
378 outputBlock->setColor( i, myDefaultColor );
383 currentOpacity *= alpha / 255.0;
389 outputBlock->setColor( i, qRgba( redVal, greenVal, blueVal, 255 ) );
393 outputBlock->setColor( i, qRgba( currentOpacity * redVal, currentOpacity * greenVal, currentOpacity * blueVal, currentOpacity * 255 ) );
398 QMap<int, QgsRasterBlock *>::const_iterator bandDelIt = bandBlocks.constBegin();
399 for ( ; bandDelIt != bandBlocks.constEnd(); ++bandDelIt )
401 delete bandDelIt.value();
404 return outputBlock.release();
409 return mRedContrastEnhancement.get();
414 if ( parentElem.isNull() )
419 QDomElement rasterRendererElem = doc.createElement( u
"rasterrenderer"_s );
421 rasterRendererElem.setAttribute( u
"redBand"_s, mRedBand );
422 rasterRendererElem.setAttribute( u
"greenBand"_s, mGreenBand );
423 rasterRendererElem.setAttribute( u
"blueBand"_s, mBlueBand );
426 if ( mRedContrastEnhancement )
428 QDomElement redContrastElem = doc.createElement( u
"redContrastEnhancement"_s );
429 mRedContrastEnhancement->writeXml( doc, redContrastElem );
430 rasterRendererElem.appendChild( redContrastElem );
432 if ( mGreenContrastEnhancement )
434 QDomElement greenContrastElem = doc.createElement( u
"greenContrastEnhancement"_s );
435 mGreenContrastEnhancement->writeXml( doc, greenContrastElem );
436 rasterRendererElem.appendChild( greenContrastElem );
438 if ( mBlueContrastEnhancement )
440 QDomElement blueContrastElem = doc.createElement( u
"blueContrastEnhancement"_s );
441 mBlueContrastEnhancement->writeXml( doc, blueContrastElem );
442 rasterRendererElem.appendChild( blueContrastElem );
444 parentElem.appendChild( rasterRendererElem );
450 if ( mRedBand != -1 )
452 bandList << mRedBand;
454 if ( mGreenBand != -1 )
456 bandList << mGreenBand;
458 if ( mBlueBand != -1 )
460 bandList << mBlueBand;
467 QList<QgsLayerTreeModelLegendNode *> res;
468 if ( mRedBand != -1 )
472 if ( mGreenBand != -1 )
476 if ( mBlueBand != -1 )
488 toSld( doc, element, context );
506 bool isDefaultCombination =
true;
507 QList<int> defaultBandCombination( { 1, 2, 3 } );
509 isDefaultCombination = isDefaultCombination && (
usesBands() == defaultBandCombination );
510 isDefaultCombination = isDefaultCombination && (
516 if ( isDefaultCombination )
519 isDefaultCombination = isDefaultCombination && (
520 ( mRedContrastEnhancement->minimumValue() == statRed.
minimumValue &&
521 mRedContrastEnhancement->maximumValue() == statRed.
maximumValue )
524 if ( isDefaultCombination )
527 isDefaultCombination = isDefaultCombination && (
528 ( mGreenContrastEnhancement->minimumValue() == statGreen.
minimumValue &&
529 mGreenContrastEnhancement->maximumValue() == statGreen.
maximumValue )
532 if ( isDefaultCombination )
535 isDefaultCombination = isDefaultCombination && (
536 ( mBlueContrastEnhancement->minimumValue() == statBlue.
minimumValue &&
537 mBlueContrastEnhancement->maximumValue() == statBlue.
maximumValue )
540 if ( isDefaultCombination )
545 QDomNodeList elements = element.elementsByTagName( u
"sld:RasterSymbolizer"_s );
546 if ( elements.size() == 0 )
550 QDomElement rasterSymbolizerElem = elements.at( 0 ).toElement();
555 QDomElement channelSelectionElem = doc.createElement( u
"sld:ChannelSelection"_s );
556 elements = rasterSymbolizerElem.elementsByTagName( u
"sld:Opacity"_s );
557 if ( elements.size() != 0 )
559 rasterSymbolizerElem.insertAfter( channelSelectionElem, elements.at( 0 ) );
563 elements = rasterSymbolizerElem.elementsByTagName( u
"sld:Geometry"_s );
564 if ( elements.size() != 0 )
566 rasterSymbolizerElem.insertAfter( channelSelectionElem, elements.at( 0 ) );
570 rasterSymbolizerElem.insertBefore( channelSelectionElem, rasterSymbolizerElem.firstChild() );
575 static QStringList tags { u
"sld:RedChannel"_s, u
"sld:GreenChannel"_s, u
"sld:BlueChannel"_s };
577 QList<QgsContrastEnhancement *> contrastEnhancements;
578 contrastEnhancements.append( mRedContrastEnhancement.get() );
579 contrastEnhancements.append( mGreenContrastEnhancement.get() );
580 contrastEnhancements.append( mBlueContrastEnhancement.get() );
583 QList<int>::const_iterator bandIt = bands.constBegin();
584 for (
int tagCounter = 0; bandIt != bands.constEnd(); ++bandIt, ++tagCounter )
589 QDomElement channelElem = doc.createElement( tags[tagCounter] );
590 channelSelectionElem.appendChild( channelElem );
593 QDomElement sourceChannelNameElem = doc.createElement( u
"sld:SourceChannelName"_s );
594 sourceChannelNameElem.appendChild( doc.createTextNode( QString::number( *bandIt ) ) );
595 channelElem.appendChild( sourceChannelNameElem );
600 if ( contrastEnhancements[tagCounter] )
602 QDomElement contrastEnhancementElem = doc.createElement( u
"sld:ContrastEnhancement"_s );
603 contrastEnhancements[tagCounter]->toSld( doc, contrastEnhancementElem );
604 channelElem.appendChild( contrastEnhancementElem );
617 bool refreshed =
false;
618 if ( min.size() >= 3 && max.size() >= 3 )
624 mRedContrastEnhancement->setMinimumValue( min[0] );
625 mRedContrastEnhancement->setMaximumValue( max[0] );
629 if ( mGreenContrastEnhancement && mGreenContrastEnhancement->contrastEnhancementAlgorithm() !=
QgsContrastEnhancement::NoEnhancement && !std::isnan( min[1] ) && !std::isnan( max[1] ) )
631 mGreenContrastEnhancement->setMinimumValue( min[1] );
632 mGreenContrastEnhancement->setMaximumValue( max[1] );
636 if ( mBlueContrastEnhancement && mBlueContrastEnhancement->contrastEnhancementAlgorithm() !=
QgsContrastEnhancement::NoEnhancement && !std::isnan( min[2] ) && !std::isnan( max[2] ) )
638 mBlueContrastEnhancement->setMinimumValue( min[2] );
639 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)