QGIS API Documentation  2.0.1-Dufour
 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 
27  QColor* colorArray, int nColors ):
28  QgsRasterRenderer( input, "paletted" ), mBand( bandNumber ), mNColors( nColors )
29 {
30  mColors = new QRgb[nColors];
31  for ( int i = 0; i < nColors; ++i )
32  {
33  mColors[i] = colorArray[i].rgba();
34  }
35  delete[] colorArray;
36 }
37 
38 QgsPalettedRasterRenderer::QgsPalettedRasterRenderer( QgsRasterInterface* input, int bandNumber, QRgb* colorArray, int nColors ):
39  QgsRasterRenderer( input, "paletted" ), mBand( bandNumber ), mColors( colorArray ), mNColors( nColors )
40 {
41 }
42 
44 {
45  delete[] mColors;
46 }
47 
49 {
51  renderer->setOpacity( mOpacity );
52  renderer->setAlphaBand( mAlphaBand );
54  return renderer;
55 }
56 
58 {
59  if ( elem.isNull() )
60  {
61  return 0;
62  }
63 
64  int bandNumber = elem.attribute( "band", "-1" ).toInt();
65  int nColors = 0;
66  QRgb* colors = 0;
67 
68  QDomElement paletteElem = elem.firstChildElement( "colorPalette" );
69  if ( !paletteElem.isNull() )
70  {
71  QDomNodeList paletteEntries = paletteElem.elementsByTagName( "paletteEntry" );
72 
73  QDomElement entryElem;
74  int value;
75  nColors = 0;
76 
77  // We cannot believe that data are correct, check first max value
78  for ( int i = 0; i < paletteEntries.size(); ++i )
79  {
80  entryElem = paletteEntries.at( i ).toElement();
81  // Could be written as doubles (with .0000) in old project files
82  value = ( int )entryElem.attribute( "value", "0" ).toDouble();
83  if ( value >= nColors && value <= 10000 ) nColors = value + 1;
84  }
85  QgsDebugMsg( QString( "nColors = %1" ).arg( nColors ) );
86 
87  colors = new QRgb[ nColors ];
88 
89  for ( int i = 0; i < nColors; ++i )
90  {
91  entryElem = paletteEntries.at( i ).toElement();
92  value = ( int )entryElem.attribute( "value", "0" ).toDouble();
93  QgsDebugMsg( entryElem.attribute( "color", "#000000" ) );
94  if ( value >= 0 && value < nColors )
95  {
96  colors[value] = QColor( entryElem.attribute( "color", "#000000" ) ).rgba();
97  }
98  else
99  {
100  QgsDebugMsg( QString( "value %1 out of range" ).arg( value ) );
101  }
102  }
103  }
104  QgsRasterRenderer* r = new QgsPalettedRasterRenderer( input, bandNumber, colors, nColors );
105  r->readXML( elem );
106  return r;
107 }
108 
110 {
111  if ( mNColors < 1 )
112  {
113  return 0;
114  }
115  QColor* colorArray = new QColor[ mNColors ];
116  for ( int i = 0; i < mNColors; ++i )
117  {
118  colorArray[i] = QColor( mColors[i] );
119  }
120  return colorArray;
121 }
122 
124 {
125  if ( mNColors < 1 )
126  {
127  return 0;
128  }
129  QRgb* rgbValues = new QRgb[mNColors];
130  for ( int i = 0; i < mNColors; ++i )
131  {
132  rgbValues[i] = mColors[i];
133  }
134  return rgbValues;
135 }
136 
137 QgsRasterBlock * QgsPalettedRasterRenderer::block( int bandNo, QgsRectangle const & extent, int width, int height )
138 {
139  QgsRasterBlock *outputBlock = new QgsRasterBlock();
140  if ( !mInput )
141  {
142  return outputBlock;
143  }
144 
145  QgsRasterBlock *inputBlock = mInput->block( bandNo, extent, width, height );
146 
147  if ( !inputBlock || inputBlock->isEmpty() )
148  {
149  QgsDebugMsg( "No raster data!" );
150  delete inputBlock;
151  return outputBlock;
152  }
153 
154  double currentOpacity = mOpacity;
155 
156  //rendering is faster without considering user-defined transparency
157  bool hasTransparency = usesTransparency();
158  QgsRasterBlock *alphaBlock = 0;
159 
160  if ( mAlphaBand > 0 && mAlphaBand != mBand )
161  {
162  alphaBlock = mInput->block( mAlphaBand, extent, width, height );
163  if ( !alphaBlock || alphaBlock->isEmpty() )
164  {
165  delete inputBlock;
166  delete alphaBlock;
167  return outputBlock;
168  }
169  }
170  else if ( mAlphaBand == mBand )
171  {
172  alphaBlock = inputBlock;
173  }
174 
175  if ( !outputBlock->reset( QGis::ARGB32_Premultiplied, width, height ) )
176  {
177  delete inputBlock;
178  delete alphaBlock;
179  return outputBlock;
180  }
181 
182  QRgb myDefaultColor = NODATA_COLOR;
183 
184  //use direct data access instead of QgsRasterBlock::setValue
185  //because of performance
186  unsigned int* outputData = ( unsigned int* )( outputBlock->bits() );
187 
188  size_t rasterSize = ( size_t )width * height;
189  for ( size_t i = 0; i < rasterSize; ++i )
190  {
191  if ( inputBlock->isNoData( i ) )
192  {
193  outputData[i] = myDefaultColor;
194  continue;
195  }
196  int val = ( int ) inputBlock->value( i );
197  if ( !hasTransparency )
198  {
199  outputData[i] = mColors[val];
200  }
201  else
202  {
203  currentOpacity = mOpacity;
204  if ( mRasterTransparency )
205  {
206  currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0;
207  }
208  if ( mAlphaBand > 0 )
209  {
210  currentOpacity *= alphaBlock->value( i ) / 255.0;
211  }
212  QColor currentColor = QColor( mColors[val] );
213  outputData[i] = qRgba( currentOpacity * currentColor.red(), currentOpacity * currentColor.green(), currentOpacity * currentColor.blue(), currentOpacity * 255 );
214  }
215  }
216 
217  delete inputBlock;
218  if ( mAlphaBand > 0 && mBand != mAlphaBand )
219  {
220  delete alphaBlock;
221  }
222 
223  return outputBlock;
224 }
225 
226 void QgsPalettedRasterRenderer::writeXML( QDomDocument& doc, QDomElement& parentElem ) const
227 {
228  if ( parentElem.isNull() )
229  {
230  return;
231  }
232 
233  QDomElement rasterRendererElem = doc.createElement( "rasterrenderer" );
234  _writeXML( doc, rasterRendererElem );
235 
236  rasterRendererElem.setAttribute( "band", mBand );
237  QDomElement colorPaletteElem = doc.createElement( "colorPalette" );
238  for ( int i = 0; i < mNColors; ++i )
239  {
240  QDomElement colorElem = doc.createElement( "paletteEntry" );
241  colorElem.setAttribute( "value", i );
242  colorElem.setAttribute( "color", QColor( mColors[i] ).name() );
243  colorPaletteElem.appendChild( colorElem );
244  }
245  rasterRendererElem.appendChild( colorPaletteElem );
246 
247  parentElem.appendChild( rasterRendererElem );
248 }
249 
250 void QgsPalettedRasterRenderer::legendSymbologyItems( QList< QPair< QString, QColor > >& symbolItems ) const
251 {
252  for ( int i = 0; i < mNColors; ++i )
253  {
254  symbolItems.push_back( qMakePair( QString::number( i ), QColor( mColors[i] ) ) );
255  }
256 }
257 
259 {
260  QList<int> bandList;
261  if ( mBand != -1 )
262  {
263  bandList << mBand;
264  }
265  return bandList;
266 }
A rectangle specified with double values.
Definition: qgsrectangle.h:35
void writeXML(QDomDocument &doc, QDomElement &parentElem) const
Write base class members to xml.
Renderer for paletted raster images.
QList< int > usesBands() const
Returns a list of band numbers used by the renderer.
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
bool isNoData(int row, int column)
Check if value at position is no data.
QgsRasterInterface * clone() const
Clone itself, create deep copy.
QgsPalettedRasterRenderer(QgsRasterInterface *input, int bandNumber, QColor *colorArray, int nColors)
Renderer owns color array.
bool usesTransparency() const
QgsRasterTransparency * mRasterTransparency
Raster transparency per color or value.
static const QRgb NODATA_COLOR
int alphaValue(double, int theGlobalTransparency=255) const
Returns the transparency value for a single value Pixel.
Raster data container.
double value(int row, int column) const
Read a single value if type of block is numeric.
QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height)
Read block of data using given extent and size.
int nColors() const
Returns number of colors.
int mAlphaBand
Read alpha value from band.
void setAlphaBand(int band)
Base class for processing filters like renderers, reprojector, resampler etc.
void readXML(const QDomElement &rendererElem)
Sets base class members from xml.
static QgsRasterRenderer * create(const QDomElement &elem, QgsRasterInterface *input)
bool reset(QGis::DataType theDataType, int theWidth, int theHeight)
Reset block.
void legendSymbologyItems(QList< QPair< QString, QColor > > &symbolItems) const
Get symbology items if provided by renderer.
char * bits(int row, int column)
Get pointer to data.
QRgb * rgbArray() const
Returns copy of rgb array (caller takes ownership)
virtual QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height)=0
Read block of data using given extent and size.
double mOpacity
Global alpha value (0-1)
void setOpacity(double opacity)
void _writeXML(QDomDocument &doc, QDomElement &rasterRendererElem) const
Write upper class info into rasterrenderer element (called by writeXML method of subclasses) ...
QgsRasterInterface * mInput
void setRasterTransparency(QgsRasterTransparency *t)
Raster renderer pipe that applies colors to a raster.
QColor * colors() const
Returns copy of color array (caller takes ownership)
bool isEmpty() const
Returns true if block is empty, i.e.