QGIS API Documentation  2.14.0-Essen
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 
40  QgsRasterRenderer( input, "paletted" ), mBand( bandNumber ), mColors( colorArray ), mNColors( nColors ), mLabels( labels )
41 {
42 }
43 
45 {
46  delete[] mColors;
47 }
48 
50 {
51  QgsPalettedRasterRenderer * renderer = new QgsPalettedRasterRenderer( nullptr, mBand, rgbArray(), mNColors );
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 nullptr;
64  }
65 
66  int bandNumber = elem.attribute( "band", "-1" ).toInt();
67  int nColors = 0;
68  QRgb* colors = nullptr;
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  QgsDebugMsgLevel( QString( "nColors = %1" ).arg( nColors ), 4 );
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  QgsDebugMsgLevel( entryElem.attribute( "color", "#000000" ), 4 );
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 nullptr;
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 nullptr;
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 
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 = nullptr;
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 
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 
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 }
QDomNodeList elementsByTagName(const QString &tagname) const
A rectangle specified with double values.
Definition: qgsrectangle.h:35
QString label(int idx) const
Return optional category label.
void writeXML(QDomDocument &doc, QDomElement &parentElem) const override
Write base class members to xml.
QDomNode appendChild(const QDomNode &newChild)
Renderer for paletted raster images.
QString attribute(const QString &name, const QString &defValue) const
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void setLabel(int idx, const QString &label)
Set category label.
virtual QgsRasterInterface * input() const
Current input.
QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height) override
Read block of data using given extent and size.
double toDouble(bool *ok) const
bool isNoData(int row, int column)
Check if value at position is no data.
void readXML(const QDomElement &rendererElem) override
Sets base class members from xml.
bool usesTransparency() const
QgsRasterTransparency * mRasterTransparency
Raster transparency per color or value.
QDomElement toElement() const
QgsPalettedRasterRenderer(QgsRasterInterface *input, int bandNumber, QColor *colorArray, int nColors, const QVector< QString > &labels=QVector< QString >())
Renderer owns color array.
static const QRgb NODATA_COLOR
int alphaValue(double, int theGlobalTransparency=255) const
Returns the transparency value for a single value Pixel.
QString number(int n, int base)
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition: qgis.h:146
void resize(int size)
Raster data container.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:34
double value(int row, int column) const
Read a single value if type of block is numeric.
int red() const
void setAttribute(const QString &name, const QString &value)
int toInt(bool *ok, int base) const
bool isEmpty() const
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.
int green() const
unsigned long long qgssize
Qgssize is used instead of size_t, because size_t is stdlib type, unknown by SIP, and it would be har...
Definition: qgis.h:392
static QgsRasterRenderer * create(const QDomElement &elem, QgsRasterInterface *input)
bool reset(QGis::DataType theDataType, int theWidth, int theHeight)
Reset block.
QList< int > usesBands() const override
Returns a list of band numbers used by the renderer.
bool isNull() const
virtual QgsRectangle extent()
Get the extent of the interface.
QgsPalettedRasterRenderer * clone() const override
Clone itself, create deep copy.
int blue() const
char * bits(int row, int column)
Get pointer to data.
QRgb * rgbArray() const
Returns copy of rgb array (caller takes ownership)
void legendSymbologyItems(QList< QPair< QString, QColor > > &symbolItems) const override
Get symbology items if provided by renderer.
QDomElement firstChildElement(const QString &tagName) const
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)
Defines the list of pixel values to be considered as transparent or semi transparent when rendering r...
void setOpacity(double opacity)
int size() const
QDomElement createElement(const QString &tagName)
void _writeXML(QDomDocument &doc, QDomElement &rasterRendererElem) const
Write upper class info into rasterrenderer element (called by writeXML method of subclasses) ...
QgsRasterInterface * mInput
int size() const
void setRasterTransparency(QgsRasterTransparency *t)
Raster renderer pipe that applies colors to a raster.
QRgb rgba() const
QColor * colors() const
Returns copy of color array (caller takes ownership)
QDomNode at(int index) const
bool isEmpty() const
Returns true if block is empty, i.e.