QGIS API Documentation  2.17.0-Master (2f94c66)
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 
26  QgsRasterRenderer( input, "singlebandgray" ), mGrayBand( grayBand ), mGradient( BlackToWhite ), mContrastEnhancement( nullptr )
27 {
28 }
29 
31 {
32  delete mContrastEnhancement;
33 }
34 
36 {
37  QgsSingleBandGrayRenderer * renderer = new QgsSingleBandGrayRenderer( nullptr, mGrayBand );
38  renderer->copyCommonProperties( this );
39 
40  renderer->setGradient( mGradient );
41  if ( mContrastEnhancement )
42  {
43  renderer->setContrastEnhancement( new QgsContrastEnhancement( *mContrastEnhancement ) );
44  }
45  return renderer;
46 }
47 
49 {
50  if ( elem.isNull() )
51  {
52  return nullptr;
53  }
54 
55  int grayBand = elem.attribute( "grayBand", "-1" ).toInt();
56  QgsSingleBandGrayRenderer* r = new QgsSingleBandGrayRenderer( input, grayBand );
57  r->readXML( elem );
58 
59  if ( elem.attribute( "gradient" ) == "WhiteToBlack" )
60  {
61  r->setGradient( WhiteToBlack ); // BlackToWhite is default
62  }
63 
64  QDomElement contrastEnhancementElem = elem.firstChildElement( "contrastEnhancement" );
65  if ( !contrastEnhancementElem.isNull() )
66  {
68  input->dataType( grayBand ) ) );
69  ce->readXML( contrastEnhancementElem );
70  r->setContrastEnhancement( ce );
71  }
72  return r;
73 }
74 
76 {
77  delete mContrastEnhancement;
78  mContrastEnhancement = ce;
79 }
80 
81 QgsRasterBlock* QgsSingleBandGrayRenderer::block( int bandNo, QgsRectangle const & extent, int width, int height )
82 {
83  Q_UNUSED( bandNo );
84  QgsDebugMsgLevel( QString( "width = %1 height = %2" ).arg( width ).arg( height ), 4 );
85 
86  QgsRasterBlock *outputBlock = new QgsRasterBlock();
87  if ( !mInput )
88  {
89  return outputBlock;
90  }
91 
92  QgsRasterBlock *inputBlock = mInput->block( mGrayBand, extent, width, height );
93  if ( !inputBlock || inputBlock->isEmpty() )
94  {
95  QgsDebugMsg( "No raster data!" );
96  delete inputBlock;
97  return outputBlock;
98  }
99 
100  QgsRasterBlock *alphaBlock = nullptr;
101 
102  if ( mAlphaBand > 0 && mGrayBand != mAlphaBand )
103  {
104  alphaBlock = mInput->block( mAlphaBand, extent, width, height );
105  if ( !alphaBlock || alphaBlock->isEmpty() )
106  {
107  // TODO: better to render without alpha
108  delete inputBlock;
109  delete alphaBlock;
110  return outputBlock;
111  }
112  }
113  else if ( mAlphaBand > 0 )
114  {
115  alphaBlock = inputBlock;
116  }
117 
118  if ( !outputBlock->reset( QGis::ARGB32_Premultiplied, width, height ) )
119  {
120  delete inputBlock;
121  delete alphaBlock;
122  return outputBlock;
123  }
124 
125  QRgb myDefaultColor = NODATA_COLOR;
126  for ( qgssize i = 0; i < ( qgssize )width*height; i++ )
127  {
128  if ( inputBlock->isNoData( i ) )
129  {
130  outputBlock->setColor( i, myDefaultColor );
131  continue;
132  }
133  double grayVal = inputBlock->value( i );
134 
135  double currentAlpha = mOpacity;
136  if ( mRasterTransparency )
137  {
138  currentAlpha = mRasterTransparency->alphaValue( grayVal, mOpacity * 255 ) / 255.0;
139  }
140  if ( mAlphaBand > 0 )
141  {
142  currentAlpha *= alphaBlock->value( i ) / 255.0;
143  }
144 
145  if ( mContrastEnhancement )
146  {
147  if ( !mContrastEnhancement->isValueInDisplayableRange( grayVal ) )
148  {
149  outputBlock->setColor( i, myDefaultColor );
150  continue;
151  }
152  grayVal = mContrastEnhancement->enhanceContrast( grayVal );
153  }
154 
155  if ( mGradient == WhiteToBlack )
156  {
157  grayVal = 255 - grayVal;
158  }
159 
160  if ( qgsDoubleNear( currentAlpha, 1.0 ) )
161  {
162  outputBlock->setColor( i, qRgba( grayVal, grayVal, grayVal, 255 ) );
163  }
164  else
165  {
166  outputBlock->setColor( i, qRgba( currentAlpha * grayVal, currentAlpha * grayVal, currentAlpha * grayVal, currentAlpha * 255 ) );
167  }
168  }
169 
170  delete inputBlock;
171  if ( mAlphaBand > 0 && mGrayBand != mAlphaBand )
172  {
173  delete alphaBlock;
174  }
175 
176  return outputBlock;
177 }
178 
180 {
181  if ( parentElem.isNull() )
182  {
183  return;
184  }
185 
186  QDomElement rasterRendererElem = doc.createElement( "rasterrenderer" );
187  _writeXML( doc, rasterRendererElem );
188 
189  rasterRendererElem.setAttribute( "grayBand", mGrayBand );
190 
192  if ( mGradient == BlackToWhite )
193  {
194  gradient = "BlackToWhite";
195  }
196  else
197  {
198  gradient = "WhiteToBlack";
199  }
200  rasterRendererElem.setAttribute( "gradient", gradient );
201 
202  if ( mContrastEnhancement )
203  {
204  QDomElement contrastElem = doc.createElement( "contrastEnhancement" );
205  mContrastEnhancement->writeXML( doc, contrastElem );
206  rasterRendererElem.appendChild( contrastElem );
207  }
208  parentElem.appendChild( rasterRendererElem );
209 }
210 
212 {
213  if ( mContrastEnhancement && mContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement )
214  {
215  QColor minColor = ( mGradient == BlackToWhite ) ? Qt::black : Qt::white;
216  QColor maxColor = ( mGradient == BlackToWhite ) ? Qt::white : Qt::black;
217  symbolItems.push_back( qMakePair( QString::number( mContrastEnhancement->minimumValue() ), minColor ) );
218  symbolItems.push_back( qMakePair( QString::number( mContrastEnhancement->maximumValue() ), maxColor ) );
219  }
220 }
221 
223 {
224  QList<int> bandList;
225  if ( mGrayBand != -1 )
226  {
227  bandList << mGrayBand;
228  }
229  return bandList;
230 }
void writeXML(QDomDocument &doc, QDomElement &parentElem) const
A rectangle specified with double values.
Definition: qgsrectangle.h:35
static QgsRasterRenderer * create(const QDomElement &elem, QgsRasterInterface *input)
QgsSingleBandGrayRenderer(QgsRasterInterface *input, int grayBand)
void readXML(const QDomElement &elem)
QDomNode appendChild(const QDomNode &newChild)
ContrastEnhancementAlgorithm contrastEnhancementAlgorithm() const
void writeXML(QDomDocument &doc, QDomElement &parentElem) const override
Write base class members to xml.
QList< int > usesBands() const override
Returns a list of band numbers used by the renderer.
QString attribute(const QString &name, const QString &defValue) const
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
bool isValueInDisplayableRange(double)
Return true if pixel is in stretable range, false if pixel is outside of range (i.e., clipped)
void copyCommonProperties(const QgsRasterRenderer *other)
Copies common properties like opacity / transparency data from other renderer.
virtual QgsRasterInterface * input() const
Current input.
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:353
void readXML(const QDomElement &rendererElem) override
Sets base class members from xml.
QgsRasterBlock * block(int bandNo, QgsRectangle const &extent, int width, int height) override
Read block of data using given extent and size.
QgsRasterTransparency * mRasterTransparency
Raster transparency per color or 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
int alphaValue(double, int theGlobalTransparency=255) const
Returns the transparency value for a single value Pixel.
QString number(int n, int base)
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition: qgis.h:150
Raster data container.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:34
double value(int row, int column) const
Read a single value if type of block is numeric.
void setAttribute(const QString &name, const QString &value)
int toInt(bool *ok, int base) const
Raster renderer pipe for single band gray.
double minimumValue() const
Return the minimum value for the contrast enhancement range.
int mAlphaBand
Read alpha value from band.
virtual QGis::DataType dataType(int bandNo) const =0
Returns data type for the band specified by number.
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:500
bool reset(QGis::DataType theDataType, int theWidth, int theHeight)
Reset block.
bool isNull() const
void setGradient(Gradient theGradient)
virtual QgsRectangle extent()
Get the extent of the interface.
void setContrastEnhancement(QgsContrastEnhancement *ce)
Takes ownership.
int enhanceContrast(double)
Apply the contrast enhancement to a value.
double maximumValue() const
Return the maximum value for the contrast enhancement range.
QDomElement firstChildElement(const QString &tagName) const
DataType
Raster data types.
Definition: qgis.h:133
virtual QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height)=0
Read block of data using given extent and size.
double mOpacity
Global alpha value (0-1)
Manipulates raster pixel values so that they enhanceContrast or clip into a specified numerical range...
QDomElement createElement(const QString &tagName)
void _writeXML(QDomDocument &doc, QDomElement &rasterRendererElem) const
Write upper class info into rasterrenderer element (called by writeXML method of subclasses) ...
QgsRasterInterface * mInput
Raster renderer pipe that applies colors to a raster.
bool isEmpty() const
Returns true if block is empty, i.e.