29 #include <QDomDocument> 
   30 #include <QDomElement> 
   35 #include <QRegularExpression> 
   36 #include <QTextStream> 
   38 const int QgsPalettedRasterRenderer::MAX_FLOAT_CLASSES = 65536;
 
   43   , mClassData( classes )
 
   51   if ( mSourceColorRamp )
 
   65   const int bandNumber = elem.attribute( QStringLiteral( 
"band" ), QStringLiteral( 
"-1" ) ).toInt();
 
   68   const QDomElement paletteElem = elem.firstChildElement( QStringLiteral( 
"colorPalette" ) );
 
   69   if ( !paletteElem.isNull() )
 
   71     const QDomNodeList paletteEntries = paletteElem.elementsByTagName( QStringLiteral( 
"paletteEntry" ) );
 
   73     QDomElement entryElem;
 
   76     for ( 
int i = 0; i < paletteEntries.size(); ++i )
 
   80       entryElem = paletteEntries.at( i ).toElement();
 
   81       value = entryElem.attribute( QStringLiteral( 
"value" ), QStringLiteral( 
"0" ) ).toDouble();
 
   82       color = QColor( entryElem.attribute( QStringLiteral( 
"color" ), QStringLiteral( 
"#000000" ) ) );
 
   83       color.setAlpha( entryElem.attribute( QStringLiteral( 
"alpha" ), QStringLiteral( 
"255" ) ).toInt() );
 
   84       label = entryElem.attribute( QStringLiteral( 
"label" ) );
 
   85       QgsDebugMsgLevel( QStringLiteral( 
"Value: %1, label: %2, color: %3" ).arg( value ).arg( 
label, entryElem.attribute( QStringLiteral( 
"color" ) ) ), 4 );
 
   94   QDomElement sourceColorRampElem = elem.firstChildElement( QStringLiteral( 
"colorramp" ) );
 
   95   if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( QStringLiteral( 
"name" ) ) == QLatin1String( 
"[source]" ) )
 
  110   const auto constMClassData = mClassData;
 
  111   for ( 
const Class &
c : constMClassData )
 
  113     if ( 
c.value == idx )
 
  122   ClassData::iterator cIt = mClassData.begin();
 
  123   for ( ; cIt != mClassData.end(); ++cIt )
 
  125     if ( cIt->value == idx )
 
  135   std::unique_ptr< QgsRasterBlock > outputBlock( 
new QgsRasterBlock() );
 
  136   if ( !
mInput || mClassData.isEmpty() )
 
  138     return outputBlock.release();
 
  141   const std::shared_ptr< QgsRasterBlock > inputBlock( 
mInput->
block( mBand, 
extent, width, height, feedback ) );
 
  143   if ( !inputBlock || inputBlock->isEmpty() )
 
  145     QgsDebugMsg( QStringLiteral( 
"No raster data!" ) );
 
  146     return outputBlock.release();
 
  154   std::shared_ptr< QgsRasterBlock > alphaBlock;
 
  159     if ( !alphaBlock || alphaBlock->isEmpty() )
 
  161       return outputBlock.release();
 
  166     alphaBlock = inputBlock;
 
  171     return outputBlock.release();
 
  178   Q_ASSERT( outputBlock ); 
 
  179   unsigned int *outputData = ( 
unsigned int * )( outputBlock->bits() );
 
  182   bool isNoData = 
false;
 
  183   for ( 
qgssize i = 0; i < rasterSize; ++i )
 
  185     const double value = inputBlock->valueAndNoData( i, isNoData );
 
  188       outputData[i] = myDefaultColor;
 
  191     if ( !mColors.contains( value ) )
 
  193       outputData[i] = myDefaultColor;
 
  197     if ( !hasTransparency )
 
  199       outputData[i] = mColors.value( value );
 
  210         currentOpacity *= alphaBlock->value( i ) / 255.0;
 
  213       const QRgb 
c = mColors.value( value );
 
  214       outputData[i] = qRgba( currentOpacity * qRed( 
c ), currentOpacity * qGreen( 
c ), currentOpacity * qBlue( 
c ), currentOpacity * qAlpha( 
c ) );
 
  218   return outputBlock.release();
 
  223   if ( parentElem.isNull() )
 
  228   QDomElement rasterRendererElem = doc.createElement( QStringLiteral( 
"rasterrenderer" ) );
 
  231   rasterRendererElem.setAttribute( QStringLiteral( 
"band" ), mBand );
 
  232   QDomElement colorPaletteElem = doc.createElement( QStringLiteral( 
"colorPalette" ) );
 
  233   ClassData::const_iterator it = mClassData.constBegin();
 
  234   for ( ; it != mClassData.constEnd(); ++it )
 
  236     const QColor color = it->color;
 
  237     QDomElement colorElem = doc.createElement( QStringLiteral( 
"paletteEntry" ) );
 
  238     colorElem.setAttribute( QStringLiteral( 
"value" ), it->value );
 
  239     colorElem.setAttribute( QStringLiteral( 
"color" ), color.name() );
 
  240     colorElem.setAttribute( QStringLiteral( 
"alpha" ), color.alpha() );
 
  241     if ( !it->label.isEmpty() )
 
  243       colorElem.setAttribute( QStringLiteral( 
"label" ), it->label );
 
  245     colorPaletteElem.appendChild( colorElem );
 
  247   rasterRendererElem.appendChild( colorPaletteElem );
 
  250   if ( mSourceColorRamp )
 
  253     rasterRendererElem.appendChild( colorRampElem );
 
  256   parentElem.appendChild( rasterRendererElem );
 
  265   const QDomNodeList elements = element.elementsByTagName( QStringLiteral( 
"sld:RasterSymbolizer" ) );
 
  266   if ( elements.size() == 0 )
 
  270   QDomElement rasterSymbolizerElem = elements.at( 0 ).toElement();
 
  273   QDomElement channelSelectionElem = doc.createElement( QStringLiteral( 
"sld:ChannelSelection" ) );
 
  274   rasterSymbolizerElem.appendChild( channelSelectionElem );
 
  277   QDomElement channelElem = doc.createElement( QStringLiteral( 
"sld:GrayChannel" ) );
 
  278   channelSelectionElem.appendChild( channelElem );
 
  281   QDomElement sourceChannelNameElem = doc.createElement( QStringLiteral( 
"sld:SourceChannelName" ) );
 
  282   sourceChannelNameElem.appendChild( doc.createTextNode( QString::number( 
band() ) ) );
 
  283   channelElem.appendChild( sourceChannelNameElem );
 
  286   QDomElement colorMapElem = doc.createElement( QStringLiteral( 
"sld:ColorMap" ) );
 
  287   colorMapElem.setAttribute( QStringLiteral( 
"type" ), QStringLiteral( 
"values" ) );
 
  288   if ( this->
classes().size() >= 255 )
 
  289     colorMapElem.setAttribute( QStringLiteral( 
"extended" ), QStringLiteral( 
"true" ) );
 
  290   rasterSymbolizerElem.appendChild( colorMapElem );
 
  294   const QList<QgsPalettedRasterRenderer::Class> 
classes = this->
classes();
 
  295   QList<QgsPalettedRasterRenderer::Class>::const_iterator classDataIt = 
classes.constBegin();
 
  296   for ( ; classDataIt != 
classes.constEnd();  ++classDataIt )
 
  298     QDomElement colorMapEntryElem = doc.createElement( QStringLiteral( 
"sld:ColorMapEntry" ) );
 
  299     colorMapElem.appendChild( colorMapEntryElem );
 
  302     colorMapEntryElem.setAttribute( QStringLiteral( 
"color" ), classDataIt->color.name() );
 
  303     colorMapEntryElem.setAttribute( QStringLiteral( 
"quantity" ), QString::number( classDataIt->value ) );
 
  304     colorMapEntryElem.setAttribute( QStringLiteral( 
"label" ), classDataIt->label );
 
  305     if ( classDataIt->color.alphaF() != 1.0 )
 
  307       colorMapEntryElem.setAttribute( QStringLiteral( 
"opacity" ), QString::number( classDataIt->color.alphaF() ) );
 
  314   if ( mSourceColorRamp )
 
  326   QList< QPair< QString, QColor > > symbolItems;
 
  329     const QString lab = classData.label.isEmpty() ? QString::number( classData.value ) : classData.label;
 
  330     symbolItems << qMakePair( lab, classData.color );
 
  338   QList<QgsLayerTreeModelLegendNode *> res;
 
  341   if ( !name.isEmpty() )
 
  347   res.reserve( res.size() + items.size() );
 
  348   for ( 
const QPair< QString, QColor > &item : items )
 
  369   mSourceColorRamp.reset( ramp );
 
  374   return mSourceColorRamp.get();
 
  379   QList<QgsColorRampShader::ColorRampItem>::const_iterator colorIt = table.constBegin();
 
  381   for ( ; colorIt != table.constEnd(); ++colorIt )
 
  392   const QRegularExpression linePartRx( QStringLiteral( 
"[\\s,:]+" ) );
 
  394 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) 
  395   const QStringList parts = 
string.split( 
'\n', QString::SkipEmptyParts );
 
  397   const QStringList parts = 
string.split( 
'\n', Qt::SkipEmptyParts );
 
  399   for ( 
const QString &part : parts )
 
  401 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) 
  402     const QStringList lineParts = part.split( linePartRx, QString::SkipEmptyParts );
 
  404     const QStringList lineParts = part.split( linePartRx, Qt::SkipEmptyParts );
 
  407     switch ( lineParts.count() )
 
  411         const int value = lineParts.at( 0 ).toInt( &ok );
 
  421         const int value = lineParts.at( 0 ).toInt( &ok );
 
  425         const QColor 
c( lineParts.at( 1 ) );
 
  433         if ( lineParts.count() < 4 )
 
  436         const int value = lineParts.at( 0 ).toInt( &ok );
 
  441         const double r = lineParts.at( 1 ).toDouble( &rOk );
 
  443         const double g = lineParts.at( 2 ).toDouble( &gOk );
 
  445         const double b = lineParts.at( 3 ).toDouble( &bOk );
 
  448         if ( rOk && gOk && bOk )
 
  450           c = QColor( r, g, b );
 
  453         if ( lineParts.count() >= 5 )
 
  455           const double alpha = lineParts.at( 4 ).toDouble( &ok );
 
  461         if ( lineParts.count() > 5 )
 
  463           label = lineParts.mid( 5 ).join( 
' ' );
 
  477   QFile inputFile( path );
 
  479   if ( inputFile.open( QIODevice::ReadOnly ) )
 
  481     QTextStream in( &inputFile );
 
  482     input = in.readAll();
 
  493   std::sort( cd.begin(), cd.end(), []( 
const Class & a, 
const Class & b ) -> 
bool 
  495     return a.value < b.value;
 
  498   const auto constCd = cd;
 
  499   for ( 
const Class &
c : constCd )
 
  501     out << QStringLiteral( 
"%1 %2 %3 %4 %5 %6" ).arg( 
c.value ).arg( 
c.color.red() )
 
  502         .arg( 
c.color.green() ).arg( 
c.color.blue() ).arg( 
c.color.alpha() ).arg( 
c.label );
 
  504   return out.join( 
'\n' );
 
  514   if ( bandNumber > 0 && bandNumber <= raster->
bandCount() )
 
  516     qlonglong numClasses = 0;
 
  530       std::set<double> values;
 
  538       const int nbBlocksWidth = 
static_cast< int >( std::ceil( 1.0 * raster->
xSize() / maxWidth ) );
 
  539       const int nbBlocksHeight = 
static_cast< int >( std::ceil( 1.0 * raster->
ySize() / maxHeight ) );
 
  540       const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
 
  546       std::unique_ptr< QgsRasterBlock > rasterBlock;
 
  548       bool isNoData = 
false;
 
  549       while ( iter.
readNextRasterPart( bandNumber, iterCols, iterRows, rasterBlock, iterLeft, iterTop, &blockExtent ) )
 
  552           feedback->
setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
 
  557         for ( 
int row = 0; row < iterRows; row++ )
 
  562           for ( 
int column = 0; column < iterCols; column++ )
 
  567             const double currentValue = rasterBlock->valueAndNoData( row, column, isNoData );
 
  568             if ( numClasses >= MAX_FLOAT_CLASSES )
 
  570               QgsMessageLog::logMessage( QStringLiteral( 
"Number of classes exceeded maximum (%1)." ).arg( MAX_FLOAT_CLASSES ), QStringLiteral( 
"Raster" ) );
 
  573             if ( !isNoData && values.find( currentValue ) == values.end() )
 
  575               values.insert( currentValue );
 
  576               data.push_back( 
Class( currentValue, QColor(), QLocale().toString( currentValue ) ) );
 
  583       std::sort( data.begin(), data.end(), []( 
const Class & a, 
const Class & b ) -> 
bool 
  585         return a.value < b.value;
 
  598       const int bins = std::ceil( max - min ) + 1;
 
  613           data << 
Class( currentValue, QColor(), QLocale().toString( currentValue ) );
 
  616         currentValue += interval;
 
  621     if ( ramp && numClasses > 0 )
 
  629         randomRamp->setTotalColorCount( data.count() );
 
  632       if ( numClasses > 1 )
 
  635       QgsPalettedRasterRenderer::ClassData::iterator cIt = data.begin();
 
  636       for ( ; cIt != data.end(); ++cIt )
 
  641           feedback->
setProgress( std::max<int>( 1, 100 * ( i + 1 ) / numClasses ) );
 
  643         cIt->color = ramp->
color( i / 
static_cast<double>( numClasses ) );
 
  651 void QgsPalettedRasterRenderer::updateArrays()
 
  654   ClassData::const_iterator it = mClassData.constBegin();
 
  655   for ( ; it != mClassData.constEnd(); ++it )
 
  657     mColors[it->value] = qPremultiply( it->color.rgba() );
 
@ Float32
Thirty two bit floating point (float)
 
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
 
@ Float64
Sixty four bit floating point (double)
 
Abstract base class for color ramps.
 
virtual QColor color(double value) const =0
Returns the color corresponding to a specified value.
 
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
 
void setProgress(double progress)
Sets the current progress for the feedback object.
 
Layer tree node points to a map layer.
 
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
 
Renderer for paletted raster images.
 
int band() const
Returns the raster band used for rendering the 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.
 
QList< QgsLayerTreeModelLegendNode * > createLegendNodes(QgsLayerTreeLayer *nodeLayer) override
Creates a set of legend nodes representing the renderer.
 
QgsColorRamp * sourceColorRamp() const
Gets the source color ramp.
 
static QgsPalettedRasterRenderer::ClassData classDataFromString(const QString &string)
Converts a string containing a color table or class data to to paletted renderer class data.
 
QString label(double idx) const
Returns optional category label.
 
void setSourceColorRamp(QgsColorRamp *ramp)
Set the source color ramp.
 
QList< int > usesBands() const override
Returns a list of band numbers used by the renderer.
 
void writeXml(QDomDocument &doc, QDomElement &parentElem) const override
Write base class members to xml.
 
QList< QgsPalettedRasterRenderer::Class > ClassData
Map of value to class properties.
 
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
 
static QgsPalettedRasterRenderer::ClassData classDataFromFile(const QString &path)
Opens a color table file and returns corresponding paletted renderer class data.
 
static QgsRasterRenderer * create(const QDomElement &elem, QgsRasterInterface *input)
 
static QgsPalettedRasterRenderer::ClassData colorTableToClassData(const QList< QgsColorRampShader::ColorRampItem > &table)
Converts a raster color table to paletted renderer class data.
 
ClassData classes() const
Returns a map of value to classes (colors) used by the renderer.
 
QList< QPair< QString, QColor > > legendSymbologyItems() const override
Returns symbology items if provided by renderer.
 
QgsPalettedRasterRenderer * clone() const override
Clone itself, create deep copy.
 
void setLabel(double idx, const QString &label)
Set category label.
 
static QgsPalettedRasterRenderer::ClassData classDataFromRaster(QgsRasterInterface *raster, int bandNumber, QgsColorRamp *ramp=nullptr, QgsRasterBlockFeedback *feedback=nullptr)
Generates class data from a raster, for the specified bandNumber.
 
static QString classDataToString(const QgsPalettedRasterRenderer::ClassData &classes)
Converts classes to a string representation, using the .clr/gdal color table file format.
 
void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props=QVariantMap()) const override
Used from subclasses to create SLD Rule elements following SLD v1.0 specs.
 
QgsPalettedRasterRenderer(QgsRasterInterface *input, int bandNumber, const ClassData &classes)
Constructor for QgsPalettedRasterRenderer.
 
Totally random color ramp.
 
The RasterBandStats struct is a container for statistics about a single raster band.
 
double minimumValue
The minimum cell value in the raster band.
 
double maximumValue
The maximum cell value in the raster band.
 
Feedback object tailored for raster block reading.
 
The QgsRasterHistogram is a container for histogram of a single raster band.
 
double minimum
The minimum histogram value.
 
double maximum
The maximum histogram value.
 
QgsRasterHistogram::HistogramVector histogramVector
Stores the histogram for a given layer.
 
int binCount
Number of bins (intervals,buckets) in histogram.
 
Base class for processing filters like renderers, reprojector, resampler etc.
 
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.
 
virtual Qgis::DataType dataType(int bandNo) const =0
Returns data type for the band specified by number.
 
virtual QgsRasterInterface * input() const
Current input.
 
virtual int xSize() const
Gets raster size.
 
virtual QgsRasterBandStats bandStatistics(int bandNo, int stats=QgsRasterBandStats::All, const QgsRectangle &extent=QgsRectangle(), int sampleSize=0, QgsRasterBlockFeedback *feedback=nullptr)
Returns the band statistics.
 
QString displayBandName(int bandNumber) const
Generates a friendly, descriptive name for the specified bandNumber.
 
QgsRasterInterface * mInput
 
virtual int ySize() const
 
virtual QgsRectangle extent() const
Gets the extent of the interface.
 
virtual QgsRasterHistogram histogram(int bandNo, int binCount=0, double minimum=std::numeric_limits< double >::quiet_NaN(), double maximum=std::numeric_limits< double >::quiet_NaN(), const QgsRectangle &extent=QgsRectangle(), int sampleSize=0, bool includeOutOfRange=false, QgsRasterBlockFeedback *feedback=nullptr)
Returns a band histogram.
 
Iterator for sequentially processing raster cells.
 
static const int DEFAULT_MAXIMUM_TILE_WIDTH
Default maximum tile width.
 
bool readNextRasterPart(int bandNumber, int &nCols, int &nRows, QgsRasterBlock **block, int &topLeftCol, int &topLeftRow)
Fetches next part of raster data, caller takes ownership of the block and caller should delete the bl...
 
static const int DEFAULT_MAXIMUM_TILE_HEIGHT
Default maximum tile height.
 
void startRasterRead(int bandNumber, qgssize nCols, qgssize nRows, const QgsRectangle &extent, QgsRasterBlockFeedback *feedback=nullptr)
Start reading of raster band.
 
Raster renderer pipe that applies colors to a raster.
 
double mOpacity
Global alpha value (0-1)
 
int mAlphaBand
Read alpha value from band.
 
QRgb renderColorForNodataPixel() const
Returns the color for the renderer to use to represent nodata pixels.
 
void _writeXml(QDomDocument &doc, QDomElement &rasterRendererElem) const
Write upper class info into rasterrenderer element (called by writeXml method of subclasses)
 
int bandCount() const override
Gets number of bands.
 
QgsRasterTransparency * mRasterTransparency
Raster transparency per color or value. Overwrites global alpha value.
 
bool usesTransparency() const
 
void copyCommonProperties(const QgsRasterRenderer *other, bool copyMinMaxOrigin=true)
Copies common properties like opacity / transparency data from other renderer.
 
virtual void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props=QVariantMap()) const
Used from subclasses to create SLD Rule elements following SLD v1.0 specs.
 
void readXml(const QDomElement &rendererElem) override
Sets base class members from xml. Usually called from create() methods of subclasses.
 
Implementation of legend node interface for displaying raster legend entries.
 
int alphaValue(double value, int globalTransparency=255) const
Returns the transparency value for a single value pixel.
 
A rectangle specified with double values.
 
Implementation of legend node interface for displaying arbitrary label with icon.
 
A color ramp entity for QgsStyle databases.
 
An interface for classes which can visit style entity (e.g.
 
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
 
static QgsColorRamp * loadColorRamp(QDomElement &element)
Creates a color ramp from the settings encoded in an XML element.
 
static QDomElement saveColorRamp(const QString &name, QgsColorRamp *ramp, QDomDocument &doc)
Encodes a color ramp's settings to an XML element.
 
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
 
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...
 
#define QgsDebugMsgLevel(str, level)
 
Properties of a single value class.
 
Contains information relating to the style entity currently being visited.