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