QGIS API Documentation  2.2.0-Valmiera
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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  QgsDebugMsg( "Entered" );
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  QgsDebugMsg( "Entered" );
78 
79  // Brightness filter can only work with single band ARGB32_Premultiplied
80  if ( !input )
81  {
82  QgsDebugMsg( "No input" );
83  return false;
84  }
85 
86  if ( !mOn )
87  {
88  // In off mode we can connect to anything
89  QgsDebugMsg( "OK" );
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  QgsDebugMsg( "OK" );
109  return true;
110 }
111 
112 QgsRasterBlock * QgsBrightnessContrastFilter::block( int bandNo, QgsRectangle const & extent, int width, int height )
113 {
114  Q_UNUSED( bandNo );
115  QgsDebugMsg( QString( "width = %1 height = %2 extent = %3" ).arg( width ).arg( height ).arg( extent.toString() ) );
116 
117  QgsRasterBlock *outputBlock = new QgsRasterBlock();
118  if ( !mInput )
119  {
120  return outputBlock;
121  }
122 
123  // At this moment we know that we read rendered image
124  int bandNumber = 1;
125  QgsRasterBlock *inputBlock = mInput->block( bandNumber, extent, width, height );
126  if ( !inputBlock || inputBlock->isEmpty() )
127  {
128  QgsDebugMsg( "No raster data!" );
129  delete inputBlock;
130  return outputBlock;
131  }
132 
133  if ( mBrightness == 0 && mContrast == 0 )
134  {
135  QgsDebugMsg( "No brightness changes." );
136  delete outputBlock;
137  return inputBlock;
138  }
139 
140  if ( !outputBlock->reset( QGis::ARGB32_Premultiplied, width, height ) )
141  {
142  delete inputBlock;
143  return outputBlock;
144  }
145 
146  // adjust image
147  QRgb myNoDataColor = qRgba( 0, 0, 0, 0 );
148  QRgb myColor;
149 
150  int r, g, b, alpha;
151  double f = qPow(( mContrast + 100 ) / 100.0, 2 );
152 
153  for ( qgssize i = 0; i < ( qgssize )width*height; i++ )
154  {
155  if ( inputBlock->color( i ) == myNoDataColor )
156  {
157  outputBlock->setColor( i, myNoDataColor );
158  continue;
159  }
160 
161  myColor = inputBlock->color( i );
162  alpha = qAlpha( myColor );
163 
164  r = adjustColorComponent( qRed( myColor ), alpha, mBrightness, f );
165  g = adjustColorComponent( qGreen( myColor ), alpha, mBrightness, f );
166  b = adjustColorComponent( qBlue( myColor ), alpha, mBrightness, f );
167 
168  outputBlock->setColor( i, qRgba( r, g, b, alpha ) );
169  }
170 
171  delete inputBlock;
172  return outputBlock;
173 }
174 
175 int QgsBrightnessContrastFilter::adjustColorComponent( int colorComponent, int alpha, int brightness, double contrastFactor ) const
176 {
177  if ( alpha == 255 )
178  {
179  // Opaque pixel, do simpler math
180  return qBound( 0, ( int )(((((( colorComponent / 255.0 ) - 0.5 ) * contrastFactor ) + 0.5 ) * 255 ) + brightness ), 255 );
181  }
182  else if ( alpha == 0 )
183  {
184  // Totally transparent pixel
185  return 0;
186  }
187  else
188  {
189  // Semi-transparent pixel. We need to adjust the math since we are using QGis::ARGB32_Premultiplied
190  // and color values have been premultiplied by alpha
191  double alphaFactor = alpha / 255.;
192  double adjustedColor = colorComponent / alphaFactor;
193 
194  // Make sure to return a premultiplied color
195  return alphaFactor * qBound( 0., (((((( adjustedColor / 255.0 ) - 0.5 ) * contrastFactor ) + 0.5 ) * 255 ) + brightness ), 255. );
196  }
197 }
198 
199 void QgsBrightnessContrastFilter::writeXML( QDomDocument& doc, QDomElement& parentElem ) const
200 {
201  if ( parentElem.isNull() )
202  {
203  return;
204  }
205 
206  QDomElement filterElem = doc.createElement( "brightnesscontrast" );
207 
208  filterElem.setAttribute( "brightness", QString::number( mBrightness ) );
209  filterElem.setAttribute( "contrast", QString::number( mContrast ) );
210  parentElem.appendChild( filterElem );
211 }
212 
213 void QgsBrightnessContrastFilter::readXML( const QDomElement& filterElem )
214 {
215  if ( filterElem.isNull() )
216  {
217  return;
218  }
219 
220  mBrightness = filterElem.attribute( "brightness", "0" ).toInt();
221  mContrast = filterElem.attribute( "contrast", "0" ).toInt();
222 }