QGIS API Documentation  2.17.0-Master (dfeb663)
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  return block2( bandNo, extent, width, height );
84 }
85 
86 QgsRasterBlock* QgsSingleBandGrayRenderer::block2( int bandNo, QgsRectangle const & extent, int width, int height, QgsRasterBlockFeedback* feedback )
87 {
88  Q_UNUSED( bandNo );
89  QgsDebugMsgLevel( QString( "width = %1 height = %2" ).arg( width ).arg( height ), 4 );
90 
91  QgsRasterBlock *outputBlock = new QgsRasterBlock();
92  if ( !mInput )
93  {
94  return outputBlock;
95  }
96 
97  QgsRasterBlock *inputBlock = mInput->block2( mGrayBand, extent, width, height, feedback );
98  if ( !inputBlock || inputBlock->isEmpty() )
99  {
100  QgsDebugMsg( "No raster data!" );
101  delete inputBlock;
102  return outputBlock;
103  }
104 
105  QgsRasterBlock *alphaBlock = nullptr;
106 
107  if ( mAlphaBand > 0 && mGrayBand != mAlphaBand )
108  {
109  alphaBlock = mInput->block2( mAlphaBand, extent, width, height, feedback );
110  if ( !alphaBlock || alphaBlock->isEmpty() )
111  {
112  // TODO: better to render without alpha
113  delete inputBlock;
114  delete alphaBlock;
115  return outputBlock;
116  }
117  }
118  else if ( mAlphaBand > 0 )
119  {
120  alphaBlock = inputBlock;
121  }
122 
123  if ( !outputBlock->reset( QGis::ARGB32_Premultiplied, width, height ) )
124  {
125  delete inputBlock;
126  delete alphaBlock;
127  return outputBlock;
128  }
129 
130  QRgb myDefaultColor = NODATA_COLOR;
131  for ( qgssize i = 0; i < ( qgssize )width*height; i++ )
132  {
133  if ( inputBlock->isNoData( i ) )
134  {
135  outputBlock->setColor( i, myDefaultColor );
136  continue;
137  }
138  double grayVal = inputBlock->value( i );
139 
140  double currentAlpha = mOpacity;
141  if ( mRasterTransparency )
142  {
143  currentAlpha = mRasterTransparency->alphaValue( grayVal, mOpacity * 255 ) / 255.0;
144  }
145  if ( mAlphaBand > 0 )
146  {
147  currentAlpha *= alphaBlock->value( i ) / 255.0;
148  }
149 
150  if ( mContrastEnhancement )
151  {
152  if ( !mContrastEnhancement->isValueInDisplayableRange( grayVal ) )
153  {
154  outputBlock->setColor( i, myDefaultColor );
155  continue;
156  }
157  grayVal = mContrastEnhancement->enhanceContrast( grayVal );
158  }
159 
160  if ( mGradient == WhiteToBlack )
161  {
162  grayVal = 255 - grayVal;
163  }
164 
165  if ( qgsDoubleNear( currentAlpha, 1.0 ) )
166  {
167  outputBlock->setColor( i, qRgba( grayVal, grayVal, grayVal, 255 ) );
168  }
169  else
170  {
171  outputBlock->setColor( i, qRgba( currentAlpha * grayVal, currentAlpha * grayVal, currentAlpha * grayVal, currentAlpha * 255 ) );
172  }
173  }
174 
175  delete inputBlock;
176  if ( mAlphaBand > 0 && mGrayBand != mAlphaBand )
177  {
178  delete alphaBlock;
179  }
180 
181  return outputBlock;
182 }
183 
185 {
186  if ( parentElem.isNull() )
187  {
188  return;
189  }
190 
191  QDomElement rasterRendererElem = doc.createElement( "rasterrenderer" );
192  _writeXML( doc, rasterRendererElem );
193 
194  rasterRendererElem.setAttribute( "grayBand", mGrayBand );
195 
197  if ( mGradient == BlackToWhite )
198  {
199  gradient = "BlackToWhite";
200  }
201  else
202  {
203  gradient = "WhiteToBlack";
204  }
205  rasterRendererElem.setAttribute( "gradient", gradient );
206 
207  if ( mContrastEnhancement )
208  {
209  QDomElement contrastElem = doc.createElement( "contrastEnhancement" );
210  mContrastEnhancement->writeXML( doc, contrastElem );
211  rasterRendererElem.appendChild( contrastElem );
212  }
213  parentElem.appendChild( rasterRendererElem );
214 }
215 
217 {
218  if ( mContrastEnhancement && mContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement )
219  {
220  QColor minColor = ( mGradient == BlackToWhite ) ? Qt::black : Qt::white;
221  QColor maxColor = ( mGradient == BlackToWhite ) ? Qt::white : Qt::black;
222  symbolItems.push_back( qMakePair( QString::number( mContrastEnhancement->minimumValue() ), minColor ) );
223  symbolItems.push_back( qMakePair( QString::number( mContrastEnhancement->maximumValue() ), maxColor ) );
224  }
225 }
226 
228 {
229  QList<int> bandList;
230  if ( mGrayBand != -1 )
231  {
232  bandList << mGrayBand;
233  }
234  return bandList;
235 }
double maximumValue() const
Return the maximum value for the contrast enhancement range.
A rectangle specified with double values.
Definition: qgsrectangle.h:35
void writeXML(QDomDocument &doc, QDomElement &parentElem) const
static QgsRasterRenderer * create(const QDomElement &elem, QgsRasterInterface *input)
QgsSingleBandGrayRenderer(QgsRasterInterface *input, int grayBand)
void readXML(const QDomElement &elem)
QDomNode appendChild(const QDomNode &newChild)
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
int alphaValue(double, int theGlobalTransparency=255) const
Returns the transparency value for a single value Pixel.
QgsRasterBlock * block2(int bandNo, QgsRectangle const &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
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.
double minimumValue() const
Return the minimum value for the contrast enhancement range.
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.
virtual QgsRasterBlock * block2(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr)
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
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
void setAttribute(const QString &name, const QString &value)
int toInt(bool *ok, int base) const
Raster renderer pipe for single band gray.
bool isEmpty() const
Returns true if block is empty, i.e.
void _writeXML(QDomDocument &doc, QDomElement &rasterRendererElem) const
Write upper class info into rasterrenderer element (called by writeXML method of subclasses) ...
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.
QDomElement firstChildElement(const QString &tagName) const
DataType
Raster data types.
Definition: qgis.h:133
double value(int row, int column) const
Read a single value if type of block is numeric.
ContrastEnhancementAlgorithm contrastEnhancementAlgorithm() const
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)
QgsRasterInterface * mInput
Feedback object tailored for raster block reading.
Raster renderer pipe that applies colors to a raster.