QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
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  return block2( bandNo, extent, width, height );
157 }
158 
159 QgsRasterBlock * QgsPalettedRasterRenderer::block2( int bandNo, QgsRectangle const & extent, int width, int height, QgsRasterBlockFeedback* feedback )
160 {
161  QgsRasterBlock *outputBlock = new QgsRasterBlock();
162  if ( !mInput || mNColors == 0 )
163  {
164  return outputBlock;
165  }
166 
167  QgsRasterBlock *inputBlock = mInput->block2( bandNo, extent, width, height, feedback );
168 
169  if ( !inputBlock || inputBlock->isEmpty() )
170  {
171  QgsDebugMsg( "No raster data!" );
172  delete inputBlock;
173  return outputBlock;
174  }
175 
176  double currentOpacity = mOpacity;
177 
178  //rendering is faster without considering user-defined transparency
179  bool hasTransparency = usesTransparency();
180  QgsRasterBlock *alphaBlock = nullptr;
181 
182  if ( mAlphaBand > 0 && mAlphaBand != mBand )
183  {
184  alphaBlock = mInput->block2( mAlphaBand, extent, width, height, feedback );
185  if ( !alphaBlock || alphaBlock->isEmpty() )
186  {
187  delete inputBlock;
188  delete alphaBlock;
189  return outputBlock;
190  }
191  }
192  else if ( mAlphaBand == mBand )
193  {
194  alphaBlock = inputBlock;
195  }
196 
197  if ( !outputBlock->reset( QGis::ARGB32_Premultiplied, width, height ) )
198  {
199  delete inputBlock;
200  delete alphaBlock;
201  return outputBlock;
202  }
203 
204  QRgb myDefaultColor = NODATA_COLOR;
205 
206  //use direct data access instead of QgsRasterBlock::setValue
207  //because of performance
208  unsigned int* outputData = ( unsigned int* )( outputBlock->bits() );
209 
210  qgssize rasterSize = ( qgssize )width * height;
211  for ( qgssize i = 0; i < rasterSize; ++i )
212  {
213  if ( inputBlock->isNoData( i ) )
214  {
215  outputData[i] = myDefaultColor;
216  continue;
217  }
218  int val = ( int ) inputBlock->value( i );
219  if ( !hasTransparency )
220  {
221  outputData[i] = mColors[val];
222  }
223  else
224  {
225  currentOpacity = mOpacity;
226  if ( mRasterTransparency )
227  {
228  currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0;
229  }
230  if ( mAlphaBand > 0 )
231  {
232  currentOpacity *= alphaBlock->value( i ) / 255.0;
233  }
234  QColor currentColor = QColor( mColors[val] );
235  outputData[i] = qRgba( currentOpacity * currentColor.red(), currentOpacity * currentColor.green(), currentOpacity * currentColor.blue(), currentOpacity * 255 );
236  }
237  }
238 
239  delete inputBlock;
240  if ( mAlphaBand > 0 && mBand != mAlphaBand )
241  {
242  delete alphaBlock;
243  }
244 
245  return outputBlock;
246 }
247 
249 {
250  if ( parentElem.isNull() )
251  {
252  return;
253  }
254 
255  QDomElement rasterRendererElem = doc.createElement( "rasterrenderer" );
256  _writeXML( doc, rasterRendererElem );
257 
258  rasterRendererElem.setAttribute( "band", mBand );
259  QDomElement colorPaletteElem = doc.createElement( "colorPalette" );
260  for ( int i = 0; i < mNColors; ++i )
261  {
262  QDomElement colorElem = doc.createElement( "paletteEntry" );
263  colorElem.setAttribute( "value", i );
264  colorElem.setAttribute( "color", QColor( mColors[i] ).name() );
265  if ( !label( i ).isEmpty() )
266  {
267  colorElem.setAttribute( "label", label( i ) );
268  }
269  colorPaletteElem.appendChild( colorElem );
270  }
271  rasterRendererElem.appendChild( colorPaletteElem );
272 
273  parentElem.appendChild( rasterRendererElem );
274 }
275 
277 {
278  for ( int i = 0; i < mNColors; ++i )
279  {
280  QString lab = label( i ).isEmpty() ? QString::number( i ) : label( i );
281  symbolItems.push_back( qMakePair( lab, QColor( mColors[i] ) ) );
282  }
283 }
284 
286 {
287  QList<int> bandList;
288  if ( mBand != -1 )
289  {
290  bandList << mBand;
291  }
292  return bandList;
293 }
QDomNodeList elementsByTagName(const QString &tagname) const
A rectangle specified with double values.
Definition: qgsrectangle.h:35
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
int alphaValue(double, int theGlobalTransparency=255) const
Returns the transparency value for a single value Pixel.
virtual QgsRasterInterface * input() const
Current input.
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.
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.
int nColors() const
Returns number of colors.
void readXML(const QDomElement &rendererElem) override
Sets base class members from xml.
virtual QgsRasterBlock * block2(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr)
Read block of data using given extent and size.
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
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
int red() const
void setAttribute(const QString &name, const QString &value)
int toInt(bool *ok, int base) const
bool isEmpty() const
bool usesTransparency() const
bool isEmpty() const
Returns true if block is empty, i.e.
void _writeXML(QDomDocument &doc, QDomElement &rasterRendererElem) const
Write upper class info into rasterrenderer element (called by writeXML method of subclasses) ...
QString label(int idx) const
Return optional category label.
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.
QColor * colors() const
Returns copy of color array (caller takes ownership)
QgsPalettedRasterRenderer * clone() const override
Clone itself, create deep copy.
int blue() const
char * bits(int row, int column)
Get pointer to data.
void legendSymbologyItems(QList< QPair< QString, QColor > > &symbolItems) const override
Get symbology items if provided by renderer.
QDomElement firstChildElement(const QString &tagName) const
double value(int row, int column) const
Read a single value if type of block is numeric.
double mOpacity
Global alpha value (0-1)
int size() const
QRgb * rgbArray() const
Returns copy of rgb array (caller takes ownership)
QDomElement createElement(const QString &tagName)
QgsRasterInterface * mInput
int size() const
Feedback object tailored for raster block reading.
Raster renderer pipe that applies colors to a raster.
QgsRasterBlock * block2(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
QRgb rgba() const
QDomNode at(int index) const