|
QGIS API Documentation
master-59fd5e0
|
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 }