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