QGIS API Documentation  2.99.0-Master (08ee180)
qgssinglebandgrayrenderer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssinglebandgrayrenderer.cpp
3  -----------------------------
4  begin : December 2011
5  copyright : (C) 2011 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 "qgscontrastenhancement.h"
20 #include "qgsrastertransparency.h"
21 #include <QDomDocument>
22 #include <QDomElement>
23 #include <QImage>
24 #include <QColor>
25 
27  QgsRasterRenderer( input, QStringLiteral( "singlebandgray" ) ), mGrayBand( grayBand ), mGradient( BlackToWhite ), mContrastEnhancement( nullptr )
28 {
29 }
30 
32 {
33  delete mContrastEnhancement;
34 }
35 
37 {
38  QgsSingleBandGrayRenderer * renderer = new QgsSingleBandGrayRenderer( nullptr, mGrayBand );
39  renderer->copyCommonProperties( this );
40 
41  renderer->setGradient( mGradient );
42  if ( mContrastEnhancement )
43  {
44  renderer->setContrastEnhancement( new QgsContrastEnhancement( *mContrastEnhancement ) );
45  }
46  return renderer;
47 }
48 
50 {
51  if ( elem.isNull() )
52  {
53  return nullptr;
54  }
55 
56  int grayBand = elem.attribute( QStringLiteral( "grayBand" ), QStringLiteral( "-1" ) ).toInt();
57  QgsSingleBandGrayRenderer* r = new QgsSingleBandGrayRenderer( input, grayBand );
58  r->readXml( elem );
59 
60  if ( elem.attribute( QStringLiteral( "gradient" ) ) == QLatin1String( "WhiteToBlack" ) )
61  {
62  r->setGradient( WhiteToBlack ); // BlackToWhite is default
63  }
64 
65  QDomElement contrastEnhancementElem = elem.firstChildElement( QStringLiteral( "contrastEnhancement" ) );
66  if ( !contrastEnhancementElem.isNull() )
67  {
69  input->dataType( grayBand ) ) );
70  ce->readXml( contrastEnhancementElem );
71  r->setContrastEnhancement( ce );
72  }
73  return r;
74 }
75 
77 {
78  delete mContrastEnhancement;
79  mContrastEnhancement = ce;
80 }
81 
82 QgsRasterBlock* QgsSingleBandGrayRenderer::block( int bandNo, QgsRectangle const & extent, int width, int height, QgsRasterBlockFeedback* feedback )
83 {
84  Q_UNUSED( bandNo );
85  QgsDebugMsgLevel( QString( "width = %1 height = %2" ).arg( width ).arg( height ), 4 );
86 
87  QgsRasterBlock *outputBlock = new QgsRasterBlock();
88  if ( !mInput )
89  {
90  return outputBlock;
91  }
92 
93  QgsRasterBlock *inputBlock = mInput->block( mGrayBand, extent, width, height, feedback );
94  if ( !inputBlock || inputBlock->isEmpty() )
95  {
96  QgsDebugMsg( "No raster data!" );
97  delete inputBlock;
98  return outputBlock;
99  }
100 
101  QgsRasterBlock *alphaBlock = nullptr;
102 
103  if ( mAlphaBand > 0 && mGrayBand != mAlphaBand )
104  {
105  alphaBlock = mInput->block( mAlphaBand, extent, width, height, feedback );
106  if ( !alphaBlock || alphaBlock->isEmpty() )
107  {
108  // TODO: better to render without alpha
109  delete inputBlock;
110  delete alphaBlock;
111  return outputBlock;
112  }
113  }
114  else if ( mAlphaBand > 0 )
115  {
116  alphaBlock = inputBlock;
117  }
118 
119  if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) )
120  {
121  delete inputBlock;
122  delete alphaBlock;
123  return outputBlock;
124  }
125 
126  QRgb myDefaultColor = NODATA_COLOR;
127  for ( qgssize i = 0; i < ( qgssize )width*height; i++ )
128  {
129  if ( inputBlock->isNoData( i ) )
130  {
131  outputBlock->setColor( i, myDefaultColor );
132  continue;
133  }
134  double grayVal = inputBlock->value( i );
135 
136  double currentAlpha = mOpacity;
137  if ( mRasterTransparency )
138  {
139  currentAlpha = mRasterTransparency->alphaValue( grayVal, mOpacity * 255 ) / 255.0;
140  }
141  if ( mAlphaBand > 0 )
142  {
143  currentAlpha *= alphaBlock->value( i ) / 255.0;
144  }
145 
146  if ( mContrastEnhancement )
147  {
148  if ( !mContrastEnhancement->isValueInDisplayableRange( grayVal ) )
149  {
150  outputBlock->setColor( i, myDefaultColor );
151  continue;
152  }
153  grayVal = mContrastEnhancement->enhanceContrast( grayVal );
154  }
155 
156  if ( mGradient == WhiteToBlack )
157  {
158  grayVal = 255 - grayVal;
159  }
160 
161  if ( qgsDoubleNear( currentAlpha, 1.0 ) )
162  {
163  outputBlock->setColor( i, qRgba( grayVal, grayVal, grayVal, 255 ) );
164  }
165  else
166  {
167  outputBlock->setColor( i, qRgba( currentAlpha * grayVal, currentAlpha * grayVal, currentAlpha * grayVal, currentAlpha * 255 ) );
168  }
169  }
170 
171  delete inputBlock;
172  if ( mAlphaBand > 0 && mGrayBand != mAlphaBand )
173  {
174  delete alphaBlock;
175  }
176 
177  return outputBlock;
178 }
179 
180 void QgsSingleBandGrayRenderer::writeXml( QDomDocument& doc, QDomElement& parentElem ) const
181 {
182  if ( parentElem.isNull() )
183  {
184  return;
185  }
186 
187  QDomElement rasterRendererElem = doc.createElement( QStringLiteral( "rasterrenderer" ) );
188  _writeXml( doc, rasterRendererElem );
189 
190  rasterRendererElem.setAttribute( QStringLiteral( "grayBand" ), mGrayBand );
191 
192  QString gradient;
193  if ( mGradient == BlackToWhite )
194  {
195  gradient = QStringLiteral( "BlackToWhite" );
196  }
197  else
198  {
199  gradient = QStringLiteral( "WhiteToBlack" );
200  }
201  rasterRendererElem.setAttribute( QStringLiteral( "gradient" ), gradient );
202 
203  if ( mContrastEnhancement )
204  {
205  QDomElement contrastElem = doc.createElement( QStringLiteral( "contrastEnhancement" ) );
206  mContrastEnhancement->writeXml( doc, contrastElem );
207  rasterRendererElem.appendChild( contrastElem );
208  }
209  parentElem.appendChild( rasterRendererElem );
210 }
211 
212 void QgsSingleBandGrayRenderer::legendSymbologyItems( QList< QPair< QString, QColor > >& symbolItems ) const
213 {
214  if ( mContrastEnhancement && mContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement )
215  {
216  QColor minColor = ( mGradient == BlackToWhite ) ? Qt::black : Qt::white;
217  QColor maxColor = ( mGradient == BlackToWhite ) ? Qt::white : Qt::black;
218  symbolItems.push_back( qMakePair( QString::number( mContrastEnhancement->minimumValue() ), minColor ) );
219  symbolItems.push_back( qMakePair( QString::number( mContrastEnhancement->maximumValue() ), maxColor ) );
220  }
221 }
222 
224 {
225  QList<int> bandList;
226  if ( mGrayBand != -1 )
227  {
228  bandList << mGrayBand;
229  }
230  return bandList;
231 }
double maximumValue() const
Return the maximum value for the contrast enhancement range.
A rectangle specified with double values.
Definition: qgsrectangle.h:35
static QgsRasterRenderer * create(const QDomElement &elem, QgsRasterInterface *input)
QgsSingleBandGrayRenderer(QgsRasterInterface *input, int grayBand)
virtual QgsRectangle extent() const
Get the extent of the interface.
QList< int > usesBands() const override
Returns a list of band numbers used by the renderer.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
int alphaValue(double, int theGlobalTransparency=255) const
Returns the transparency value for a single value Pixel.
bool isValueInDisplayableRange(double)
Return true if pixel is in stretable range, false if pixel is outside of range (i.e., clipped)
virtual QgsRasterInterface * input() const
Current input.
void copyCommonProperties(const QgsRasterRenderer *other)
Copies common properties like opacity / transparency data from other renderer.
DataType
Raster data types.
Definition: qgis.h:60
double minimumValue() const
Return the minimum value for the contrast enhancement range.
virtual Qgis::DataType dataType(int bandNo) const =0
Returns data type for the band specified by number.
QgsSingleBandGrayRenderer * clone() const override
Clone itself, create deep copy.
bool isNoData(int row, int column)
Check if value at position is no data.
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:196
QgsRasterTransparency * mRasterTransparency
Raster transparency per color or value. Overwrites global alpha value.
void legendSymbologyItems(QList< QPair< QString, QColor > > &symbolItems) const override
Get symbology items if provided by renderer.
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.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:34
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.
void _writeXml(QDomDocument &doc, QDomElement &rasterRendererElem) const
Write upper class info into rasterrenderer element (called by writeXml method of subclasses) ...
void readXml(const QDomElement &elem)
Raster renderer pipe for single band gray.
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.
Base class for processing filters like renderers, reprojector, resampler etc.
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 setGradient(Gradient theGradient)
void setContrastEnhancement(QgsContrastEnhancement *ce)
Takes ownership.
int enhanceContrast(double)
Apply the contrast enhancement to a value. Return values are 0 - 254, -1 means the pixel was clipped ...
QgsRasterBlock * block(int bandNo, QgsRectangle const &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
double value(int row, int column) const
Read a single value if type of block is numeric.
ContrastEnhancementAlgorithm contrastEnhancementAlgorithm() const
void writeXml(QDomDocument &doc, QDomElement &parentElem) const
double mOpacity
Global alpha value (0-1)
Manipulates raster pixel values so that they enhanceContrast or clip into a specified numerical range...
void writeXml(QDomDocument &doc, QDomElement &parentElem) const override
Write base class members to xml.
QgsRasterInterface * mInput
Feedback object tailored for raster block reading.
Raster renderer pipe that applies colors to a raster.