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