QGIS API Documentation  2.99.0-Master (c42dad3)
qgssinglebandpseudocolorrenderer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssinglebandpseudocolorrenderer.cpp
3  ------------------------------------
4  begin : January 2012
5  copyright : (C) 2012 by Marco Hugentobler
6  email : marco at sourcepole dot ch
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 
19 #include "qgscolorrampshader.h"
20 #include "qgsrastershader.h"
21 #include "qgsrastertransparency.h"
22 #include "qgsrasterviewport.h"
23 #include <QDomDocument>
24 #include <QDomElement>
25 #include <QImage>
26 
28  QgsRasterRenderer( input, QStringLiteral( "singlebandpseudocolor" ) )
29  , mShader( shader )
30  , mBand( band )
31  , mClassificationMin( std::numeric_limits<double>::quiet_NaN() )
32  , mClassificationMax( std::numeric_limits<double>::quiet_NaN() )
33  , mClassificationMinMaxOrigin( QgsRasterRenderer::MinMaxUnknown )
34 {
35 }
36 
38 {
39  delete mShader;
40 }
41 
43 {
44  if ( bandNo > mInput->bandCount() || bandNo <= 0 )
45  {
46  return;
47  }
48  mBand = bandNo;
49 }
50 
52 {
53  QgsRasterShader *shader = nullptr;
54 
55  if ( mShader )
56  {
57  shader = new QgsRasterShader( mShader->minimumValue(), mShader->maximumValue() );
58 
59  // Shader function
60  const QgsColorRampShader* origColorRampShader = dynamic_cast<const QgsColorRampShader*>( mShader->rasterShaderFunction() );
61 
62  if ( origColorRampShader )
63  {
64  QgsColorRampShader * colorRampShader = new QgsColorRampShader( mShader->minimumValue(), mShader->maximumValue() );
65 
66  colorRampShader->setColorRampName( origColorRampShader->colorRampName() );
67  colorRampShader->setColorRampType( origColorRampShader->colorRampType() );
68  colorRampShader->setClip( origColorRampShader->clip() );
69  colorRampShader->setColorRampItemList( origColorRampShader->colorRampItemList() );
70  shader->setRasterShaderFunction( colorRampShader );
71  }
72  }
73  QgsSingleBandPseudoColorRenderer * renderer = new QgsSingleBandPseudoColorRenderer( nullptr, mBand, shader );
74  renderer->copyCommonProperties( this );
75 
76  return renderer;
77 }
78 
80 {
81  delete mShader;
82  mShader = shader;
83 }
84 
86 {
87  if ( elem.isNull() )
88  {
89  return nullptr;
90  }
91 
92  int band = elem.attribute( QStringLiteral( "band" ), QStringLiteral( "-1" ) ).toInt();
93  QgsRasterShader* shader = nullptr;
94  QDomElement rasterShaderElem = elem.firstChildElement( QStringLiteral( "rastershader" ) );
95  if ( !rasterShaderElem.isNull() )
96  {
97  shader = new QgsRasterShader();
98  shader->readXml( rasterShaderElem );
99  }
100 
102  r->readXml( elem );
103 
104  // TODO: add _readXML in superclass?
105  r->setClassificationMin( elem.attribute( QStringLiteral( "classificationMin" ), QStringLiteral( "NaN" ) ).toDouble() );
106  r->setClassificationMax( elem.attribute( QStringLiteral( "classificationMax" ), QStringLiteral( "NaN" ) ).toDouble() );
107  r->setClassificationMinMaxOrigin( QgsRasterRenderer::minMaxOriginFromName( elem.attribute( QStringLiteral( "classificationMinMaxOrigin" ), QStringLiteral( "Unknown" ) ) ) );
108 
109  return r;
110 }
111 
113 {
114  Q_UNUSED( bandNo );
115 
116  QgsRasterBlock *outputBlock = new QgsRasterBlock();
117  if ( !mInput || !mShader )
118  {
119  return outputBlock;
120  }
121 
122 
123  QgsRasterBlock *inputBlock = mInput->block( mBand, extent, width, height, feedback );
124  if ( !inputBlock || inputBlock->isEmpty() )
125  {
126  QgsDebugMsg( "No raster data!" );
127  delete inputBlock;
128  return outputBlock;
129  }
130 
131  //rendering is faster without considering user-defined transparency
132  bool hasTransparency = usesTransparency();
133 
134  QgsRasterBlock *alphaBlock = nullptr;
135  if ( mAlphaBand > 0 && mAlphaBand != mBand )
136  {
137  alphaBlock = mInput->block( mAlphaBand, extent, width, height, feedback );
138  if ( !alphaBlock || alphaBlock->isEmpty() )
139  {
140  delete inputBlock;
141  delete alphaBlock;
142  return outputBlock;
143  }
144  }
145  else if ( mAlphaBand == mBand )
146  {
147  alphaBlock = inputBlock;
148  }
149 
150  if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) )
151  {
152  delete inputBlock;
153  delete alphaBlock;
154  return outputBlock;
155  }
156 
157  QRgb myDefaultColor = NODATA_COLOR;
158 
159  for ( qgssize i = 0; i < ( qgssize )width*height; i++ )
160  {
161  if ( inputBlock->isNoData( i ) )
162  {
163  outputBlock->setColor( i, myDefaultColor );
164  continue;
165  }
166  double val = inputBlock->value( i );
167  int red, green, blue, alpha;
168  if ( !mShader->shade( val, &red, &green, &blue, &alpha ) )
169  {
170  outputBlock->setColor( i, myDefaultColor );
171  continue;
172  }
173 
174  if ( alpha < 255 )
175  {
176  // Working with premultiplied colors, so multiply values by alpha
177  red *= ( alpha / 255.0 );
178  blue *= ( alpha / 255.0 );
179  green *= ( alpha / 255.0 );
180  }
181 
182  if ( !hasTransparency )
183  {
184  outputBlock->setColor( i, qRgba( red, green, blue, alpha ) );
185  }
186  else
187  {
188  //opacity
189  double currentOpacity = mOpacity;
190  if ( mRasterTransparency )
191  {
192  currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0;
193  }
194  if ( mAlphaBand > 0 )
195  {
196  currentOpacity *= alphaBlock->value( i ) / 255.0;
197  }
198 
199  outputBlock->setColor( i, qRgba( currentOpacity * red, currentOpacity * green, currentOpacity * blue, currentOpacity * alpha ) );
200  }
201  }
202 
203  delete inputBlock;
204  if ( mAlphaBand > 0 && mBand != mAlphaBand )
205  {
206  delete alphaBlock;
207  }
208 
209  return outputBlock;
210 }
211 
212 void QgsSingleBandPseudoColorRenderer::writeXml( QDomDocument& doc, QDomElement& parentElem ) const
213 {
214  if ( parentElem.isNull() )
215  {
216  return;
217  }
218 
219  QDomElement rasterRendererElem = doc.createElement( QStringLiteral( "rasterrenderer" ) );
220  _writeXml( doc, rasterRendererElem );
221  rasterRendererElem.setAttribute( QStringLiteral( "band" ), mBand );
222  if ( mShader )
223  {
224  mShader->writeXml( doc, rasterRendererElem ); //todo: include color ramp items directly in this renderer
225  }
226  rasterRendererElem.setAttribute( QStringLiteral( "classificationMin" ), QgsRasterBlock::printValue( mClassificationMin ) );
227  rasterRendererElem.setAttribute( QStringLiteral( "classificationMax" ), QgsRasterBlock::printValue( mClassificationMax ) );
228  rasterRendererElem.setAttribute( QStringLiteral( "classificationMinMaxOrigin" ), QgsRasterRenderer::minMaxOriginName( mClassificationMinMaxOrigin ) );
229 
230  parentElem.appendChild( rasterRendererElem );
231 }
232 
233 void QgsSingleBandPseudoColorRenderer::legendSymbologyItems( QList< QPair< QString, QColor > >& symbolItems ) const
234 {
235  if ( mShader )
236  {
237  QgsRasterShaderFunction* shaderFunction = mShader->rasterShaderFunction();
238  if ( shaderFunction )
239  {
240  shaderFunction->legendSymbologyItems( symbolItems );
241  }
242  }
243 }
244 
246 {
247  QList<int> bandList;
248  if ( mBand != -1 )
249  {
250  bandList << mBand;
251  }
252  return bandList;
253 }
virtual int bandCount() const =0
Get number of bands.
A rectangle specified with double values.
Definition: qgsrectangle.h:35
Interface for all raster shaders.
static QString printValue(double value)
Print double value with all necessary significant digits.
void legendSymbologyItems(QList< QPair< QString, QColor > > &symbolItems) const override
Get symbology items if provided by renderer.
QgsSingleBandPseudoColorRenderer * clone() const override
Clone itself, create deep copy.
virtual QgsRectangle extent() const
Get the extent of the interface.
static QgsRasterRenderer * create(const QDomElement &elem, QgsRasterInterface *input)
A ramp shader will color a raster pixel based on a list of values ranges in a ramp.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
int alphaValue(double, int theGlobalTransparency=255) const
Returns the transparency value for a single value Pixel.
virtual QgsRasterInterface * input() const
Current input.
void copyCommonProperties(const QgsRasterRenderer *other)
Copies common properties like opacity / transparency data from other renderer.
static int minMaxOriginFromName(const QString &theName)
void setColorRampItemList(const QList< QgsColorRampShader::ColorRampItem > &theList)
Set custom colormap.
void setClip(bool clip)
Sets whether the shader should not render values out of range.
void setColorRampName(const QString &theName)
Sets the source color ramp name.
virtual void legendSymbologyItems(QList< QPair< QString, QColor > > &symbolItems) const
bool isNoData(int row, int column)
Check if value at position is no data.
void setShader(QgsRasterShader *shader)
Takes ownership of the shader.
QgsRasterTransparency * mRasterTransparency
Raster transparency per color or value. Overwrites global alpha value.
bool setColor(int row, int column, QRgb color)
Set color on position.
static const QRgb NODATA_COLOR
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition: qgis.h:75
Raster data container.
QgsSingleBandPseudoColorRenderer(QgsRasterInterface *input, int band, QgsRasterShader *shader)
Note: takes ownership of QgsRasterShader.
virtual QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr)=0
Read block of data using given extent and size.
QgsRasterShaderFunction * rasterShaderFunction()
void _writeXml(QDomDocument &doc, QDomElement &rasterRendererElem) const
Write upper class info into rasterrenderer element (called by writeXml method of subclasses) ...
The raster shade function applies a shader to a pixel at render time - typically used to render grays...
double maximumValue()
Return the maximum value for the raster shader.
Raster renderer pipe for single band pseudocolor.
bool usesTransparency() const
bool shade(double, int *, int *, int *, int *)
generates and new RGBA value based on one input value
bool isEmpty() const
Returns true if block is empty, i.e.
int mAlphaBand
Read alpha value from band.
void readXml(const QDomElement &rendererElem) override
Sets base class members from xml. Usually called from create() methods of subclasses.
QList< int > usesBands() const override
Returns a list of band numbers used by the renderer.
void setRasterShaderFunction(QgsRasterShaderFunction *)
A public method that allows the user to set their own shader function.
Base class for processing filters like renderers, reprojector, resampler etc.
void setColorRampType(QgsColorRampShader::ColorRamp_TYPE theColorRampType)
Set the color ramp type.
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...
Definition: qgis.h:336
bool reset(Qgis::DataType theDataType, int theWidth, int theHeight)
Reset block.
void writeXml(QDomDocument &doc, QDomElement &parent) const
static QString minMaxOriginName(int theOrigin)
double minimumValue()
Return the minimum value for the raster shader.
double value(int row, int column) const
Read a single value if type of block is numeric.
void setBand(int bandNo)
Sets the band used by the renderer.
double mOpacity
Global alpha value (0-1)
QgsRasterInterface * mInput
Feedback object tailored for raster block reading.
QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
Raster renderer pipe that applies colors to a raster.
int band() const
Returns the band used by the renderer.
void writeXml(QDomDocument &doc, QDomElement &parentElem) const override
Write base class members to xml.
void readXml(const QDomElement &elem)