QGIS API Documentation  2.17.0-Master (eef6f05)
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  , mZoomedInResampler( nullptr )
38  , mZoomedOutResampler( nullptr )
39  , mMaxOversampling( 2.0 )
40 {
41 }
42 
44 {
45  delete mZoomedInResampler;
46  delete mZoomedOutResampler;
47 }
48 
50 {
51  QgsDebugMsgLevel( "Entered", 4 );
52  QgsRasterResampleFilter * resampler = new QgsRasterResampleFilter( nullptr );
53  if ( mZoomedInResampler )
54  {
56  }
57  if ( mZoomedOutResampler )
58  {
60  }
62  return resampler;
63 }
64 
66 {
67  if ( mOn ) return 1;
68 
69  if ( mInput ) return mInput->bandCount();
70 
71  return 0;
72 }
73 
75 {
76  if ( mOn ) return QGis::ARGB32_Premultiplied;
77 
78  if ( mInput ) return mInput->dataType( bandNo );
79 
80  return QGis::UnknownDataType;
81 }
82 
84 {
85  QgsDebugMsgLevel( "Entered", 4 );
86 
87  // Resampler can only work with single band ARGB32_Premultiplied
88  if ( !input )
89  {
90  QgsDebugMsg( "No input" );
91  return false;
92  }
93 
94  if ( !mOn )
95  {
96  // In off mode we can connect to anything
97  QgsDebugMsgLevel( "OK", 4 );
98  mInput = input;
99  return true;
100  }
101 
102  if ( input->bandCount() < 1 )
103  {
104  QgsDebugMsg( "No input band" );
105  return false;
106  }
107 
108  if ( input->dataType( 1 ) != QGis::ARGB32_Premultiplied &&
109  input->dataType( 1 ) != QGis::ARGB32 )
110  {
111  QgsDebugMsg( "Unknown input data type" );
112  return false;
113  }
114 
115  mInput = input;
116  QgsDebugMsgLevel( "OK", 4 );
117  return true;
118 }
119 
121 {
122  delete mZoomedInResampler;
123  mZoomedInResampler = r;
124 }
125 
127 {
128  delete mZoomedOutResampler;
130 }
131 
132 QgsRasterBlock * QgsRasterResampleFilter::block( int bandNo, QgsRectangle const & extent, int width, int height )
133 {
134  return block2( bandNo, extent, width, height );
135 }
136 
137 QgsRasterBlock * QgsRasterResampleFilter::block2( int bandNo, QgsRectangle const & extent, int width, int height, QgsRasterBlockFeedback* feedback )
138 {
139  Q_UNUSED( bandNo );
140  QgsDebugMsgLevel( QString( "width = %1 height = %2 extent = %3" ).arg( width ).arg( height ).arg( extent.toString() ), 4 );
141  QgsRasterBlock *outputBlock = new QgsRasterBlock();
142  if ( !mInput ) return outputBlock;
143 
144  double oversampling = 1.0; // approximate global oversampling factor
145 
147  {
148  QgsRasterDataProvider *provider = dynamic_cast<QgsRasterDataProvider*>( mInput->srcInput() );
149  if ( provider && ( provider->capabilities() & QgsRasterDataProvider::Size ) )
150  {
151  double xRes = extent.width() / width;
152  double providerXRes = provider->extent().width() / provider->xSize();
153  double pixelRatio = xRes / providerXRes;
154  oversampling = ( pixelRatio > mMaxOversampling ) ? mMaxOversampling : pixelRatio;
155  QgsDebugMsgLevel( QString( "xRes = %1 providerXRes = %2 pixelRatio = %3 oversampling = %4" ).arg( xRes ).arg( providerXRes ).arg( pixelRatio ).arg( oversampling ), 4 );
156  }
157  else
158  {
159  // We don't know exact data source resolution (WMS) so we expect that
160  // server data have higher resolution (which is not always true) and use
161  // mMaxOversampling
162  oversampling = mMaxOversampling;
163  }
164  }
165 
166  QgsDebugMsgLevel( QString( "oversampling %1" ).arg( oversampling ), 4 );
167 
168  int bandNumber = 1;
169 
170  // Do no oversampling if no resampler for zoomed in / zoomed out (nearest neighbour)
171  // We do mZoomedInResampler if oversampling == 1 (otherwise for example reprojected
172  // zoom in rasters are never resampled because projector limits resolution.
173  if ((( oversampling < 1.0 || qgsDoubleNear( oversampling, 1.0 ) ) && !mZoomedInResampler ) || ( oversampling > 1.0 && !mZoomedOutResampler ) )
174  {
175  QgsDebugMsgLevel( "No oversampling.", 4 );
176  delete outputBlock;
177  return mInput->block2( bandNumber, extent, width, height, feedback );
178  }
179 
180  //effective oversampling factors are different to global one because of rounding
181  double oversamplingX = ( static_cast< double >( width ) * oversampling ) / width;
182  double oversamplingY = ( static_cast< double >( height ) * oversampling ) / height;
183 
184  // TODO: we must also increase the extent to get correct result on borders of parts
185 
186  int resWidth = width * oversamplingX;
187  int resHeight = height * oversamplingY;
188 
189  QgsRasterBlock *inputBlock = mInput->block2( bandNumber, extent, resWidth, resHeight, feedback );
190  if ( !inputBlock || inputBlock->isEmpty() )
191  {
192  QgsDebugMsg( "No raster data!" );
193  delete inputBlock;
194  return outputBlock;
195  }
196 
197  if ( !outputBlock->reset( QGis::ARGB32_Premultiplied, width, height ) )
198  {
199  delete inputBlock;
200  return outputBlock;
201  }
202 
203  //resample image
204  QImage img = inputBlock->image();
205 
206  QImage dstImg = QImage( width, height, QImage::Format_ARGB32_Premultiplied );
207 
208  if ( mZoomedInResampler && ( oversamplingX < 1.0 || qgsDoubleNear( oversampling, 1.0 ) ) )
209  {
210  QgsDebugMsgLevel( "zoomed in resampling", 4 );
211  mZoomedInResampler->resample( img, dstImg );
212  }
213  else if ( mZoomedOutResampler && oversamplingX > 1.0 )
214  {
215  QgsDebugMsgLevel( "zoomed out resampling", 4 );
216  mZoomedOutResampler->resample( img, dstImg );
217  }
218  else
219  {
220  // Should not happen
221  QgsDebugMsg( "Unexpected resampling" );
222  dstImg = img.scaled( width, height );
223  }
224 
225  outputBlock->setImage( &dstImg );
226 
227  delete inputBlock;
228  return outputBlock; // No resampling
229 }
230 
232 {
233  if ( parentElem.isNull() )
234  {
235  return;
236  }
237 
238  QDomElement rasterRendererElem = doc.createElement( "rasterresampler" );
239 
240  rasterRendererElem.setAttribute( "maxOversampling", QString::number( mMaxOversampling ) );
241  if ( mZoomedInResampler )
242  {
243  rasterRendererElem.setAttribute( "zoomedInResampler", mZoomedInResampler->type() );
244  }
245  if ( mZoomedOutResampler )
246  {
247  rasterRendererElem.setAttribute( "zoomedOutResampler", mZoomedOutResampler->type() );
248  }
249  parentElem.appendChild( rasterRendererElem );
250 }
251 
253 {
254  if ( filterElem.isNull() )
255  {
256  return;
257  }
258 
259  mMaxOversampling = filterElem.attribute( "maxOversampling", "2.0" ).toDouble();
260 
261  QString zoomedInResamplerType = filterElem.attribute( "zoomedInResampler" );
262  if ( zoomedInResamplerType == "bilinear" )
263  {
265  }
266  else if ( zoomedInResamplerType == "cubic" )
267  {
269  }
270 
271  QString zoomedOutResamplerType = filterElem.attribute( "zoomedOutResampler" );
272  if ( zoomedOutResamplerType == "bilinear" )
273  {
275  }
276 }
QgsRasterBlock * block2(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
virtual int bandCount() const =0
Get number of bands.
A rectangle specified with double values.
Definition: qgsrectangle.h:35
Cubic Raster Resampler.
QGis::DataType dataType(int bandNo) const override
Returns data type for the band specified by number.
Unknown or unspecified type.
Definition: qgis.h:135
Interface for resampling rasters (e.g.
QDomNode appendChild(const QDomNode &newChild)
QString attribute(const QString &name, const QString &defValue) const
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
virtual void resample(const QImage &srcImage, QImage &dstImage)=0
virtual QgsRasterInterface * input() const
Current input.
Resample filter pipe for rasters.
void readXML(const QDomElement &filterElem) override
Sets base class members from xml.
double toDouble(bool *ok) const
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:353
virtual QgsRasterBlock * block2(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr)
Read block of data using given extent and size.
QgsRasterResampler * mZoomedOutResampler
Resampler used if raster resolution is higher than raster resolution (zoomed out).
QString toString(bool automaticPrecision=false) const
returns string representation of form xmin,ymin xmax,ymax
QString number(int n, int base)
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition: qgis.h:150
Raster data container.
virtual QString type() const =0
bool setImage(const QImage *image)
set image.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:34
virtual int capabilities() const
Returns a bitmask containing the supported capabilities.
void setAttribute(const QString &name, const QString &value)
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:207
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition: qgis.h:148
bool isEmpty() const
Returns true if block is empty, i.e.
virtual QGis::DataType dataType(int bandNo) const =0
Returns data type for the band specified by number.
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).
bool reset(QGis::DataType theDataType, int theWidth, int theHeight)
Reset block.
bool setInput(QgsRasterInterface *input) override
Set input.
QImage image() const
Get image if type is color.
bool isNull() const
virtual QgsRectangle extent() override=0
Get the extent of the data source.
virtual QgsRectangle extent()
Get the extent of the interface.
QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height) override
Read block of data using given extent and size.
void setZoomedInResampler(QgsRasterResampler *r)
Set resampler for zoomed in scales.
QgsRasterResampleFilter * clone() const override
Clone itself, create deep copy.
Bilinear Raster Resampler.
DataType
Raster data types.
Definition: qgis.h:133
virtual QgsRasterResampler * clone() const =0
void setZoomedOutResampler(QgsRasterResampler *r)
Set resampler for zoomed out scales.
QgsRasterResampler * mZoomedInResampler
Resampler used if screen resolution is higher than raster resolution (zoomed in). ...
virtual const QgsRasterInterface * srcInput() const
Get source / raw input, the first in pipe, usually provider.
void writeXML(QDomDocument &doc, QDomElement &parentElem) const override
Write base class members to xml.
QDomElement createElement(const QString &tagName)
QgsRasterInterface * mInput
Feedback object tailored for raster block reading.
virtual int xSize() const
Get raster size.
QImage scaled(int width, int height, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const
int bandCount() const override
Get number of bands.
Base class for raster data providers.