QGIS API Documentation  2.99.0-Master (9caa722)
qgsrasterresamplefilter.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrasterresamplefilter.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 "qgsrasterdataprovider.h"
20 #include "qgsrasterresampler.h"
21 #include "qgsrasterprojector.h"
22 #include "qgsrastertransparency.h"
23 #include "qgsrasterviewport.h"
24 #include "qgsmaptopixel.h"
25 
26 //resamplers
29 
30 #include <QDomDocument>
31 #include <QDomElement>
32 #include <QImage>
33 #include <QPainter>
34 
36  : QgsRasterInterface( input )
37  , mMaxOversampling( 2.0 )
38 {
39 }
40 
42 {
43  QgsDebugMsgLevel( "Entered", 4 );
44  QgsRasterResampleFilter *resampler = new QgsRasterResampleFilter( nullptr );
45  if ( mZoomedInResampler )
46  {
47  resampler->setZoomedInResampler( mZoomedInResampler->clone() );
48  }
49  if ( mZoomedOutResampler )
50  {
51  resampler->setZoomedOutResampler( mZoomedOutResampler->clone() );
52  }
54  return resampler;
55 }
56 
58 {
59  if ( mOn ) return 1;
60 
61  if ( mInput ) return mInput->bandCount();
62 
63  return 0;
64 }
65 
67 {
68  if ( mOn ) return Qgis::ARGB32_Premultiplied;
69 
70  if ( mInput ) return mInput->dataType( bandNo );
71 
72  return Qgis::UnknownDataType;
73 }
74 
76 {
77  QgsDebugMsgLevel( "Entered", 4 );
78 
79  // Resampler can only work with single band ARGB32_Premultiplied
80  if ( !input )
81  {
82  QgsDebugMsg( "No input" );
83  return false;
84  }
85 
86  if ( !mOn )
87  {
88  // In off mode we can connect to anything
89  QgsDebugMsgLevel( "OK", 4 );
90  mInput = input;
91  return true;
92  }
93 
94  if ( input->bandCount() < 1 )
95  {
96  QgsDebugMsg( "No input band" );
97  return false;
98  }
99 
100  if ( input->dataType( 1 ) != Qgis::ARGB32_Premultiplied &&
101  input->dataType( 1 ) != Qgis::ARGB32 )
102  {
103  QgsDebugMsg( "Unknown input data type" );
104  return false;
105  }
106 
107  mInput = input;
108  QgsDebugMsgLevel( "OK", 4 );
109  return true;
110 }
111 
113 {
114  mZoomedInResampler.reset( r );
115 }
116 
118 {
119  mZoomedOutResampler.reset( r );
120 }
121 
122 QgsRasterBlock *QgsRasterResampleFilter::block( int bandNo, QgsRectangle const &extent, int width, int height, QgsRasterBlockFeedback *feedback )
123 {
124  Q_UNUSED( bandNo );
125  QgsDebugMsgLevel( QString( "width = %1 height = %2 extent = %3" ).arg( width ).arg( height ).arg( extent.toString() ), 4 );
126  std::unique_ptr< QgsRasterBlock > outputBlock( new QgsRasterBlock() );
127  if ( !mInput )
128  return outputBlock.release();
129 
130  double oversampling = 1.0; // approximate global oversampling factor
131 
133  {
134  QgsRasterDataProvider *provider = dynamic_cast<QgsRasterDataProvider *>( mInput->sourceInput() );
135  if ( provider && ( provider->capabilities() & QgsRasterDataProvider::Size ) )
136  {
137  double xRes = extent.width() / width;
138  double providerXRes = provider->extent().width() / provider->xSize();
139  double pixelRatio = xRes / providerXRes;
140  oversampling = ( pixelRatio > mMaxOversampling ) ? mMaxOversampling : pixelRatio;
141  QgsDebugMsgLevel( QString( "xRes = %1 providerXRes = %2 pixelRatio = %3 oversampling = %4" ).arg( xRes ).arg( providerXRes ).arg( pixelRatio ).arg( oversampling ), 4 );
142  }
143  else
144  {
145  // We don't know exact data source resolution (WMS) so we expect that
146  // server data have higher resolution (which is not always true) and use
147  // mMaxOversampling
148  oversampling = mMaxOversampling;
149  }
150  }
151 
152  QgsDebugMsgLevel( QString( "oversampling %1" ).arg( oversampling ), 4 );
153 
154  int bandNumber = 1;
155 
156  // Do no oversampling if no resampler for zoomed in / zoomed out (nearest neighbour)
157  // We do mZoomedInResampler if oversampling == 1 (otherwise for example reprojected
158  // zoom in rasters are never resampled because projector limits resolution.
159  if ( ( ( oversampling < 1.0 || qgsDoubleNear( oversampling, 1.0 ) ) && !mZoomedInResampler ) || ( oversampling > 1.0 && !mZoomedOutResampler ) )
160  {
161  QgsDebugMsgLevel( "No oversampling.", 4 );
162  return mInput->block( bandNumber, extent, width, height, feedback );
163  }
164 
165  //effective oversampling factors are different to global one because of rounding
166  double oversamplingX = ( static_cast< double >( width ) * oversampling ) / width;
167  double oversamplingY = ( static_cast< double >( height ) * oversampling ) / height;
168 
169  // TODO: we must also increase the extent to get correct result on borders of parts
170 
171  int resWidth = width * oversamplingX;
172  int resHeight = height * oversamplingY;
173 
174  std::unique_ptr< QgsRasterBlock > inputBlock( mInput->block( bandNumber, extent, resWidth, resHeight, feedback ) );
175  if ( !inputBlock || inputBlock->isEmpty() )
176  {
177  QgsDebugMsg( "No raster data!" );
178  return outputBlock.release();
179  }
180 
181  if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) )
182  {
183  return outputBlock.release();
184  }
185 
186  //resample image
187  QImage img = inputBlock->image();
188 
189  QImage dstImg = QImage( width, height, QImage::Format_ARGB32_Premultiplied );
190 
191  if ( mZoomedInResampler && ( oversamplingX < 1.0 || qgsDoubleNear( oversampling, 1.0 ) ) )
192  {
193  QgsDebugMsgLevel( "zoomed in resampling", 4 );
194  mZoomedInResampler->resample( img, dstImg );
195  }
196  else if ( mZoomedOutResampler && oversamplingX > 1.0 )
197  {
198  QgsDebugMsgLevel( "zoomed out resampling", 4 );
199  mZoomedOutResampler->resample( img, dstImg );
200  }
201  else
202  {
203  // Should not happen
204  QgsDebugMsg( "Unexpected resampling" );
205  dstImg = img.scaled( width, height );
206  }
207 
208  outputBlock->setImage( &dstImg );
209 
210  return outputBlock.release(); // No resampling
211 }
212 
213 void QgsRasterResampleFilter::writeXml( QDomDocument &doc, QDomElement &parentElem ) const
214 {
215  if ( parentElem.isNull() )
216  {
217  return;
218  }
219 
220  QDomElement rasterRendererElem = doc.createElement( QStringLiteral( "rasterresampler" ) );
221 
222  rasterRendererElem.setAttribute( QStringLiteral( "maxOversampling" ), QString::number( mMaxOversampling ) );
223  if ( mZoomedInResampler )
224  {
225  rasterRendererElem.setAttribute( QStringLiteral( "zoomedInResampler" ), mZoomedInResampler->type() );
226  }
227  if ( mZoomedOutResampler )
228  {
229  rasterRendererElem.setAttribute( QStringLiteral( "zoomedOutResampler" ), mZoomedOutResampler->type() );
230  }
231  parentElem.appendChild( rasterRendererElem );
232 }
233 
234 void QgsRasterResampleFilter::readXml( const QDomElement &filterElem )
235 {
236  if ( filterElem.isNull() )
237  {
238  return;
239  }
240 
241  mMaxOversampling = filterElem.attribute( QStringLiteral( "maxOversampling" ), QStringLiteral( "2.0" ) ).toDouble();
242 
243  QString zoomedInResamplerType = filterElem.attribute( QStringLiteral( "zoomedInResampler" ) );
244  if ( zoomedInResamplerType == QLatin1String( "bilinear" ) )
245  {
247  }
248  else if ( zoomedInResamplerType == QLatin1String( "cubic" ) )
249  {
251  }
252 
253  QString zoomedOutResamplerType = filterElem.attribute( QStringLiteral( "zoomedOutResampler" ) );
254  if ( zoomedOutResamplerType == QLatin1String( "bilinear" ) )
255  {
257  }
258 }
virtual QgsRectangle extent() const override=0
Returns the extent of the layer.
virtual int bandCount() const =0
Get number of bands.
A rectangle specified with double values.
Definition: qgsrectangle.h:38
Cubic Raster Resampler.
Interface for resampling rasters (e.g.
virtual QgsRectangle extent() const
Get the extent of the interface.
#define QgsDebugMsg(str)
Definition: qgslogger.h:37
virtual QgsRasterInterface * input() const
Current input.
DataType
Raster data types.
Definition: qgis.h:74
Resample filter pipe for rasters.
QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
virtual Qgis::DataType dataType(int bandNo) const =0
Returns data type for the band specified by number.
void readXml(const QDomElement &filterElem) override
Sets base class members from xml. Usually called from create() methods of subclasses.
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:210
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition: qgis.h:89
Raster data container.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:38
virtual QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr)=0
Read block of data using given extent and size.
virtual int capabilities() const
Returns a bitmask containing the supported capabilities.
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:123
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
Unknown or unspecified type.
Definition: qgis.h:76
QgsRasterResampleFilter(QgsRasterInterface *input=nullptr)
Base class for processing filters like renderers, reprojector, resampler etc.
double mMaxOversampling
Maximum boundary for oversampling (to avoid too much data traffic). Default: 2.0. ...
bool setInput(QgsRasterInterface *input) override
Set input.
std::unique_ptr< QgsRasterResampler > mZoomedOutResampler
Resampler used if raster resolution is higher than raster resolution (zoomed out). 0 mean no resampling (nearest neighbour)
Qgis::DataType dataType(int bandNo) const override
Returns data type for the band specified by number.
void setZoomedInResampler(QgsRasterResampler *r)
Set resampler for zoomed in scales. Takes ownership of the object.
QgsRasterResampleFilter * clone() const override
Clone itself, create deep copy.
Bilinear Raster Resampler.
void writeXml(QDomDocument &doc, QDomElement &parentElem) const override
Write base class members to xml.
void setZoomedOutResampler(QgsRasterResampler *r)
Set resampler for zoomed out scales. Takes ownership of the object.
std::unique_ptr< QgsRasterResampler > mZoomedInResampler
Resampler used if screen resolution is higher than raster resolution (zoomed in). 0 means no resampli...
QgsRasterInterface * mInput
Feedback object tailored for raster block reading.
virtual int xSize() const
Get raster size.
int bandCount() const override
Get number of bands.
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition: qgis.h:88
virtual const QgsRasterInterface * sourceInput() const
Get source / raw input, the first in pipe, usually provider.
Base class for raster data providers.