QGIS API Documentation  master-59fd5e0
src/core/raster/qgsbrightnesscontrastfilter.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                          qgsbrightnesscontrastfilter.cpp
00003                          ---------------------
00004     begin                : February 2013
00005     copyright            : (C) 2013 by Alexander Bruy
00006     email                : alexander dot bruy at gmail dot com
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 #include "qgsrasterdataprovider.h"
00019 #include "qgsbrightnesscontrastfilter.h"
00020 
00021 #include <qmath.h>
00022 #include <QDomDocument>
00023 #include <QDomElement>
00024 
00025 QgsBrightnessContrastFilter::QgsBrightnessContrastFilter( QgsRasterInterface* input )
00026     : QgsRasterInterface( input ),
00027     mBrightness( 0 ),
00028     mContrast( 0 )
00029 {
00030 }
00031 
00032 QgsBrightnessContrastFilter::~QgsBrightnessContrastFilter()
00033 {
00034 }
00035 
00036 QgsRasterInterface * QgsBrightnessContrastFilter::clone() const
00037 {
00038   QgsDebugMsg( "Entered" );
00039   QgsBrightnessContrastFilter * filter = new QgsBrightnessContrastFilter( 0 );
00040   filter->setBrightness( mBrightness );
00041   filter->setContrast( mContrast );
00042   return filter;
00043 }
00044 
00045 int QgsBrightnessContrastFilter::bandCount() const
00046 {
00047   if ( mOn )
00048   {
00049     return 1;
00050   }
00051 
00052   if ( mInput )
00053   {
00054     return mInput->bandCount();
00055   }
00056 
00057   return 0;
00058 }
00059 
00060 QGis::DataType QgsBrightnessContrastFilter::dataType( int bandNo ) const
00061 {
00062   if ( mOn )
00063   {
00064     return QGis::ARGB32_Premultiplied;
00065   }
00066 
00067   if ( mInput )
00068   {
00069     return mInput->dataType( bandNo );
00070   }
00071 
00072   return QGis::UnknownDataType;
00073 }
00074 
00075 bool QgsBrightnessContrastFilter::setInput( QgsRasterInterface* input )
00076 {
00077   QgsDebugMsg( "Entered" );
00078 
00079   // Brightness filter can only work with single band ARGB32_Premultiplied
00080   if ( !input )
00081   {
00082     QgsDebugMsg( "No input" );
00083     return false;
00084   }
00085 
00086   if ( !mOn )
00087   {
00088     // In off mode we can connect to anything
00089     QgsDebugMsg( "OK" );
00090     mInput = input;
00091     return true;
00092   }
00093 
00094   if ( input->bandCount() < 1 )
00095   {
00096     QgsDebugMsg( "No input band" );
00097     return false;
00098   }
00099 
00100   if ( input->dataType( 1 ) != QGis::ARGB32_Premultiplied &&
00101        input->dataType( 1 ) != QGis::ARGB32 )
00102   {
00103     QgsDebugMsg( "Unknown input data type" );
00104     return false;
00105   }
00106 
00107   mInput = input;
00108   QgsDebugMsg( "OK" );
00109   return true;
00110 }
00111 
00112 QgsRasterBlock * QgsBrightnessContrastFilter::block( int bandNo, QgsRectangle  const & extent, int width, int height )
00113 {
00114   Q_UNUSED( bandNo );
00115   QgsDebugMsg( QString( "width = %1 height = %2 extent = %3" ).arg( width ).arg( height ).arg( extent.toString() ) );
00116 
00117   QgsRasterBlock *outputBlock = new QgsRasterBlock();
00118   if ( !mInput )
00119   {
00120     return outputBlock;
00121   }
00122 
00123   // At this moment we know that we read rendered image
00124   int bandNumber = 1;
00125   QgsRasterBlock *inputBlock = mInput->block( bandNumber, extent, width, height );
00126   if ( !inputBlock || inputBlock->isEmpty() )
00127   {
00128     QgsDebugMsg( "No raster data!" );
00129     delete inputBlock;
00130     return outputBlock;
00131   }
00132 
00133   if ( mBrightness == 0 && mContrast == 0 )
00134   {
00135     QgsDebugMsg( "No brightness changes." );
00136     delete outputBlock;
00137     return inputBlock;
00138   }
00139 
00140   if ( !outputBlock->reset( QGis::ARGB32_Premultiplied, width, height ) )
00141   {
00142     delete inputBlock;
00143     return outputBlock;
00144   }
00145 
00146   // adjust image
00147   QRgb myNoDataColor = qRgba( 0, 0, 0, 0 );
00148   QRgb myColor;
00149 
00150   int r, g, b, alpha;
00151   double f = qPow(( mContrast + 100 ) / 100.0, 2 );
00152 
00153   for ( size_t i = 0; i < ( size_t )width*height; i++ )
00154   {
00155     if ( inputBlock->color( i ) == myNoDataColor )
00156     {
00157       outputBlock->setColor( i, myNoDataColor );
00158       continue;
00159     }
00160 
00161     myColor = inputBlock->color( i );
00162     alpha = qAlpha( myColor );
00163 
00164     r = adjustColorComponent( qRed( myColor ), alpha, mBrightness, f );
00165     g = adjustColorComponent( qGreen( myColor ), alpha, mBrightness, f );
00166     b = adjustColorComponent( qBlue( myColor ), alpha, mBrightness, f );
00167 
00168     outputBlock->setColor( i, qRgba( r, g, b, alpha ) );
00169   }
00170 
00171   delete inputBlock;
00172   return outputBlock;
00173 }
00174 
00175 int QgsBrightnessContrastFilter::adjustColorComponent( int colorComponent, int alpha, int brightness, double contrastFactor ) const
00176 {
00177   if ( alpha == 255 )
00178   {
00179     // Opaque pixel, do simpler math
00180     return qBound( 0, ( int )(((((( colorComponent / 255.0 ) - 0.5 ) * contrastFactor ) + 0.5 ) * 255 ) + brightness ), 255 );
00181   }
00182   else
00183   {
00184     // Semi-transparent pixel. We need to adjust the math since we are using QGis::ARGB32_Premultiplied
00185     // and color values have been premultiplied by alpha
00186     double alphaFactor = alpha / 255.;
00187     double adjustedColor = colorComponent / alphaFactor;
00188 
00189     // Make sure to return a premultiplied color
00190     return alphaFactor * qBound( 0., (((((( adjustedColor / 255.0 ) - 0.5 ) * contrastFactor ) + 0.5 ) * 255 ) + brightness ), 255. );
00191   }
00192 }
00193 
00194 void QgsBrightnessContrastFilter::writeXML( QDomDocument& doc, QDomElement& parentElem ) const
00195 {
00196   if ( parentElem.isNull() )
00197   {
00198     return;
00199   }
00200 
00201   QDomElement filterElem = doc.createElement( "brightnesscontrast" );
00202 
00203   filterElem.setAttribute( "brightness", QString::number( mBrightness ) );
00204   filterElem.setAttribute( "contrast", QString::number( mContrast ) );
00205   parentElem.appendChild( filterElem );
00206 }
00207 
00208 void QgsBrightnessContrastFilter::readXML( const QDomElement& filterElem )
00209 {
00210   if ( filterElem.isNull() )
00211   {
00212     return;
00213   }
00214 
00215   mBrightness = filterElem.attribute( "brightness", "0" ).toInt();
00216   mContrast = filterElem.attribute( "contrast", "0" ).toInt();
00217 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines