1 /***************************************************************************
2                          qgssinglebandcolordatarenderer.cpp
3                          ----------------------------------
4     begin                : January 2012
5     copyright            : (C) 2012 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 "qgssinglebandcolordatarenderer.h"
19 #include "qgsrastertransparency.h"
20 #include "qgsrasterviewport.h"
21 #include <QDomDocument>
22 #include <QDomElement>
23 #include <QImage>
24 #include <memory>
25 
QgsSingleBandColorDataRenderer(QgsRasterInterface * input,int band)26 QgsSingleBandColorDataRenderer::QgsSingleBandColorDataRenderer( QgsRasterInterface *input, int band ):
27   QgsRasterRenderer( input, QStringLiteral( "singlebandcolordata" ) ), mBand( band )
28 {
29 
30 }
31 
clone() const32 QgsSingleBandColorDataRenderer *QgsSingleBandColorDataRenderer::clone() const
33 {
34   QgsSingleBandColorDataRenderer *renderer = new QgsSingleBandColorDataRenderer( nullptr, mBand );
35   renderer->copyCommonProperties( this );
36   return renderer;
37 }
38 
create(const QDomElement & elem,QgsRasterInterface * input)39 QgsRasterRenderer *QgsSingleBandColorDataRenderer::create( const QDomElement &elem, QgsRasterInterface *input )
40 {
41   if ( elem.isNull() )
42   {
43     return nullptr;
44   }
45 
46   int band = elem.attribute( QStringLiteral( "band" ), QStringLiteral( "-1" ) ).toInt();
47   QgsRasterRenderer *r = new QgsSingleBandColorDataRenderer( input, band );
48   r->readXml( elem );
49   return r;
50 }
51 
block(int bandNo,QgsRectangle const & extent,int width,int height,QgsRasterBlockFeedback * feedback)52 QgsRasterBlock *QgsSingleBandColorDataRenderer::block( int bandNo, QgsRectangle  const &extent, int width, int height, QgsRasterBlockFeedback *feedback )
53 {
54   Q_UNUSED( bandNo )
55 
56   std::unique_ptr< QgsRasterBlock > outputBlock( new QgsRasterBlock() );
57   if ( !mInput )
58   {
59     return outputBlock.release();
60   }
61 
62   std::unique_ptr< QgsRasterBlock > inputBlock( mInput->block( mBand, extent, width, height, feedback ) );
63   if ( !inputBlock || inputBlock->isEmpty() )
64   {
65     QgsDebugMsg( QStringLiteral( "No raster data!" ) );
66     return outputBlock.release();
67   }
68 
69   bool hasTransparency = usesTransparency();
70   if ( !hasTransparency )
71   {
72     // Nothing to do, just retype if necessary
73     inputBlock->convert( Qgis::ARGB32_Premultiplied );
74     return inputBlock.release();
75   }
76 
77   if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) )
78   {
79     return outputBlock.release();
80   }
81 
82   // make sure input is also premultiplied!
83   inputBlock->convert( Qgis::ARGB32_Premultiplied );
84 
85   QRgb *inputBits = ( QRgb * )inputBlock->bits();
86   QRgb *outputBits = ( QRgb * )outputBlock->bits();
87   for ( qgssize i = 0; i < ( qgssize )width * height; i++ )
88   {
89     QRgb c = inputBits[i];
90     outputBits[i] = qRgba( mOpacity * qRed( c ), mOpacity * qGreen( c ), mOpacity * qBlue( c ), mOpacity * qAlpha( c ) );
91   }
92 
93   return outputBlock.release();
94 }
95 
writeXml(QDomDocument & doc,QDomElement & parentElem) const96 void QgsSingleBandColorDataRenderer::writeXml( QDomDocument &doc, QDomElement &parentElem ) const
97 {
98   if ( parentElem.isNull() )
99     return;
100 
101   QDomElement rasterRendererElem = doc.createElement( QStringLiteral( "rasterrenderer" ) );
102   _writeXml( doc, rasterRendererElem );
103   rasterRendererElem.setAttribute( QStringLiteral( "band" ), mBand );
104   parentElem.appendChild( rasterRendererElem );
105 }
106 
usesBands() const107 QList<int> QgsSingleBandColorDataRenderer::usesBands() const
108 {
109   QList<int> bandList;
110   if ( mBand != -1 )
111   {
112     bandList << mBand;
113   }
114   return bandList;
115 }
116 
setInput(QgsRasterInterface * input)117 bool QgsSingleBandColorDataRenderer::setInput( QgsRasterInterface *input )
118 {
119   // Renderer can only work with numerical values in at least 1 band
120   if ( !input ) return false;
121 
122   if ( !mOn )
123   {
124     // In off mode we can connect to anything
125     mInput = input;
126     return true;
127   }
128 
129   if ( input->dataType( 1 ) == Qgis::ARGB32 ||
130        input->dataType( 1 ) == Qgis::ARGB32_Premultiplied )
131   {
132     mInput = input;
133     return true;
134   }
135   return false;
136 }
137