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