Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsrasterrenderer.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 : : 18 : : #include "qgsrasterrenderer.h" 19 : : #include "qgsrastertransparency.h" 20 : : 21 : : #include "qgssymbollayerutils.h" 22 : : #include "qgslayertreemodellegendnode.h" 23 : : 24 : : #include <QCoreApplication> 25 : : #include <QDomDocument> 26 : : #include <QDomElement> 27 : : #include <QImage> 28 : : #include <QPainter> 29 : : 30 : : // See #9101 before any change of NODATA_COLOR! 31 : : const QRgb QgsRasterRenderer::NODATA_COLOR = qRgba( 0, 0, 0, 0 ); 32 : : 33 : 0 : QgsRasterRenderer::QgsRasterRenderer( QgsRasterInterface *input, const QString &type ) 34 : 0 : : QgsRasterInterface( input ) 35 : 0 : , mType( type ) 36 : 0 : { 37 : 0 : } 38 : : 39 : 0 : QgsRasterRenderer::~QgsRasterRenderer() 40 : 0 : { 41 : 0 : delete mRasterTransparency; 42 : 0 : } 43 : : 44 : 0 : int QgsRasterRenderer::bandCount() const 45 : : { 46 : 0 : if ( mOn ) return 1; 47 : : 48 : 0 : if ( mInput ) return mInput->bandCount(); 49 : : 50 : 0 : return 0; 51 : 0 : } 52 : : 53 : 0 : Qgis::DataType QgsRasterRenderer::dataType( int bandNo ) const 54 : : { 55 : 0 : QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 ); 56 : : 57 : 0 : if ( mOn ) return Qgis::ARGB32_Premultiplied; 58 : : 59 : 0 : if ( mInput ) return mInput->dataType( bandNo ); 60 : : 61 : 0 : return Qgis::UnknownDataType; 62 : 0 : } 63 : : 64 : 0 : bool QgsRasterRenderer::setInput( QgsRasterInterface *input ) 65 : : { 66 : : // Renderer can only work with numerical values in at least 1 band 67 : 0 : if ( !input ) return false; 68 : : 69 : 0 : if ( !mOn ) 70 : : { 71 : : // In off mode we can connect to anything 72 : 0 : mInput = input; 73 : 0 : return true; 74 : : } 75 : : 76 : 0 : for ( int i = 1; i <= input->bandCount(); i++ ) 77 : : { 78 : 0 : const Qgis::DataType bandType = input->dataType( i ); 79 : : // we always allow unknown data types to connect - otherwise invalid layers cannot setup 80 : : // their original rendering pipe and this information is lost 81 : 0 : if ( bandType != Qgis::UnknownDataType && !QgsRasterBlock::typeIsNumeric( bandType ) ) 82 : : { 83 : 0 : return false; 84 : : } 85 : 0 : } 86 : 0 : mInput = input; 87 : 0 : return true; 88 : 0 : } 89 : : 90 : 0 : bool QgsRasterRenderer::usesTransparency() const 91 : : { 92 : 0 : if ( !mInput ) 93 : : { 94 : 0 : return true; 95 : : } 96 : 0 : return ( mAlphaBand > 0 || ( mRasterTransparency && !mRasterTransparency->isEmpty() ) || !qgsDoubleNear( mOpacity, 1.0 ) ); 97 : 0 : } 98 : : 99 : 0 : void QgsRasterRenderer::setRasterTransparency( QgsRasterTransparency *t ) 100 : : { 101 : 0 : delete mRasterTransparency; 102 : 0 : mRasterTransparency = t; 103 : 0 : } 104 : : 105 : 0 : QList< QPair< QString, QColor > > QgsRasterRenderer::legendSymbologyItems() const 106 : : { 107 : 0 : return QList< QPair< QString, QColor > >(); 108 : : } 109 : : 110 : 0 : QList<QgsLayerTreeModelLegendNode *> QgsRasterRenderer::createLegendNodes( QgsLayerTreeLayer *nodeLayer ) 111 : : { 112 : 0 : QList<QgsLayerTreeModelLegendNode *> nodes; 113 : : 114 : 0 : QList< QPair< QString, QColor > > rasterItemList = legendSymbologyItems(); 115 : 0 : if ( rasterItemList.isEmpty() ) 116 : 0 : return nodes; 117 : : 118 : : // Paletted raster may have many colors, for example UInt16 may have 65536 colors 119 : : // and it is very slow, so we limit max count 120 : 0 : int count = 0; 121 : 0 : int max_count = 1000; 122 : : 123 : 0 : for ( auto itemIt = rasterItemList.constBegin(); itemIt != rasterItemList.constEnd(); ++itemIt, ++count ) 124 : : { 125 : 0 : nodes << new QgsRasterSymbolLegendNode( nodeLayer, itemIt->second, itemIt->first ); 126 : : 127 : 0 : if ( count == max_count ) 128 : : { 129 : 0 : QString label = tr( "following %1 items\nnot displayed" ).arg( rasterItemList.size() - max_count ); 130 : 0 : nodes << new QgsSimpleLegendNode( nodeLayer, label ); 131 : : break; 132 : 0 : } 133 : 0 : } 134 : : 135 : 0 : return nodes; 136 : 0 : } 137 : : 138 : 0 : void QgsRasterRenderer::_writeXml( QDomDocument &doc, QDomElement &rasterRendererElem ) const 139 : : { 140 : 0 : if ( rasterRendererElem.isNull() ) 141 : : { 142 : 0 : return; 143 : : } 144 : : 145 : 0 : rasterRendererElem.setAttribute( QStringLiteral( "type" ), mType ); 146 : 0 : rasterRendererElem.setAttribute( QStringLiteral( "opacity" ), QString::number( mOpacity ) ); 147 : 0 : rasterRendererElem.setAttribute( QStringLiteral( "alphaBand" ), mAlphaBand ); 148 : 0 : rasterRendererElem.setAttribute( QStringLiteral( "nodataColor" ), mNodataColor.isValid() ? QgsSymbolLayerUtils::encodeColor( mNodataColor ) : QString() ); 149 : : 150 : 0 : if ( mRasterTransparency ) 151 : : { 152 : 0 : mRasterTransparency->writeXml( doc, rasterRendererElem ); 153 : 0 : } 154 : : 155 : 0 : QDomElement minMaxOriginElem = doc.createElement( QStringLiteral( "minMaxOrigin" ) ); 156 : 0 : mMinMaxOrigin.writeXml( doc, minMaxOriginElem ); 157 : 0 : rasterRendererElem.appendChild( minMaxOriginElem ); 158 : 0 : } 159 : : 160 : 0 : QRgb QgsRasterRenderer::renderColorForNodataPixel() const 161 : : { 162 : 0 : if ( !mNodataColor.isValid() ) 163 : 0 : return NODATA_COLOR; 164 : : else 165 : 0 : return mNodataColor.rgba(); 166 : 0 : } 167 : : 168 : 0 : void QgsRasterRenderer::readXml( const QDomElement &rendererElem ) 169 : : { 170 : 0 : if ( rendererElem.isNull() ) 171 : : { 172 : 0 : return; 173 : : } 174 : : 175 : 0 : mType = rendererElem.attribute( QStringLiteral( "type" ) ); 176 : 0 : mOpacity = rendererElem.attribute( QStringLiteral( "opacity" ), QStringLiteral( "1.0" ) ).toDouble(); 177 : 0 : mAlphaBand = rendererElem.attribute( QStringLiteral( "alphaBand" ), QStringLiteral( "-1" ) ).toInt(); 178 : 0 : const QString colorEncoded = rendererElem.attribute( QStringLiteral( "nodataColor" ) ); 179 : 0 : mNodataColor = !colorEncoded.isEmpty() ? QgsSymbolLayerUtils::decodeColor( colorEncoded ) : QColor(); 180 : : 181 : 0 : QDomElement rasterTransparencyElem = rendererElem.firstChildElement( QStringLiteral( "rasterTransparency" ) ); 182 : 0 : if ( !rasterTransparencyElem.isNull() ) 183 : : { 184 : 0 : delete mRasterTransparency; 185 : 0 : mRasterTransparency = new QgsRasterTransparency(); 186 : 0 : mRasterTransparency->readXml( rasterTransparencyElem ); 187 : 0 : } 188 : : 189 : 0 : QDomElement minMaxOriginElem = rendererElem.firstChildElement( QStringLiteral( "minMaxOrigin" ) ); 190 : 0 : if ( !minMaxOriginElem.isNull() ) 191 : : { 192 : 0 : mMinMaxOrigin.readXml( minMaxOriginElem ); 193 : 0 : } 194 : 0 : } 195 : : 196 : 0 : void QgsRasterRenderer::copyCommonProperties( const QgsRasterRenderer *other, bool copyMinMaxOrigin ) 197 : : { 198 : 0 : if ( !other ) 199 : 0 : return; 200 : : 201 : 0 : setOpacity( other->opacity() ); 202 : 0 : setAlphaBand( other->alphaBand() ); 203 : 0 : setRasterTransparency( other->rasterTransparency() ? new QgsRasterTransparency( *other->rasterTransparency() ) : nullptr ); 204 : 0 : setNodataColor( other->nodataColor() ); 205 : 0 : if ( copyMinMaxOrigin ) 206 : 0 : setMinMaxOrigin( other->minMaxOrigin() ); 207 : 0 : } 208 : : 209 : 0 : void QgsRasterRenderer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap & ) const 210 : : { 211 : 0 : QDomElement rasterSymbolizerElem = doc.createElement( QStringLiteral( "sld:RasterSymbolizer" ) ); 212 : 0 : element.appendChild( rasterSymbolizerElem ); 213 : : 214 : : // add opacity only is different from default 215 : 0 : if ( !qgsDoubleNear( opacity(), 1.0 ) ) 216 : : { 217 : 0 : QDomElement opacityElem = doc.createElement( QStringLiteral( "sld:Opacity" ) ); 218 : 0 : opacityElem.appendChild( doc.createTextNode( QString::number( opacity() ) ) ); 219 : 0 : rasterSymbolizerElem.appendChild( opacityElem ); 220 : 0 : } 221 : 0 : } 222 : : 223 : 0 : bool QgsRasterRenderer::accept( QgsStyleEntityVisitorInterface * ) const 224 : : { 225 : 0 : return true; 226 : : }