QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
qgsbrightnesscontrastfilter.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsbrightnesscontrastfilter.cpp
3  ---------------------
4  begin : February 2013
5  copyright : (C) 2013 by Alexander Bruy
6  email : alexander dot bruy at gmail dot com
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 
18 #include "qgsrasterdataprovider.h"
20 
21 #include <qmath.h>
22 #include <QDomDocument>
23 #include <QDomElement>
24 
26  : QgsRasterInterface( input )
27  , mBrightness( 0 )
28  , mContrast( 0 )
29 {
30 }
31 
33 {
34 }
35 
37 {
38  QgsDebugMsgLevel( "Entered", 4 );
40  filter->setBrightness( mBrightness );
41  filter->setContrast( mContrast );
42  return filter;
43 }
44 
46 {
47  if ( mOn )
48  {
49  return 1;
50  }
51 
52  if ( mInput )
53  {
54  return mInput->bandCount();
55  }
56 
57  return 0;
58 }
59 
61 {
62  if ( mOn )
63  {
65  }
66 
67  if ( mInput )
68  {
69  return mInput->dataType( bandNo );
70  }
71 
72  return QGis::UnknownDataType;
73 }
74 
76 {
77  QgsDebugMsgLevel( "Entered", 4 );
78 
79  // Brightness filter can only work with single band ARGB32_Premultiplied
80  if ( !input )
81  {
82  QgsDebugMsgLevel( "No input", 4 );
83  return false;
84  }
85 
86  if ( !mOn )
87  {
88  // In off mode we can connect to anything
89  QgsDebugMsgLevel( "OK", 4 );
90  mInput = input;
91  return true;
92  }
93 
94  if ( input->bandCount() < 1 )
95  {
96  QgsDebugMsg( "No input band" );
97  return false;
98  }
99 
100  if ( input->dataType( 1 ) != QGis::ARGB32_Premultiplied &&
101  input->dataType( 1 ) != QGis::ARGB32 )
102  {
103  QgsDebugMsg( "Unknown input data type" );
104  return false;
105  }
106 
107  mInput = input;
108  QgsDebugMsgLevel( "OK", 4 );
109  return true;
110 }
111 
112 QgsRasterBlock * QgsBrightnessContrastFilter::block( int bandNo, QgsRectangle const & extent, int width, int height )
113 {
114  return block2( bandNo, extent, width, height );
115 }
116 
117 QgsRasterBlock * QgsBrightnessContrastFilter::block2( int bandNo, QgsRectangle const & extent, int width, int height, QgsRasterBlockFeedback* feedback )
118 {
119  Q_UNUSED( bandNo );
120  QgsDebugMsgLevel( QString( "width = %1 height = %2 extent = %3" ).arg( width ).arg( height ).arg( extent.toString() ), 4 );
121 
122  QgsRasterBlock *outputBlock = new QgsRasterBlock();
123  if ( !mInput )
124  {
125  return outputBlock;
126  }
127 
128  // At this moment we know that we read rendered image
129  int bandNumber = 1;
130  QgsRasterBlock *inputBlock = mInput->block2( bandNumber, extent, width, height, feedback );
131  if ( !inputBlock || inputBlock->isEmpty() )
132  {
133  QgsDebugMsg( "No raster data!" );
134  delete inputBlock;
135  return outputBlock;
136  }
137 
138  if ( mBrightness == 0 && mContrast == 0 )
139  {
140  QgsDebugMsgLevel( "No brightness changes.", 4 );
141  delete outputBlock;
142  return inputBlock;
143  }
144 
145  if ( !outputBlock->reset( QGis::ARGB32_Premultiplied, width, height ) )
146  {
147  delete inputBlock;
148  return outputBlock;
149  }
150 
151  // adjust image
152  QRgb myNoDataColor = qRgba( 0, 0, 0, 0 );
153  QRgb myColor;
154 
155  int r, g, b, alpha;
156  double f = qPow(( mContrast + 100 ) / 100.0, 2 );
157 
158  for ( qgssize i = 0; i < ( qgssize )width*height; i++ )
159  {
160  if ( inputBlock->color( i ) == myNoDataColor )
161  {
162  outputBlock->setColor( i, myNoDataColor );
163  continue;
164  }
165 
166  myColor = inputBlock->color( i );
167  alpha = qAlpha( myColor );
168 
169  r = adjustColorComponent( qRed( myColor ), alpha, mBrightness, f );
170  g = adjustColorComponent( qGreen( myColor ), alpha, mBrightness, f );
171  b = adjustColorComponent( qBlue( myColor ), alpha, mBrightness, f );
172 
173  outputBlock->setColor( i, qRgba( r, g, b, alpha ) );
174  }
175 
176  delete inputBlock;
177  return outputBlock;
178 }
179 
180 int QgsBrightnessContrastFilter::adjustColorComponent( int colorComponent, int alpha, int brightness, double contrastFactor ) const
181 {
182  if ( alpha == 255 )
183  {
184  // Opaque pixel, do simpler math
185  return qBound( 0, ( int )(((((( colorComponent / 255.0 ) - 0.5 ) * contrastFactor ) + 0.5 ) * 255 ) + brightness ), 255 );
186  }
187  else if ( alpha == 0 )
188  {
189  // Totally transparent pixel
190  return 0;
191  }
192  else
193  {
194  // Semi-transparent pixel. We need to adjust the math since we are using QGis::ARGB32_Premultiplied
195  // and color values have been premultiplied by alpha
196  double alphaFactor = alpha / 255.;
197  double adjustedColor = colorComponent / alphaFactor;
198 
199  // Make sure to return a premultiplied color
200  return alphaFactor * qBound( 0., (((((( adjustedColor / 255.0 ) - 0.5 ) * contrastFactor ) + 0.5 ) * 255 ) + brightness ), 255. );
201  }
202 }
203 
205 {
206  if ( parentElem.isNull() )
207  {
208  return;
209  }
210 
211  QDomElement filterElem = doc.createElement( "brightnesscontrast" );
212 
213  filterElem.setAttribute( "brightness", QString::number( mBrightness ) );
214  filterElem.setAttribute( "contrast", QString::number( mContrast ) );
215  parentElem.appendChild( filterElem );
216 }
217 
219 {
220  if ( filterElem.isNull() )
221  {
222  return;
223  }
224 
225  mBrightness = filterElem.attribute( "brightness", "0" ).toInt();
226  mContrast = filterElem.attribute( "contrast", "0" ).toInt();
227 }
virtual int bandCount() const =0
Get number of bands.
A rectangle specified with double values.
Definition: qgsrectangle.h:35
QgsBrightnessContrastFilter * clone() const override
Clone itself, create deep copy.
Unknown or unspecified type.
Definition: qgis.h:135
QDomNode appendChild(const QDomNode &newChild)
QgsRasterBlock * block2(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height) override
Read block of data using given extent and size.
QString attribute(const QString &name, const QString &defValue) const
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
virtual QgsRasterInterface * input() const
Current input.
int bandCount() const override
Get number of bands.
void writeXML(QDomDocument &doc, QDomElement &parentElem) const override
Write base class members to xml.
virtual QgsRasterBlock * block2(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr)
Read block of data using given extent and size.
bool setColor(int row, int column, QRgb color)
Set color on position.
QGis::DataType dataType(int bandNo) const override
Returns data type for the band specified by number.
QString toString(bool automaticPrecision=false) const
returns string representation of form xmin,ymin xmax,ymax
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
QRgb color(int row, int column) const
Read a single color.
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition: qgis.h:148
bool isEmpty() const
Returns true if block is empty, i.e.
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
virtual QgsRectangle extent()
Get the extent of the interface.
bool setInput(QgsRasterInterface *input) override
Set input.
Brightness/contrast filter pipe for rasters.
DataType
Raster data types.
Definition: qgis.h:133
QDomElement createElement(const QString &tagName)
void readXML(const QDomElement &filterElem) override
Sets base class members from xml.
QgsRasterInterface * mInput
Feedback object tailored for raster block reading.
QgsBrightnessContrastFilter(QgsRasterInterface *input=nullptr)