QGIS API Documentation  3.2.0-Bonn (bc43194)
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 }
A rectangle specified with double values.
Definition: qgsrectangle.h:40
static QgsRasterRenderer * create(const QDomElement &elem, QgsRasterInterface *input)
QgsSingleBandGrayRenderer(QgsRasterInterface *input, int grayBand)
virtual QgsRectangle extent() const
Gets 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:38
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:251
virtual QgsRasterInterface * input() const
Current input.
DataType
Raster data types.
Definition: qgis.h:91
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.
QgsRasterTransparency * mRasterTransparency
Raster transparency per color or value. Overwrites global alpha value.
void legendSymbologyItems(QList< QPair< QString, QColor > > &symbolItems) const override
Gets 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:106
Raster data container.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
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.
int alphaValue(double value, int globalTransparency=255) const
Returns the transparency value for a single value pixel.
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:510
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.