QGIS API Documentation  2.8.2-Wien
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsmultibandcolorrenderer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmultibandcolorrenderer.cpp
3  -----------------------------
4  begin : December 2011
5  copyright : (C) 2011 by Marco Hugentobler
6  email : marco at sourcepole dot ch
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 
19 #include "qgscontrastenhancement.h"
20 #include "qgsrastertransparency.h"
21 #include "qgsrasterviewport.h"
22 #include <QDomDocument>
23 #include <QDomElement>
24 #include <QImage>
25 #include <QSet>
26 
27 QgsMultiBandColorRenderer::QgsMultiBandColorRenderer( QgsRasterInterface* input, int redBand, int greenBand, int blueBand,
28  QgsContrastEnhancement* redEnhancement,
29  QgsContrastEnhancement* greenEnhancement,
30  QgsContrastEnhancement* blueEnhancement ):
31  QgsRasterRenderer( input, "multibandcolor" ), mRedBand( redBand ), mGreenBand( greenBand ), mBlueBand( blueBand ),
32  mRedContrastEnhancement( redEnhancement ), mGreenContrastEnhancement( greenEnhancement ), mBlueContrastEnhancement( blueEnhancement )
33 {
34 }
35 
37 {
38  delete mRedContrastEnhancement;
39  delete mGreenContrastEnhancement;
40  delete mBlueContrastEnhancement;
41 }
42 
44 {
45  QgsMultiBandColorRenderer * renderer = new QgsMultiBandColorRenderer( 0, mRedBand, mGreenBand, mBlueBand );
46  if ( mRedContrastEnhancement )
47  {
48  renderer->setRedContrastEnhancement( new QgsContrastEnhancement( *mRedContrastEnhancement ) );
49  }
50  if ( mGreenContrastEnhancement )
51  {
52  renderer->setGreenContrastEnhancement( new QgsContrastEnhancement( *mGreenContrastEnhancement ) );
53  }
54  if ( mBlueContrastEnhancement )
55  {
56  renderer->setBlueContrastEnhancement( new QgsContrastEnhancement( *mBlueContrastEnhancement ) );
57  }
58  renderer->setOpacity( mOpacity );
59  renderer->setAlphaBand( mAlphaBand );
61 
62  return renderer;
63 }
64 
66 {
67  delete mRedContrastEnhancement; mRedContrastEnhancement = ce;
68 }
69 
71 {
72  delete mGreenContrastEnhancement; mGreenContrastEnhancement = ce;
73 }
74 
76 {
77  delete mBlueContrastEnhancement; mBlueContrastEnhancement = ce;
78 }
79 
81 {
82  if ( elem.isNull() )
83  {
84  return 0;
85  }
86 
87  //red band, green band, blue band
88  int redBand = elem.attribute( "redBand", "-1" ).toInt();
89  int greenBand = elem.attribute( "greenBand", "-1" ).toInt();
90  int blueBand = elem.attribute( "blueBand", "-1" ).toInt();
91 
92  //contrast enhancements
94  QDomElement redContrastElem = elem.firstChildElement( "redContrastEnhancement" );
95  if ( !redContrastElem.isNull() )
96  {
97  redContrastEnhancement = new QgsContrastEnhancement(( QGis::DataType )(
98  input->dataType( redBand ) ) );
99  redContrastEnhancement->readXML( redContrastElem );
100  }
101 
103  QDomElement greenContrastElem = elem.firstChildElement( "greenContrastEnhancement" );
104  if ( !greenContrastElem.isNull() )
105  {
106  greenContrastEnhancement = new QgsContrastEnhancement(( QGis::DataType )(
107  input->dataType( greenBand ) ) );
108  greenContrastEnhancement->readXML( greenContrastElem );
109  }
110 
112  QDomElement blueContrastElem = elem.firstChildElement( "blueContrastEnhancement" );
113  if ( !blueContrastElem.isNull() )
114  {
115  blueContrastEnhancement = new QgsContrastEnhancement(( QGis::DataType )(
116  input->dataType( blueBand ) ) );
117  blueContrastEnhancement->readXML( blueContrastElem );
118  }
119 
120  QgsRasterRenderer* r = new QgsMultiBandColorRenderer( input, redBand, greenBand, blueBand, redContrastEnhancement,
121  greenContrastEnhancement, blueContrastEnhancement );
122  r->readXML( elem );
123  return r;
124 }
125 
126 QgsRasterBlock* QgsMultiBandColorRenderer::block( int bandNo, QgsRectangle const & extent, int width, int height )
127 {
128  Q_UNUSED( bandNo );
129  QgsRasterBlock *outputBlock = new QgsRasterBlock();
130  if ( !mInput )
131  {
132  return outputBlock;
133  }
134 
135  //In some (common) cases, we can simplify the drawing loop considerably and save render time
136  bool fastDraw = ( !usesTransparency()
137  && mRedBand > 0 && mGreenBand > 0 && mBlueBand > 0
138  && mAlphaBand < 1 && !mRedContrastEnhancement && !mGreenContrastEnhancement && !mBlueContrastEnhancement );
139 
140  QSet<int> bands;
141  if ( mRedBand > 0 )
142  {
143  bands << mRedBand;
144  }
145  if ( mGreenBand > 0 )
146  {
147  bands << mGreenBand;
148  }
149  if ( mBlueBand > 0 )
150  {
151  bands << mBlueBand;
152  }
153  if ( bands.size() < 1 )
154  {
155  // no need to draw anything if no band is set
156  // TODO:: we should probably return default color block
157  return outputBlock;
158  }
159 
160  if ( mAlphaBand > 0 )
161  {
162  bands << mAlphaBand;
163  }
164 
165  QMap<int, QgsRasterBlock*> bandBlocks;
166  QgsRasterBlock* defaultPointer = 0;
167  QSet<int>::const_iterator bandIt = bands.constBegin();
168  for ( ; bandIt != bands.constEnd(); ++bandIt )
169  {
170  bandBlocks.insert( *bandIt, defaultPointer );
171  }
172 
173  QgsRasterBlock* redBlock = 0;
174  QgsRasterBlock* greenBlock = 0;
175  QgsRasterBlock* blueBlock = 0;
176  QgsRasterBlock* alphaBlock = 0;
177 
178  bandIt = bands.constBegin();
179  for ( ; bandIt != bands.constEnd(); ++bandIt )
180  {
181  bandBlocks[*bandIt] = mInput->block( *bandIt, extent, width, height );
182  if ( !bandBlocks[*bandIt] )
183  {
184  // We should free the alloced mem from block().
185  QgsDebugMsg( "No input band" );
186  --bandIt;
187  for ( ; bandIt != bands.constBegin(); --bandIt )
188  {
189  delete bandBlocks[*bandIt];
190  }
191  return outputBlock;
192  }
193  }
194 
195  if ( mRedBand > 0 )
196  {
197  redBlock = bandBlocks[mRedBand];
198  }
199  if ( mGreenBand > 0 )
200  {
201  greenBlock = bandBlocks[mGreenBand];
202  }
203  if ( mBlueBand > 0 )
204  {
205  blueBlock = bandBlocks[mBlueBand];
206  }
207  if ( mAlphaBand > 0 )
208  {
209  alphaBlock = bandBlocks[mAlphaBand];
210  }
211 
212  if ( !outputBlock->reset( QGis::ARGB32_Premultiplied, width, height ) )
213  {
214  for ( int i = 0; i < bandBlocks.size(); i++ )
215  {
216  delete bandBlocks.value( i );
217  }
218  return outputBlock;
219  }
220 
221  QRgb myDefaultColor = NODATA_COLOR;
222 
223  for ( qgssize i = 0; i < ( qgssize )width*height; i++ )
224  {
225  if ( fastDraw ) //fast rendering if no transparency, stretching, color inversion, etc.
226  {
227  if ( redBlock->isNoData( i ) ||
228  greenBlock->isNoData( i ) ||
229  blueBlock->isNoData( i ) )
230  {
231  outputBlock->setColor( i, myDefaultColor );
232  }
233  else
234  {
235  int redVal = ( int )redBlock->value( i );
236  int greenVal = ( int )greenBlock->value( i );
237  int blueVal = ( int )blueBlock->value( i );
238  outputBlock->setColor( i, qRgba( redVal, greenVal, blueVal, 255 ) );
239  }
240  continue;
241  }
242 
243  bool isNoData = false;
244  double redVal = 0;
245  double greenVal = 0;
246  double blueVal = 0;
247  if ( mRedBand > 0 )
248  {
249  redVal = redBlock->value( i );
250  if ( redBlock->isNoData( i ) ) isNoData = true;
251  }
252  if ( !isNoData && mGreenBand > 0 )
253  {
254  greenVal = greenBlock->value( i );
255  if ( greenBlock->isNoData( i ) ) isNoData = true;
256  }
257  if ( !isNoData && mBlueBand > 0 )
258  {
259  blueVal = blueBlock->value( i );
260  if ( blueBlock->isNoData( i ) ) isNoData = true;
261  }
262  if ( isNoData )
263  {
264  outputBlock->setColor( i, myDefaultColor );
265  continue;
266  }
267 
268  //apply default color if red, green or blue not in displayable range
269  if (( mRedContrastEnhancement && !mRedContrastEnhancement->isValueInDisplayableRange( redVal ) )
270  || ( mGreenContrastEnhancement && !mGreenContrastEnhancement->isValueInDisplayableRange( redVal ) )
271  || ( mBlueContrastEnhancement && !mBlueContrastEnhancement->isValueInDisplayableRange( redVal ) ) )
272  {
273  outputBlock->setColor( i, myDefaultColor );
274  continue;
275  }
276 
277  //stretch color values
278  if ( mRedContrastEnhancement )
279  {
280  redVal = mRedContrastEnhancement->enhanceContrast( redVal );
281  }
282  if ( mGreenContrastEnhancement )
283  {
284  greenVal = mGreenContrastEnhancement->enhanceContrast( greenVal );
285  }
286  if ( mBlueContrastEnhancement )
287  {
288  blueVal = mBlueContrastEnhancement->enhanceContrast( blueVal );
289  }
290 
291  //opacity
292  double currentOpacity = mOpacity;
293  if ( mRasterTransparency )
294  {
295  currentOpacity = mRasterTransparency->alphaValue( redVal, greenVal, blueVal, mOpacity * 255 ) / 255.0;
296  }
297  if ( mAlphaBand > 0 )
298  {
299  currentOpacity *= alphaBlock->value( i ) / 255.0;
300  }
301 
302  if ( qgsDoubleNear( currentOpacity, 1.0 ) )
303  {
304  outputBlock->setColor( i, qRgba( redVal, greenVal, blueVal, 255 ) );
305  }
306  else
307  {
308  outputBlock->setColor( i, qRgba( currentOpacity * redVal, currentOpacity * greenVal, currentOpacity * blueVal, currentOpacity * 255 ) );
309  }
310  }
311 
312  //delete input blocks
313  QMap<int, QgsRasterBlock*>::const_iterator bandDelIt = bandBlocks.constBegin();
314  for ( ; bandDelIt != bandBlocks.constEnd(); ++bandDelIt )
315  {
316  delete bandDelIt.value();
317  }
318 
319  return outputBlock;
320 }
321 
322 void QgsMultiBandColorRenderer::writeXML( QDomDocument& doc, QDomElement& parentElem ) const
323 {
324  if ( parentElem.isNull() )
325  {
326  return;
327  }
328 
329  QDomElement rasterRendererElem = doc.createElement( "rasterrenderer" );
330  _writeXML( doc, rasterRendererElem );
331  rasterRendererElem.setAttribute( "redBand", mRedBand );
332  rasterRendererElem.setAttribute( "greenBand", mGreenBand );
333  rasterRendererElem.setAttribute( "blueBand", mBlueBand );
334 
335  //contrast enhancement
336  if ( mRedContrastEnhancement )
337  {
338  QDomElement redContrastElem = doc.createElement( "redContrastEnhancement" );
339  mRedContrastEnhancement->writeXML( doc, redContrastElem );
340  rasterRendererElem.appendChild( redContrastElem );
341  }
342  if ( mGreenContrastEnhancement )
343  {
344  QDomElement greenContrastElem = doc.createElement( "greenContrastEnhancement" );
345  mGreenContrastEnhancement->writeXML( doc, greenContrastElem );
346  rasterRendererElem.appendChild( greenContrastElem );
347  }
348  if ( mBlueContrastEnhancement )
349  {
350  QDomElement blueContrastElem = doc.createElement( "blueContrastEnhancement" );
351  mBlueContrastEnhancement->writeXML( doc, blueContrastElem );
352  rasterRendererElem.appendChild( blueContrastElem );
353  }
354  parentElem.appendChild( rasterRendererElem );
355 }
356 
358 {
359  QList<int> bandList;
360  if ( mRedBand != -1 )
361  {
362  bandList << mRedBand;
363  }
364  if ( mGreenBand != -1 )
365  {
366  bandList << mGreenBand;
367  }
368  if ( mBlueBand != -1 )
369  {
370  bandList << mBlueBand;
371  }
372  return bandList;
373 }