QGIS API Documentation  2.99.0-Master (9f5e33a)
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" ) )
29  , mGrayBand( grayBand )
30  , mGradient( BlackToWhite )
31  , mContrastEnhancement( nullptr )
32 {
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( QStringLiteral( "grayBand" ), QStringLiteral( "-1" ) ).toInt();
56  QgsSingleBandGrayRenderer *r = new QgsSingleBandGrayRenderer( input, grayBand );
57  r->readXml( elem );
58 
59  if ( elem.attribute( QStringLiteral( "gradient" ) ) == QLatin1String( "WhiteToBlack" ) )
60  {
61  r->setGradient( WhiteToBlack ); // BlackToWhite is default
62  }
63 
64  QDomElement contrastEnhancementElem = elem.firstChildElement( QStringLiteral( "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  mContrastEnhancement.reset( ce );
78 }
79 
80 QgsRasterBlock *QgsSingleBandGrayRenderer::block( int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback )
81 {
82  Q_UNUSED( bandNo );
83  QgsDebugMsgLevel( QString( "width = %1 height = %2" ).arg( width ).arg( height ), 4 );
84 
85  std::unique_ptr< QgsRasterBlock > outputBlock( new QgsRasterBlock() );
86  if ( !mInput )
87  {
88  return outputBlock.release();
89  }
90 
91  std::shared_ptr< QgsRasterBlock > inputBlock( mInput->block( mGrayBand, extent, width, height, feedback ) );
92  if ( !inputBlock || inputBlock->isEmpty() )
93  {
94  QgsDebugMsg( "No raster data!" );
95  return outputBlock.release();
96  }
97 
98  std::shared_ptr< QgsRasterBlock > alphaBlock;
99 
100  if ( mAlphaBand > 0 && mGrayBand != mAlphaBand )
101  {
102  alphaBlock.reset( mInput->block( mAlphaBand, extent, width, height, feedback ) );
103  if ( !alphaBlock || alphaBlock->isEmpty() )
104  {
105  // TODO: better to render without alpha
106  return outputBlock.release();
107  }
108  }
109  else if ( mAlphaBand > 0 )
110  {
111  alphaBlock = inputBlock;
112  }
113 
114  if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) )
115  {
116  return outputBlock.release();
117  }
118 
119  QRgb myDefaultColor = NODATA_COLOR;
120  for ( qgssize i = 0; i < ( qgssize )width * height; i++ )
121  {
122  if ( inputBlock->isNoData( i ) )
123  {
124  outputBlock->setColor( i, myDefaultColor );
125  continue;
126  }
127  double grayVal = inputBlock->value( i );
128 
129  double currentAlpha = mOpacity;
130  if ( mRasterTransparency )
131  {
132  currentAlpha = mRasterTransparency->alphaValue( grayVal, mOpacity * 255 ) / 255.0;
133  }
134  if ( mAlphaBand > 0 )
135  {
136  currentAlpha *= alphaBlock->value( i ) / 255.0;
137  }
138 
139  if ( mContrastEnhancement )
140  {
141  if ( !mContrastEnhancement->isValueInDisplayableRange( grayVal ) )
142  {
143  outputBlock->setColor( i, myDefaultColor );
144  continue;
145  }
146  grayVal = mContrastEnhancement->enhanceContrast( grayVal );
147  }
148 
149  if ( mGradient == WhiteToBlack )
150  {
151  grayVal = 255 - grayVal;
152  }
153 
154  if ( qgsDoubleNear( currentAlpha, 1.0 ) )
155  {
156  outputBlock->setColor( i, qRgba( grayVal, grayVal, grayVal, 255 ) );
157  }
158  else
159  {
160  outputBlock->setColor( i, qRgba( currentAlpha * grayVal, currentAlpha * grayVal, currentAlpha * grayVal, currentAlpha * 255 ) );
161  }
162  }
163 
164  return outputBlock.release();
165 }
166 
167 void QgsSingleBandGrayRenderer::writeXml( QDomDocument &doc, QDomElement &parentElem ) const
168 {
169  if ( parentElem.isNull() )
170  {
171  return;
172  }
173 
174  QDomElement rasterRendererElem = doc.createElement( QStringLiteral( "rasterrenderer" ) );
175  _writeXml( doc, rasterRendererElem );
176 
177  rasterRendererElem.setAttribute( QStringLiteral( "grayBand" ), mGrayBand );
178 
179  QString gradient;
180  if ( mGradient == BlackToWhite )
181  {
182  gradient = QStringLiteral( "BlackToWhite" );
183  }
184  else
185  {
186  gradient = QStringLiteral( "WhiteToBlack" );
187  }
188  rasterRendererElem.setAttribute( QStringLiteral( "gradient" ), gradient );
189 
190  if ( mContrastEnhancement )
191  {
192  QDomElement contrastElem = doc.createElement( QStringLiteral( "contrastEnhancement" ) );
193  mContrastEnhancement->writeXml( doc, contrastElem );
194  rasterRendererElem.appendChild( contrastElem );
195  }
196  parentElem.appendChild( rasterRendererElem );
197 }
198 
199 void QgsSingleBandGrayRenderer::legendSymbologyItems( QList< QPair< QString, QColor > > &symbolItems ) const
200 {
201  if ( mContrastEnhancement && mContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement )
202  {
203  QColor minColor = ( mGradient == BlackToWhite ) ? Qt::black : Qt::white;
204  QColor maxColor = ( mGradient == BlackToWhite ) ? Qt::white : Qt::black;
205  symbolItems.push_back( qMakePair( QString::number( mContrastEnhancement->minimumValue() ), minColor ) );
206  symbolItems.push_back( qMakePair( QString::number( mContrastEnhancement->maximumValue() ), maxColor ) );
207  }
208 }
209 
211 {
212  QList<int> bandList;
213  if ( mGrayBand != -1 )
214  {
215  bandList << mGrayBand;
216  }
217  return bandList;
218 }
int alphaValue(double, int globalTransparency=255) const
Returns the transparency value for a single value Pixel.
A rectangle specified with double values.
Definition: qgsrectangle.h:38
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:37
virtual QgsRasterInterface * input() const
Current input.
DataType
Raster data types.
Definition: qgis.h:74
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:203
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:89
Raster data container.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:38
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 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)
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:348
void setContrastEnhancement(QgsContrastEnhancement *ce)
Takes ownership.
QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
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...
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.