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
23 #include <QCoreApplication>
24 #include <QDomDocument>
25 #include <QDomElement>
26 #include <QImage>
27 #include <QPainter>
28
29 // See #9101 before any change of NODATA_COLOR!
30 const QRgb QgsRasterRenderer::NODATA_COLOR = qRgba( 0, 0, 0, 0 );
31
QgsRasterRenderer(QgsRasterInterface * input,const QString & type)32 QgsRasterRenderer::QgsRasterRenderer( QgsRasterInterface *input, const QString &type )
33 : QgsRasterInterface( input )
34 , mType( type )
35 {
36 }
37
~QgsRasterRenderer()38 QgsRasterRenderer::~QgsRasterRenderer()
39 {
40 delete mRasterTransparency;
41 }
42
bandCount() const43 int QgsRasterRenderer::bandCount() const
44 {
45 if ( mOn ) return 1;
46
47 if ( mInput ) return mInput->bandCount();
48
49 return 0;
50 }
51
dataType(int bandNo) const52 Qgis::DataType QgsRasterRenderer::dataType( int bandNo ) const
53 {
54 QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
55
56 if ( mOn ) return Qgis::ARGB32_Premultiplied;
57
58 if ( mInput ) return mInput->dataType( bandNo );
59
60 return Qgis::UnknownDataType;
61 }
62
setInput(QgsRasterInterface * input)63 bool QgsRasterRenderer::setInput( QgsRasterInterface *input )
64 {
65 // Renderer can only work with numerical values in at least 1 band
66 if ( !input ) return false;
67
68 if ( !mOn )
69 {
70 // In off mode we can connect to anything
71 mInput = input;
72 return true;
73 }
74
75 for ( int i = 1; i <= input->bandCount(); i++ )
76 {
77 const Qgis::DataType bandType = input->dataType( i );
78 // we always allow unknown data types to connect - otherwise invalid layers cannot setup
79 // their original rendering pipe and this information is lost
80 if ( bandType != Qgis::UnknownDataType && !QgsRasterBlock::typeIsNumeric( bandType ) )
81 {
82 return false;
83 }
84 }
85 mInput = input;
86 return true;
87 }
88
usesTransparency() const89 bool QgsRasterRenderer::usesTransparency() const
90 {
91 if ( !mInput )
92 {
93 return true;
94 }
95 return ( mAlphaBand > 0 || ( mRasterTransparency && !mRasterTransparency->isEmpty() ) || !qgsDoubleNear( mOpacity, 1.0 ) );
96 }
97
setRasterTransparency(QgsRasterTransparency * t)98 void QgsRasterRenderer::setRasterTransparency( QgsRasterTransparency *t )
99 {
100 delete mRasterTransparency;
101 mRasterTransparency = t;
102 }
103
_writeXml(QDomDocument & doc,QDomElement & rasterRendererElem) const104 void QgsRasterRenderer::_writeXml( QDomDocument &doc, QDomElement &rasterRendererElem ) const
105 {
106 if ( rasterRendererElem.isNull() )
107 {
108 return;
109 }
110
111 rasterRendererElem.setAttribute( QStringLiteral( "type" ), mType );
112 rasterRendererElem.setAttribute( QStringLiteral( "opacity" ), QString::number( mOpacity ) );
113 rasterRendererElem.setAttribute( QStringLiteral( "alphaBand" ), mAlphaBand );
114 rasterRendererElem.setAttribute( QStringLiteral( "nodataColor" ), mNodataColor.isValid() ? QgsSymbolLayerUtils::encodeColor( mNodataColor ) : QString() );
115
116 if ( mRasterTransparency )
117 {
118 mRasterTransparency->writeXml( doc, rasterRendererElem );
119 }
120
121 QDomElement minMaxOriginElem = doc.createElement( QStringLiteral( "minMaxOrigin" ) );
122 mMinMaxOrigin.writeXml( doc, minMaxOriginElem );
123 rasterRendererElem.appendChild( minMaxOriginElem );
124 }
125
renderColorForNodataPixel() const126 QRgb QgsRasterRenderer::renderColorForNodataPixel() const
127 {
128 if ( !mNodataColor.isValid() )
129 return NODATA_COLOR;
130 else
131 return mNodataColor.rgba();
132 }
133
readXml(const QDomElement & rendererElem)134 void QgsRasterRenderer::readXml( const QDomElement &rendererElem )
135 {
136 if ( rendererElem.isNull() )
137 {
138 return;
139 }
140
141 mType = rendererElem.attribute( QStringLiteral( "type" ) );
142 mOpacity = rendererElem.attribute( QStringLiteral( "opacity" ), QStringLiteral( "1.0" ) ).toDouble();
143 mAlphaBand = rendererElem.attribute( QStringLiteral( "alphaBand" ), QStringLiteral( "-1" ) ).toInt();
144 const QString colorEncoded = rendererElem.attribute( QStringLiteral( "nodataColor" ) );
145 mNodataColor = !colorEncoded.isEmpty() ? QgsSymbolLayerUtils::decodeColor( colorEncoded ) : QColor();
146
147 QDomElement rasterTransparencyElem = rendererElem.firstChildElement( QStringLiteral( "rasterTransparency" ) );
148 if ( !rasterTransparencyElem.isNull() )
149 {
150 delete mRasterTransparency;
151 mRasterTransparency = new QgsRasterTransparency();
152 mRasterTransparency->readXml( rasterTransparencyElem );
153 }
154
155 QDomElement minMaxOriginElem = rendererElem.firstChildElement( QStringLiteral( "minMaxOrigin" ) );
156 if ( !minMaxOriginElem.isNull() )
157 {
158 mMinMaxOrigin.readXml( minMaxOriginElem );
159 }
160 }
161
copyCommonProperties(const QgsRasterRenderer * other,bool copyMinMaxOrigin)162 void QgsRasterRenderer::copyCommonProperties( const QgsRasterRenderer *other, bool copyMinMaxOrigin )
163 {
164 if ( !other )
165 return;
166
167 setOpacity( other->opacity() );
168 setAlphaBand( other->alphaBand() );
169 setRasterTransparency( other->rasterTransparency() ? new QgsRasterTransparency( *other->rasterTransparency() ) : nullptr );
170 setNodataColor( other->nodataColor() );
171 if ( copyMinMaxOrigin )
172 setMinMaxOrigin( other->minMaxOrigin() );
173 }
174
toSld(QDomDocument & doc,QDomElement & element,const QgsStringMap &) const175 void QgsRasterRenderer::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap & ) const
176 {
177 QDomElement rasterSymbolizerElem = doc.createElement( QStringLiteral( "sld:RasterSymbolizer" ) );
178 element.appendChild( rasterSymbolizerElem );
179
180 // add opacity only is different from default
181 if ( !qgsDoubleNear( opacity(), 1.0 ) )
182 {
183 QDomElement opacityElem = doc.createElement( QStringLiteral( "sld:Opacity" ) );
184 opacityElem.appendChild( doc.createTextNode( QString::number( opacity() ) ) );
185 rasterSymbolizerElem.appendChild( opacityElem );
186 }
187 }
188
accept(QgsStyleEntityVisitorInterface *) const189 bool QgsRasterRenderer::accept( QgsStyleEntityVisitorInterface * ) const
190 {
191 return true;
192 }
193