QGIS API Documentation  2.99.0-Master (08c2e66)
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 #include <memory>
26 
28  QgsRasterRenderer( input, QStringLiteral( "singlebandgray" ) ), mGrayBand( grayBand ), mGradient( BlackToWhite ), mContrastEnhancement( nullptr )
29 {
30 }
31 
33 {
34  delete mContrastEnhancement;
35 }
36 
38 {
39  QgsSingleBandGrayRenderer * renderer = new QgsSingleBandGrayRenderer( nullptr, mGrayBand );
40  renderer->copyCommonProperties( this );
41 
42  renderer->setGradient( mGradient );
43  if ( mContrastEnhancement )
44  {
45  renderer->setContrastEnhancement( new QgsContrastEnhancement( *mContrastEnhancement ) );
46  }
47  return renderer;
48 }
49 
51 {
52  if ( elem.isNull() )
53  {
54  return nullptr;
55  }
56 
57  int grayBand = elem.attribute( QStringLiteral( "grayBand" ), QStringLiteral( "-1" ) ).toInt();
58  QgsSingleBandGrayRenderer* r = new QgsSingleBandGrayRenderer( input, grayBand );
59  r->readXml( elem );
60 
61  if ( elem.attribute( QStringLiteral( "gradient" ) ) == QLatin1String( "WhiteToBlack" ) )
62  {
63  r->setGradient( WhiteToBlack ); // BlackToWhite is default
64  }
65 
66  QDomElement contrastEnhancementElem = elem.firstChildElement( QStringLiteral( "contrastEnhancement" ) );
67  if ( !contrastEnhancementElem.isNull() )
68  {
70  input->dataType( grayBand ) ) );
71  ce->readXml( contrastEnhancementElem );
72  r->setContrastEnhancement( ce );
73  }
74  return r;
75 }
76 
78 {
79  delete mContrastEnhancement;
80  mContrastEnhancement = ce;
81 }
82 
83 QgsRasterBlock* QgsSingleBandGrayRenderer::block( int bandNo, QgsRectangle const & extent, int width, int height, QgsRasterBlockFeedback* feedback )
84 {
85  Q_UNUSED( bandNo );
86  QgsDebugMsgLevel( QString( "width = %1 height = %2" ).arg( width ).arg( height ), 4 );
87 
88  std::unique_ptr< QgsRasterBlock > outputBlock( new QgsRasterBlock() );
89  if ( !mInput )
90  {
91  return outputBlock.release();
92  }
93 
94  std::shared_ptr< QgsRasterBlock > inputBlock( mInput->block( mGrayBand, extent, width, height, feedback ) );
95  if ( !inputBlock || inputBlock->isEmpty() )
96  {
97  QgsDebugMsg( "No raster data!" );
98  return outputBlock.release();
99  }
100 
101  std::shared_ptr< QgsRasterBlock > alphaBlock;
102 
103  if ( mAlphaBand > 0 && mGrayBand != mAlphaBand )
104  {
105  alphaBlock.reset( mInput->block( mAlphaBand, extent, width, height, feedback ) );
106  if ( !alphaBlock || alphaBlock->isEmpty() )
107  {
108  // TODO: better to render without alpha
109  return outputBlock.release();
110  }
111  }
112  else if ( mAlphaBand > 0 )
113  {
114  alphaBlock = inputBlock;
115  }
116 
117  if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) )
118  {
119  return outputBlock.release();
120  }
121 
122  QRgb myDefaultColor = NODATA_COLOR;
123  for ( qgssize i = 0; i < ( qgssize )width*height; i++ )
124  {
125  if ( inputBlock->isNoData( i ) )
126  {
127  outputBlock->setColor( i, myDefaultColor );
128  continue;
129  }
130  double grayVal = inputBlock->value( i );
131 
132  double currentAlpha = mOpacity;
133  if ( mRasterTransparency )
134  {
135  currentAlpha = mRasterTransparency->alphaValue( grayVal, mOpacity * 255 ) / 255.0;
136  }
137  if ( mAlphaBand > 0 )
138  {
139  currentAlpha *= alphaBlock->value( i ) / 255.0;
140  }
141 
142  if ( mContrastEnhancement )
143  {
144  if ( !mContrastEnhancement->isValueInDisplayableRange( grayVal ) )
145  {
146  outputBlock->setColor( i, myDefaultColor );
147  continue;
148  }
149  grayVal = mContrastEnhancement->enhanceContrast( grayVal );
150  }
151 
152  if ( mGradient == WhiteToBlack )
153  {
154  grayVal = 255 - grayVal;
155  }
156 
157  if ( qgsDoubleNear( currentAlpha, 1.0 ) )
158  {
159  outputBlock->setColor( i, qRgba( grayVal, grayVal, grayVal, 255 ) );
160  }
161  else
162  {
163  outputBlock->setColor( i, qRgba( currentAlpha * grayVal, currentAlpha * grayVal, currentAlpha * grayVal, currentAlpha * 255 ) );
164  }
165  }
166 
167  return outputBlock.release();
168 }
169 
170 void QgsSingleBandGrayRenderer::writeXml( QDomDocument& doc, QDomElement& parentElem ) const
171 {
172  if ( parentElem.isNull() )
173  {
174  return;
175  }
176 
177  QDomElement rasterRendererElem = doc.createElement( QStringLiteral( "rasterrenderer" ) );
178  _writeXml( doc, rasterRendererElem );
179 
180  rasterRendererElem.setAttribute( QStringLiteral( "grayBand" ), mGrayBand );
181 
182  QString gradient;
183  if ( mGradient == BlackToWhite )
184  {
185  gradient = QStringLiteral( "BlackToWhite" );
186  }
187  else
188  {
189  gradient = QStringLiteral( "WhiteToBlack" );
190  }
191  rasterRendererElem.setAttribute( QStringLiteral( "gradient" ), gradient );
192 
193  if ( mContrastEnhancement )
194  {
195  QDomElement contrastElem = doc.createElement( QStringLiteral( "contrastEnhancement" ) );
196  mContrastEnhancement->writeXml( doc, contrastElem );
197  rasterRendererElem.appendChild( contrastElem );
198  }
199  parentElem.appendChild( rasterRendererElem );
200 }
201 
202 void QgsSingleBandGrayRenderer::legendSymbologyItems( QList< QPair< QString, QColor > >& symbolItems ) const
203 {
204  if ( mContrastEnhancement && mContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement )
205  {
206  QColor minColor = ( mGradient == BlackToWhite ) ? Qt::black : Qt::white;
207  QColor maxColor = ( mGradient == BlackToWhite ) ? Qt::white : Qt::black;
208  symbolItems.push_back( qMakePair( QString::number( mContrastEnhancement->minimumValue() ), minColor ) );
209  symbolItems.push_back( qMakePair( QString::number( mContrastEnhancement->maximumValue() ), maxColor ) );
210  }
211 }
212 
214 {
215  QList<int> bandList;
216  if ( mGrayBand != -1 )
217  {
218  bandList << mGrayBand;
219  }
220  return bandList;
221 }
A rectangle specified with double values.
Definition: qgsrectangle.h:36
void writeXml(QDomDocument &doc, QDomElement &parentElem) const
static QgsRasterRenderer * create(const QDomElement &elem, QgsRasterInterface *input)
QgsSingleBandGrayRenderer(QgsRasterInterface *input, int grayBand)
ContrastEnhancementAlgorithm contrastEnhancementAlgorithm() const
QList< int > usesBands() const override
Returns a list of band numbers used by the renderer.
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
int alphaValue(double, int globalTransparency=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)
DataType
Raster data types.
Definition: qgis.h:61
virtual QgsRasterInterface * input() const
Current input.
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 qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:198
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.
static const QRgb NODATA_COLOR
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition: qgis.h:76
Raster data container.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:37
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 copyCommonProperties(const QgsRasterRenderer *other, bool copyMinMaxOrigin=true)
Copies common properties like opacity / transparency data from other renderer.
void readXml(const QDomElement &elem)
Raster renderer pipe for single band gray.
void setGradient(Gradient gradient)
double minimumValue() const
Return the minimum value for the contrast enhancement range.
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:338
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 ...
virtual QgsRectangle extent() const
Get the extent of the interface.
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 maximumValue() const
Return the maximum value for the contrast enhancement range.
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
void _writeXml(QDomDocument &doc, QDomElement &rasterRendererElem) const
Write upper class info into rasterrenderer element (called by writeXml method of subclasses) ...
Feedback object tailored for raster block reading.
Raster renderer pipe that applies colors to a raster.