QGIS API Documentation  2.99.0-Master (37c43df)
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, QStringLiteral( "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, QStringLiteral( "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( QStringLiteral( "band" ), QStringLiteral( "-1" ) ).toInt();
66  int nColors = 0;
67  QRgb* colors = nullptr;
68  QVector<QString> labels;
69 
70  QDomElement paletteElem = elem.firstChildElement( QStringLiteral( "colorPalette" ) );
71  if ( !paletteElem.isNull() )
72  {
73  QDomNodeList paletteEntries = paletteElem.elementsByTagName( QStringLiteral( "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( QStringLiteral( "value" ), QStringLiteral( "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( QStringLiteral( "value" ), QStringLiteral( "0" ) ).toDouble();
95  QgsDebugMsgLevel( entryElem.attribute( "color", "#000000" ), 4 );
96  if ( value >= 0 && value < nColors )
97  {
98  colors[value] = QColor( entryElem.attribute( QStringLiteral( "color" ), QStringLiteral( "#000000" ) ) ).rgba();
99  QString label = entryElem.attribute( QStringLiteral( "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 
145 void QgsPalettedRasterRenderer::setLabel( int idx, const QString& label )
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, QgsRasterBlockFeedback* feedback )
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, feedback );
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, feedback );
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 
243 void QgsPalettedRasterRenderer::writeXml( QDomDocument& doc, QDomElement& parentElem ) const
244 {
245  if ( parentElem.isNull() )
246  {
247  return;
248  }
249 
250  QDomElement rasterRendererElem = doc.createElement( QStringLiteral( "rasterrenderer" ) );
251  _writeXml( doc, rasterRendererElem );
252 
253  rasterRendererElem.setAttribute( QStringLiteral( "band" ), mBand );
254  QDomElement colorPaletteElem = doc.createElement( QStringLiteral( "colorPalette" ) );
255  for ( int i = 0; i < mNColors; ++i )
256  {
257  QDomElement colorElem = doc.createElement( QStringLiteral( "paletteEntry" ) );
258  colorElem.setAttribute( QStringLiteral( "value" ), i );
259  colorElem.setAttribute( QStringLiteral( "color" ), QColor( mColors[i] ).name() );
260  if ( !label( i ).isEmpty() )
261  {
262  colorElem.setAttribute( QStringLiteral( "label" ), label( i ) );
263  }
264  colorPaletteElem.appendChild( colorElem );
265  }
266  rasterRendererElem.appendChild( colorPaletteElem );
267 
268  parentElem.appendChild( rasterRendererElem );
269 }
270 
271 void QgsPalettedRasterRenderer::legendSymbologyItems( QList< QPair< QString, QColor > >& symbolItems ) const
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 }
A rectangle specified with double values.
Definition: qgsrectangle.h:35
Renderer for paletted raster images.
virtual QgsRectangle extent() const
Get the extent of the interface.
#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.
void writeXml(QDomDocument &doc, QDomElement &parentElem) const override
Write base class members to xml.
bool isNoData(int row, int column)
Check if value at position is no data.
int nColors() const
Returns number of colors.
QgsRasterTransparency * mRasterTransparency
Raster transparency per color or value. Overwrites global alpha value.
QgsPalettedRasterRenderer(QgsRasterInterface *input, int bandNumber, QColor *colorArray, int nColors, const QVector< QString > &labels=QVector< QString >())
Renderer owns color array.
static const QRgb NODATA_COLOR
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition: qgis.h:75
Raster data container.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:34
virtual QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr)=0
Read block of data using given extent and size.
void _writeXml(QDomDocument &doc, QDomElement &rasterRendererElem) const
Write upper class info into rasterrenderer element (called by writeXml method of subclasses) ...
bool usesTransparency() const
bool isEmpty() const
Returns true if block is empty, i.e.
QString label(int idx) const
Return optional category label.
int mAlphaBand
Read alpha value from band.
void readXml(const QDomElement &rendererElem) override
Sets base class members from xml. Usually called from create() methods of subclasses.
Base class for processing filters like renderers, reprojector, resampler etc.
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:336
static QgsRasterRenderer * create(const QDomElement &elem, QgsRasterInterface *input)
QList< int > usesBands() const override
Returns a list of band numbers used by the renderer.
bool reset(Qgis::DataType theDataType, int theWidth, int theHeight)
Reset block.
QColor * colors() const
Returns copy of color array (caller takes ownership)
QgsPalettedRasterRenderer * clone() const override
Clone itself, create deep copy.
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.
double value(int row, int column) const
Read a single value if type of block is numeric.
double mOpacity
Global alpha value (0-1)
QRgb * rgbArray() const
Returns copy of rgb array (caller takes ownership)
QgsRasterInterface * mInput
Feedback object tailored for raster block reading.
Raster renderer pipe that applies colors to a raster.
QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.