QGIS API Documentation  3.20.0-Odense (decaadbb31)
qgsgdalutils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsgdalutils.cpp
3  ----------------
4  begin : September 2018
5  copyright : (C) 2018 Even Rouault
6  email : even.rouault at spatialys.com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsgdalutils.h"
17 #include "qgslogger.h"
19 #include "qgssettings.h"
20 
21 #define CPL_SUPRESS_CPLUSPLUS //#spellok
22 #include "gdal.h"
23 #include "gdalwarper.h"
24 #include "cpl_string.h"
25 
26 #include <QNetworkProxy>
27 #include <QString>
28 #include <QImage>
29 
30 bool QgsGdalUtils::supportsRasterCreate( GDALDriverH driver )
31 {
32  QString driverShortName = GDALGetDriverShortName( driver );
33  if ( driverShortName == QLatin1String( "SQLite" ) )
34  {
35  // it supports Create() but only for vector side
36  return false;
37  }
38  char **driverMetadata = GDALGetMetadata( driver, nullptr );
39  return CSLFetchBoolean( driverMetadata, GDAL_DCAP_CREATE, false ) &&
40  CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER, false );
41 }
42 
43 gdal::dataset_unique_ptr QgsGdalUtils::createSingleBandMemoryDataset( GDALDataType dataType, const QgsRectangle &extent, int width, int height, const QgsCoordinateReferenceSystem &crs )
44 {
45  return createMultiBandMemoryDataset( dataType, 1, extent, width, height, crs );
46 }
47 
48 gdal::dataset_unique_ptr QgsGdalUtils::createMultiBandMemoryDataset( GDALDataType dataType, int bands, const QgsRectangle &extent, int width, int height, const QgsCoordinateReferenceSystem &crs )
49 {
50  GDALDriverH hDriverMem = GDALGetDriverByName( "MEM" );
51  if ( !hDriverMem )
52  {
53  return gdal::dataset_unique_ptr();
54  }
55 
56  gdal::dataset_unique_ptr hSrcDS( GDALCreate( hDriverMem, "", width, height, bands, dataType, nullptr ) );
57 
58  double cellSizeX = extent.width() / width;
59  double cellSizeY = extent.height() / height;
60  double geoTransform[6];
61  geoTransform[0] = extent.xMinimum();
62  geoTransform[1] = cellSizeX;
63  geoTransform[2] = 0;
64  geoTransform[3] = extent.yMinimum() + ( cellSizeY * height );
65  geoTransform[4] = 0;
66  geoTransform[5] = -cellSizeY;
67 
68  GDALSetProjection( hSrcDS.get(), crs.toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED_GDAL ).toLatin1().constData() );
69  GDALSetGeoTransform( hSrcDS.get(), geoTransform );
70  return hSrcDS;
71 }
72 
73 gdal::dataset_unique_ptr QgsGdalUtils::createSingleBandTiffDataset( const QString &filename, GDALDataType dataType, const QgsRectangle &extent, int width, int height, const QgsCoordinateReferenceSystem &crs )
74 {
75  double cellSizeX = extent.width() / width;
76  double cellSizeY = extent.height() / height;
77  double geoTransform[6];
78  geoTransform[0] = extent.xMinimum();
79  geoTransform[1] = cellSizeX;
80  geoTransform[2] = 0;
81  geoTransform[3] = extent.yMinimum() + ( cellSizeY * height );
82  geoTransform[4] = 0;
83  geoTransform[5] = -cellSizeY;
84 
85  GDALDriverH hDriver = GDALGetDriverByName( "GTiff" );
86  if ( !hDriver )
87  {
88  return gdal::dataset_unique_ptr();
89  }
90 
91  // Create the output file.
92  gdal::dataset_unique_ptr hDstDS( GDALCreate( hDriver, filename.toLocal8Bit().constData(), width, height, 1, dataType, nullptr ) );
93  if ( !hDstDS )
94  {
95  return gdal::dataset_unique_ptr();
96  }
97 
98  // Write out the projection definition.
99  GDALSetProjection( hDstDS.get(), crs.toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED_GDAL ).toLatin1().constData() );
100  GDALSetGeoTransform( hDstDS.get(), geoTransform );
101  return hDstDS;
102 }
103 
105 {
106  if ( image.isNull() )
107  return nullptr;
108 
109  const QRgb *rgb = reinterpret_cast<const QRgb *>( image.constBits() );
110  GDALDriverH hDriverMem = GDALGetDriverByName( "MEM" );
111  if ( !hDriverMem )
112  {
113  return nullptr;
114  }
115  gdal::dataset_unique_ptr hSrcDS( GDALCreate( hDriverMem, "", image.width(), image.height(), 0, GDT_Byte, nullptr ) );
116 
117  char **papszOptions = QgsGdalUtils::papszFromStringList( QStringList()
118  << QStringLiteral( "PIXELOFFSET=%1" ).arg( sizeof( QRgb ) )
119  << QStringLiteral( "LINEOFFSET=%1" ).arg( image.bytesPerLine() )
120  << QStringLiteral( "DATAPOINTER=%1" ).arg( reinterpret_cast< qulonglong >( rgb ) + 2 ) );
121  GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
122  CSLDestroy( papszOptions );
123 
124  papszOptions = QgsGdalUtils::papszFromStringList( QStringList()
125  << QStringLiteral( "PIXELOFFSET=%1" ).arg( sizeof( QRgb ) )
126  << QStringLiteral( "LINEOFFSET=%1" ).arg( image.bytesPerLine() )
127  << QStringLiteral( "DATAPOINTER=%1" ).arg( reinterpret_cast< qulonglong >( rgb ) + 1 ) );
128  GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
129  CSLDestroy( papszOptions );
130 
131  papszOptions = QgsGdalUtils::papszFromStringList( QStringList()
132  << QStringLiteral( "PIXELOFFSET=%1" ).arg( sizeof( QRgb ) )
133  << QStringLiteral( "LINEOFFSET=%1" ).arg( image.bytesPerLine() )
134  << QStringLiteral( "DATAPOINTER=%1" ).arg( reinterpret_cast< qulonglong >( rgb ) ) );
135  GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
136  CSLDestroy( papszOptions );
137 
138  papszOptions = QgsGdalUtils::papszFromStringList( QStringList()
139  << QStringLiteral( "PIXELOFFSET=%1" ).arg( sizeof( QRgb ) )
140  << QStringLiteral( "LINEOFFSET=%1" ).arg( image.bytesPerLine() )
141  << QStringLiteral( "DATAPOINTER=%1" ).arg( reinterpret_cast< qulonglong >( rgb ) + 3 ) );
142  GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
143  CSLDestroy( papszOptions );
144 
145  return hSrcDS;
146 }
147 
148 bool QgsGdalUtils::resampleSingleBandRaster( GDALDatasetH hSrcDS, GDALDatasetH hDstDS, GDALResampleAlg resampleAlg, const char *pszCoordinateOperation )
149 {
150  gdal::warp_options_unique_ptr psWarpOptions( GDALCreateWarpOptions() );
151  psWarpOptions->hSrcDS = hSrcDS;
152  psWarpOptions->hDstDS = hDstDS;
153 
154  psWarpOptions->nBandCount = 1;
155  psWarpOptions->panSrcBands = reinterpret_cast< int * >( CPLMalloc( sizeof( int ) * 1 ) );
156  psWarpOptions->panDstBands = reinterpret_cast< int * >( CPLMalloc( sizeof( int ) * 1 ) );
157  psWarpOptions->panSrcBands[0] = 1;
158  psWarpOptions->panDstBands[0] = 1;
159 
160  psWarpOptions->eResampleAlg = resampleAlg;
161 
162  // Establish reprojection transformer.
163  char **papszOptions = nullptr;
164  if ( pszCoordinateOperation != nullptr )
165  papszOptions = CSLSetNameValue( papszOptions, "COORDINATE_OPERATION", pszCoordinateOperation );
166  psWarpOptions->pTransformerArg = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, papszOptions );
167  CSLDestroy( papszOptions );
168 
169  if ( ! psWarpOptions->pTransformerArg )
170  {
171  return false;
172  }
173 
174  psWarpOptions->pfnTransformer = GDALGenImgProjTransform;
175 
176  // Initialize and execute the warp operation.
177  GDALWarpOperation oOperation;
178  oOperation.Initialize( psWarpOptions.get() );
179 
180  const bool retVal { oOperation.ChunkAndWarpImage( 0, 0, GDALGetRasterXSize( hDstDS ), GDALGetRasterYSize( hDstDS ) ) == CE_None };
181  GDALDestroyGenImgProjTransformer( psWarpOptions->pTransformerArg );
182  return retVal;
183 }
184 
185 QImage QgsGdalUtils::resampleImage( const QImage &image, QSize outputSize, GDALRIOResampleAlg resampleAlg )
186 {
188  if ( !srcDS )
189  return QImage();
190 
191  GDALRasterIOExtraArg extra;
192  INIT_RASTERIO_EXTRA_ARG( extra );
193  extra.eResampleAlg = resampleAlg;
194 
195  QImage res( outputSize, image.format() );
196  if ( res.isNull() )
197  return QImage();
198 
199  GByte *rgb = reinterpret_cast<GByte *>( res.bits() );
200 
201  CPLErr err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 1 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 2, outputSize.width(),
202  outputSize.height(), GDT_Byte, sizeof( QRgb ), res.bytesPerLine(), &extra );
203  if ( err != CE_None )
204  {
205  QgsDebugMsg( QStringLiteral( "failed to read red band" ) );
206  return QImage();
207  }
208 
209  err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 2 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 1, outputSize.width(),
210  outputSize.height(), GDT_Byte, sizeof( QRgb ), res.bytesPerLine(), &extra );
211  if ( err != CE_None )
212  {
213  QgsDebugMsg( QStringLiteral( "failed to read green band" ) );
214  return QImage();
215  }
216 
217  err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 3 ), GF_Read, 0, 0, image.width(), image.height(), rgb, outputSize.width(),
218  outputSize.height(), GDT_Byte, sizeof( QRgb ), res.bytesPerLine(), &extra );
219  if ( err != CE_None )
220  {
221  QgsDebugMsg( QStringLiteral( "failed to read blue band" ) );
222  return QImage();
223  }
224 
225  err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 4 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 3, outputSize.width(),
226  outputSize.height(), GDT_Byte, sizeof( QRgb ), res.bytesPerLine(), &extra );
227  if ( err != CE_None )
228  {
229  QgsDebugMsg( QStringLiteral( "failed to read alpha band" ) );
230  return QImage();
231  }
232 
233  return res;
234 }
235 
236 QString QgsGdalUtils::helpCreationOptionsFormat( const QString &format )
237 {
238  QString message;
239  GDALDriverH myGdalDriver = GDALGetDriverByName( format.toLocal8Bit().constData() );
240  if ( myGdalDriver )
241  {
242  // first report details and help page
243  char **GDALmetadata = GDALGetMetadata( myGdalDriver, nullptr );
244  message += QLatin1String( "Format Details:\n" );
245  message += QStringLiteral( " Extension: %1\n" ).arg( CSLFetchNameValue( GDALmetadata, GDAL_DMD_EXTENSION ) );
246  message += QStringLiteral( " Short Name: %1" ).arg( GDALGetDriverShortName( myGdalDriver ) );
247  message += QStringLiteral( " / Long Name: %1\n" ).arg( GDALGetDriverLongName( myGdalDriver ) );
248  message += QStringLiteral( " Help page: http://www.gdal.org/%1\n\n" ).arg( CSLFetchNameValue( GDALmetadata, GDAL_DMD_HELPTOPIC ) );
249 
250  // next get creation options
251  // need to serialize xml to get newlines, should we make the basic xml prettier?
252  CPLXMLNode *psCOL = CPLParseXMLString( GDALGetMetadataItem( myGdalDriver,
253  GDAL_DMD_CREATIONOPTIONLIST, "" ) );
254  char *pszFormattedXML = CPLSerializeXMLTree( psCOL );
255  if ( pszFormattedXML )
256  message += QString( pszFormattedXML );
257  if ( psCOL )
258  CPLDestroyXMLNode( psCOL );
259  if ( pszFormattedXML )
260  CPLFree( pszFormattedXML );
261  }
262  return message;
263 }
264 
265 char **QgsGdalUtils::papszFromStringList( const QStringList &list )
266 {
267  char **papszRetList = nullptr;
268  const auto constList = list;
269  for ( const QString &elem : constList )
270  {
271  papszRetList = CSLAddString( papszRetList, elem.toLocal8Bit().constData() );
272  }
273  return papszRetList;
274 }
275 
276 QString QgsGdalUtils::validateCreationOptionsFormat( const QStringList &createOptions, const QString &format )
277 {
278  GDALDriverH myGdalDriver = GDALGetDriverByName( format.toLocal8Bit().constData() );
279  if ( ! myGdalDriver )
280  return QStringLiteral( "invalid GDAL driver" );
281 
282  char **papszOptions = papszFromStringList( createOptions );
283  // get error string?
284  int ok = GDALValidateCreationOptions( myGdalDriver, papszOptions );
285  CSLDestroy( papszOptions );
286 
287  if ( !ok )
288  return QStringLiteral( "Failed GDALValidateCreationOptions() test" );
289  return QString();
290 }
291 
292 #if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(3,2,0)
293 
294 GDALDatasetH GDALAutoCreateWarpedVRTEx( GDALDatasetH hSrcDS, const char *pszSrcWKT, const char *pszDstWKT, GDALResampleAlg eResampleAlg,
295  double dfMaxError, const GDALWarpOptions *psOptionsIn, char **papszTransformerOptions )
296 {
297  VALIDATE_POINTER1( hSrcDS, "GDALAutoCreateWarpedVRT", nullptr );
298 
299  /* -------------------------------------------------------------------- */
300  /* Populate the warp options. */
301  /* -------------------------------------------------------------------- */
302  GDALWarpOptions *psWO = nullptr;
303  if ( psOptionsIn != nullptr )
304  psWO = GDALCloneWarpOptions( psOptionsIn );
305  else
306  psWO = GDALCreateWarpOptions();
307 
308  psWO->eResampleAlg = eResampleAlg;
309 
310  psWO->hSrcDS = hSrcDS;
311 
312  GDALWarpInitDefaultBandMapping( psWO, GDALGetRasterCount( hSrcDS ) );
313 
314  /* -------------------------------------------------------------------- */
315  /* Setup no data values */
316  /* -------------------------------------------------------------------- */
317  for ( int i = 0; i < psWO->nBandCount; i++ )
318  {
319  GDALRasterBandH rasterBand = GDALGetRasterBand( psWO->hSrcDS, psWO->panSrcBands[i] );
320 
321  int hasNoDataValue;
322  double noDataValue = GDALGetRasterNoDataValue( rasterBand, &hasNoDataValue );
323 
324  if ( hasNoDataValue )
325  {
326  // Check if the nodata value is out of range
327  int bClamped = FALSE;
328  int bRounded = FALSE;
329  CPL_IGNORE_RET_VAL(
330  GDALAdjustValueToDataType( GDALGetRasterDataType( rasterBand ),
331  noDataValue, &bClamped, &bRounded ) );
332  if ( !bClamped )
333  {
334  GDALWarpInitNoDataReal( psWO, -1e10 );
335 
336  psWO->padfSrcNoDataReal[i] = noDataValue;
337  psWO->padfDstNoDataReal[i] = noDataValue;
338  }
339  }
340  }
341 
342  if ( psWO->padfDstNoDataReal != nullptr )
343  {
344  if ( CSLFetchNameValue( psWO->papszWarpOptions, "INIT_DEST" ) == nullptr )
345  {
346  psWO->papszWarpOptions =
347  CSLSetNameValue( psWO->papszWarpOptions, "INIT_DEST", "NO_DATA" );
348  }
349  }
350 
351  /* -------------------------------------------------------------------- */
352  /* Create the transformer. */
353  /* -------------------------------------------------------------------- */
354  psWO->pfnTransformer = GDALGenImgProjTransform;
355 
356  char **papszOptions = nullptr;
357  if ( pszSrcWKT != nullptr )
358  papszOptions = CSLSetNameValue( papszOptions, "SRC_SRS", pszSrcWKT );
359  if ( pszDstWKT != nullptr )
360  papszOptions = CSLSetNameValue( papszOptions, "DST_SRS", pszDstWKT );
361  papszOptions = CSLMerge( papszOptions, papszTransformerOptions );
362  psWO->pTransformerArg =
363  GDALCreateGenImgProjTransformer2( psWO->hSrcDS, nullptr,
364  papszOptions );
365  CSLDestroy( papszOptions );
366 
367  if ( psWO->pTransformerArg == nullptr )
368  {
369  GDALDestroyWarpOptions( psWO );
370  return nullptr;
371  }
372 
373  /* -------------------------------------------------------------------- */
374  /* Figure out the desired output bounds and resolution. */
375  /* -------------------------------------------------------------------- */
376  double adfDstGeoTransform[6] = { 0.0 };
377  int nDstPixels = 0;
378  int nDstLines = 0;
379  CPLErr eErr =
380  GDALSuggestedWarpOutput( hSrcDS, psWO->pfnTransformer,
381  psWO->pTransformerArg,
382  adfDstGeoTransform, &nDstPixels, &nDstLines );
383  if ( eErr != CE_None )
384  {
385  GDALDestroyTransformer( psWO->pTransformerArg );
386  GDALDestroyWarpOptions( psWO );
387  return nullptr;
388  }
389 
390  /* -------------------------------------------------------------------- */
391  /* Update the transformer to include an output geotransform */
392  /* back to pixel/line coordinates. */
393  /* */
394  /* -------------------------------------------------------------------- */
395  GDALSetGenImgProjTransformerDstGeoTransform(
396  psWO->pTransformerArg, adfDstGeoTransform );
397 
398  /* -------------------------------------------------------------------- */
399  /* Do we want to apply an approximating transformation? */
400  /* -------------------------------------------------------------------- */
401  if ( dfMaxError > 0.0 )
402  {
403  psWO->pTransformerArg =
404  GDALCreateApproxTransformer( psWO->pfnTransformer,
405  psWO->pTransformerArg,
406  dfMaxError );
407  psWO->pfnTransformer = GDALApproxTransform;
408  GDALApproxTransformerOwnsSubtransformer( psWO->pTransformerArg, TRUE );
409  }
410 
411  /* -------------------------------------------------------------------- */
412  /* Create the VRT file. */
413  /* -------------------------------------------------------------------- */
414  GDALDatasetH hDstDS
415  = GDALCreateWarpedVRT( hSrcDS, nDstPixels, nDstLines,
416  adfDstGeoTransform, psWO );
417 
418  GDALDestroyWarpOptions( psWO );
419 
420  if ( pszDstWKT != nullptr )
421  GDALSetProjection( hDstDS, pszDstWKT );
422  else if ( pszSrcWKT != nullptr )
423  GDALSetProjection( hDstDS, pszSrcWKT );
424  else if ( GDALGetGCPCount( hSrcDS ) > 0 )
425  GDALSetProjection( hDstDS, GDALGetGCPProjection( hSrcDS ) );
426  else
427  GDALSetProjection( hDstDS, GDALGetProjectionRef( hSrcDS ) );
428 
429  return hDstDS;
430 }
431 #endif
432 
433 
435  GDALDatasetH hSrcDS,
436  const char *pszSrcWKT,
437  const char *pszDstWKT,
438  GDALResampleAlg eResampleAlg,
439  double dfMaxError,
440  const GDALWarpOptions *psOptionsIn )
441 {
442  char **opts = nullptr;
443  if ( GDALGetMetadata( hSrcDS, "RPC" ) )
444  {
445  // well-behaved RPC should have height offset a good value for RPC_HEIGHT
446  const char *heightOffStr = GDALGetMetadataItem( hSrcDS, "HEIGHT_OFF", "RPC" );
447  if ( heightOffStr )
448  opts = CSLAddNameValue( opts, "RPC_HEIGHT", heightOffStr );
449  }
450 
451  return GDALAutoCreateWarpedVRTEx( hSrcDS, pszSrcWKT, pszDstWKT, eResampleAlg, dfMaxError, psOptionsIn, opts );
452 }
453 
454 void *QgsGdalUtils::rpcAwareCreateTransformer( GDALDatasetH hSrcDS, GDALDatasetH hDstDS, char **papszOptions )
455 {
456  char **opts = CSLDuplicate( papszOptions );
457  if ( GDALGetMetadata( hSrcDS, "RPC" ) )
458  {
459  // well-behaved RPC should have height offset a good value for RPC_HEIGHT
460  const char *heightOffStr = GDALGetMetadataItem( hSrcDS, "HEIGHT_OFF", "RPC" );
461  if ( heightOffStr )
462  opts = CSLAddNameValue( opts, "RPC_HEIGHT", heightOffStr );
463  }
464  void *transformer = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, opts );
465  CSLDestroy( opts );
466  return transformer;
467 }
468 
469 #ifndef QT_NO_NETWORKPROXY
471 {
472  // Check proxy configuration, they are application level but
473  // instead of adding an API and complex signal/slot connections
474  // given the limited cost of checking them on every provider instantiation
475  // we can do it here so that new settings are applied whenever a new layer
476  // is created.
477  QgsSettings settings;
478  // Check that proxy is enabled
479  if ( settings.value( QStringLiteral( "proxy/proxyEnabled" ), false ).toBool() )
480  {
481  // Get the first configured proxy
482  QList<QNetworkProxy> proxies( QgsNetworkAccessManager::instance()->proxyFactory()->queryProxy( ) );
483  if ( ! proxies.isEmpty() )
484  {
485  QNetworkProxy proxy( proxies.first() );
486  // TODO/FIXME: check excludes (the GDAL config options are global, we need a per-connection config option)
487  //QStringList excludes;
488  //excludes = settings.value( QStringLiteral( "proxy/proxyExcludedUrls" ), "" ).toStringList();
489 
490  QString proxyHost( proxy.hostName() );
491  qint16 proxyPort( proxy.port() );
492 
493  QString proxyUser( proxy.user() );
494  QString proxyPassword( proxy.password() );
495 
496  if ( ! proxyHost.isEmpty() )
497  {
498  QString connection( proxyHost );
499  if ( proxyPort )
500  {
501  connection += ':' + QString::number( proxyPort );
502  }
503  CPLSetConfigOption( "GDAL_HTTP_PROXY", connection.toUtf8() );
504  if ( ! proxyUser.isEmpty( ) )
505  {
506  QString credentials( proxyUser );
507  if ( ! proxyPassword.isEmpty( ) )
508  {
509  credentials += ':' + proxyPassword;
510  }
511  CPLSetConfigOption( "GDAL_HTTP_PROXYUSERPWD", credentials.toUtf8() );
512  }
513  }
514  }
515  }
516 }
517 #endif
This class represents a coordinate reference system (CRS).
@ WKT_PREFERRED_GDAL
Preferred format for conversion of CRS to WKT for use with the GDAL library.
QString toWkt(WktVariant variant=WKT1_GDAL, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
static QString helpCreationOptionsFormat(const QString &format)
Gets creation options metadata for a given format.
static bool resampleSingleBandRaster(GDALDatasetH hSrcDS, GDALDatasetH hDstDS, GDALResampleAlg resampleAlg, const char *pszCoordinateOperation)
Resamples a single band raster to the destination dataset with different resolution (and possibly wit...
static GDALDatasetH rpcAwareAutoCreateWarpedVrt(GDALDatasetH hSrcDS, const char *pszSrcWKT, const char *pszDstWKT, GDALResampleAlg eResampleAlg, double dfMaxError, const GDALWarpOptions *psOptionsIn)
This is a copy of GDALAutoCreateWarpedVRT optimized for imagery using RPC georeferencing that also se...
static bool supportsRasterCreate(GDALDriverH driver)
Reads whether a driver supports GDALCreate() for raster purposes.
static gdal::dataset_unique_ptr createSingleBandTiffDataset(const QString &filename, GDALDataType dataType, const QgsRectangle &extent, int width, int height, const QgsCoordinateReferenceSystem &crs)
Creates a new single band TIFF dataset with given parameters.
static gdal::dataset_unique_ptr createSingleBandMemoryDataset(GDALDataType dataType, const QgsRectangle &extent, int width, int height, const QgsCoordinateReferenceSystem &crs)
Creates a new single band memory dataset with given parameters.
static QString validateCreationOptionsFormat(const QStringList &createOptions, const QString &format)
Validates creation options for a given format, regardless of layer.
static gdal::dataset_unique_ptr imageToMemoryDataset(const QImage &image)
Converts an image to a GDAL memory dataset by borrowing image data.
static void * rpcAwareCreateTransformer(GDALDatasetH hSrcDS, GDALDatasetH hDstDS=nullptr, char **papszOptions=nullptr)
This is a wrapper around GDALCreateGenImgProjTransformer2() that takes into account RPC georeferencin...
static void setupProxy()
Sets the gdal proxy variables.
static char ** papszFromStringList(const QStringList &list)
Helper function.
static QImage resampleImage(const QImage &image, QSize outputSize, GDALRIOResampleAlg resampleAlg)
Resamples a QImage image using GDAL resampler.
static gdal::dataset_unique_ptr createMultiBandMemoryDataset(GDALDataType dataType, int bands, const QgsRectangle &extent, int width, int height, const QgsCoordinateReferenceSystem &crs)
Creates a new multi band memory dataset with given parameters.
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:198
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:230
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
std::unique_ptr< std::remove_pointer< GDALDatasetH >::type, GDALDatasetCloser > dataset_unique_ptr
Scoped GDAL dataset.
Definition: qgsogrutils.h:136
std::unique_ptr< GDALWarpOptions, GDALWarpOptionsDeleter > warp_options_unique_ptr
Scoped GDAL warp options.
Definition: qgsogrutils.h:151
void * GDALDatasetH
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
const QgsCoordinateReferenceSystem & crs