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() );