QGIS API Documentation  2.5.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgspalettedrasterrenderer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgspalettedrasterrenderer.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 "qgsrastertransparency.h"
20 #include "qgsrasterviewport.h"
21 #include <QColor>
22 #include <QDomDocument>
23 #include <QDomElement>
24 #include <QImage>
25 #include <QVector>
26 
28  QColor* colorArray, int nColors, const QVector<QString> labels ):
29  QgsRasterRenderer( input, "paletted" ), mBand( bandNumber ), mNColors( nColors ), mLabels( labels )
30 {
31  mColors = new QRgb[nColors];
32  for ( int i = 0; i < nColors; ++i )
33  {
34  mColors[i] = colorArray[i].rgba();
35  }
36  delete[] colorArray;
37 }
38 
39 QgsPalettedRasterRenderer::QgsPalettedRasterRenderer( QgsRasterInterface* input, int bandNumber, QRgb* colorArray, int nColors, const QVector<QString> labels ):
40  QgsRasterRenderer( input, "paletted" ), mBand( bandNumber ), mColors( colorArray ), mNColors( nColors ), mLabels( labels )
41 {
42 }
43 
45 {
46  delete[] mColors;
47 }
48 
50 {
52  renderer->setOpacity( mOpacity );
53  renderer->setAlphaBand( mAlphaBand );
55  renderer->mLabels = mLabels;
56  return renderer;
57 }
58 
60 {
61  if ( elem.isNull() )
62  {
63  return 0;
64  }
65 
66  int bandNumber = elem.attribute( "band", "-1" ).toInt();
67  int nColors = 0;
68  QRgb* colors = 0;
69  QVector<QString> labels;
70 
71  QDomElement paletteElem = elem.firstChildElement( "colorPalette" );
72  if ( !paletteElem.isNull() )
73  {
74  QDomNodeList paletteEntries = paletteElem.elementsByTagName( "paletteEntry" );
75 
76  QDomElement entryElem;
77  int value;
78  nColors = 0;
79 
80  // We cannot believe that data are correct, check first max value
81  for ( int i = 0; i < paletteEntries.size(); ++i )
82  {
83  entryElem = paletteEntries.at( i ).toElement();
84  // Could be written as doubles (with .0000) in old project files
85  value = ( int )entryElem.attribute( "value", "0" ).toDouble();
86  if ( value >= nColors && value <= 10000 ) nColors = value + 1;
87  }
88  QgsDebugMsg( QString( "nColors = %1" ).arg( nColors ) );
89 
90  colors = new QRgb[ nColors ];
91 
92  for ( int i = 0; i < nColors; ++i )
93  {
94  entryElem = paletteEntries.at( i ).toElement();
95  value = ( int )entryElem.attribute( "value", "0" ).toDouble();
96  QgsDebugMsg( entryElem.attribute( "color", "#000000" ) );
97  if ( value >= 0 && value < nColors )
98  {
99  colors[value] = QColor( entryElem.attribute( "color", "#000000" ) ).rgba();
100  QString label = entryElem.attribute( "label" );
101  if ( !label.isEmpty() )
102  {
103  if ( value >= labels.size() ) labels.resize( value + 1 );
104  labels[value] = label;
105  }
106  }
107  else
108  {
109  QgsDebugMsg( QString( "value %1 out of range" ).arg( value ) );
110  }
111  }
112  }
113  QgsPalettedRasterRenderer* r = new QgsPalettedRasterRenderer( input, bandNumber, colors, nColors, labels );
114  r->readXML( elem );
115  return r;
116 }
117 
119 {
120  if ( mNColors < 1 )
121  {
122  return 0;
123  }
124  QColor* colorArray = new QColor[ mNColors ];
125  for ( int i = 0; i < mNColors; ++i )
126  {
127  colorArray[i] = QColor( mColors[i] );
128  }
129  return colorArray;
130 }
131 
133 {
134  if ( mNColors < 1 )
135  {
136  return 0;
137  }
138  QRgb* rgbValues = new QRgb[mNColors];
139  for ( int i = 0; i < mNColors; ++i )
140  {
141  rgbValues[i] = mColors[i];
142  }
143  return rgbValues;
144 }
145 
146 void QgsPalettedRasterRenderer::setLabel( int idx, QString label )
147 {
148  if ( idx >= mLabels.size() )
149  {
150  mLabels.resize( idx + 1 );
151  }
152  mLabels[idx] = label;
153 }
154 
155 QgsRasterBlock * QgsPalettedRasterRenderer::block( int bandNo, QgsRectangle const & extent, int width, int height )
156 {
157  QgsRasterBlock *outputBlock = new QgsRasterBlock();
158  if ( !mInput || mNColors == 0 )
159  {
160  return outputBlock;
161  }
162 
163  QgsRasterBlock *inputBlock = mInput->block( bandNo, extent, width, height );
164 
165  if ( !inputBlock || inputBlock->isEmpty() )
166  {
167  QgsDebugMsg( "No raster data!" );
168  delete inputBlock;
169  return outputBlock;
170  }
171 
172  double currentOpacity = mOpacity;
173 
174  //rendering is faster without considering user-defined transparency
175  bool hasTransparency = usesTransparency();
176  QgsRasterBlock *alphaBlock = 0;
177 
178  if ( mAlphaBand > 0 && mAlphaBand != mBand )
179  {
180  alphaBlock = mInput->block( mAlphaBand, extent, width, height );
181  if ( !alphaBlock || alphaBlock->isEmpty() )
182  {
183  delete inputBlock;
184  delete alphaBlock;
185  return outputBlock;
186  }
187  }
188  else if ( mAlphaBand == mBand )
189  {
190  alphaBlock = inputBlock;
191  }
192 
193  if ( !outputBlock->reset( QGis::ARGB32_Premultiplied, width, height ) )
194  {
195  delete inputBlock;
196  delete alphaBlock;
197  return outputBlock;
198  }
199 
200  QRgb myDefaultColor = NODATA_COLOR;
201 
202  //use direct data access instead of QgsRasterBlock::setValue
203  //because of performance
204  unsigned int* outputData = ( unsigned int* )( outputBlock->bits() );
205 
206  qgssize rasterSize = ( qgssize )width * height;
207  for ( qgssize i = 0; i < rasterSize; ++i )
208  {
209  if ( inputBlock->isNoData( i ) )
210  {
211  outputData[i] = myDefaultColor;
212  continue;
213  }
214  int val = ( int ) inputBlock->value( i );
215  if ( !hasTransparency )
216  {
217  outputData[i] = mColors[val];
218  }
219  else
220  {
221  currentOpacity = mOpacity;
222  if ( mRasterTransparency )
223  {
224  currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0;
225  }
226  if ( mAlphaBand > 0 )
227  {
228  currentOpacity *= alphaBlock->value( i ) / 255.0;
229  }
230  QColor currentColor = QColor( mColors[val] );
231  outputData[i] = qRgba( currentOpacity * currentColor.red(), currentOpacity * currentColor.green(), currentOpacity * currentColor.blue(), currentOpacity * 255 );
232  }
233  }
234 
235  delete inputBlock;
236  if ( mAlphaBand > 0 && mBand != mAlphaBand )
237  {
238  delete alphaBlock;
239  }
240 
241  return outputBlock;
242 }
243 
244 void QgsPalettedRasterRenderer::writeXML( QDomDocument& doc, QDomElement& parentElem ) const
245 {
246  if ( parentElem.isNull() )
247  {
248  return;
249  }
250 
251  QDomElement rasterRendererElem = doc.createElement( "rasterrenderer" );
252  _writeXML( doc, rasterRendererElem );
253 
254  rasterRendererElem.setAttribute( "band", mBand );
255  QDomElement colorPaletteElem = doc.createElement( "colorPalette" );
256  for ( int i = 0; i < mNColors; ++i )
257  {
258  QDomElement colorElem = doc.createElement( "paletteEntry" );
259  colorElem.setAttribute( "value", i );
260  colorElem.setAttribute( "color", QColor( mColors[i] ).name() );
261  if ( !label( i ).isEmpty() )
262  {
263  colorElem.setAttribute( "label", label( i ) );
264  }
265  colorPaletteElem.appendChild( colorElem );
266  }
267  rasterRendererElem.appendChild( colorPaletteElem );
268 
269  parentElem.appendChild( rasterRendererElem );
270 }
271 
272 void QgsPalettedRasterRenderer::legendSymbologyItems( QList< QPair< QString, QColor > >& symbolItems ) const
273 {
274  for ( int i = 0; i < mNColors; ++i )
275  {
276  QString lab = label( i ).isEmpty() ? QString::number( i ) : label( i );
277  symbolItems.push_back( qMakePair( lab, QColor( mColors[i] ) ) );
278  }
279 }
280 
282 {
283  QList<int> bandList;
284  if ( mBand != -1 )
285  {
286  bandList << mBand;
287  }
288  return bandList;
289 }