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