Quantum GIS API Documentation  master-693a1fe
src/core/raster/qgsmultibandcolorrenderer.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                          qgsmultibandcolorrenderer.cpp
00003                          -----------------------------
00004     begin                : December 2011
00005     copyright            : (C) 2011 by Marco Hugentobler
00006     email                : marco at sourcepole dot ch
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 "qgsmultibandcolorrenderer.h"
00019 #include "qgscontrastenhancement.h"
00020 #include "qgsrastertransparency.h"
00021 #include "qgsrasterviewport.h"
00022 #include <QDomDocument>
00023 #include <QDomElement>
00024 #include <QImage>
00025 #include <QSet>
00026 
00027 QgsMultiBandColorRenderer::QgsMultiBandColorRenderer( QgsRasterInterface* input, int redBand, int greenBand, int blueBand,
00028     QgsContrastEnhancement* redEnhancement,
00029     QgsContrastEnhancement* greenEnhancement,
00030     QgsContrastEnhancement* blueEnhancement ):
00031     QgsRasterRenderer( input, "multibandcolor" ), mRedBand( redBand ), mGreenBand( greenBand ), mBlueBand( blueBand ),
00032     mRedContrastEnhancement( redEnhancement ), mGreenContrastEnhancement( greenEnhancement ), mBlueContrastEnhancement( blueEnhancement )
00033 {
00034 }
00035 
00036 QgsMultiBandColorRenderer::~QgsMultiBandColorRenderer()
00037 {
00038   delete mRedContrastEnhancement;
00039   delete mGreenContrastEnhancement;
00040   delete mBlueContrastEnhancement;
00041 }
00042 
00043 QgsRasterInterface * QgsMultiBandColorRenderer::clone() const
00044 {
00045   QgsMultiBandColorRenderer * renderer = new QgsMultiBandColorRenderer( 0, mRedBand, mGreenBand, mBlueBand );
00046   if ( mRedContrastEnhancement )
00047   {
00048     renderer->setRedContrastEnhancement( new QgsContrastEnhancement( *mRedContrastEnhancement ) );
00049   }
00050   if ( mGreenContrastEnhancement )
00051   {
00052     renderer->setGreenContrastEnhancement( new QgsContrastEnhancement( *mGreenContrastEnhancement ) );
00053   }
00054   if ( mBlueContrastEnhancement )
00055   {
00056     renderer->setBlueContrastEnhancement( new QgsContrastEnhancement( *mBlueContrastEnhancement ) );
00057   }
00058   renderer->setOpacity( mOpacity );
00059   renderer->setAlphaBand( mAlphaBand );
00060   renderer->setRasterTransparency( mRasterTransparency );
00061 
00062   return renderer;
00063 }
00064 
00065 void QgsMultiBandColorRenderer::setRedContrastEnhancement( QgsContrastEnhancement* ce )
00066 {
00067   delete mRedContrastEnhancement; mRedContrastEnhancement = ce;
00068 }
00069 
00070 void QgsMultiBandColorRenderer::setGreenContrastEnhancement( QgsContrastEnhancement* ce )
00071 {
00072   delete mGreenContrastEnhancement; mGreenContrastEnhancement = ce;
00073 }
00074 
00075 void QgsMultiBandColorRenderer::setBlueContrastEnhancement( QgsContrastEnhancement* ce )
00076 {
00077   delete mBlueContrastEnhancement; mBlueContrastEnhancement = ce;
00078 }
00079 
00080 QgsRasterRenderer* QgsMultiBandColorRenderer::create( const QDomElement& elem, QgsRasterInterface* input )
00081 {
00082   if ( elem.isNull() )
00083   {
00084     return 0;
00085   }
00086 
00087   //red band, green band, blue band
00088   int redBand = elem.attribute( "redBand", "-1" ).toInt();
00089   int greenBand = elem.attribute( "greenBand", "-1" ).toInt();
00090   int blueBand = elem.attribute( "blueBand", "-1" ).toInt();
00091 
00092   //contrast enhancements
00093   QgsContrastEnhancement* redContrastEnhancement = 0;
00094   QDomElement redContrastElem = elem.firstChildElement( "redContrastEnhancement" );
00095   if ( !redContrastElem.isNull() )
00096   {
00097     redContrastEnhancement = new QgsContrastEnhancement(( QGis::DataType )(
00098           input->dataType( redBand ) ) );
00099     redContrastEnhancement->readXML( redContrastElem );
00100   }
00101 
00102   QgsContrastEnhancement* greenContrastEnhancement = 0;
00103   QDomElement greenContrastElem = elem.firstChildElement( "greenContrastEnhancement" );
00104   if ( !greenContrastElem.isNull() )
00105   {
00106     greenContrastEnhancement = new QgsContrastEnhancement(( QGis::DataType )(
00107           input->dataType( greenBand ) ) );
00108     greenContrastEnhancement->readXML( greenContrastElem );
00109   }
00110 
00111   QgsContrastEnhancement* blueContrastEnhancement = 0;
00112   QDomElement blueContrastElem = elem.firstChildElement( "blueContrastEnhancement" );
00113   if ( !blueContrastElem.isNull() )
00114   {
00115     blueContrastEnhancement = new QgsContrastEnhancement(( QGis::DataType )(
00116           input->dataType( blueBand ) ) );
00117     blueContrastEnhancement->readXML( blueContrastElem );
00118   }
00119 
00120   QgsRasterRenderer* r = new QgsMultiBandColorRenderer( input, redBand, greenBand, blueBand, redContrastEnhancement,
00121       greenContrastEnhancement, blueContrastEnhancement );
00122   r->readXML( elem );
00123   return r;
00124 }
00125 
00126 QgsRasterBlock* QgsMultiBandColorRenderer::block( int bandNo, QgsRectangle  const & extent, int width, int height )
00127 {
00128   Q_UNUSED( bandNo );
00129   QgsRasterBlock *outputBlock = new QgsRasterBlock();
00130   if ( !mInput )
00131   {
00132     return outputBlock;
00133   }
00134 
00135   //In some (common) cases, we can simplify the drawing loop considerably and save render time
00136   bool fastDraw = ( !usesTransparency()
00137                     && mRedBand > 0 && mGreenBand > 0 && mBlueBand > 0
00138                     && mAlphaBand < 1 && !mRedContrastEnhancement && !mGreenContrastEnhancement && !mBlueContrastEnhancement );
00139 
00140   QSet<int> bands;
00141   if ( mRedBand > 0 )
00142   {
00143     bands << mRedBand;
00144   }
00145   if ( mGreenBand > 0 )
00146   {
00147     bands << mGreenBand;
00148   }
00149   if ( mBlueBand > 0 )
00150   {
00151     bands << mBlueBand;
00152   }
00153   if ( bands.size() < 1 )
00154   {
00155     // no need to draw anything if no band is set
00156     // TODO:: we should probably return default color block
00157     return outputBlock;
00158   }
00159 
00160   if ( mAlphaBand > 0 )
00161   {
00162     bands << mAlphaBand;
00163   }
00164 
00165   QMap<int, QgsRasterBlock*> bandBlocks;
00166   QgsRasterBlock* defaultPointer = 0;
00167   QSet<int>::const_iterator bandIt = bands.constBegin();
00168   for ( ; bandIt != bands.constEnd(); ++bandIt )
00169   {
00170     bandBlocks.insert( *bandIt, defaultPointer );
00171   }
00172 
00173   QgsRasterBlock* redBlock = 0;
00174   QgsRasterBlock* greenBlock = 0;
00175   QgsRasterBlock* blueBlock = 0;
00176   QgsRasterBlock* alphaBlock = 0;
00177 
00178   bandIt = bands.constBegin();
00179   for ( ; bandIt != bands.constEnd(); ++bandIt )
00180   {
00181     bandBlocks[*bandIt] =  mInput->block( *bandIt, extent, width, height );
00182     if ( !bandBlocks[*bandIt] )
00183     {
00184       // We should free the alloced mem from block().
00185       QgsDebugMsg( "No input band" );
00186       bandIt--;
00187       for ( ; bandIt != bands.constBegin(); bandIt-- )
00188       {
00189         delete bandBlocks[*bandIt];
00190       }
00191       return outputBlock;
00192     }
00193   }
00194 
00195   if ( mRedBand > 0 )
00196   {
00197     redBlock = bandBlocks[mRedBand];
00198   }
00199   if ( mGreenBand > 0 )
00200   {
00201     greenBlock = bandBlocks[mGreenBand];
00202   }
00203   if ( mBlueBand > 0 )
00204   {
00205     blueBlock = bandBlocks[mBlueBand];
00206   }
00207   if ( mAlphaBand > 0 )
00208   {
00209     alphaBlock = bandBlocks[mAlphaBand];
00210   }
00211 
00212   if ( !outputBlock->reset( QGis::ARGB32_Premultiplied, width, height ) )
00213   {
00214     for ( int i = 0; i < bandBlocks.size(); i++ )
00215     {
00216       delete bandBlocks.value( i );
00217     }
00218     return outputBlock;
00219   }
00220 
00221   QRgb myDefaultColor = NODATA_COLOR;
00222 
00223   for ( size_t i = 0; i < ( size_t )width*height; i++ )
00224   {
00225     if ( fastDraw ) //fast rendering if no transparency, stretching, color inversion, etc.
00226     {
00227       if ( redBlock->isNoData( i ) ||
00228            greenBlock->isNoData( i ) ||
00229            blueBlock->isNoData( i ) )
00230       {
00231         outputBlock->setColor( i, myDefaultColor );
00232       }
00233       else
00234       {
00235         int redVal = ( int )redBlock->value( i );
00236         int greenVal = ( int )greenBlock->value( i );
00237         int blueVal = ( int )blueBlock->value( i );
00238         outputBlock->setColor( i, qRgba( redVal, greenVal, blueVal, 255 ) );
00239       }
00240       continue;
00241     }
00242 
00243     bool isNoData = false;
00244     double redVal = 0;
00245     double greenVal = 0;
00246     double blueVal = 0;
00247     if ( mRedBand > 0 )
00248     {
00249       redVal = redBlock->value( i );
00250       if ( redBlock->isNoData( i ) ) isNoData = true;
00251     }
00252     if ( !isNoData && mGreenBand > 0 )
00253     {
00254       greenVal = greenBlock->value( i );
00255       if ( greenBlock->isNoData( i ) ) isNoData = true;
00256     }
00257     if ( !isNoData && mBlueBand > 0 )
00258     {
00259       blueVal = blueBlock->value( i );
00260       if ( blueBlock->isNoData( i ) ) isNoData = true;
00261     }
00262     if ( isNoData )
00263     {
00264       outputBlock->setColor( i, myDefaultColor );
00265       continue;
00266     }
00267 
00268     //apply default color if red, green or blue not in displayable range
00269     if (( mRedContrastEnhancement && !mRedContrastEnhancement->isValueInDisplayableRange( redVal ) )
00270         || ( mGreenContrastEnhancement && !mGreenContrastEnhancement->isValueInDisplayableRange( redVal ) )
00271         || ( mBlueContrastEnhancement && !mBlueContrastEnhancement->isValueInDisplayableRange( redVal ) ) )
00272     {
00273       outputBlock->setColor( i, myDefaultColor );
00274       continue;
00275     }
00276 
00277     //stretch color values
00278     if ( mRedContrastEnhancement )
00279     {
00280       redVal = mRedContrastEnhancement->enhanceContrast( redVal );
00281     }
00282     if ( mGreenContrastEnhancement )
00283     {
00284       greenVal = mGreenContrastEnhancement->enhanceContrast( greenVal );
00285     }
00286     if ( mBlueContrastEnhancement )
00287     {
00288       blueVal = mBlueContrastEnhancement->enhanceContrast( blueVal );
00289     }
00290 
00291     //opacity
00292     double currentOpacity = mOpacity;
00293     if ( mRasterTransparency )
00294     {
00295       currentOpacity = mRasterTransparency->alphaValue( redVal, greenVal, blueVal, mOpacity * 255 ) / 255.0;
00296     }
00297     if ( mAlphaBand > 0 )
00298     {
00299       currentOpacity *= alphaBlock->value( i ) / 255.0;
00300     }
00301 
00302     if ( qgsDoubleNear( currentOpacity, 1.0 ) )
00303     {
00304       outputBlock->setColor( i, qRgba( redVal, greenVal, blueVal, 255 ) );
00305     }
00306     else
00307     {
00308       outputBlock->setColor( i, qRgba( currentOpacity * redVal, currentOpacity * greenVal, currentOpacity * blueVal, currentOpacity * 255 ) );
00309     }
00310   }
00311 
00312   for ( int i = 0; i < bandBlocks.size(); i++ )
00313   {
00314     delete bandBlocks.value( i );
00315   }
00316 
00317   return outputBlock;
00318 }
00319 
00320 void QgsMultiBandColorRenderer::writeXML( QDomDocument& doc, QDomElement& parentElem ) const
00321 {
00322   if ( parentElem.isNull() )
00323   {
00324     return;
00325   }
00326 
00327   QDomElement rasterRendererElem = doc.createElement( "rasterrenderer" );
00328   _writeXML( doc, rasterRendererElem );
00329   rasterRendererElem.setAttribute( "redBand", mRedBand );
00330   rasterRendererElem.setAttribute( "greenBand", mGreenBand );
00331   rasterRendererElem.setAttribute( "blueBand", mBlueBand );
00332 
00333   //contrast enhancement
00334   if ( mRedContrastEnhancement )
00335   {
00336     QDomElement redContrastElem = doc.createElement( "redContrastEnhancement" );
00337     mRedContrastEnhancement->writeXML( doc, redContrastElem );
00338     rasterRendererElem.appendChild( redContrastElem );
00339   }
00340   if ( mGreenContrastEnhancement )
00341   {
00342     QDomElement greenContrastElem = doc.createElement( "greenContrastEnhancement" );
00343     mGreenContrastEnhancement->writeXML( doc, greenContrastElem );
00344     rasterRendererElem.appendChild( greenContrastElem );
00345   }
00346   if ( mBlueContrastEnhancement )
00347   {
00348     QDomElement blueContrastElem = doc.createElement( "blueContrastEnhancement" );
00349     mBlueContrastEnhancement->writeXML( doc, blueContrastElem );
00350     rasterRendererElem.appendChild( blueContrastElem );
00351   }
00352   parentElem.appendChild( rasterRendererElem );
00353 }
00354 
00355 QList<int> QgsMultiBandColorRenderer::usesBands() const
00356 {
00357   QList<int> bandList;
00358   if ( mRedBand != -1 )
00359   {
00360     bandList << mRedBand;
00361   }
00362   if ( mGreenBand != -1 )
00363   {
00364     bandList << mGreenBand;
00365   }
00366   if ( mBlueBand != -1 )
00367   {
00368     bandList << mBlueBand;
00369   }
00370   return bandList;
00371 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines